STM32串口通信之队列实现
1、学习资源
学习资源来自于B站优质单片机up铁头山羊,有需要全程学习的同学可以点击如下链接:
铁头山羊教程
2、为什么要用队列实现串口的消息收发?
为了实现串口消息收发这一目的,我们有许多方式,包括轮训标志位、 中断收发 、队列收发,其中。队列收发可看做中断收发的一种升级形式,其能更好的收发消息,避免消息的遗失。下面我们来看一下具体为什么。
2.1 轮训标志位
2.1.1 数据的发送
总代码如下
#include "stm32f10x.h"
#include "stm32f10x_pal.h"
#include <string.h>
int main(void)
{
GPIO_InitTypeDef GPIOInitStruct;
PAL_Init();
// 初始化Tx PB6 AF_PP 10MHz
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); // 开启GPIOB的时钟
GPIOInitStruct.GPIO_Pin = GPIO_Pin_6;
GPIOInitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
GPIOInitStruct.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_Init(GPIOB, &GPIOInitStruct);
// 初始化Rx PB7 IPU
GPIOInitStruct.GPIO_Pin = GPIO_Pin_7;
GPIOInitStruct.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOB, &GPIOInitStruct);
// 重映射USART1的Tx和Rx引脚
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); //开启AFIO的时钟
GPIO_PinRemapConfig(GPIO_Remap_USART1, ENABLE);
// 使能USART1的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
// 设置USART1的参数
USART_InitTypeDef USARTInitStruct;
USARTInitStruct.USART_BaudRate = 9600;
USARTInitStruct.USART_WordLength = USART_WordLength_8b;
USARTInitStruct.USART_StopBits = USART_StopBits_1;
USARTInitStruct.USART_Parity = USART_Parity_No;
USARTInitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USARTInitStruct.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
USART_Init(USART1, &USARTInitStruct);
// 闭合USART1的总开关
USART_Cmd(USART1, ENABLE);
//
发送单个数据
// // 1. 等待TDR寄存器清空
// while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET){}
//
// // 2. 写入要发送的数据
// USART_SendData(USART1, 0x5a);
//
// // 3. 等待数据发送完成
// while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET){}
//
发送一个数组
// uint8_t a[] = {0,1,2,3,4,5};
// uint32_t i;
//---------------------------------------------------------------
// 方法一:
// for(i=0;i<sizeof(a) / sizeof(uint8_t);i++)
// {
// // 1. 等待TXE置位
// while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
// // 2. 数据写入TDR
// USART_SendData(USART1, a[i]);
// }
//
// // 3. 等待数据发送完成
// while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
//------------------------------------------------------------------
//方法二:
// while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
// USART_SendData(USART1, 'a');
// while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
发送一个字符串:
// const char *str = "Hello world";
// uint32_t i;
// for(i=0; i<strlen(str);i++)
// {
// // 1. 等待TXE置位
// while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
// // 2. TDR
// USART_SendData(USART1, str[i]);
// }
// // 3. TC置位
// while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
轮询标志位最大的特点就是在USART/UART初始化时没有对NVIC进行配置,同时在消息收发时采用如下代码对标志位进行检验:
单个数据的发送
while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET){
}
// 2. 写入要发送的数据
USART_SendData(USART1, 0x5a);
// 3. 等待数据发送完成
while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET){
}
数组的发送
uint8_t a[] = {
0,1,2,3,4,5};
uint32_t i;
for(i=0;i<sizeof(a) / sizeof(uint8_t);i++)
{
// 1. 等待TXE置位
while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
// 2. 数据写入TDR
USART_SendData(USART1, a[i]);
}
// 3. 等待数据发送完成
while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
USART_SendData(USART1, 'a');
while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
字符串的发送
const char *str = "Hello world";
uint32_t i;
for(i=0; i<strlen(str);i++)
{
// 1. 等待TXE置位
while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
// 2. TDR
USART_SendData(USART1, str[i]);
}
// 3. TC置位
while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET)