本文章时本人根据江科大视频所记录的笔记,希望对大家的学习能提供帮助。
1.通信接口
通信的目的:将一个设备的数据传送到另一个设备,扩展硬件系统(stm32内部芯片无法得到的数据,需要连接外部芯片获取)
通信协议:制定通信的规则,通信双方按照协议规则进行数据收发
USART:TX(数据发送脚)、RX(数据接收脚)
I2C:SCL(时钟)、SDA(数据)
SPI:SCLK(时钟)、MOSI(主机输出数据脚)、MISO(主机输入数据脚)、CS(片选,指定通信的对象)
CAN:CAN_H、CAN_L(差分数据脚,用两个引脚表示一个差分数据)
USB:DP、DM(一对差分数据脚)
双工特性:全双工就是指通信双方能够同时进行双向通信,一般来说,全双工的通信都有两根通信线,发送线路和接收线路互补影响;半双工只用一根数据线;单工是指数据只能从一个设备到另一个设备,而不能反着来。
时钟特性:I2C和SPI有单独的时钟线,所以它们是同步的,接收方可以在时钟信号的指引下进行采样;剩下的串口、CAN、USB没有时钟线,所以双方约定一个采样频率,就是异步通信,并且还要加一些帧头帧尾等,进行采样位置的对齐。
电平特性:上面3个都是单端信号,就是它们的引脚的高低电平都是对GND的电压差,所以单端信号通信的双方必须要共地,就是把GND、接在一起,所以说这里通信的引脚,前三个还应该加一个GND引脚,不接GND无法通信;后面的CAN和USB是差分信号,它是靠两个差分引脚的电压差来传输信号的是差分信号,在通信时可以不需要GND(不过USB协议里面也有一些地方需要单端信号,所以USB、还需要共地),使用差分信号可以极大地提高抗干扰能力,所以差分信号一般传输速度和距离都会非常高。
设备特性:点对点通信就直接传输数据就可以了;多设备通信需要有一个寻址的过程,以确定通信的对象。
2.串口的通信协议
2.1 串口通信
串口是一种应用十分广泛的通讯接口,串口成本低、容易使用、通信线路简单,可实现两个设备的互相通信
单片机的串口可以使单片机与单片机、单片机与电脑、单片机与各式各样的模块互相通信,极大地扩展了单片机的应用范围,增强了单片机系统的硬件实力
2.2 硬件电路
下面的三根线必须连接(TX接RX、RX接TX、GND接GND,TX与RX要交叉连接),上方的VCC如果有单独供电可以不用连接,但没有供电时需要单独连接。当只需单向的数据传输时,可以只接一根通信线,当电平标准不一致时,需要加电平转换芯片。
电平标准:
电平标准是数据1和数据0的表达方式,是传输线缆中人为规定的电压与数据的对应关系,串口常用的电平标准有如下三种:
TTL电平:+3.3V或+5V表示1,0V表示0
RS232电平:-3~-15V表示1,+3~+15V表示0
RS485电平:两线压差+2~+6V表示1,-2~-6V表示0(差分信号)
2.3 串口参数及时序
波特率:串口通信的速率
起始位:标志一个数据帧的开始,固定为低电平
数据位:数据帧的有效载荷,1为高电平,0为低电平,低位先行
校验位:用于数据验证,根据数据位计算得来
停止位:用于数据帧间隔,固定为高电平
3.USART串口通信
3.1 串口简介
USART是STM32内部集成的硬件外设,可根据数据寄存器的一个字节数据自动生成数据帧时序,从TX引脚发送出去,也可自动接收RX引脚的数据帧时序,拼接为一个字节数据,存放在数据寄存器里
自带波特率发生器,最高达4.5Mbits/s
可配置数据位长度(8/9)、停止位长度(0.5/1/1.5/2)
可选校验位(无校验/奇校验/偶校验)
支持同步模式、硬件流控制、DMA、智能卡、IrDA、LIN
3.2 USART基本结构
最左边的是波特率发生器,用于产生约定的通信速率,时钟来源是PCLK2或1,经过波特率发生器分频后,产生的时钟通向发送控制器和接收控制器,发送控制器和接收控制器,用来控制发送移位和接受移位,之后,由发送数据寄存器和发送移位寄存器这两个寄存器的配合,将数据一位移位地移出去,通过GPIO地复用输出,输出到TX引脚残生串口协议规定地波形(右移的符号就是表示这个移位寄存器是往右移的,是低位先行),当数据由数据巨蠢器移位到移位寄存器时,会置一个TXE的标志位,通过判断这个标志位就可以知道是不是可以写下一个数据了。然后接受部分也是类似的,RX引脚的波形,通过GPIO输入,在接收控制器的控制下,一位一位地移入接收移位寄存器(也是右移),因为时地位先行,所以要从左边开始移进来,移完一帧数据后,数据就会统一运到接受数据寄存器,在转移的同时,置一个RXNE标志位,通过检查这个标志位就知道是否接收到数据,同时这个标志位可以申请标志位,在接收到数据时,直接进入中断函数,然后快速地读取和保存数据。
3.3 波特率发生器
发送器和接收器的波特率由波特率寄存器BRR里的DIV确定
计算公式:波特率 = fPCLK2/1 / (16 * DIV) (因为内部有一个16倍波特率地采样时钟,所以输入时钟/DIV要等于16倍地波特率)
DIV(分频系数),分为整数部分和小数部分,可以实现更细腻地分频
3.4 USART配置
1.开启时钟,把需要用的USART和GPIO的时钟打开
2.GPIO初始化,把TX配置成复用输出,RX配置成输入
3.配置USART
USART_InitTypeDef USART_InitStructure;
USART_InitStructure.USART_BaudRate //波特率USART_InitStructure.USART_HardwareFlowControl //硬件流控制,不需要
USART_InitStructure.USART_Mode //模式,发送模式和接收模式
USART_InitStructure.USART_Parity //奇偶校验
USART_InitStructure.USART_StopBits //停止位
USART_InitStructure.USART_WordLength; //字长
USART_Init(USART1, &USART_InitStructure);
4.配置中断(如果只有发送就不需要配置)
3.5 USART串口文本
数据包的作用:将一个个单独的数据给打包起来,方便我们进行多字节的数据通信,把属于同一批的数据进行打包和分割,方便接收方识别
串口数据包,通常使用的是额外添加包头包尾的方式
HEX数据包:优点是传输最直接,解析数据非常简单,比较适合一些模块发送原始的数据;缺点灵活性不足、载荷和包头包尾重复
文本数据包:优点是数据直观理解,非常灵活,比较适合一些输入指令进行人机交互的场合:缺点是解析效率低
问题1:包头包尾和数据载荷重复
解决办法:
1.如果可以的话,我们可以在发送的时候,对数据进行限幅
2.如果无法避免载荷数据和包头包尾重复,那我们就经量使用固定长度的数据包
3.增加包头包尾的数量,并且让它尽量呈现出载荷数据出现不了的状态
问题2:包头包尾并不完全需要
但是有了包尾,无论数据怎么变化,都可以分辨出包头包尾的
问题3:固定包长和可变包场选择的问题
如果载荷会出现和包头包尾重复的情况,最好使用固定包长,避免接收错误
如果载荷不会出现和包头包尾重复,可以选择可变包长
问题4:各种数据转换为字节流的问题
用Uin8_t的指针指向它,把它们当作一个字节数组发送
数据包接收:
每收到一个字节,程序都会进一遍中断,在中断函数里,可以拿到一个字节,拿到后退出中断,所以每拿到一个数据都是一个独立的过程,而对于数据包来说,它具有前后关联性,包头之后是数据,数据之后是包尾,对于包头数据包尾三种状态,需要不同的处理逻辑,在程序中设计一个能记住不同状态的机制,在不同状态执行不同状态的操作,同时话要进行状态的合理转移,这种程序思维,就叫做“状态机”。
4.附加
pintf函数移植
1.
int fputc(int ch, FILE *f)
{
Serial_SendByte(ch); //将printf的底层重定向到自己的发送字节函数
return ch;
}
然后就可以在主函数中直接调用,但这样只能在一个串口使用。
2.
#include <stdarg.h>
void Serial_Printf(char *format, ...)
{
char String[100]; //定义字符数组
va_list arg; //定义可变参数列表数据类型的变量arg
va_start(arg, format); //从format开始,接收参数列表到arg变量
vsprintf(String, format, arg); //使用vsprintf打印格式化字符串和参数列表到字符数组中
va_end(arg); //结束变量arg
Serial_SendString(String); //串口发送字符数组(字符串)
}
封装Sprintf函数
显示汉字:
1.
keil软件选择UTF-8编码,串口也要选择UTF-8编码
打开工程选项,C/C++,杂项控制栏写上 --no-multibyte-chars
2.
切换为GB2312编码
标签:USART,通信协议,通信,STM32,包尾,串口,波特率,数据 From: https://blog.csdn.net/2401_83265518/article/details/139423033