STM32-串口通信printf重定向

发布者:火箭飞人最新更新时间:2018-06-10 来源: eefocus关键字:STM32  串口通信  printf重定向 手机看文章 扫描二维码
随时随地手机看文章

前言:平时我们进行c语言编程的时候会经常用到printf函数进行打印输出,来调试代码。可是这个printf函数C库已经帮我们实现好了,通常只需要直接调用即可,但是如果在一个新的开发平台,如果库没有帮我们实现好,比如STM32开发板,那么我们怎么实现printf打印输出呢?

首先我们来了解一下串口通信!

1、什么是串口通信?

串口通信(Serial Communication),是指外设和计算机间,通过数据信号线、地线等,按位进行传输数据的一种通讯方式。 
串口是一种接口标准,它规定了接口的电气标准,没有规定接口插件电缆以及使用的协议。


2、串口通信协议

在串口通信中,常用的协议包括RS-232、RS-422和RS-485。 
•RS-232:标准串口,最常用的一种串行通讯接口。有三种类型(A,B和C),它们分别采用不同的电压来表示on和off。最被广泛使用的是RS-232C,它将mark(on)比特的电压定义为-3V到-12V之间,而将space(off)的电压定义到+3V到+12V之间。传送距离最大为约15米,最高速率为20kb/s。RS-232是为点对点(即只用一对收、发设备)通讯而设计的,其驱动器负载为3~7kΩ。所以RS-232适合本地设备之间的通信。 
•RS-422:最大传输距离为1219米,最大传输速率为10Mb/s。其平衡双绞线的长度与传输速率成反比,在100kb/s速率以下,才可能达到最大传输距离。只有在很短的距离下才能获得最高速率传输。一般100米长的双绞线上所能获得的最大传输速率仅为1Mb/s。 
•RS-485:从RS-422基础上发展而来的,最大传输距离约为1219米,最大传输速率为10Mb/s。平衡双绞线的长度与传输速率成反比,在100kb/s速率以下,才可能使用规定最长的电缆长度。只有在很短的距离下才能获得最高速率传输。一般100米长双绞线最大传输速率仅为1Mb/s。

3、同步通信?异步通信?

同步通信:是一种比特同步通信技术,要求发收双方具有同频同相的同步时钟信号,只需在传送报文的最前面附加特定的同步字符,使发收双方建立同步,此后便在同步时钟的控制下逐位发送/接收。如:SPI总线,I2C总线。 
异步通信:指两个互不同步的设备通过计时机制或其他技术进行数据传输。也就是说,双方不需要共同的时钟。发送方可以随时传输数据,而接收方必须在信息到达时准备好接收。如:串口(USART)


4、通信方式


•单工模式(Simplex Communication):单向的数据传输。通信双方中,一方为发送端,一方则为接收端。信息只能沿一个方向传输,使用一根传输线。双方是固定的。 
•半双工模式(Half Duplex):通信使用同一根传输线,既可以发送数据又可以接收数据,但不能同时进行发送和接收。数据传输允许数据在两个方向上传输,但是,在任何时刻只能由其中的一方发送数据,另一方接收数据。 
•全双工模式(Full Duplex)通信允许数据同时在两个方向上传输。因此,全双工通信是两个单工通信方式的结合,它要求发送设备和接收设备都有独立的接收和发送能力。在全双工模式中,每一端都有发送器和接收器,有两条传输线,信息传输效率高。


5、数据格式

(1)起始位:起始位必须是持续一个比特时间的“0”,标志传输一个字符的开始。 
(2)数据位:数据位紧跟在起始位之后,是通信中的真正有效信息。数据位的位数可以由通信双方共同约定,一般可以是5位、7位或8位。传输数据时先传送字符的低位,后传送字符的高位。 
(3)奇偶校验位:奇偶校验位仅占一位,用于进行奇校验或偶校验,奇偶检验位不是必须有的。如果是奇校验,需要保证传输的数据总共有奇数个“1”;如果是偶校验,需要保证传输的数据总共有偶数个“1”

(4)停止位:停止位可以是是1位、1.5位或2位,可以由软件设定。它一定是“1”,标志着传输一个字符的结束。 


了解了串口通信的基础知识之后,我们再来看看STM32开发板上是如何实现串口通信的,我以实现printf重定向为例来进行分析!

先看代码:

main.c:

  1. #include "printf.h"  

  2.   

  3. int main()  

  4. {       

  5.     printf_init();    

  6.         printf("\nhello!every body!\n");  

  7.     printf("I am zoulei\n");  

  8.     printf("serial communications is so  mystical and interesting!\n");  

  9.     printf("keep striving!\n");  

  10.       

  11. }  


printf.c:


  1. #include "printf.h"  

  2. #include "stm32f10x.h"       

  3. #include "stm32f10x_rcc.h"  

  4. #include "stm32f10x_gpio.h"  

  5. #include "stm32f10x_usart.h"       

  6. #include "misc.h"     

  7. int fputc(int ch,FILE *f)  

  8. {    

  9.     while(USART_GetFlagStatus(USART2,USART_FLAG_TC) != SET);   

  10.     USART_SendData(USART2,(unsigned char)ch);      

  11.     while(USART_GetFlagStatus(USART2,USART_FLAG_TC) != SET);    

  12.     return (ch);    

  13. }  

  14.   

  15. void printf_init(void)  

  16. {  

  17.     GPIO_InitTypeDef GPIO_InitStructure;    

  18.     USART_InitTypeDef USART_InitStructure;  

  19.       

  20.        /*config USART clock*/  

  21.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO,ENABLE);   

  22.     RCC_APB1PeriphClockCmd( RCC_APB1Periph_USART2,ENABLE);  

  23.        /*USART1 GPIO config*/     

  24.     GPIO_InitStructure.GPIO_Pin= GPIO_Pin_2;    

  25.     GPIO_InitStructure.GPIO_Mode= GPIO_Mode_AF_PP; //复用推挽输出    

  26.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;    

  27.     GPIO_Init(GPIOA,&GPIO_InitStructure);   

  28.       

  29.       GPIO_InitStructure.GPIO_Pin= GPIO_Pin_3;    

  30.     GPIO_InitStructure.GPIO_Mode= GPIO_Mode_IN_FLOATING;  //复用开漏输入    

  31.     GPIO_Init(GPIOA,&GPIO_InitStructure);   

  32.        /*USART1 mode Config*/     

  33.     USART_InitStructure.USART_BaudRate = 115200;  

  34.     USART_InitStructure.USART_WordLength = USART_WordLength_8b;  

  35.     USART_InitStructure.USART_StopBits = USART_StopBits_1;  

  36.     USART_InitStructure.USART_Parity = USART_Parity_No;  

  37.     USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;  

  38.     USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;  

  39.     USART_Init(USART2,&USART_InitStructure);  

  40.     USART_Cmd(USART2,ENABLE);   

  41.           

  42.           


printf.h:


  1. #ifndef __printf_H  

  2. #define __printf_H  

  3.   

  4. #include "stm32f10x.h"  

  5. #include   

  6. void printf_init(void);  

  7. int fputc(int ch,FILE *f);  

  8.   

  9. #endif  


代码分析:

1.串口初始化配置

学了STM串口通信之后,我们知道配置串口通信至少要配置:字长(一次传送的数据长度),波特率(每秒传输的数据位数),奇偶校验位,还有停止位。当然我在

配置过程中把他们分别设为8,115200,No ,1。

串口的配置主要与USART_InitTypeDef这个结构体有关,里面存放了控制参数成员:


  1. typedef struct  

  2. {  

  3.   uint32_t USART_BaudRate;     //波特率        

  4.   uint16_t USART_WordLength;     //字长      

  5.   uint16_t USART_StopBits;         //停止位    

  6.   uint16_t USART_Parity;         //奇偶校验位      

  7.   uint16_t USART_Mode;           // 收发数据使能或失能                                             

  8.   uint16_t USART_HardwareFlowControl; //硬件控制流  

  9.                                           

  10. } USART_InitTypeDef;  


其实在学习32的时候,一般如果要用到32的内设或者外设,都要进行相应的初始化,也就是相应的结构体成员进行配置,而我们本次要实现的printf重定向,也

就用到了串口,所以也要对串口进行初始化!而我是用的USART2,所以要对其进行相应的配置。

查看STM32硬件原理图:


由原理图可知,这个串口是支持TTL电平的,接收数据RX是接在PA3管脚上的,发送数据是接在PA2上的。由于我是要输出到PC上的串口终端,所以PA2要

设为复用推挽输出模式,PA3设为复用开漏输入模式。

