1、串口通信协议
(1)串口基础
一般串口通信不需要时钟,所以串口采用的是异步串行全双工的通信方式
通信时需要三个引脚:RX,TX,GND。
(2)串口通讯标准(电平标准)
232 电平:原生串口电平。高电平+15V,低电平-15V。因为电位差大,即容错空间大,抗干扰能力强,所以一般用于工业设备直接通信。电平转换芯片一般有MAX3232,SP3232
TTL 电平:MCU,IC出来的电平。高电平为5V(51单片机)或者3.3V(stm32)
RS232电平与TTL电平逻辑刚好相反。TTL 1为高电平,0为低电平。RS232相反。
(3)串口通讯方式
①两设备通过232标准通讯
电平转换芯片一般有MAX3232,SP3232
②USB转串口与电脑进行通讯
图中设备B与设备A通信是先将USB转232电平,232电平再转TTL电平与主控通信。
电脑上采用的是USB口。USB转串口主要用于设备跟电脑通信。
电平转换芯片一般有CH340、PL2303、CP2102、FT232
③TTL电平之间的直接通讯
原生的串口通信主要是控制器跟串口的设备或者传感器通信,不需要经过电平转换芯片来转换电平,可直接用TTL电平通信。例如GPS模块、GSM模块、串口转WIFI模块、HC04蓝牙模块等与控制器之间的通讯。
(4)串口数据帧分析
【嵌入式】---- 串口UART波形分析
2、STM32串口框图
1-引脚
引脚最常用的是RX,TX。
SCLK使用时,串口为USART,通过时钟来规范传输的数据。不使用SCLK,串口就是UART,通过特定格式的数据帧来做通讯。
2-数据寄存器
发送(写操作):MCU或DMA将数据写入发送数据寄存器,然后发送数据寄存器将数据写到发送移位寄存器,发送寄存器发送完成后TXE位为1,发送移位寄存器将数据一位一位送到TX端口,TC位此时为1,证明数据全部发送完成。
接收(读操作):写操作的反向操作。RXNE位为1,表示收到数据,从RDR中可读出数据。
TXE,TC和RXNE位在USART_SR寄存器中。
3-控制器
4-波特率
波特率配置时需要注意 fck 是APB1(36M)还是APB2(72M)
eg:
USART:USART1,时钟为72M
波特率:115200
3、核心代码
/** * @brief USART GPIO 配置,工作参数配置 */void USART_Config(void){GPIO_InitTypeDef GPIO_InitStructure;USART_InitTypeDef USART_InitStructure;// 打开串口GPIO的时钟DEBUG_USART_GPIO_APBxClkCmd(DEBUG_USART_GPIO_CLK, ENABLE);// 打开串口外设的时钟DEBUG_USART_APBxClkCmd(DEBUG_USART_CLK, ENABLE);// 将USART Tx的GPIO配置为推挽复用模式GPIO_InitStructure.GPIO_Pin = DEBUG_USART_TX_GPIO_PIN;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(DEBUG_USART_TX_GPIO_PORT, &GPIO_InitStructure); // 将USART Rx的GPIO配置为浮空输入模式GPIO_InitStructure.GPIO_Pin = DEBUG_USART_RX_GPIO_PIN;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;GPIO_Init(DEBUG_USART_RX_GPIO_PORT, &GPIO_InitStructure);// 配置串口的工作参数// 配置波特率USART_InitStructure.USART_BaudRate = DEBUG_USART_BAUDRATE;// 配置 针数据字长USART_InitStructure.USART_WordLength = USART_WordLength_8b;// 配置停止位USART_InitStructure.USART_StopBits = USART_StopBits_1;// 配置校验位USART_InitStructure.USART_Parity = USART_Parity_No ;// 配置硬件流控制USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;// 配置工作模式,收发一起USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;// 完成串口的初始化配置USART_Init(DEBUG_USARTx, &USART_InitStructure);// 串口中断优先级配置NVIC_Configuration();// 使能串口接收中断USART_ITConfig(DEBUG_USARTx, USART_IT_RXNE, ENABLE);// 使能串口USART_Cmd(DEBUG_USARTx, ENABLE); // 清除发送完成标志//USART_ClearFlag(USART1, USART_FLAG_TC); } /***************** 发送一个字符 **********************/void Usart_SendByte( USART_TypeDef * pUSARTx, uint8_t ch){/* 发送一个字节数据到USART */USART_SendData(pUSARTx,ch);/* 等待发送数据寄存器为空 */while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);} /***************** 发送一个16位数 **********************/void Usart_SendHalfWord( USART_TypeDef * pUSARTx, uint16_t ch){uint8_t temp_h, temp_l;/* 取出高八位 */temp_h = (ch&0XFF00)>>8;/* 取出低八位 */temp_l = ch&0XFF;/* 发送高八位 */USART_SendData(pUSARTx,temp_h);while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);/* 发送低八位 */USART_SendData(pUSARTx,temp_l);while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);} /***************** 发送字符串 **********************/void Usart_SendString( USART_TypeDef * pUSARTx, char *str){unsigned int k=0; do { Usart_SendByte( pUSARTx, *(str + k) ); k++; } while(*(str + k)!=' '); /* 等待发送完成 */ while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TC)==RESET) {}}
使用 printf()函数时需要重定向 fputc,使用scanf()函数时需要重定向 fgetc。因为printf底层会调用 fputc 函数,要使用printf需要重新定义fputc,scanf同理。不要忘记包含stdio.h头文件
//重定向c库函数printf到串口,重定向后可使用printf函数int fputc(int ch, FILE *f){/* 发送一个字节数据到串口 */USART_SendData(DEBUG_USARTx, (uint8_t) ch);/* 等待发送完毕 */while (USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_TXE) == RESET);return (ch);}//重定向c库函数scanf到串口,重写向后可使用scanf、getchar等函数int fgetc(FILE *f){/* 等待串口输入数据 */while (USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_RXNE) == RESET);return (int)USART_ReceiveData(DEBUG_USARTx);}
4、程序分享
链接:https://pan.baidu.com/s/1L2ArO0pE3Q8h5SgC_y8f3Q
提取码:9wob