基于探索者STM32F407单片机学习——串口1初始化函数
2024/11/08单片机学习之串口代码分析
一:编写场景
在学习STM32F407时,对串口代码学习的思路分析。
二:代码源码
//初始化 IO 串口 1
//bound:波特率
void uart_init(u32 bound){
//GPIO 端口设置
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);
//使能 GPIOA 时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
//使能 USART1 时钟
GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_USART1);
//GPIOA9 复用为 USART1
GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_USART1);
//GPIOA10 复用为 USART1
//USART1 PA.9 PA.10
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10; //GPIOA9 与 GPIOA10
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //速度 50MHz
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽复用输出
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //上拉
GPIO_Init(GPIOA,&GPIO_InitStructure); //初始化 PA9,PA10
//USART 初始化设置
USART_InitStructure.USART_BaudRate = bound;//一般设置为 9600;
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); //初始化串口
USART_Cmd(USART1, ENABLE); //使能串口
USART_ClearFlag(USART1, USART_FLAG_TC);
#if EN_USART1_RX
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启中断
//Usart1 NVIC 配置
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 寄存器、
#endif
}
void USART1_IRQHandler(void) //串口 1 中断服务程序
{
u8 Res;
#if SYSTEM_SUPPORT_OS //如果 SYSTEM_SUPPORT_OS 为真,则需要支持 OS.
OSIntEnter();
#endif
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
//接收中断(接收到的数据必须是 0x0d 0x0a 结尾)
{
Res =USART_ReceiveData(USART1);//(USART1->DR); //读取接收到的数据
if((USART_RX_STA&0x8000)==0)//接收未完成
{
if(USART_RX_STA&0x4000)//接收到了 0x0d
{
if(Res!=0x0a)USART_RX_STA=0;//接收错误,重新开始
else USART_RX_STA|=0x8000; //接收完成了
}
else //还没收到 0X0D
{
if(Res==0x0d)USART_RX_STA|=0x4000;
else
{
USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ;
USART_RX_STA++;
if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;
//接收数据错误,重新开始接收
}
}
}
}
#if SYSTEM_SUPPORT_OS //如果 SYSTEM_SUPPORT_OS 为真,则需要支持 OS.
OSIntExit();
#endif
}
#endif
三:分析理解
3.1: 初始化端口:
针对初始化代码,较为简单,要记住GPIO初始化流程如下:
1:使能时钟模块–GPIO时钟+串口时钟
2:配置GPIO管脚映射
3:初始化GPIO相关管脚
4:串口1终端初始化
5:设置中断优先级
3.2:串口中断服务函数
重点分析中断服务函数:假设第一次接收到的数据为 abcd ;
u8 Res;
#if SYSTEM_SUPPORT_OS //如果 SYSTEM_SUPPORT_OS 为真,则需要支持 OS.
OSIntEnter();
#endif
1:定义 :变量Res:
目的:存储接收到的数据,成功则传递给数组USART_RX_BUF[ ];
2:检测是否使用系统
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
//接收中断(接收到的数据必须是 0x0d 0x0a 结尾)
{
Res =USART_ReceiveData(USART1);//(USART1->DR); //读取接收到的数据
.
.
.
}
3:判断是否接受中断
if 嵌套判断语句,最外层的 if 语句;
USART_GetITStatus函数,用于检测串口中断标志位的状态,判断是否因为USARTx接收到数据而产生中断;
ITStatus USART_GetITStatus(USART_TypeDef* USARTx, uint16_t USART_IT)
返回值为SET或RESET;
4:将数据一位一位读取
接受到中断后,进入 if 判断语句,进行USART_ReceiveData(USART_TypeDef* USARTx)函数,读取接收到的第一位数据 a ,并存入 Res 中(Res = a);
if((USART_RX_STA&0x8000)==0)//接收未完成
{
if(USART_RX_STA&0x4000)//接收到了 0x0d
{
if(Res!=0x0a)USART_RX_STA=0;//接收错误,重新开始
else USART_RX_STA|=0x8000; //接收完成了.
}
else //还没收到 0X0D
{
if(Res==0x0d)USART_RX_STA|=0x4000;
else
{
USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ;
USART_RX_STA++;
if(USART_RX_STA>(USART_REC_LEN-1))
USART_RX_STA=0;
//接收数据错误,重新开始接收
}
}
}
5:判断是否完成数据接收
u16 USART_RX_STA=0; //接收状态标记(在ASCII中0x0A和0x0D分别代表回车符和换行符)
USART_RX_STA | ||
bit15 | bit14 | bit13~0 |
接收完成标志 | 接收到0x0D标志 | 接收到的有效数据个数 |
所以此时0&0x8000==0,进入 if 判断语句。
6:判断USART_RX_STA是否接收到0x0D标志
USART_RX_STA&0x4000 判断接收状态标记的第14位是否为1;
7:若为1,则判断接收的数据是否错误,。
如果接收到的数据位不是0X0a,就将 USART_RX_STA 置零。
否则将USART_RX_STA 或上0x8000;
此时USART_RX_STA为0,否则进入else;
8:否则,判断尚未存入的最后一位数据是否为0x0D
判断Res参数中是否存入了最后一位数据0X0D,如果为真,将USART_RX_STA 或上0x4000,第14位置高;
9:具体赋值操作
否则将Res参数中暂时存储的数据存入USART_RX_BUF数组中;
此时USART_RX_STA的值为 0 ,USART_RX_STA&0X3FFF 为 0。
则USART_RX_BUF[0]中存放着Res的数据。
并且USART_RX_STA自增1。
若下次在执行此语句,则USART_RX_STA&0X3FFF的值将为1。
则将b存放在USART_RX_BUF[1]中。一直循环下去,直到接收到0x0d。
10:判断负赋值操作是否正常
#define USART_REC_LEN 200 //定义最大接收数据字数 200
如果USART_RX_STA状态标志中存储的数据多余200时,标定为接收错误,同时置零,重新开始接收。
作者:晚生三石