查看stm32f10x_it.c这个代码可知USART2是挂接在APB1总线上的,GPIO是挂在APB2总线上的,如下所示:



所以我们在进行时钟初始化的时候要特别注意。

2.printf重定向

其实printf重定向就是我们将printf重新定向到串口,也就是我们可以自己重写C的库函数,当连接器检查到用户编写了与C库函数相同的名字,优先采用

用户编写的函数这样用户就可以实现对库的修改了。

 printf函数实际是一个宏,最终调用的是 fputc(int ch,FILE *f)这个函数,所以我们需要修改这个函数。

下面我们着重分析一下fputc函数:

    这个库函数调用了两个ST库函数,分别是:USART_GetFlagStatus()与USART_SendData(),形参ch表示串口将要发送的数据,也就是说。当使用printf()时,它先调用fpuc()函数,然后使用ST库的串口发送函数USART_SendData(),把数据转移到发送数据寄存器TDR.触发我们的串口向PC发送一个相应的数据,调用完USART_SendData()之后,

使用 while(USART_GetFlagStatus(USART2,USART_FLAG_TC) != SET)语句不停的检查串口的数据是否发送完成的标志位TC,一直检查到标志为“完成”,才进行下一步操作,

要注意的是USART_SendData()每次只发送一个字节的数据!

注意:由于fputc()函数的形参调用了C库的FILE,所以在程序中加入stdio.h这个头文件,便且在keil的编译器的设置中勾选Use MicroLIB(使用微库)

3.硬件连接

首先硬件上我们将USB转串口线的TXD,RXD,GND,分别接在32开发板USART2上的RXD,TXD,GND。

由于USART2是TTL电平,所以我们用的usb转串口线一定要是支持TTL电平的,否则串口通信不上!

4.效果图

串口调试助手显示:


关键字:STM32  串口通信  printf重定向 引用地址:STM32-串口通信printf重定向

上一篇:STM32中关于串口通信的printf()函数重定向问题
下一篇:STM32的printf函数重定向

推荐阅读最新更新时间:2024-03-16 16:05

