STM32串口通讯printf函数实现
通过串口利用printf函数输出数据
通过串口利用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发送字符串到串口
问题:在使用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之串口通信_you are great
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 表示回车键)来检测是否结束。
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,输出不正常。
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),同时把接收到的数据个数保存在定义的变量中。
单片机程序巧用printf
1、在 KEIL 下使用 printf 函数,以 STM32 为例 在 uart.c 中添加如下代码 View Code /************************************************ ******************************* 函数名:fputc 输 入: 输 出:
return (int)USART_ReceiveData(USART1); }
这样,只要在需要用 printf 的文件里#include ;就 可以了,printf 会自已的调用 fputc 函数来实现串口数 据的输出。 2、添加 Retarget.c,实现在 KEIL 下使用 printf 函数, 以 LPC2478 为例
int sendchar (int ch) { // Write character to Serial Port while (!(U0LSR & 0x20)); return (U0THR = ch); } int getkey (void) { // Read character from Serial Port while (!(U0LSR & 0x01)); return (U0RBR); } 这样,只要在需要用 printf 的文件里#include ;就 可以了,printf 会通过 Retarget 中的 fputc 函数调用 sendchar 来实现串口数据的输出。 事实上,和第一种的方式是一样的。 3、自定义 printf 函数,以 AVR 为例 前面介绍的是在 KEIL 编译器上使用 printf 函数,但 不是所有的编译器平台都能适用,因此有时候我们需要
记录stm32f407使用hal库,串口2重定向到printf的一些问题(已解决)
记录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
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单片机串口的定义及应用方法一、串口定义:串口是一种通过物理上的串行传输来进行数据传输和通信的接口。
在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单片机的串口功能时,可以实现异步收发的功能,即在发送数据的同时可以接收数据。
实测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。
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已经全部封装好了,这样能让我们更加专注的写逻辑代码,⽽不⽤再去考虑太多底层配置的问题。
STM32单片机编程printf()函数重定向
STM32单片机编程printf()函数重定向
在stm32 单片机编程中,可以重定向printf()函数来输出调试信息。
编写fputc()函数其实printf()函数在头文件中被定义成了一个宏,会调用到
fputc()函数,但在stm32 单片机编程中不可以直接调用标准库的fputc()函
数进行输出信息,需要自己编写fputc()函数供printf()函数来调用。
编译
器进行编译时首先会调用自己编写的fputc()函数,而不是库函数。
intfputc(int ch,FILE*f)
{
USART_SendData(USART1, (uint16_t)ch); //通过串口输出
while(USART_GetFlagStatus(USART1, USART_FLAG_TC) !=SET);//等待输出完毕
return ch;
}
此时假定串口1 即USART1 可以正常通讯,fputc()函数的作用就是把
printf()函数重定向到串口1 上输出信息。
配置自己动手写好fputc()后,要在文件中包含stdio.h 文件。
#include 在MDK 软件界面单击Target options 按钮,在Code Genetation 一栏中选择Use MicroLIB 选项,即完成了配置,此时printf()函数一定重定向到了串口1 即USART1 上,可以正常使用printf()函数。
tips:感谢大家的阅读,本文由我司
收集整编。
仅供参阅!。
MDK连接JLINKSWO调试STM32输出串口信息到Debug(printf)Viewer
现在最新的mdk和jlink可以在硬件实时调试时实现printf命令输出调试信息到debugviewer窗口来实现上面的功能速度更快连接方便也可以节省串口的两个端口
MDK连接JLINKSWO调试STM32输出串口信息到序时有时需要使用到 printf() 命令将一些调试信息输出到 PC 作为debug 参考。传统方式是用UART的 RX,TX 两个引脚再用一根串口线(现在很多电脑不支持串口)或者USB转串口线连到电脑,然后用串口助手软件来实现。
STM32程序添加printf函数后无法运行的解决方法
标准库函数的默认输出设备是显示器,要实现在串口或LCD输出,必须重定义标准库函数里调用的与输出设备相关的函数.例如:printf输出到串口,需要将fpu tc里面的输出指向串口(重定向),方法如下:#ifdef__GNUC__/* With GCC/RAISON ANCE, smallprintf (option LDLinker->Librar ies->Smallprintfset to 'Yes') calls__io_p utcha r() */#define PUTCHA R_PRO TOTYP E int __io_p utcha r(int ch)#else#define PUTCHA R_PRO TOTYP E int fputc(int ch, FILE *f)#endif/* __GNUC__ */PUTCHA R_PRO TOTYP E{/* Placeyour implem entat ion of fputchere *//* e.g. writea charac ter to the USART*/USART_SendD ata(USART1, (uint8_t) ch);/* Loop untilthe end of transm issio n */while(USART_GetFl agSta tus(USART1, USART_FLAG_TC) == RESET);return ch;}因print f()之类的函数,使用了半主机模式。
使用标准库会导致程序无法运行,以下是解决方法:方法1.使用微库,因为使用微库的话,不会使用半主机模式.方法2.仍然使用标准库,在主程序添加下面代码:#pragma import(__use_no_se mihos ting)_sys_e xit(int x){x = x;}struct __FILE{int handle;/* Whatev er you requir e here. If the only file you are usingis */ /* standa rd output usingprintf() for debugg ing, no file handli ng *//* is requir ed. */};/* FILE is typede f’ d in stdio.h. */FILE __stdo ut;。
stm32重定向printf的原理
stm32重定向printf的原理在STM32的开发中,我们经常需要使用printf函数输出调试信息。
但是,由于STM32没有像PC一样的标准输出设备,我们需要通过串口或LCD等外设来实现printf函数的输出。
本文将介绍如何通过重定向printf函数来实现STM32的调试输出。
1. printf函数的实现原理printf函数是C语言标准库中的一个输出函数,它可以将格式化的字符串输出到标准输出设备上。
在PC机上,标准输出设备一般是控制台窗口,而在STM32上,则需要通过外设来实现。
在C语言中,printf函数的实现是由库函数提供的。
库函数将printf函数中的字符串格式化成一定的格式,然后将格式化后的字符串输出到标准输出设备上。
在PC机上,标准输出设备一般是stdout指向的文件流,而在STM32上,则需要将stdout指向相应的外设。
2. 重定向printf函数的实现原理重定向printf函数的实现原理是将标准输出设备stdout指向外设。
在STM32中,我们可以通过重定向printf函数来将stdout 指向串口或LCD等外设。
2.1 重定向到串口将printf函数重定向到串口,可以将调试信息通过串口输出到PC机上的串口调试助手等工具中,方便调试。
在重定向printf函数到串口前,需要先初始化串口。
以下是串口初始化的代码:```UART_HandleTypeDef huart;void MX_USART_Init(void){huart.Instance = USART1;huart.Init.BaudRate = 115200;huart.Init.WordLength = UART_WORDLENGTH_8B;huart.Init.StopBits = UART_STOPBITS_1;huart.Init.Parity = UART_PARITY_NONE;huart.Init.Mode = UART_MODE_TX_RX;huart.Init.HwFlowCtl = UART_HWCONTROL_NONE;huart.Init.OverSampling = UART_OVERSAMPLING_16;if (HAL_UART_Init(&huart) != HAL_OK){Error_Handler();}}```在初始化串口后,需要重定向printf函数到串口。
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");```在串口接收到数据后,会自动将其发送到电脑终端,用于调试和输出信息。