USART的使用
通信的概念:
作用:
设备之间进行数据的交换。
分类:
传输方式:
有线通信:电平的变化
-
串行:传输数据的时候,是1bit 1bit 的传输
速度相对较慢,传输距离比较远
串口通信:UART、485、CAN、IIC、SPI....
-
并行:传输数据的时候 并发,多个位同时发送
速度快,抗干扰性差:传输距离近
CPU 跟存储区之间通信。 屏幕:(数据量大)、8080
无线通信:
-
短距离无线通信:
蓝牙、WIFI、红外、2.4G:无线鼠标,ZIGBEE、Lora:2-5Km
-
远距离无线通信:
2G、3G、4G、5G
通信的方式
-
单工:传输数据时,设备只能发送或者是只能接收。
-
双工:
半双工:可以实现发送和接收,但是不能同时完成。
例如:对讲机
全双工:可以同时实现发送和接收。
例如:手机
-
同步:通信设备之间有共同的时钟线。设备按照这个时钟来通信。
谁提供时钟?两个设备之间都有时钟,谁起主导作用,用谁的。谁是主机谁发送。
-
异步:通信设备各自有自己的时钟,要求通信速率要一致。
UART通信
-
通信方式:串行 异步 全双工 的通信方式
全双工也可以做成单工。
-
使用范围广:
串口本身不厉害,转成其他的通信方式,就很厉害了。
串口转蓝牙(设备本身没有蓝牙功能,可以转到其他的通信方式)
串口转 WIFI
串口转232电平、串口转485、
一些传感器:串口的传感器
硬件结构
全双工:一根线用来发,一根线用来收。
两个设备之间要共地,就是有一个电平相同(GND)。参考电位保持一致。没有共地,数据没有参考价值。
T:发送管脚
R:接收管脚
GND
连接方式:
- 直接相连:两个设备用相同的逻辑电平TTL,共地(参考电平相同)
芯片与芯片之间用UART时
- 间接相连:用到电平转换芯片(芯片的电压不同)
硬件接口:
UART、232、485
不同的硬件接口,是可以用相同的协议。
不同的硬件接口电平不同。
协议层:232协议
- 协议是传输方式
一般来说,总线空闲为高电平
| 开始位 | 数据位 | 校验位 | 停止位 | |
|---|---|---|---|---|
| 电平状态 | 低 | 高/低 | 高/低 | 高 |
| 数据位数 | 1位 | 5-8位 | 1位 | 1-2位 |
奇偶校验:错偶数个 都检测不出来。一般来说 奇偶校验 不需要开。
偶校验:数据位中1的个数 + 校验位1的个数 = 偶数
奇校验:数据位中1的个数 + 校验位1的个数 = 奇数
嵌入式设备串口采用比较常用的协议格式是:
1开始 + 8个数据 + 不开校验 + 1个停止 = 10bit
不开校验的原因:1、不准;2、速度慢
数据比较:
一帧数据 是 10个bit 11个bit
假设:1s能够传输 9600bit
一帧数据10bit 1s 960 字节
一帧数据11bit 1s 9600 / 11 = 872 字节
一般不开校验:而是再指定更上层的协议格式,进行校验
波特率:
数据传输的速率。bit/s
每秒钟能够发送的数据 “位” 数
波特率要保持一致
STM32串口
数据结构
1个开始位 8/9数据位
奇偶校验位 0.5 / 1 / 1.5 / 2个停止位
常用的数据格式:1个开始位 + 8个数据位 + 无奇偶校验 + 1个停止位
时钟源的配置
FCLKx(x=1, 2) 的选择是根据USART外设所在的外设总线决定的。
TE、RE 两个使能位,
如果关闭了发送/接收,就不会再提供波特率,数据也就不完整了,所以要等到数据发送完成后在关闭使能位
波特率的计算方法
波特率的寄存器设置
DIV_Mantissa[11:0]:USARTDIV的整数部分
DIV_Fraction[3:0]:USARTDIV的小数部分小数部分在寄存器的值如何计算?
DIV_Fraction = 小数部分 * 16, 向上取整(四舍五入), 如果有进位,整数部分要加上进位。
发送数据
配置步骤
1. 通过在USART_CR1寄存器上置位UE位来激活USART 2. 编程USART_CR1的M位来定义字长。 3. 在USART_CR2中编程停止位的位数。 4. 如果采用多缓冲器通信,配置USART_CR3中的DMA使能位(DMAT)。按多缓冲器通信中 的描述配置DMA寄存器。 5. 利用USART_BRR寄存器选择要求的波特率。 6. 设置USART_CR1中的TE位,发送一个空闲帧作为第一次数据发送。 7. 把要发送的数据写进USART_DR寄存器(此动作清除TXE位)。在只有一个缓冲器的情况 下,对每个待发送的数据重复步骤7。 8. 在USART_DR寄存器中写入最后一个数据字后,要等待TC=1,它表示最后一个数据帧的 传输结束。当需要关闭USART或需要进入停机模式之前,需要确认传输结束,避免破坏 最后一次传输。
字节发送过程
清零TXE位 是通过 对数据寄存器的写 操作来完成的。 TXE位由硬件来设置,它表明:
● 数据已经从TDR移送到移位寄存器,数据发送已经开始
● TDR寄存器被清空
● 下一个数据可以被写进USART_DR寄存器而不会覆盖先前的数据如果TXEIE位被设置,此标志将产生一个中断。
当一帧发送完成时(停止位发送后)并且设置了TXE位, TC位被置起,如果USART_CR1寄存器
中的TCIE位被置起时,则会产生中断
发送的状态寄存器
1、TXE:
如果该标志位被置1,就说明 “数据寄存器” 的内容被转移到了 “移位寄存器”;就可以往DR寄存器里面写数据,此时数据不会被覆盖。
2、TC:
如果该标志位被置1,就说明 “一帧数据” 发送完成。
3、TE
一般来说发送数据 是 不需要开中断的 ,想发数据的时候,就把数据发出去就行了。
接收数据
配置步骤
1. 将USART_CR1寄存器的UE置1来激活USART。 2. 编程USART_CR1的M位定义字长 3. 在USART_CR2中编写停止位的个数 4. 如果需多缓冲器通信,选择USART_CR3中的DMA使能位(DMAR)。按多缓冲器通信所 要求的配置DMA寄存器。 5. 利用波特率寄存器USART_BRR选择希望的波特率。 6. 设置USART_CR1的RE位。激活接收器,使它开始寻找起始位。
RXNE位被置位。它表明移位寄存器的内容被转移到RDR。换句话说,数据已经被接收并且可以被读出(包括与之有关的错误标志)。
如果RXNEIE位被设置,产生中断。
接收数据的状态位
1、RXNE
接收寄存器非空,我们就可以读取寄存器DR的值。
2、RXNEIE
一般都要打开中断,在中断里面接收数据,这样不会阻塞CPU的运行。
3、RE
DR寄存器的介绍
数据寄存器是9位的。

