STM32串口通讯printf函数实现
- 格式:docx
- 大小:44.87 KB
- 文档页数:1
通过串口利用printf函数输出数据一。
printf函数格式printf函数具有强大的输出功能%表示格式化字符串输出目前printf支持以下格式的输出,例如:printf("%c",a);输出单个字符。
printf("%d",a);输出十进制整数。
printf("%f",a);输出十进制浮点数.printf("%o",a);输出八进制数。
printf("%s",a);输出字符串。
printf("%u",a);输出无符号十进制数。
printf("%x",a);输出十六进制数。
例如:n = 15printf("The result is %d", n); //通过屏幕输出十进制数15n = 15.2printf("The result is %f", n); //通过屏幕输出十进制浮点数15 二。
实现方法在uart.c文件中加入#include "stdio.h"////////////////////////////////////////////////////////////////// //加入以下代码,支持printf函数,而不需要选择use MicroLIB #if 1#pragma import(__use_no_semihosting)//标准库需要的支持函数struct __FILE{int handle;};FILE __stdout;//定义_sys_exit()以避免使用半主机模式_sys_exit(int x){x = x;}//重定义fputc函数int fputc(int ch, FILE *f){while((USART1->SR&0X40)==0);//把数据通过串口1循环发送,直到发送完毕 ,如果使用串口2,则改成 USART2USART1->DR = (u8) ch;return ch;}#endif三。
在STM32中使用printf发送字符串到串口
问题:在使用STM32 调试时,经常使用串口发送信息,为了方便调试与
串口发送信息,用printf()函数实现通过串口打印信息。
方法一:
1.添加包含printf()函数的头文件:#include “stdio.h”
2.重写stdio.h 头文件中的int fputc(int ch, FILE *f) 函数
int fputc(int ch, FILE *f)
{
while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
//等待先前的字符发送完成
USART_SendData(USART1, (uint8_t) ch);
//发送字符
return ch;
}
//示例函数中使用了USART1 来发送消息
//实际情况可以根据硬件板来决定使用哪个串口
注意:使用while 循环先等待先前的字符发送完成,避免造成字符串首字符发
送丢失的问题。
3.将该函数” int fputc(int ch, FILE *f) “放在main()函数能够调用到的文件中,KEIL->Options for Target’xxx’->Target->Code Generation,勾选Use MicroLIB
方法二:
//加入以下代码,支持printf 函数,而不需要选择use MicroLIB
#if USART_DEBUG。
STM32之串口通信标签: stm32串口通信usartit分类:STM32实验目的:实现利用串口1 不停的打印一个信息到电脑上,同时接收从串口发过来的数据,把发送过来的数据直接送回给电脑。
实验平台:基于STM32F103C8T6的彩屏开发板硬件接口:注意:因为我的开发板上的串口和LED 共用了PA9和PA10,所以在使用USART1时务必屏蔽LED ,不然两者会互相影响而导致实现现象无法呈现。
相关寄存器:1,串口时钟使能。
串口作为STM32 的一个外设,其时钟由外设时钟使能寄存器控制,这 里我们使用的串口1 是在APB2ENR 寄存器的第14 位。
2,串口复位。
串口1 的复位是通过配置APB2RSTR 寄存器的第14 位来实现的。
通过向该位写1来复位串口1,写0 结束复位。
3,串口波特率设置。
每个串口都有一个自己独立的波特率寄存器USART_BRR波特率的计算,STM32 的串口波特率计算公式如下:上式中,是给串口的时钟(PCLK1 用于USART2、3、4、5,PCLK2 用于USART1);USARTDIV是一个无符号定点数。
我们只要得到USARTDIV 的值,就可以得到串口波特率寄存器USART1->BRR 的值。
4,串口控制。
STM32 的每个串口都有3 个控制寄存器USART_CR1~3,串口的很多配置都是通过这3 个寄存器来设置的5,数据发送与接收。
STM32 的发送与接收是通过数据寄存器USART_DR 来实现的,这是一个双寄存器,包含了TDR 和RDR。
6,串口状态。
串口的状态可以通过状态寄存器USART_SR 读取。
(注:详细的介绍使用请参考ST公司的数据手册)程序设计:(注:本人的usart.cusart.hdelay.cdelay.hsys.csys.h是引用网上一位网友整理的)usart.h#ifndef __USART_H#define __USART_H#include <stm32f10x_lib.h>#include "stdio.h"extern u8 USART_RX_BUF[64]; //接收缓冲,最大63个字节.末字节为换行符extern u8 USART_RX_STA; //接收状态标记//如果想串口中断接收,请不要注释以下宏定义#define EN_USART1_RX //使能串口1接收voiduart_init(u32 pclk2,u32 bound);#endifusart.c#include "sys.h"#include "usart.h"//加入以下代码,支持printf函数,而不需要选择use MicroLIB#if 1#pragma import(__use_no_semihosting)//标准库需要的支持函数struct __FILE{int handle;};FILE __stdout;//定义_sys_exit()以避免使用半主机模式_sys_exit(int x){x = x;}//重定义fputc函数intfputc(intch, FILE *f){while((USART1->SR&0X40)==0);//循环发送,直到发送完毕USART1->DR = (u8) ch;returnch;}#endif//end//////////////////////////////////////////////////////////////////#ifdef EN_USART1_RX //如果使能了接收//串口1中断服务程序//注意,读取USARTx->SR能避免莫名其妙的错误u8 USART_RX_BUF[64]; //接收缓冲,最大64个字节.//接收状态//bit7,接收完成标志//bit6,接收到0x0d//bit5~0,接收到的有效字节数目u8 USART_RX_STA=0; //接收状态标记void USART1_IRQHandler(void){u8 res;if(USART1->SR&(1<<5))//接收到数据{res=USART1->DR;if((USART_RX_STA&0x80)==0)//接收未完成{if(USART_RX_STA&0x40)//接收到了0x0d{if(res!=0x0a)USART_RX_STA=0;//接收错误,重新开始elseUSART_RX_STA|=0x80; //接收完成了}else //还没收到0X0D{if(res==0x0d)USART_RX_STA|=0x40;else{USART_RX_BUF[USART_RX_STA&0X3F]=res;USART_RX_STA++;if(USART_RX_STA>63)USART_RX_STA=0;//接收数据错误,重新开始接收}}}}}#endif//该函数的重点就是判断接收是否完成,通过检测是否收到0X0D、0X0A 的连续2 个字节//(0X0D 后跟0X0A 表示回车键)来检测是否结束。
[1楼] 正点原子等级:站长注册时间:2010/12/02 10:41 回复数: 43927 这等于你自己重构了一个printf接用写不够用过我的淘宝小店:主题数: 356酷贴数:25论坛积分:47495 来自: 湖南离线 回复[2楼] licgang等级:注册时间:2012/06/19 11:08 回复数: 20主题数: 5论坛积分:35离线现在是要用printf较麻烦,输出的格式有点多回复[3楼] 正点原子等级:站长注册时间:2010/12/02 10:41 回复数: 43927主题数: 356酷贴数:25论坛积分:47495来自: 湖南离线哦的实现方法我的淘宝小店: 回复[4楼] licgang等级:注册时间:2012/06/19 11:08 回复数: 20主题数: 5论坛积分:35离线这两天有空研究了下数,参照网上资料自己写了个模拟现多串口其实变参数的获取了,这里要用到stdarg.h问题了。
void myitoa(int data,char *buf ){int temp,j=0,i=0;while(data) //反序生成数字,可自己取个数字测试,如123,反序字符数组中的值为321{buf[i++] = data%10+'0';//将转换后的数字字符存放在字符数组中data = data/10; //删除已经转换的数字,为取下一个数字做好准备}buf[i--]='\0'; //转换完后还需要在字符数组后面加一个字符串结束标志'/0',代表是一个字符串while( j < i ) //刚刚转换好的字符串是逆序的必须把它反转过来{temp = buf[j];buf[j] = buf[i];buf[i] = temp;i--,j++;}}//------------------------COM3 printf------------------------------//void DBGprintf(const char*format, ...){va_list ap;char c,nc;va_start(ap, format);//从右到左将参数入栈,ap指向formatwhile (c = *format++){if(c == '%'&&(nc = *format++) != '\0'){switch(nc){case 'c': //输出1个字符{char ch = va_arg(ap, int); //调用后栈回复[5楼] 正点原子可以写成形如myprintf(u8 uartx,const char *format, ...)其中等级:站长注册时间:2010/12/02 10:41 回复数: 43927主题数: 356酷贴数:25论坛积分:47495来自: 湖南离线如1,2,3,4,5对应串口1~5.后见面的两个参数就是标准的printf参数了.这样使用起来更方便.我的淘宝小店: 回复2012/08/05 11:54[6楼] licgang等级:注册时间:2012/06/19 11:08 回复数: 20主题数: 5论坛积分:35离线后面是要这样写方便些,贴出代码来主要是让大家看下,顺便测试看有没有什么问题,目前测试都还正常刚才测试打印INT整数,发现STM32int是32位的,上面程序默认的INT类型是有符号的,超出0x7fffffff,输出不正常。
STM32串⼝接收、发送数据实验-程序代码分析串⼝通信实验Printf⽀持printf向串⼝发送⼀些字符串数据。
如果使⽤串⼝2,可以修改while((USART1->SR&0X40)==0);和USART1->DR = (u8) ch; 中的USART1为USART2.//加⼊以下代码,⽀持printf函数,⽽不需要选择use MicroLIB#if 1#pragma import(__use_no_semihosting)//解决HAL库使⽤时,某些情况可能报错的bugint _ttywrch(int ch){ch=ch;return ch;}//标准库需要的⽀持函数struct __FILE{int handle;/* Whatever you require here. If the only file you are using is *//* standard output using printf() for debugging, no file handling *//* is required. */};/* FILE is typedef’ d in stdio.h. */FILE __stdout;//定义_sys_exit()以避免使⽤半主机模式void _sys_exit(int x){x = x;}//重定义fputc函数int fputc(int ch, FILE *f){while((USART1->SR&0X40)==0);//循环发送,直到发送完毕USART1->DR = (u8) ch;return ch;}#endif实验现象从电脑串⼝助⼿发送长度为200以内任意长度的字符串给STM32串⼝1(字符串以回车换⾏标识结束),STM32接收到字符串之后,⼀次性通过串⼝1把所有数据返回给电脑。
实现过程把每个接收到的数据保存在⼀个程序定义的Buffer数组中(数组长度为200),同时把接收到的数据个数保存在定义的变量中。
记录stm32f407使⽤hal库,串⼝2重定向到printf的⼀些问题(已解决)⼤致介绍在使⽤usart2时,使⽤中断传输进⾏printf会出现异常。
使⽤阻塞传输⽆问题。
在usart1中⽆问题。
在GD32F407中⽆问题。
直接使⽤中断传输⽆问题。
使⽤代码正常配置串⼝,勾选microlib库,重写fputcint fputc(int ch, FILE *f){while(HAL_UART_Transmit_IT(&huart2, (unsigned char *)&ch, 1)!=HAL_OK){};return ch;}结果只配置usart2时,使⽤printf打印,只能接收到0x0C;同时配置了usart1时,使⽤printf打印,只能接收到0x14;同时配置usart3时,使⽤printf打印,只能接收到0x16;同时配置usart6时,使⽤printf打印,只能接收到0x1e;原因所在在查询串⼝相关的讯息时,考虑到不使⽤microlib库打印会如何。
加⼊标准库⽀持后,打印正常。
#pragma import(__use_no_semihosting)//标准库需要的⽀持函数struct __FILE{int handle;};FILE __stdout;/*** @brief 定义_sys_exit()以避免使⽤半主机模式* @param void* @return void*/void _sys_exit(int x){x = x;}同时发现,使⽤微库时,优化等级也会造成影响。
在-o3,-o2,-o1时时,除了usart1以外,其他的均会出现以上情况。
-o0时,⼀切正常。
(以上均是仅测试usart1,usart2,usart3)。
考虑到有在⽹上见到过:选上Use MicroLIB,例如你⽤printf()函数的时候,就会从串⼝1输出字符串,直接默认定向到串⼝1。
法1可实现串⼝1数据输出,但要定向到串⼝2,串⼝3,microLIB就不合⽤了;这样的⾔论,也许有⼀定关系吧。
STM32HAL库UART使⽤printf// 添加这个函数int fputc(int ch,FILE *f){uint8_t temp[1]={ch};HAL_UART_Transmit(&UartHandle,temp,1,2);}MDK设置:勾选Use Micro LIB测试板⼦:STM32F746NG-DISCOVERYmain.c⽂件/* Includes ------------------------------------------------------------------*/#include "main.h"#include <stdio.h>/** @addtogroup STM32F7xx_HAL_Examples* @{*//** @addtogroup UART_TwoBoards_ComDMA* @{*//* Private typedef -----------------------------------------------------------*//* Private define ------------------------------------------------------------*/#define TRANSMITTER_BOARD/* Private macro -------------------------------------------------------------*//* Private variables ---------------------------------------------------------*//* UART handler declaration */UART_HandleTypeDef UartHandle;__IO ITStatus UartReady = RESET;__IO uint32_t UserButtonStatus = 0; /* set to 1 after User Button interrupt *//* Buffer used for transmission */uint8_t aTxBuffer[] = " ****UART_TwoBoards communication based on DMA**** ****UART_TwoBoards communication based on DMA**** ****UART_TwoBoards communication based on DMA**** "; /* Buffer used for reception */uint8_t aRxBuffer[RXBUFFERSIZE];/* Private function prototypes -----------------------------------------------*/void SystemClock_Config(void);static void Error_Handler(void);static uint16_t Buffercmp(uint8_t* pBuffer1, uint8_t* pBuffer2, uint16_t BufferLength);static void MPU_Config(void);static void CPU_CACHE_Enable(void);/* Private functions ---------------------------------------------------------*/UART_HandleTypeDef UartHandle;uint8_t sendbuf[]="send ok ";// 添加这个函数int fputc(int ch,FILE *f){uint8_t temp[1]={ch};HAL_UART_Transmit(&UartHandle,temp,1,2);/*** @brief Main program* @param None* @retval None*/int main(void){/* Configure the MPU attributes as Write Through */MPU_Config();/* Enable the CPU Cache */CPU_CACHE_Enable();/* STM32F7xx HAL library initialization:- Configure the Flash ART accelerator- Systick timer is configured by default as source of time base, but usercan eventually implement his proper time base source (a general purpose timer for example or other time source), keeping in mind that Time baseduration should be kept 1ms since PPP_TIMEOUT_VALUEs are defined and handled in milliseconds basis.- Set NVIC Group Priority to 4- Low Level Initialization*/HAL_Init();/* Configure the system clock to 216 MHz */SystemClock_Config();/* Configure LED1 */BSP_LED_Init(LED1);UartHandle.Instance = DISCOVERY_COM1;UartHandle.Init.BaudRate = 9600;UartHandle.Init.WordLength = UART_WORDLENGTH_8B;UartHandle.Init.StopBits = UART_STOPBITS_1;UartHandle.Init.Parity = UART_PARITY_NONE;UartHandle.Init.HwFlowCtl = UART_HWCONTROL_NONE;UartHandle.Init.Mode = UART_MODE_TX_RX;BSP_COM_DeInit(COM1,&UartHandle);BSP_COM_Init(COM1,&UartHandle);// HAL_UART_Transmit(&UartHandle,sendbuf,sizeof(sendbuf),10);/* Configure User push-button in Interrupt mode */BSP_PB_Init(BUTTON_KEY, BUTTON_MODE_EXTI);/* Wait for User push-button press before starting the Communication.In the meantime, LED1 is blinking */printf("hello");while(UserButtonStatus == 0){/* Toggle LED1*/BSP_LED_Toggle(LED1);HAL_Delay(100);}/* Turn on LED1 if test passes then enter infinite loop */BSP_LED_On(LED1);/* Infinite loop */while (1){}}/*** @brief System Clock Configuration* The system Clock is configured as follow :* System Clock source = PLL (HSE)* SYSCLK(Hz) = 216000000* HCLK(Hz) = 216000000* AHB Prescaler = 1* APB1 Prescaler = 4* APB2 Prescaler = 2* HSE Frequency(Hz) = 25000000* PLL_M = 25* PLL_N = 432* PLL_P = 2* PLL_Q = 9* VDD(V) = 3.3* Main regulator output voltage = Scale1 mode* Flash Latency(WS) = 7* @param None* @retval None*/void SystemClock_Config(void)RCC_ClkInitTypeDef RCC_ClkInitStruct;RCC_OscInitTypeDef RCC_OscInitStruct;HAL_StatusTypeDef ret = HAL_OK;/* Enable HSE Oscillator and activate PLL with HSE as source */RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;RCC_OscInitStruct.HSEState = RCC_HSE_ON;RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;RCC_OscInitStruct.PLL.PLLM = 25;RCC_OscInitStruct.PLL.PLLN = 432;RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;RCC_OscInitStruct.PLL.PLLQ = 9;ret = HAL_RCC_OscConfig(&RCC_OscInitStruct);if(ret != HAL_OK){while(1) { ; }}/* Activate the OverDrive to reach the 216 MHz Frequency */ret = HAL_PWREx_EnableOverDrive();if(ret != HAL_OK){while(1) { ; }}/* Select PLL as system clock source and configure the HCLK, PCLK1 and PCLK2 clocks dividers */RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2); RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;ret = HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_7);if(ret != HAL_OK){while(1) { ; }}}/*** @brief Tx Transfer completed callback* @param UartHandle: UART handle.* @note This example shows a simple way to report end of DMA Tx transfer, and* you can add your own implementation.* @retval None*/void HAL_UART_TxCpltCallback(UART_HandleTypeDef *UartHandle){/* Set transmission flag: trasfer complete*/UartReady = SET;}/*** @brief Rx Transfer completed callback* @param UartHandle: UART handle* @note This example shows a simple way to report end of DMA Rx transfer, and* you can add your own implementation.* @retval None*/void HAL_UART_RxCpltCallback(UART_HandleTypeDef *UartHandle){/* Set transmission flag: trasfer complete*/UartReady = SET;}/*** @brief UART error callbacks* @param UartHandle: UART handle* @note This example shows a simple way to report transfer error, and you can* add your own implementation.* @retval None*/void HAL_UART_ErrorCallback(UART_HandleTypeDef *UartHandle){Error_Handler();}/*** @brief EXTI line detection callbacks* @param GPIO_Pin: Specifies the pins connected EXTI line* @retval None*/void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin){if(GPIO_Pin == KEY_BUTTON_PIN){UserButtonStatus = 1;}}/*** @brief Compares two buffers.* @param pBuffer1, pBuffer2: buffers to be compared.* @param BufferLength: buffer's length* @retval 0 : pBuffer1 identical to pBuffer2* >0 : pBuffer1 differs from pBuffer2*/static uint16_t Buffercmp(uint8_t* pBuffer1, uint8_t* pBuffer2, uint16_t BufferLength) {while (BufferLength--){if ((*pBuffer1) != *pBuffer2){return BufferLength;}pBuffer1++;pBuffer2++;}return0;}/*** @brief This function is executed in case of error occurrence.* @param None* @retval None*/static void Error_Handler(void){/* Turn LED1 on */BSP_LED_On(LED1);while(1){/* Error if LED1 is slowly blinking (1 sec. period) */BSP_LED_Toggle(LED1);HAL_Delay(1000);}}#ifdef USE_FULL_ASSERT/*** @brief Reports the name of the source file and the source line number* where the assert_param error has occurred.* @param file: pointer to the source file name* @param line: assert_param error line source number* @retval None*/void assert_failed(uint8_t* file, uint32_t line){/* User can add his own implementation to report the file name and line number, ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) *//* Infinite loop */while (1){}}#endif/*** @brief Configure the MPU attributes as Write Through for SRAM1/2.* @note The Base Address is 0x20010000 since this memory interface is the AXI. * The Region Size is 256KB, it is related to SRAM1 and SRAM2 memory size. * @param None* @retval None*/static void MPU_Config(void){MPU_Region_InitTypeDef MPU_InitStruct;/* Disable the MPU */HAL_MPU_Disable();/* Configure the MPU attributes as WT for SRAM */MPU_InitStruct.Enable = MPU_REGION_ENABLE;MPU_InitStruct.BaseAddress = 0x20010000;MPU_InitStruct.Size = MPU_REGION_SIZE_256KB;MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE;MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;MPU_InitStruct.Number = MPU_REGION_NUMBER0;MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;MPU_InitStruct.SubRegionDisable = 0x00;MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;HAL_MPU_ConfigRegion(&MPU_InitStruct);/* Enable the MPU */HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);}/*** @brief CPU L1-Cache enable.* @param None* @retval None*/static void CPU_CACHE_Enable(void){/* Enable I-Cache */SCB_EnableICache();/* Enable D-Cache */SCB_EnableDCache();}/*** @}*//*** @}*//************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/。
STM32单片机串口的定义及应用方法一、串口定义:串口是一种通过物理上的串行传输来进行数据传输和通信的接口。
在STM32单片机中,串口是通过UART(通用异步收发传输器)模块来实现的。
在STM32单片机中,UART模块通常包括了多个串口,每个串口都有一个唯一的标识号,比如USART1、USART2等。
每个串口模块通常包括发送和接收两个数据线路,分别是Tx和Rx。
其中,Tx是发送线路,负责将数据从单片机发送出去;Rx是接收线路,负责从外部设备接收数据。
二、应用方法:1.引脚配置:在使用串口之前,需要对引脚进行配置,将引脚设置为串口功能。
具体配置方法如下:a.打开时钟使能,使能UART相应的时钟。
b.配置相应的GPIO引脚为复用功能,选择对应的UART号。
c.设置GPIO的输出模式、输入模式、输出速度等参数。
2.串口参数配置:在使用串口之前,需要对串口进行参数配置,包括波特率、数据位、停止位、奇偶校验等。
具体配置方法如下:a.打开时钟使能,使能UART相应的时钟。
b.设置波特率,将UART的波特率寄存器设置为目标波特率。
c.配置数据位、停止位、奇偶校验等参数。
3.串口中断配置:在串口通信过程中,可以配置串口接收中断和发送中断,实现数据的异步收发。
具体配置方法如下:a.使能串口接收中断和发送中断。
b.在中断服务函数中,处理接收和发送的逻辑,包括接收到数据后的处理操作和发送数据完成后的处理操作。
4.数据发送:使用串口发送数据时,需要按照以下步骤进行操作:a.判断发送缓冲区是否为空,如果不为空,则等待缓冲区为空。
b.将要发送的数据写入发送缓冲区。
c.等待发送完成。
5.数据接收:使用串口接收数据时,需要按照以下步骤进行操作:a.判断接收缓冲区是否为空,如果为空,则等待数据接收完成。
b.从接收缓冲区读取接收到的数据。
6.异步收发:使用STM32单片机的串口功能时,可以实现异步收发的功能,即在发送数据的同时可以接收数据。