【STM32F103笔记】5、串口通信——你好呀~
这一篇来说说STM32的串口通信功能,可以说串口通信是每个工程师在开发过程中第一或者第二个进行调试的程序(第一个可能是点灯,固定时间闪烁的那种),因为作为一种通信手段,单片机可以输出一些必要的信息,为调试其他程序提供有力的帮助(当然如果用JLink的话,配合keil uVision5可以单步调试啦。。但是不能否认串口通信在大多数情况下都调试的好帮手)。
这一篇将编写STM32的USART程序,并通过USB转串口的小设备将蓝色最小系统板的串口接到电脑上进行通信。
USART
STM32集成了USART(universal synchronous asynchronous receiver and transmitter),也就是通用同步异步收发器,即可以用于异步通信,也可以提供同步时钟与其他设备进行同步通信,这里我们主要用到的是异步通信功能,即UART(universal asynchronous receiver and transmitter),请明确其两者的区别。(笔者面试的时候踩了坑呢T.T)
数据传输格式
这里给出一张图简要说明异步串口通信的数据传输格式:
- 串口通信按字(Word)传输,一个字可以是8位也可以是9位,通过程序配置,一般来说8位用的比较多(因为8是整数啊!get?);
- 发送引脚TX清0表示起始位,置1表示停止位;
- 空闲帧(Idle Frame)和断开帧(Break Frame)可用于产生中断进行其它处理,这里不做说明。
STM32的USART配置
这里并不对串口通信的协议进行深入说明,因为在官方库中已经给出了用于USART配置与使用的函数。这里对配置要点进行说明:
- 波特率(Baudrate):每秒传输的二进制数据的多少,通常可以设置为2400、4800、9600、19200、38400、57600、115200;
- 数据位数(Word Length):也就是上面说的“字”的位数;
- 停止位(Stop Bits):可以设置为半位、一位、一位半、两位;
- 校验位(Parity):可以配置为奇校验或偶校验,也可以无校验。
若进行异步串口通信,则双方设备的上述设置均应一致。
电路
串口通信最简单的电路只需要3根信号线,TX、RX、GND:
- 注意这里的TX1连接到了RX2,即两个设备采取串口通信的话,其TX端口与RX端口是交叉相连的(仔细想想我发送你接收,没毛病~)。
在蓝色的最小系统板上,已经将串口1(USART1)单独用排针引了出来,PA9、PA10复用为USART的通信引脚:
- TX:PA9
- RX:PA10
注意在STM32手册中有说明,当GPIO引脚用于复用功能时,输出引脚配置为相应的复用输出功能,而输入引脚需要配置为浮空、上拉或者下拉:
(这里我们用的USB转串口设备的TX引脚平时输出为低电平,即有驱动电路,因此设置成浮空模式就行)
程序说明
对引脚进行配置:
GPIO_InitTypeDef GPIOInitStruct;
// PA9 TX
GPIOInitStruct.GPIO_Pin = GPIO_Pin_9;
// 复用推挽输出
GPIOInitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
GPIOInitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIOInitStruct);
// PA10 RX
GPIOInitStruct.GPIO_Pin = GPIO_Pin_10;
// 浮空输入
GPIOInitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIOInitStruct);
对USART进行配置,同样,官方库中提供了相应的初始化结构体:
USART_InitTypeDef USARTInitStruct;
// 设置波特率
USARTInitStruct.USART_BaudRate = 115200;
// 设置字长为8位
USARTInitStruct.USART_WordLength = USART_WordLength_8b;
// 1位停止位
USARTInitStruct.USART_StopBits = USART_StopBits_1;
// 不使用校验
USARTInitStruct.USART_Parity = USART_Parity_No;
// 不使用硬件控制
USARTInitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
// 设置为发送、接收模式
USARTInitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
// 初始化USART1
USART_Init(USART1, &USARTInitStruct);
// 使能USART1
USART_Cmd(USART1, ENABLE);
// 读取USART1发送状态,确保TX buffer中无数据
while(USART_GetFlagStatus(USART1, USART_FLAG_TC) != SET);
- 注意这里最后调用USART_GetFlagStatus()函数读取USART1的Transmitter Complete标志位,确保TX缓存中没有数据,否则当下次输出时可能出错。
在这里Keil uVision5提供了用于单片机、嵌入式设备的微型标准库,在设置中勾选,并将标准输入输出头文件stdio.h包含进工程,就可以使用:
/* Includes ------------------------------------------------------------------*/
#include "stm32f10x.h"
#include "stdio.h"
为了能够使用格式化输出函数 printf,需要重定向写字符文件函数 fputc,将其中的输出选择为串口字节输出函数 USART_SendData:
/**
* @brief 重定向fputc
* @param ch - 要写入文件流的字符
* f - 文件指针
* @retval ch
*/
int fputc(int ch, FILE *f)
{
USART_SendData(USART1, (unsigned char)ch);
while(USART_GetFlagStatus(USART1, USART_FLAG_TC) != SET);
return ch;
}
这里暂时不用scanf函数(其实是笔者没有调通,请各位大神指点)
完整程序
/* Includes ------------------------------------------------------------------*/
#include "stm32f10x.h"
#include "stdio.h"
/* Private functions ---------------------------------------------------------*/
void USART1Config(void);
int main(void)
{
float a = 3.1415926;
USART1Config();
printf("Hello, I know Pi: %f\n", a);
while(1);
}
void USART1Config(void)
{
GPIO_InitTypeDef GPIOInitStruct;
USART_InitTypeDef USARTInitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);
GPIOInitStruct.GPIO_Pin = GPIO_Pin_9;
GPIOInitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
GPIOInitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIOInitStruct);
GPIOInitStruct.GPIO_Pin = GPIO_Pin_10;
GPIOInitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIOInitStruct);
USARTInitStruct.USART_BaudRate = 115200;
USARTInitStruct.USART_WordLength = USART_WordLength_8b;
USARTInitStruct.USART_StopBits = USART_StopBits_1;
USARTInitStruct.USART_Parity = USART_Parity_No;
USARTInitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USARTInitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(USART1, &USARTInitStruct);
USART_Cmd(USART1, ENABLE);
while(USART_GetFlagStatus(USART1, USART_FLAG_TC) != SET);
}
int fputc(int ch, FILE *f)
{
USART_SendData(USART1, (unsigned char)ch);
while(USART_GetFlagStatus(USART1, USART_FLAG_TC) != SET);
return ch;
}
运行结果
编译通过并下载程序,找一个串口软件或者看笔者的博客自己写一个,就可以看到你的STM32对你say hi,并且还贴心的告诉你圆周率是多少,只是被它自己四舍五入了:
完结撒花✿✿ヽ(°▽°)ノ✿
上一篇: linux安装elasticsearch的中文分词器
下一篇: STM32笔记--SPI通信