stm32---SPI与外部FLASH
stm32外部flash是EN25QXX 芯片 使用 STM32F1 的 SPI 和外部 FLASH(EN25QXX)进行通信,实现数据的读写 操作。本章要实现的功能是:首先检测外部 FLASH 是否正常,然后使用 K__UP 和 K_DOWN 键控制 FLASH 的写入和读取,并将 数据显示在 串口助手上,同时控制 D1 指示灯不断闪烁,提示系统正常 运行 W25Q128 将 16M 的容量分为 256 个块( Block),每个块大小为 64K 字 节,每个块又分为 16 个扇区( Sector),每个扇区 4K 个字节。 W25Q128 的最小擦除单位为一个扇区,也就是每次必须擦除 4K 个字节。这样我们需要给 W2
[单片机]
毕业设计| 不超过100元的简易防疲劳驾驶检测
以下就简单的介绍下项目组成: 实现的功能 面板上共四个按键,对应不同的功能: 按键1:按下后,将一分钟内的平均脉搏设为正常脉搏,正常脉博值更新后蜂鸣器隔一秒响一次,正常脉博值未更新时蜂鸣器一秒响4次。这样能知道当前什么状态,报警状态就是一直响。如果已经按下过按键1 ,那再按一次就会蜂鸣器快响,并计算平均值,计算完蜂鸣器再慢响,相当于更新了一次平均值。 按键2:实时检测xyz轴加速度,并且设置对应的三个报警值,超过报警值蜂鸣器报警,需要按按键4手动取消报警,报警值设置程序中采用宏定义的方式,方便用户更改调试,每次更改后需重新下载程序。再按一次按键2加虚度检测停止工作。按键2 相当于只检测加速度。 按键3:脉搏报警值和
[单片机]
毕业设计| 不超过100元的简易防疲劳驾驶检测
STM32HAL库使用DAC输出任意指定电压
1-uart.c实现重定向,记得包含stdio.h int fputc(int ch,FILE* f) { uint8_t temp ={ch}; { HAL_UART_Transmit(&huart1,temp,1,2); } return HAL_OK; } 2-启动DAC转换 HAL_DAC_Start(&hdac1,DAC1_CHANNEL_2);//启动DAC转换 3-编写测试函数 //如果按键1按下 if(HAL_GPIO_ReadPin(KEY1_GPIO_Port,KEY1_Pin)==GPIO_PIN_RESET) { HAL_Delay(100); i
[单片机]
stm32时钟选择与配置HSL HSE PLL
1. stm32时钟源分析 stm32f4有四个时钟源可供选择,分别是: HSE(外部高速),HSI(内部高速), LSE(外部低速), LSL(内部低速)。 1.1 外部时钟源一般由外挂晶振产生 LSE为32.767KHz晶振输入。 HSE为8MHz或16MHz,实验用的是16MHz 1.2 内部时钟源一般为内部RC震荡电路 LSI 为内部32.767KHz的RC电路 HSI 为内部16MHz的RC电路 2. stm32时钟源配置  四个时钟源中,只有HSI和HSE能作为整个系统的时钟源,LSI和LSE只作为看门狗,RTC及外部输出的时钟源。  HSI和HSE频率都不高,所以ARM设计了PLL(锁相环)来进行倍频,把
[单片机]
<font color='red'>stm32</font>时钟选择与配置HSL HSE PLL
这8种STM32中GPIO工作模式,你都知道吗?
一、推挽输出:可以输出高、低电平,连接数字器件;推挽结构一般是指两个三极管分别受两个互补信号的控制,总是在一个三极管导通的时候另一个截止。高低电平由IC的电源决定。 推挽电路是两个参数相同的三极管或MOSFET,以推挽方式存在于电路中,各负责正负半周的波形放大任务,电路工作时,两只对称的功率开关管每次只有一个导通,所以导通损耗小、效率高。输出既可以向负载灌电流,也可以从负载抽取电流。推拉式输出级既提高电路的负载能力,又提高开关速度。 二、开漏输出:输出端相当于三极管的集电极,要得到高电平状态需要上拉电阻才行。适合于做电流型的驱动,其吸收电流的能力相对强(一般20mA以内)。开漏形式的电路有以下几个特点: 1、利用外部电
[单片机]
这8种<font color='red'>STM32</font>中GPIO工作模式,你都知道吗?
合作共赢,生态共建是STM32的DNA
2019年4月26至27日,一年一度的意法半导体STM32峰会在深圳如期举行,根据最终统计,实际参会人数达到了3,500人,在线人数最高达5万人。 正是因为STM32在中国大获成功,因此此次峰会也得到了ST公司的重视。意法半导体总裁兼首席执行官Jean-Marc Chery是在刚刚开完季度投资者峰会后直接从欧洲赶赴深圳,同时前来的还有意法半导体数字、模拟、销售等全球或亚太区部门总监,不光是意法半导体在中国所召开的最顶级的峰会,同时也是MCU界的顶级盛会。 ST CEO在大会上发言 在此次峰会的主题演讲中,不光有来自意法半导体的高层分别介绍公司的愿景、单片机及传感器相关的产品规划,更重要的是邀请到了阿里巴巴集团副总裁、阿里
[单片机]
合作共赢,生态共建是<font color='red'>STM32</font>的DNA
STM32 模拟I2C 程序
STM32的硬件I2C不太好用,N多人深受其困扰,本人也不例外.所以干脆一不做二不休,用模拟的I2C算了,虽然速度不及硬件I2C,在一般的应用中还是不错的.帖上代码和协议分析图,造福广大受STM32的I2C困扰的朋友,哈哈!为了跟硬件I2C有所区别,本人把模拟的I2C名字写成TWI. H文件内容如下: #i nclude stm32f10x.h #ifndef _TWI_H_ #define _TWI_H_ //条件编译 1:使用软件模拟I2C #define TWI_ENABLE 1 #define TWI_SCL_0 GPIOB- BRR=GPIO_Pin_8 #define TWI_SCL_1 GPIOB- BSRR=GPI
[单片机]
基于STM32对DS1302的驱动
// 程序名: STM32驱动DS1302 //头文件 #include “stm32f10x.h” #include “usart.h” #define uchar unsigned char #define uint unsigned int ////DS1302引脚定义,可根据实际情况自行修改端口定义 #define RST PAout(5) #define IO PAout(6) #define SCK PAout(7) //DS1302地址定义 #define ds1302_sec_add 0x80 //秒数据地址 #define ds1302_min_add 0x82 //分数据地址 #define ds1302_
[单片机]
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved