STM32下多个串口的Printf用法
如何在STM32串口通信程序中使用printf发送数据

如何在STM32串口通信程序中使用printf发送数据
如何在STM32串口通信程序中使用printf发送数据
在STM32串口通信程序中使用printf发送数据,非常的方便。
可在刚开始使用的时候总是遇到问题,常见的是硬件访真时无法进入main主函数,其实只要简单的配置一下就可以了。
下面就说一下使用printf需要做哪些配置。
有两种配置方法:
一、对工程属性进行配置,详细步骤如下
1、首先要在你的main 文件中包含“stdio.h”(标准输入输出头文件)。
2、在main文件中重定义函数如下:
// 发送数据
int fputc(int ch,FILE *f)
{
USART_SendData(USART1,(unsigned char)ch);// USART1 可以换成USART2 等while (!(USART1-》SR return (ch);
}
// 接收数据
int GetKey (void){
while (!(USART1-》SR
return ((int)(USART1-》DR
}
这样在使用printf时就会调用自定义的fputc函数,来发送字符。
3、在工程属性的“Target“-》”Code Generation“选项中勾选”Use MicroLIB“”MicroLIB 是缺省C的备份库,关于它可以到网上查找详细资料。
至此完成配置,在工程中可以随意使用printf向串口发送数据了。
STM32-串口配置与使用

STM32-串⼝配置与使⽤1、通讯基础串⾏通讯与并⾏通讯串⾏通信设备之间通过少量数据信号线(⼀般是 8 根以下),地线以及控制信号线,按数据位形式⼀位⼀位地传输数据。
同⼀时刻只能传输⼀个数据位的数据并⾏通讯使⽤ 8、16、32 及 64 根或更多的数据线进⾏传输的通讯⽅式可同时传输多个数据位的数据全双⼯、半双⼯及单⼯通讯全双⼯在同⼀时刻,两个设备之间可以同时收发数据半双⼯两个设备之间可以收发数据,但不能在同⼀时刻进⾏单⼯在任何时刻都只能进⾏⼀个⽅向的通讯,即⼀个固定为发送设备,另⼀个固定为接收设备同步通讯、异步通讯同步通讯收发设备双⽅使⽤⼀根信号线表⽰时钟信号,在时钟信号的驱动下双⽅进⾏协调,同步数据通讯中通常双⽅会统⼀规定在时钟信号的上升沿或下降沿对数据线进⾏采样异步通讯不使⽤时钟信号进⾏数据同步,直接在数据信号中穿插⼀些同步⽤的信号位,或者把主体数据进⾏打包,以数据帧的格式传输数据某些通讯中需要双⽅约定数据的传输速率,以便更好地同步通讯速率⽐特率(Bitrate)每秒传输的⼆进制位数,单位bis/s波特率(Baudrate)每秒钟传输的码元通讯中常⽤时间间隔相同的符号来表⽰⼀个⼆进制数字,这样的信号称为码元常见波特率4800,9600,1152002、USART串⼝通讯协议层起始和停⽌信号串⼝通讯的⼀个数据包从起始信号开始,直到停⽌信号结束。
数据包的起始信号由⼀个逻辑 0 的数据位表⽰,⽽数据包的停⽌信号可由 0.5、1、1.5 或 2 个逻辑 1 的数据位表⽰,只要双⽅约定⼀致即可。
有效数据在数据包的起始位之后紧接着的就是要传输的主体数据内容,也称为有效数据,有效数据的长度常被约定为 5、6、7 或 8 位长数据校验在有效数据之后,有⼀个可选的数据校验位。
由于数据通信相对更容易受到外部⼲扰导致传输数据出现偏差,可以在传输过程加上校验位来解决这个问题。
校验⽅法有奇校验 (odd)、偶校验(even)、0 校验(space)、1 校验(mark)以及⽆校验(noparity)。
在STM32中使用printf发送字符串到串口

在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多串口公用printf的问题

[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的原理

stm32重定向printf的原理在嵌入式系统中,调试是一个非常重要的环节。
而在调试过程中,printf函数是最常用的调试手段之一。
在STM32中,printf函数默认是向串口发送数据,但是有时候我们需要将printf函数的输出重定向到其他设备或者接口上。
本文将以STM32为例,介绍如何实现printf函数的重定向。
一、printf函数的实现原理printf函数是C语言标准库中的一个输出函数,其原型为:int printf(const char *format, ...);。
printf函数的作用是将格式化的字符串输出到标准输出设备上。
在STM32中,默认情况下,printf 函数的输出设备是串口。
其实现原理如下:1.调用stm32fxxx_hal_uart.c中的HAL_UART_Transmit函数,将格式化的字符串发送到串口中。
2.在stm32fxxx_hal_uart.c中,HAL_UART_Transmit函数通过USARTx_SR寄存器判断发送是否完成,如果未完成,则等待发送完成。
3.发送完成后,HAL_UART_Transmit函数返回。
二、printf函数的重定向在某些情况下,我们需要将printf函数的输出重定向到其他设备或接口上,例如:SD卡、LCD屏幕、WiFi模块等。
这时候,我们需要自定义一个输出函数,并将其与printf函数关联起来,实现printf函数的重定向。
下面,我们将以重定向printf函数输出到LCD 屏幕为例,介绍如何实现printf函数的重定向。
1.定义一个输出函数我们先定义一个输出函数,将其命名为LCD_Printf,其实现原理如下:void LCD_Printf(char *str){/* 将格式化的字符串输出到LCD屏幕上 */}2.将LCD_Printf函数与printf函数关联在main函数中,我们需要将LCD_Printf函数与printf函数关联起来,代码如下:/* 重定向printf函数 */int fputc(int ch, FILE *f){/* 将字符转换成字符串 */char str[2] = {0};str[0] = ch;/* 调用LCD_Printf函数,将字符输出到LCD屏幕上 */LCD_Printf(str);return ch;}在上述代码中,我们定义了一个名为fputc的函数,该函数的作用是将printf函数的输出重定向到LCD屏幕上。
STM32KEIL下的printf函数

L下的 printf函数
1 //加入以下代码,支持printf函数,而不需要选择use MicroLIB 2 #if 1 3 #pragma import(__use_no_semihosting) 4 //标准库需要的支持函数 5 struct __FILE 6{ 7 int handle; 8 9 }; 10 11 FILE __stdout; 12 //定义_sys_exit()以避免使用半主机模式 13 _sys_exit(int x) 14 { 15 x = x; 16 } 17 //重定义fputc函数 18 int fputc(int ch, FILE *f) 19 { 20 //return ITM_SendChar(ch); 21 22 while((USART2->SR&0X40)==0);//循环发送,直到发送完毕 23 USART2->DR = (u8) ch; 24 return ch; 25 } 26 #endif
如上图: 保留这一部分时:
其中 可以更换任意的串口 printf输出用串口发送出去 当 下图圈圈中的部分编译
则 通过JTAG (6线) 打印到SEGGER软件上
但是当串口初始化函数运行了的时候 上面就失效了 原因是?
STM32串口接收、发送数据实验-程序代码分析

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),同时把接收到的数据个数保存在定义的变量中。
STM32串口使用Printf()函数问题

方法 2.仍然使用标准库,在主程序添加下面代码:
/*为确保没有从 C 库链接使用半主机的函数,因为不使用半主机,标准 C 库 stdio.h 中有些使用半主机的 函数要重新写,您必须为这些函数提供自己的实现*/
#pragma import(__use_no_semihosting) //确保没有从 C 库链接使用半主机的函数
PUTCHAR_PROTOTYPE { /* Place your implementation of fputc here */ /* e.g. write a character to the USART */ USART_SendData(USART1, (uint8_t) ch); /* Loop until the end of transmission */ while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET); return ch; }
标准库函数的默认输出设备是显示器,要实现在串口或 LCD 输出,必须重定义标准库函数里调用的与输出 设备相关的函数.
例如:printf 输出到串口,需要将 fputc 里面的输putc(int ch, FILE *f)函数,能够输出字符就可以了
为确保没有从 C 库链接使用半主机的函数,必须导入符号 __use_no_semihosting。可在您工程的
任何 C 或汇编语言源文件中执行此操作,如下所示:
• 在 C 模块中,使用 #pragma 指令: #pragma import(__use_no_semihosting)
• 在汇编语言模块中,使用 IMPORT 指令: IMPORT __use_no_semihosting
_sys_exit(int x) { x = x; }
STM32HAL库UART使用printf

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****/。
实测STM32F4中printf的效率问题

实测STM32F4中printf的效率问题实测STM32F4中printf的效率问题⼀直认为printf所做的⼯作就是格式化字符串,然后依次调⽤fputc函数发送出去。
于是以前都认为printf函数的瓶颈是在fputc这⾥,是因为发送⼀个字节所占的时间太长,才导致printf效率慢。
也就是说,⼀直认为如果串⼝的波特率设置成115200的话,printf⾄少也是能达到115200的波特率的。
⽽这⼏天在学习ucOS,于是想到,如果printf的瓶颈是在等在串⼝发送完成的话,那么我在等待串⼝发送完成中断的时候是不是挂起⼀个信号量,然后就可以去做点别的事情了呢?这也正是RTOS的⽬的之⼀嘛————最⼤化利⽤CPU。
花了点时间时间试了下之后,发现完全没有改善!于是有了测试两次进⼊fputc间隔时间的想法。
测试环境:MDK5.12 + ⾃带STM32F4 HAL层 + UCOS3.04.04硬件平台:安富莱V5板卡,主芯⽚STM32F407IG,USB转串⼝线CH430芯⽚,ThinkPad T420代码如下:int fputc(int ch, FILE *f){OS_ERR err;CPU_TS ts;Dbg_printf_time[Dbg_printf_cnt++] = STK_VAL_REG; //进⼊函数前读取systick的寄存器值Dbg_printf_inter[Dbg_printf_cnt] = Dbg_printf_time[Dbg_printf_cnt-2] - Dbg_printf_time[Dbg_printf_cnt-1];//⽤刚读取的寄存器值减去上⼀次退出该函数的寄存器值,从⽽得到两次进⼊该函数之间的时间 while (HAL_UART_Transmit_IT(&huart, (uint8_t *)&ch, 1) != HAL_OK){OSTaskSemPend(10, OS_OPT_PEND_BLOCKING, &ts, &err);//check “err”}Dbg_printf_time[Dbg_printf_cnt++] = STK_VAL_REG; //退出函数前读取systick的寄存器值Dbg_printf_inter[Dbg_printf_cnt] = Dbg_printf_time[Dbg_printf_cnt-2] - Dbg_printf_time[Dbg_printf_cnt-1];//⽤刚读取的寄存器值减去进⼊该函数的寄存器值,从⽽得到两次进⼊该函数之间的时间if (Dbg_printf_cnt > 90){Dbg_printf_cnt = 1;}return ch;}重点关注Dbg_printf_inter的值,结果如下:可以看到进⼊两次fputc之间的间隔达到了15937个tick,考虑到主频为168M由time=tick/sysfreq可以计算得出time=94.86us。
stm32 printf 用法

stm32 printf 用法题目:stm32 printf 用法详解:从基础用法到高级应用的一步一步回答导语:在嵌入式系统开发中,对于调试和输出信息的需求是不可或缺的。
printf 函数作为一个强大的输出函数,在stm32开发中也有着广泛的应用。
本文将从基础的printf用法开始,逐步深入,介绍stm32 printf的用法和高级应用,助您更好地掌握和运用这一重要工具。
第一步:了解printf函数printf函数是C语言标准库中的一个输出函数,其原型如下:cint printf(const char *format, ...);printf函数的参数是一个格式化字符串(format)和可选的其他参数,用于指定输出格式和内容。
它以变长参数的方式,根据格式化字符串中的占位符,将对应的参数格式化并输出到标准输出。
第二步:配置串口进行printf输出在stm32开发中,一般会使用串口作为printf的输出接口。
首先,我们需要配置相应的串口,设置波特率、数据位、奇偶校验位等参数。
具体配置方法可参考stm32芯片的参考手册和相关资料。
第三步:重定向printf输出为了让printf函数的输出不再通过标准输出进行显示,而是通过串口输出,我们需要进行输出重定向。
在C语言中,可以通过重定义标准输出流(stdout)的方式实现。
下面是一个示例代码:c#include <stdio.h>#include <sys/stat.h>int _write(int file, char *ptr, int len){HAL_UART_Transmit(&huart1, (uint8_t *)ptr, len, 1000); 将输出通过串口发送出去return len;}int main(){printf("Hello, world!\n"); 通过串口输出"Hello, world!"return 0;}在上述代码中,通过实现_write函数,将printf函数的输出通过HAL_UART_Transmit函数发送到串口进行输出。
STM32串口通信中使用PRINTF发送数据配置方法

STM32串口通信中使用PRINTF发送数据配置方法在 STM32 系列微控制器中,使用 Printf 函数进行串口通信是一种常见的开发调试方式。
以下是配置方法的详细步骤:1.配置USART或UART硬件:-启用相应的串口接口,例如USART1或USART2-选择串口引脚并配置为复用功能模式,以便将串口引脚与微控制器的外部引脚相连。
-配置串口的波特率、数据位、停止位、校验位等参数。
2. 配置 Printf 环境:- 在使用 Printf 函数之前,需要在代码中引入相关的库文件,例如stdio.h 和 stdarg.h。
```c#include <stdio.h>#include <stdarg.h>```- 在代码中定义一个 `int fputc(int ch, FILE *f)` 函数,该函数用于重定向 `printf` 输出到串口。
```cint fputc(int ch, FILE *f)/*将待发送的字符写入串口数据寄存器*/USART_SendData(USART1, (uint8_t) ch);/*等待串口发送完毕*/while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);return ch;}```- 在代码中定义一个 `int fgetc(FILE *f)` 函数,该函数用于重定向 `scanf` 输入到串口。
```cint fgetc(FILE *f)/*等待串口接收到数据*/while (USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET);/*读取并返回串口接收到的数据*/return (int)USART_ReceiveData(USART1);}```- 在代码中使用 `setvbuf` 函数将缓冲区大小设置为 0,以便立即输出数据(可选)。
STM32F103C8T6串口输出printf函数内调fputc接口改造硬件分析、CUBE。。。

STM32F103C8T6串⼝输出printf函数内调fputc接⼝改造硬件分析、CUBE。
STM32F103C8T6今天这⼀节教程作为stm32⼊门教程讲解从硬件分析、CUBEMX初始化、 敲代码、代码分析,来领着⼤家对STM32的项⽬过程有个⼤致的了解以及养成建⽴⼀套规范化的⼯程⽂件架构的习惯废话不多说,上⼲货⼀、硬件分析这⾥先不⽤了解太多底层的,因为我们对32的程序上体现的控制基本上已经被封装的很完美了,这⾥推荐⽤HAL库。
简直就像Arduino⼀样的简单,所以说,⼊门32其实不难,但是学通32还是很难的。
所以要加油了!基本的硬件介绍就在笔记中了,看不懂么得关系,咱们先看更⾼⼀层的。
...⼆、CUBEMX的程序代码初始化1、打开cubemx (官⽹最新版本的)2、输⼊STM32F103C8双击这⼀块3、先配置时钟源在RCC⾥⾯的HSE配置的是晶振时钟,配置完成后我们会看到两个相关管脚变成了绿⾊,说明已初始化。
4、配置我们的烧录⽅式引脚5、配置我们的复⽤引脚复⽤,即平时的时候是IO⼝,但是当我们有特殊⽤途的时候,⽐如说UART通信(异步全双⼯串⼝通信)PA9可以作为TX,PA10可作为RX使⽤。
直接在我们的右⾯的可视框图⾥⾯点击相应的引脚配置就OK。
但是配置完之后还是黄⾊的,不是绿⾊的,代表我们还没有完全的配置完毕,不要着急,请看下⼀步。
6、在Connectivity⾥⾯的USART1模式⾥⾯选择异步全双⼯通信模式然后我们引脚就配置好了这⼀块内容就是波特率的设置,⼀般系统⾃动按默认值11520bps,不过我们可以修改;默认的码元是8N1型的,8N1是什么,请看我的另⼀篇⽂章:7、然后在我们的时钟树⾥⾯配置如下图8、在Project Manager中进⾏配置起个⾃⼰想要的名字,配置下路径,配置下想要⽣成的代码适⽤的编译器,这⾥选择MDK-ARM在这⾥勾选上那个,这样⽣成的代码会将不同硬件初始化的代码分开成不同的c⽂件,不集中在⼀个c⽂件⾥⾯,这样就更加⽅便的去调⽤和更改啥的9、然后就最后⼀步⾄此,代码初始化的事⼉已经全部完成,我们在这⾥⾯并没有接触到寄存器啥的,因为这个mx已经全部封装好了,这样能让我们更加专注的写逻辑代码,⽽不⽤再去考虑太多底层配置的问题。
MDK连接JLINKSWO调试STM32输出串口信息到Debug(printf)Viewer

现在最新的mdk和jlink可以在硬件实时调试时实现printf命令输出调试信息到debugviewer窗口来实现上面的功能速度更快连接方便也可以节省串口的两个端口
MDK连接JLINKSWO调试STM32输出串口信息到序时有时需要使用到 printf() 命令将一些调试信息输出到 PC 作为debug 参考。传统方式是用UART的 RX,TX 两个引脚再用一根串口线(现在很多电脑不支持串口)或者USB转串口线连到电脑,然后用串口助手软件来实现。
stm32重定向printf的原理

stm32重定向printf的原理在STM32开发中,我们常常需要使用printf函数输出调试信息。
但是,由于STM32没有像PC一样的标准输出设备(如显示器或串口),因此需要将printf函数重定向到一个输出设备上。
本文将介绍如何在STM32中实现printf函数的重定向,并讨论其原理和实现方法。
一、printf函数的基本原理printf函数是C语言中常用的输出函数,可以将格式化的数据输出到标准输出设备(如显示器或串口)。
其原型为:int printf(const char *format, ...);其中format是格式化字符串,...表示可变参数。
printf函数会将format字符串中的占位符替换成实际的参数,并输出到标准输出设备上。
例如:printf('Hello, %s!', 'world');输出结果为:Hello, world!在PC开发中,printf函数的标准输出设备通常是控制台窗口。
但是,在嵌入式开发中,标准输出设备通常是串口或LCD屏幕等外设,因此需要将printf函数重定向到相应的输出设备上。
二、重定向printf函数的原理在STM32中,如果要将printf函数重定向到串口或LCD屏幕等外设上,需要定义一个名为_putchar的函数,该函数将输出字符送到外设上。
然后,通过重定向stdout流的方式,将printf函数的输出重定向到_putchar函数上。
1. 定义_putchar函数_putchar函数的原型如下:int _putchar(char ch)其中ch为要输出的字符。
在实现_putchar函数时,需要将ch送到串口或LCD屏幕等外设上,具体实现方法取决于外设的驱动方式。
例如,如果要将输出送到串口上,可以使用HAL库提供的串口发送函数:int _putchar(char ch){HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xFFFF);return ch;}上述代码中,HAL_UART_Transmit函数用于将一个字节的数据送到串口上,huart1是串口句柄,1表示数据长度为1字节,0xFFFF表示超时时间为无限大。
stm32中printf函数的用法和配置

stm32中printf函数的用法和配置在STM32中使用printf函数来进行串口打印输出是一种常见的调试手段。
printf函数是C语言标准库中的一个函数,用于格式化输出字符串。
要在STM32中使用printf函数,需要完成以下几个步骤:1.配置串口:首先,需要在STM32的引脚配置中设置相应的引脚为串口模式,并且初始化串口对应的寄存器。
2. 配置printf函数:接下来,需要在代码中重新定义printf函数,使其能够与串口进行通信。
这可以通过重写标准库中的retarget.c文件完成。
3.初始化串口:在主函数中,需要进行串口的初始化,包括波特率、数据位、停止位等参数的配置。
4. 使用printf函数:配置完成后,可以直接在代码中使用printf函数来进行串口打印输出。
具体的配置和用法如下所示:1.配置串口:首先,在STM32的引脚配置中,将相应的引脚设置为串口功能,并初始化串口寄存器。
2. 配置printf函数:需要重新定义printf函数,将输出的数据通过串口发送出去。
可以在标准库的retarget.c文件中,重写以下函数:- int _write(int fd, char 某ptr, int len): 重写该函数,将ptr参数中的数据通过串口发送出去。
- int _read(int fd, char 某ptr, int len): 重写该函数,将串口接收到的数据存储到ptr参数中。
在以上两个函数中,可以使用串口的发送和接收函数来完成相应的操作。
3.初始化串口:在主函数中,需要进行串口的初始化,包括波特率、数据位、停止位等参数的配置。
可以使用CubeMX等工具来配置串口参数,并生成相应的初始化代码。
4. 使用printf函数:配置完成后,可以在代码中使用printf函数来进行串口打印输出。
例如:```cprintf("Hello, World!\n");```在串口接收到数据后,会自动将其发送到电脑终端,用于调试和输出信息。
STM32学习笔记——printf

STM32学习笔记——printfprintf复习当我们写printf("%d\n", 1);的时候,printf函数并不能通过C语⾔语法得知第⼆个参数是int类型。
printf是⼀个变参函数(variadic function):int printf(const char *restrict format, ...);参数的类型都是通过格式串format推导出的。
如果参数类型与格式串中指定的不匹配,或提供的参数数量少于需要的,将导致未定义⾏为。
由于参数类型是动态的,printf和scanf⽐静态类型的std::cout和std::cin慢,前提是后者的众多overhead被⼿动消除。
C为可变参数提供了va_start、va_arg、va_copy、va_end、va_list等⼯具,定义在头⽂件<stdarg.h>中。
va_arg⽤于取出参数,va_copy⽤于拷贝参数供多次使⽤。
引⽤上的例⼦:#include <stdio.h>#include <stdarg.h>#include <math.h>double sample_stddev(int count, ...){/* Compute the mean with args1. */double sum = 0;va_list args1;va_start(args1, count);va_list args2;va_copy(args2, args1); /* copy va_list object */for (int i = 0; i < count; ++i) {double num = va_arg(args1, double);sum += num;}va_end(args1);double mean = sum / count;/* Compute standard deviation with args2 and mean. */double sum_sq_diff = 0;for (int i = 0; i < count; ++i) {double num = va_arg(args2, double);sum_sq_diff += (num-mean) * (num-mean);}va_end(args2);return sqrt(sum_sq_diff / count);}int main(void){printf("%f\n", sample_stddev(4, 25.0, 27.3, 26.9, 25.7));}<stdio.h>还定义了vprintf系列函数,与不带v的相⽐,可变参数...都换成了va_list的实例:int vprintf(const char *format, va_list vlist);可以借此实现⾃⼰的printf。