目录
5 串口USART
5.1 基本原理
(1)USART
(2)/USART框图
(3)/波特率计算
5.2 硬件连接
(1)USB/RS232/TTL
(2)CH340
(3)/RS-232
5.3 步骤
5.4 printf重定向
端口复用+中断+USART
通信方式 |
并行通信 |
|
|
|
串行通信 |
传送方向 |
单工 |
单向数据传输方式 |
|
半双工 |
可切换方向的数据双向传输方式 |
|||
全双工 |
双向数据传输方式 |
|||
通信方式 |
同步通信 |
带时钟信号 |
||
SPI,IIC通信接口 |
||||
异步通信 |
带波特率、不带时钟 接收双方(stm32/串口助手)波特率相同 |
|||
UART(通用异步收发器),单总线 |
常见的串行通信接口:
通信标准 |
引脚说明 |
通信方式 |
通信方向 |
UART |
TXD:发送端 RXD:接受端 GND:公共地 |
异步通信 |
全双工 |
单总线 (1-wire) |
DQ:发送/接受端 |
异步通信 |
半双工 |
SPI |
SCK:同步时钟 MISO:主机输入,从机输出 MOSI:主机输出,从机输入 |
同步通信 |
全双工 |
I2C |
SCL:同步时钟 SDA:数据输入/输出端 |
同步通信 |
半双工 |
UART
STM32F10x系列 |
3USART 通用同步异步收发器 |
可用作UART |
|||||
2UART 通用异步收发器 |
RXD 数据输入引脚 |
PA10 |
PA3 |
PB11 |
PC11 |
PD2 |
|
TXD 数据发送引脚 |
PA9 |
PA2 |
PB10 |
PC10 |
PC12 |
||
串口号 |
1 |
2 |
3 |
4 |
5 |
中文参考手册
衡量通信性能的一个非常重要的参数就是通信速率,通常以比特率(Bitrate)来表示。比特率是每秒钟传输二进制代码的位数,单位是:位/秒(bps)。如每秒钟传送240个字符,而每个字符格式包含10位(1个起始位、1个停止位、8个数据位),这时的比特率为: 10位×240个/秒 = 2400 bps
这里的fCK是给外设的时钟(PCLK1用于USART2、 3、 4、 5, PCLK2用于USART1)
USARTDIV是一个无符号的定点数。这12位的值设置在USART_BRR寄存器。
寄存器版:如何通过 USARTDIV 得到串口 USART_BRR 寄存器的值。 假设我们的串 口 1 要设置为 115200 的波特率,而 PCLK2 的时钟为 72M。这样,我们根据上面的公式有:
USARTDIV=72000000/(115200*16)= 39.0625
那么:DIV_Fraction=16*0. 0625=1=0X01;DIV_Mantissa=39=0X27;
这样,我们就得到了 USART1->BRR 的值为 0X0271。只要设置串口 1 的 BRR 寄存器值为0X0271 就可以得到 115200 的波特率。
XCOM串口助手与STM32实现数据串行通信,注意USART相关参数要一致!
STM32通过USART1实现与PC机对话,STM32的USART1收到PC机发来的数据后原封不动的返回给PC机显示。
PA9,PA10(串口1)连接到了USB串口电路。
在计算机和单片机组成的RS-232串口通信系统中,下位机由单片机系统组成,上位机为普通的PC机。但现在的电脑上,已经不存在串口,所以一般使用USB转串口芯片,把电脑的USB口映射为串口用。
上位机 |
电平转换芯片 |
下位机 |
实例 |
串口RS232(-12-12V) |
MAX232 |
TTL(0-5V) |
51--计算机 |
串口RS232(-12-12V) |
MAX3232 |
TTL(0-5V/3.3V) |
STM32--计算机 |
USB(-12-12V) |
CH340 |
串口(0-5V/3.3V) |
51/STM32--计算机 |
用串口和CH340模块都可以让计算机和单片机进行通信,但是使用CH340更加方便,省去了使用串口的麻烦。CH340是一个USB总线的转接芯片,实现USB转串口、USB转IrDA红外或者USB转打印口。
CH340将普通的串口设备直接升级到USB总线、通过USB总线为计算机增加额外串口。通过外加电平转换器件,可以进一步提供RS232、RS485、RS422 等接口。
RS-232C定义了数据终端设备(DTE)与数据通信设备(DCE)之间的物理接口标准,20。RS-232C接口规定使用25针连接器,连接器的尺寸及每个插针的排 列位置都有明确的定义。(阳/公头)
插针序号 |
信号名称 |
功能 |
信号方向 |
1 |
PGND |
保护接地 |
|
2(3) |
TXD |
发送数据(串行输出) |
DTE→DCE |
3(2) |
RXD |
接收数据(串行输入) |
DTE→DCE |
4(7) |
RTS |
请求发送 |
DTE→DCE |
5(8) |
CTS |
允许发送 |
DTE→DCE |
6(6) |
DSR |
DCE就绪(数据建立就绪) |
DTE→DCE |
7(5) |
SGND |
信号接地 |
|
8(1) |
DCD |
载波检测 |
DTE→DCE |
20(4) |
DTR |
DTE就绪(数据终端准备就绪) |
DTE→DCE |
22(9) |
RI |
振铃指示 |
DTE→DCE |
main.c文件下的stm32f10x_usart.h文件中可以查到大部分相关函数!
1时钟使能-复用端口 |
|||
|
串口时钟使能,GPIO时钟使能 |
||
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//使能GPIOA时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); //使能串口1时钟 |
|||
2串口复位 |
|||
|
当外设出现异常的时候可以通过复位设置,实现该外设的复位 |
||
void USART_DeInit(USART_TypeDef* USARTx); |
|||
USART_DeInit(USART1); //复位串口 1 |
|||
3 GPIO端口初始化 |
|||
|
GPIO_Init(); |
||
GPIO_InitTypeDef GPIO_InitStructure; //结构体定义
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //ISART1_TX PA.9
|
|||
4串口参数初始化 |
|||
|
①波特率②字长③停止位④奇偶校验位⑤硬件数据流控制⑥模式(收/发) |
||
void uart_init(u32 bound);//115200 |
|||
USART_InitTypeDef USART_InitStructure; //定义结构体
USART_InitStructure.USART_BaudRate = bound; //波特率设置,用变量bound方便移植
|
|||
5 使能串口 |
|||
|
串口先初始化,再使能 USART_Cmd(USART1, ENABLE); //使能串口 1 |
||
6 中断组/级初始化 |
stm32f10x.h(IRQ) |
||
|
中断先初始化,再开启中断 |
||
|
NVIC_InitTypeDef NVIC_InitStructure; //定义结构体
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;//串口1中断
|
||
7开启串口中断IT |
stm32f10x_usart.h |
||
|
当需要开启串口中断,则应使能串口中断,串口中断有很多,需要确定是那种中断 |
||
void USART_ITConfig(USART_TypeDef* USARTx, uint16_t USART_IT, |
|||
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); //开启中断,接收到数据中断 USART_ITConfig(USART1, USART_IT_TC, ENABLE); //发送数据结束中断 |
|||
8编写中断处理函数IRQ |
startup_stm32f10x_hd.s(IRQ) |
||
|
void USART1_IRQHandler(void); |
||
8.1中断响应状态 |
|||
|
使能了某中断,当中断发生会置位状态寄存器某标志位,在中断处理函数中可以调用函数判断该中断是哪种中断 判断是否发生了该中断,发生则说明串口状态肯定改变了 |
||
①串口发送数据完成中断响应;②串口接收数据完成中断响应;③清除发送完成状态位 |
|||
USART_GetITStatus(USART1, USART_IT_RXNE) != RESET;//若使能串口接收完成中断,当中断发生了,便可以在中断处理函数中用函数判断到底是否发生该中断 USART_GetITStatus(USART1, USART_IT_TC) != RESET;//是否发送完成 |
|||
8.2 串口状态 |
|||
|
在没有使能相应的中断函数时,通常使用该函数来判断标志位是否置位 |
||
串口的状态可以通过状态寄存器 USART_SR 读取, RXNE(读数据寄存器非空),当该位被置 1 的时候,就是提示已经有数据被接收到了,并且可以读出来了。这时候我们要做的就是尽快去读取 USART_DR,通过读 USART_DR 可以将该位清零,也可以向该位写 0,直接清除; TC(发送完成),当该位被置位的时候,表示 USART_DR 内的数据已经被发送完成了,如果设置了这个位的中断,则会产生中断,该位也有两种清零方式: 1)读 USART_SR,写USART_DR; 2)直接向该位写 0 |
|||
|
USART_GetFlagStatus(USART1, USART_FLAG_RXNE!=SET); //是否读取完成 USART_GetFlagStatus(USART1, USART_FLAG_TC)!=SET; //是否发送完成 |
||
8.3 串口传输数据获取 |
|||
|
void USART_SendData(USART_TypeDef* USARTx, uint16_t Data); //发送数据到串口 uint16_t USART_ReceiveData(USART_TypeDef* USARTx); //从DR读取接受到的数据 |
||
|
//usart.c中数据接收: void USART1_IRQHandler(void) //串口1中断服务程序 { if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET);//串口接收1字节数据 Res =USART_ReceiveData(USART1);//(USART1->DR),读取接收到的数据 //main.c中数据发送: len=USART_RX_STA&0x3f; //得到此次接收到的数据长度 } |
正点:
#define USART_REC_LEN 200 //定义最大接收字节数 200
u8 USART_RX_BUF[USART_REC_LEN];
//接收缓冲,最大USART_REC_LEN个字节.末字节为换行符
u16 USART_RX_STA; //接收状态标记
USART_RX_STA |
||
bit15 |
bit14 |
bit14 |
接收完成标志 |
接收到0X0D标志 |
接收到的有效数据个数 |
ABCDEFGHI…….(0x0D),(0x0A)
我们知道C语言中printf函数默认输出设备是显示器,如果要实现在串口或者LCD上显示,必须重定义标准库函数里调用的与输出设备相关的函数。比如使用printf输出到串口,需要将fputc里面的输出指向串口,这一过程就叫重定向。
那么如何让STM32使用printf函数呢?
#include “stdio.h”//头文件一定不能忘
int fputc(int ch,FILE *p) //函数默认的,在使用printf函数时自动调用
{
USART_SendData(USART1,(u8)ch);
while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);
return ch;
}