基于探索者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时,标定为接收错误,同时置零,重新开始接收。

作者:晚生三石

物联沃分享整理
物联沃-IOTWORD物联网 » 基于探索者STM32F407单片机学习——串口1初始化函数

发表回复