DR寄存器连接两个寄存器 TDR 和 RDR ;发送时,就是往TDR寄存器写,接收时,就是从RDR寄存器读。但是操作的同一个寄存器。
如何读和写寄存器???
赋值 就是 读 和 写
写:USART1->DR = 'A'; 读:data = USART1->DR;
引脚配置
对于芯片:
串口调试
串口调试助手:推荐使用微软商城。
串口助手的接收和发送
-
串口助手接收到的是 “字符”(8位数)。
-
串口发送
因为数据时 8bit 的,所以每次的发送应该是发送 8bit 的数据。
1、字符(8bit),每次发送一个字符,就是8bit 的数据。
2、16进制的数据(4bit),因为每个16进制数,只有4bit,所以说每次发16进制的数,要发两个。(8bit)
STM32串口接收数据(从串口助手发送数据时),数据格式。
1、16进制:一个16进制的数是4位,一个数据是两个16进制数,发一个接收的数据有问题,所以说一次要发送两个。
以下是发送接收到一个1蜂鸣器响,但是发送一个16进制的1是没有任何反应的。
发送一个16进制的01,这时候就可以收到你想要的数据1
2、字符:一个字符是8位
printf 发送
如何在STM32代码中使用 printf ? ? ?
构造一个printf函数
STM32中构造的 printf 函数,只需要重写 pfutc 函数。
1、在设置里面勾选 “微库”
![]()
2、重写
fputc//包含头文件,在哪使用printf函数,就在那加入 #include "stdio.h" //重写printf函数 int fputc(int ch, FILE * Stream) { while((USART1->SR & (1<<6)) == 0); //等待发送完成,阻塞型发送 USART1->DR = ch; return ch; }
完成了 fputc函数的重写,就可以使用printf 函数,打印数据了。
相当于一个字符一个字符的往 “串口文件” 打。 执行效率慢,在中断时尽量不要用。
中断的引入
为什么进入中断??
发送数据和接收数据的时候,需要等到他的寄存器空/寄存器有数据,这个时候,CPU处于被阻塞的状态,如果一直不发数据,CPU只能等;如果不一直等,就会使得重要的数据不能及时接收。
开启中断
对于STM32的串口,有很多中断,但是一般只需要开启 接收中断 ,发送中断不需要开,想发数据的时候,直接发送就行了
开启方法:将对应的中断寄存器的值写1,就使能了对应的中断。
中断服务函数
串口的中断有很多,但是只有一个中断服务函数,所以说,当进入中断服务函数的时候,要先判断是哪个中断源引起的中断。
- 中断的到来判断:判断状态寄存器是否被置1
- 中断的清除:看
stm32对应的SR寄存器,看是否需要软件清零
串口中断是多个中断,要判断是那个中断
清中断标志位
if(USART1->SR & (1<<5))
{
data = USART1->DR; //读取DR寄存器,就会清除接收中断
}
接收多个字符
1、 阻塞型 接收
存在的问题,虽然能够接收多个字符,但是属于阻塞型程序的运行,程序的其他端口会出问题,比如说按键的检测。
2、发送中断 接收
当接收寄存器非空时,就会产生中断,进入中断服务函数,在中断中接收数据。
每一次中断就是一帧数据。
但是要清除中断标志位,清除方法:读取DR寄存器的值。
STM32串口配置代码
//配置串口
void Usart1_Config(uint32_t brr)
{
RCC->APB2ENR |= (1<<2) ;
RCC->APB2ENR |= (1<<14);
//PA9 复用推挽输出
GPIOA->CRH &= ~(0xF<<4);
GPIOA->CRH |= (0xB<<4);
//PA10 浮空输入/上拉
GPIOA->CRH &= ~(0xF<<8);
GPIOA->CRH |= (0x8<<8);
GPIOA->ODR |= (1<<10);
float USARTDIV = 72000000.0f/16/brr; //浮点型,否则将不会产生小数
uint16_t Mantissa = USARTDIV; //整数部分
uint16_t Fraction = (USARTDIV-Mantissa)*16; //小数部分
USART1->BRR = (Mantissa<<4) | Fraction; //写入BRR寄存器
//USART1->CR1 = 0; //CR1直接置1,很多按照默认的都可以不用管。
USART1->CR1 |= (1<<13); //使能
USART1->CR1 &=~(1<<12);
USART1->CR1 |= (1<<3)|(1<<2)|(1<<5);
USART1->CR2 &= ~(0x3<<12);
//NVIC
NVIC_SetPriority(USART1_IRQn, 3);
NVIC_EnableIRQ(USART1_IRQn);
}
//阻塞型 , 发送数据
void Usart1_SendByte(u8 data)
{
while((USART1->SR & (1<<6)) == 0); //等待寄存器的第6位被置一
USART1->DR = data;
}
void Usart1_SendString(u8 * str, u16 len)
{
while(len--)
{
Usart1_SendByte(*str--);
}
}
//阻塞型, 接收数据
u8 Usart1_RecvByte(void)
{
while((USART1->SR & (1<<5)) == 0); //等待寄存器的第6位被置一
return USART1->DR;
}
//中断接收数据
u8 data = 0;
void USART1_IRQHandler(void)
{
//接收非空
if(USART1->SR & (1<<5))
{
data = USART1->DR;
}
}







浙公网安备 33010602011771号