首页 > 编程知识 正文

stm32与stm32串口通信,stm32串口通信协议

时间:2023-05-03 23:11:39 阅读:241061 作者:3878

文章目录 0 传输引脚1 传输一个字节1.1 发送一个字节1.2 接收一个字节 2 代码2.1 配置2.2 发送一个字节2.3 接收一个字节

0 传输引脚

串口收发共需要三根线

其中,TX脚为发送引脚, RX脚为发送引脚, GND为地, 作为电平的参考. 如果A发B收, 只需要连接两条线: A的TX连接B的RX, 以及GND相连即可

1 传输一个字节 1.1 发送一个字节

首先, 从传输一个字节开始说起. 抛开奇偶校验,多个停止位的情况, 假设, 我们设置一帧数据有十位, 里边包含一个起始位, 八个数据位, 还有一个停止位. 那么,我们发送一个字节, 只需要一次传输.

我们以传输0x01为例, 它的时序图如下

那怎么把这个字节变成时序呢? 发送器会帮我们完成. 只要配置好相应的波特率和停止位等即可. 发送器在起始位之后, 加入0x01对应的八个数据位, 最后加上停止位, 即可完成发送一个字节的时序. (0x01会通过发送数据寄存器(TDR), 存放到移位寄存器, 在每个时钟沿触发移位).

1.2 接收一个字节

我们以接收0x01为例(假设接收来自1.1的时序).首先我们必须设置波特率, 停止位位数, 跟接收到的时序保持一致.
那接收这边怎么知道对方是时序是什么意思呢? 波特率一致. 假设波特率为9600, 那么发送一个位需要的时间位1/9600 秒. 当RX脚检测到起始位(一个位的低电平, 持续1/9600秒), 就知道, 接下来的1/9600秒, 传输的是数据位的第一位, 再接下来的1/9600秒, 传输的是数据位的第二位… 这样即可通过移位寄存器在合适的时间去读取电平, 并保存0x01到接收数据寄存器(RDR). 我们通过程序去读取RDR即可得到0x01.

2 代码

以STM32F1的串口1为例

2.1 配置 void uart_init(u32 bound){ //GPIO端口设置 GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE); //使能USART1,GPIOA时钟 //USART1_TX GPIOA.9 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//复用推挽输出 GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.9 //USART1_RX GPIOA.10初始化 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA10 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入 GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.10 //Usart1 NVIC 配置(接受到数据时,会产生接收中断, 执行中断服务程序USART1_IRQHandler()) NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级3 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;//子优先级3 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//IRQ通道使能 NVIC_Init(&NVIC_InitStructure);//根据指定的参数初始化VIC寄存器 //USART 初始化设置 USART_InitStructure.USART_BaudRate = bound;//串口波特率 USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式 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(USART1, &USART_InitStructure); //初始化串口1 USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启串口接受中断 USART_Cmd(USART1, ENABLE); //使能串口1 } 2.2 发送一个字节 main函数:int main(void){ delay_init(); //延时函数初始化 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置中断优先级分组为组2:2位抢占优先级,2位响应优先级uart_init(9600); //串口初始化为 115200while(1)//每个500ms向串口1发送0x01{delay_ms(500);USART_SendData(USART1,0x01);} return 0;}


连接好之后, 打开串口调试助手设置波特率等, 可以看到, PC端每隔500ms, 接收到一个数据(0x01)

2.3 接收一个字节

串口1每接受完一帧数据, 都会跳转到串口中断服务程序USART1_IRQHandler(). 我们这么做, 在接收到一个字节的数据后, 把该数据加一, 然后发送出去. 例如接收到0x01, 那就发送0x02.

void USART1_IRQHandler(void) //串口1中断服务程序{u8 Res;if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收中断{ Res =USART_ReceiveData(USART1);//读取接收到的数据 USART_SendData(USART1,Res+1); //把该数据加一, 从串口1发送出去 } }

main函数:

int main(void){ delay_init(); //延时函数初始化 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置中断优先级分组为组2:2位抢占优先级,2位响应优先级uart_init(9600); //串口初始化为 115200while(1)//死循环,什么都不做{delay_ms(500);} return 0;}

在串口调试助手,向单片机发送0x01时,可以看到, 单片机接收到了, 并且给电脑发回来0x02.

对于串口的理解仅上, 想进一步理解配置过程的, 建议好好研究一下参考手册.

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。