UART协议帧
在 UART中,传输模式为数据包形式。数据包由起始位、数据帧、奇偶校验位和停止位组成。
起始位
当不传输数据时, UART 数据传输线通常保持高电压电平。若要开始数据传输,发送UART 会将传输线从高电平拉到低电平并保持1 个时钟周期。当接收 UART 检测到高到低电压跃迁时,便开始以波特率对应的频率读取数据帧中的位。
数据位
数据帧包含所传输的实际数据。如果使用奇偶校验位,数据帧长度可以是5 位到 8 位。如果不使用奇偶校验位,数据帧长度可以是9 位。在大多数情况下,数据以最低有效位优先方式发送。
奇偶校验位
校验位可以配置成 1 位偶校验或 1 位奇校验或无校验位。接收UART 读取数据帧后,将统计数值为 1 的位,检查总数是偶数还是奇数。如果奇偶校验位为0 (偶数奇偶校验),则数据帧中的1或逻辑高位总计应为偶数。如果奇偶校验位为 1 (奇数奇偶校验),则数据帧中的1 或逻辑高位总计应为奇数。当奇偶校验位与数据匹配时,UART 认为传输未出错。但是,如果奇偶校验位为0 ,而总和为奇数,或者奇偶校验位为 1 ,而总和为偶数,则UART 认为数据帧中的位已改变
停止位
为了表示数据包结束,发送 UART 将数据传输线从低电压驱动到高电压并保持1到2位时间。
串口工作过程
- 当串口信号处于空闲位时,不需要发送数据,串口一直处于高电平状态
-
当需要发送数据时,将串口电平拉低一位,此时串口处于起始位,表示需要发送数据
-
发送完8位数据后(可以选择无校验),接着有一位停止位将电平拉高表示发送结束,再留一个空闲位,空闲位过后发送下一个数据帧
- 所以串口发送数据的效率只有80%
串口配置
//在使用串口通信之前需要先配置串口,在使用串口同时也要使用引脚,所以也要配置端口工作模式,需要使用引脚时配置引脚工作模式永远排在第一位
//配置GPIO端口工作模式函数
void GPIO_Config(){GPIO_InitTypeDef init;init.Mode = GPIO_PullUp;init.Pin = GPIO_Pin_0 | GPIO_Pin_0;//我们使用的引脚是P30和P31GPIO_Inilize(GPIO_P3,&init);//我们使用的端口是第3组
}
//串口配置函数
void UART_Config(){COMx_InitDefine init;init.UART_Mode = UART_8bit_BRTx;//传输模式配置init.UART_BRT_Use = BRT_Timer1;//波特率发生器init.UART_BaudRate = 115200;//波特率配置init.UART_RxEnable = ENABLE;//允许接收init.Morecommunicate = DISABLE;//多机通讯允许, ENABLE,DISABLEinit.BaudRateDouble = DISABLE;//波特率加倍UART_Configuration(UART1,&init);//这里的UART1是指支持UART协议的端口分组NVIC_UART1_Init(ENABLE,Priority_1);//配置UART1的中断使能,配置中断优先级UART1_SW(UART1_SW_P30_P31);//引脚切换配置
}
void main(){GPIO_Config();UART_Config();//打开全局中断开关EA = 1;TX1_write2buff(97);//MCU使用串口1发送97给PC,对应字符awhile(1);
}
//现在已经配置好了串口,PC和单片机已经可以互相发送数据了,但是由于单片机不能像PC一样给用户一个直观的反馈所以我们需要通过串口通信将PC发送给单片机的数据发送回电脑,来验证能互相通信
//需要在while循环内加上以下代码
//单片机每个串口都有数据寄存器SBUF和存放数据的数组RX1_Buffer[128],当PC发送数据过来时,串口会用SBUF将数据移动到数组中,所以检验PC发送个单片机数据有没有成功,就看数组中有没有发送的数据即可
if(COM1.RX_Cnt > 0 && --COM1.RX_TimeOut == 0){//COM1.RX_Cnt是单片机中存放数据的数组的已经存放的长度标志,COM1.RX_TimeOut是一个计数功能,能够保证发送数据的连续性for(i = 0;i < COM1.RX_Cnt;i++){//遍历单片机中存放数据的数组,通过串口1发送回给PCTX1_write2buff(RX1_Buffer[i]);}COM1.RX_Cnt = 0;//取完数据之后将数组中长度标志置零,如果不置零,下次PC发送过来的数据就会继续往后存
}
多机通信
//PC1,PC2
void main(){int i = 0;GPIO_Config();UART_Config();EA = 1;while(1){if(COM1.RX_Cnt > 0 && --COM1.RX_TimeOut == 0){for(i = 0;i < COM1.RX_Cnt;i++){TX2_write2buff(RX1_Buffer[i]);//使用串口2将串口1的数组里面的数据拷贝到串口2的数组中TX1_write2buff(RX2_Buffer[i]);//同步输出串口1数组中的数据,可以随时打印对方PC发送给单片机的数据}COM1.RX_Cnt = 0;}delay_ms(20);}
}
void GPIO_Config(){GPIO_InitTypeDef init;init.Mode = GPIO_PullUp;init.Pin = GPIO_Pin_0 | GPIO_Pin_1;GPIO_Inilize(GPIO_P3,&init);GPIO_Inilize(GPIO_P1,&init);
}
void UART_Config(){COMx_InitDefine init; init.UART_Mode = UART_8bit_BRTx;init.UART_BRT_Use = BRT_Timer1;init.UART_BaudRate = 115200;init.Morecommunicate = ENABLE;init.UART_RxEnable = ENABLE;init.BaudRateDouble = DISABLE;UART1_SW(UART1_SW_P30_P31);NVIC_UART1_Init(ENABLE,Priority_0);UART_Configuration(UART1,&init);init.UART_BRT_Use = BRT_Timer2;NVIC_UART2_Init(ENABLE,Priority_0);UART_Configuration(UART2,&init);
}