一: 通信接口
- 通信的目的: 将一个设备的数据传送到另一个设备,扩展硬件系统
- 通信协议: 制定通信规则,通信双方按照协议规则进行数据收发
-
4. 硬件电路
- VCC 和 GND 是供电 , TX,RX 是通信的引脚 一个发送 一个接收(交叉连接)
- TX RX 是单端信号,它们的高低电平都是相对于GND的 -> TX RX GND 必须要接
- 上面的VCC 如果两个设备都有独立供电,那可以不接
- 像这里直接从控制器出来的信号,一般都是TTL 电平,相同的电平才能互相通信,不同的电平信号,需要加一个电平转换芯片。
- 在硬件电路上,协议规定: 一个设备使用TX发送高低电平,另一个设备使用RX接收高低电平,在线路中,使用TTL电平,stm32是3.3V器件,所以如果线路对地是3.3V,就代表发送了逻辑 1,如果线路对地是0V,就代表发送了逻辑 0
- 常用的电平标准 电平标准是数据1和数据0的表达方式
|1| TTL电平: +3.3 或 +5 表示1 0V 表示0
|2| RS232电平: -3 -> -15表示1 +3 -> +15 表示0
|3| RS485电平: 两线压差 +2 -> +6 表示1 -2 ->-6表示0 (差分信号)
二:串口参数及时序
- 波特率 : 串口通信的速率 (异步通信 -> 需要双方约定一个通信速率)决定了每隔 多久发送一位
- 起始位 : 标志一个数据帧的开始,固定为 低电平 产生下降沿,告诉接收设备
- 数据位 : 数据帧的有效载荷,1为高电平 0为低电平 低位先行
- 校验位 : 用于数据验证,根据数据位计算得来
- 停止位 : 用于数据帧间隔,固定为高电平 把引脚恢复成高电平
- 时序图
- 串口中,每一个字节都装载在一个数据帧里面,每个数据帧都有起始位 数据位 停止位组成。这里数据位有8个,代表一个字节的8位
- 在右边的数据帧里面,还可以在数据位最后加一个奇偶校验位 -> 9 位
三: USART简介
- 可以根据数据寄存器的一个字节数据自动生成数据帧时序,从TX引脚发送出去,也可以自动接收RX引脚的数据帧时序,拼接为一个字节数据,存放在数据寄存器里
- 自带波特率发生器,最高达4.5Mbits/s
- 可配置数据位长度(8/9),停止位长度(0.5/1/1.5/2)
- 可选校验位
- 支持同步模式,硬件流,DMA等
6.波特率发生器
[1]USART_BRR波特率寄存器
[2] 公式里面的16 因为 它内部还有一个16倍波特率的采样时钟
以下代码供参考
uint8_t RxData;
uint8_t RxFlag;
void Init(void){
RCC_APB2PeriphClockCmd(RCC_APB2Perigh_USART1,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Perigh_GPIOA,ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
USART_InitTypeDef USART_InitStructure;
USART_InitStructure.USART_BaudRate = 9600;//波特率
USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None; //无控流
USART_InitStructure.USART_Mode = USART_Mode_Tx;//只有发送模式 | USART_Mode_Rx
USART_InitStructure.USART_Parity =USART_Parity_No;//无校验
USART_InitStructure.USART_StopBits=USART_StopBits_1;//1位停止位
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//8字长
USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;
NVIC_Init(&NVIC_InitStructure);
USART_Cmd(USART1,ENABLE);
}
void USART1_IRQHandler(void){
if(USART_GetITStatus(USART1,USART_IT_RXNE)==SET){
RxData = USART_ReceiveData(USART1);
RxFlag = 1;
USART_ClearITPendingBit(USART1,USART_IT_RXNE);
}
}
void SendByte(uint8_t Byte){
USART_SendDate(USART1,Byte);
While(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET );
}
ps: 配置一致性
封装
void SendArray(uint8_t *Array , uint18_t Length){
uint16_t i ;
for(i=0 ; i<Length ;i++){
SendByte(Array[i]);
}
}
void SendString (char *String){
uint8_t i;
for(i=0; String[i] !='\0';i++){
SendByte(String[i]);
}
}
uint32_t Pow(uint32_t X , uint32_t Y){
uint32_t Result = 1;
while(Y--){
Result *=X;
}
return Result;
}
void SendNumber(uint32_t Number, uint32_t Length){
uint8_t i;
for(i=0;i<Length;i++){
SendByte(Number / Pow(10,Length-i-1) % 10 +'0';
}
}
#include<stdarg.h>
// 重点学习 C语言 可变参数
void Printf*(char *format,...){
char String[100];
va_list arg;
va_start(arg,format);
vsprintf(String,format,arg);
va_end(arg);
SendString(String);
}
uint8_t TxPacket[4];
uint8_t RxPacket[4];
uint8_t RxFlag;
void SendPacket(void){
SendByte(0xFF);
SendArray(TxPacket,4);
SendAByte(0xEF);
}
// 在刚才的中断处理函数中实现以下代码
static uint8_t pRxPacket=0;
static uint8_t RxState = 0;
if(USART_GetITStatus(USART1,USART_IT_RXNE) == SET){
uint8_t RxData = USART_ReceiveData(USART1);
if(RxState == 0 ){
if(RxData ==0xFF){
RxState = 1;
pRxPacket=0;
}
}else if(RxState ==1 ){
RxPacket[pRxPacket] = RxData;
pRxPacket++;
if(pRxPacket>=4){
RxState =2;
}
}else if(RxState ==2 ){
if(RxData ==0xFE){
RxState = 0;
RxFlag = 1;
}
}
}
//用 RxFlag==1 来判断有没有结束哦
char RxPacket[100];
// 在刚才的中断处理函数中实现以下代码
static uint8_t pRxPacket=0;
static uint8_t RxState = 0;
if(USART_GetITStatus(USART1,USART_IT_RXNE) == SET){
uint8_t RxData = USART_ReceiveData(USART1);
if(RxState == 0 ){
if(RxData == '@'){
RxState = 1;
pRxPacket=0;
}
}else if(RxState ==1 ){
if(RxData =='\r'){
RxState=2;
}else{
RxPacket[pRxPacket] = RxData;
pRxPacket++;
}
}else if(RxState =='\n' ){
if(RxData ==0xFE){
RxState = 0;
RxPacket[pRxPacket] = '\0';
RxFlag = 1;
}
}
}