×
单片机 > 单片机程序设计 > 详情

STM32 UART常用的3种中断接收

发布时间:2020-08-21 发布时间:
|

#include "sys.h"
#include "usart.h"  
#include "main.h"


//如果使用ucos,则包括下面的头文件即可.
#if SYSTEM_SUPPORT_OS
#include "includes.h" //ucos 使用 
#endif




//注意,读取USARTx->SR能避免莫名其妙的错误   
u8 USART1_RX_BUF[USART_RX_LEN];     //接收缓冲,最USART_RX_LEN个字节
u8 USART2_RX_BUF[USART_RX_LEN];      //接收缓冲,最USART_RX_LEN个字节
u8 USART1_TX_BUF[USART_TX_LEN]; //发送缓冲,最大USART_TX_LEN个字节
u8 USART2_TX_BUF[USART_TX_LEN]; //发送缓冲,最大USART_TX_LEN个字节
u8 USART1_RX_STA;       //接收完成状态标记 
u8 USART2_RX_STA;       //接收完成状态标记
u8 USART3_RX_STA;       //接收完成状态标记
//u8 USART1_Count =0; //USART1接收计数器
//u8 USART2_Count =0; //USART2接收计数器
u8 TX1_cn,TX1_no,RX1_cn,RX_no;
u8 TX2_cn,TX2_no,RX2_cn,RX2_no;
u8 u8Uart2_FSM;


void usart1_init(u32 baud)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
// NVIC_InitTypeDef NVIC_InitStructure;


/* 第1步:打开GPIO和USART部件的时钟 */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);


/* 第2步:将USART Tx的GPIO配置为推挽复用模式 */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);


/* 第3步:将USART Rx的GPIO配置为浮空输入模式
由于CPU复位后,GPIO缺省都是浮空输入模式,因此下面这个步骤不是必须的
但是,我还是建议加上便于阅读,并且防止其它地方修改了这个口线的设置参数
*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/*  第3步已经做了,因此这步可以不做
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
*/
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* 第4步:配置USART参数
   - 波特率   = 115200 baud
   - 数据长度 = 8 Bits
   - 1个停止位
   - 无校验
   - 禁止硬件流控(即禁止RTS和CTS)
   - 使能接收和发送
*/
USART_InitStructure.USART_BaudRate = baud;
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(USART1, &USART_InitStructure);  
//  //Usart1 NVIC 配置
//  NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
// NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1 ;//抢占优先级1
// NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;//子优先级3
// NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//IRQ通道使能
// NVIC_Init(&NVIC_InitStructure);//根据指定的参数初始化VIC寄存器
    
  USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启串口接受中断
  /* 第5步:使能 USART, 配置完毕 */
USART_Cmd(USART1, ENABLE);
// CPU的小缺陷:串口配置好,如果直接Send,则第1个字节发送不出去
// 如下语句解决第1个字节无法正确发送出去的问题:
// 清发送完成标志,Transmission Complete flag 
USART_ClearFlag(USART1, USART_FLAG_TC); 
}




/*************************************************************************************************************************
* 函数 : void uart2_init(u32 baud) 
* 功能 :  USART2做RS485接口使用,
* 参数 :  输入的波特率
* 返回 :  无
* 依赖 :  底层库函数
* 作者 :  li_qcxy@126.com
* 时间 :  2016-12-9
* 最后修改时间 : 
* 说明 : PA1为接收发送使能脚
*************************************************************************************************************************/ 
void usart2_init(u32 baud)     //485通信串口初始化
{
  //GPIO端口设置
  GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
 
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//使能USART2,GPIOA时钟
  
//USART2_TX   GPIOA.2
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; //PA.2
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //复用推挽输出
  GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.2
   
  //USART2_RX  GPIOA.3初始化
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;//PA3
  //GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
  GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.3  

//USART2_RX_EN使能
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;//PA1
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//IO口速度为50MHz
GPIO_Init(GPIOA, &GPIO_InitStructure);//根据设定参数初始化GPIOA1
EN_USART2_RX();//接收模式

  //Usart2 NVIC 配置
  NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1 ;//抢占优先级1
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;//子优先级3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//IRQ通道使能
NVIC_Init(&NVIC_InitStructure);//根据指定的参数初始化VIC寄存器
  
  //USART 初始化设置
USART_InitStructure.USART_BaudRate = baud;//串口波特率
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(USART2, &USART_InitStructure); //初始化串口2
  USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);//开启串口接受中断
  USART_Cmd(USART2, ENABLE);                    //使能串口2 
  USART2 -> CR1 = USART2 -> CR1;
}






//获取USART2当前接收计数器值
u32 UARTx_GetRxCnt(void)
{
return TX2_no;
}


/*************************************************************************************************************************
* 函数 : void USART1_IRQHandler(void) 
* 功能 :  采用缓冲区满标志位的方法判断数据接收完成
* 参数 :  无
* 返回 :  无
* 依赖 :  底层读写函数
* 作者 :  li_qcxy@126.com
* 时间 :  2016-12-8
* 最后修改时间 : 
* 说明 : 
*************************************************************************************************************************/
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_RX_BUF[TX2_no++]=Res; 
     } 
else if(TX2_no == USART_RX_LEN)//接收缓冲区接收满,即接收完成
{
TX2_no = 0;
USART1_RX_STA = 1;
}
#if SYSTEM_SUPPORT_OS //如果SYSTEM_SUPPORT_OS为真,则需要支持OS.
OSIntExit();   
#endif
}
/*************************************************************************************************************************
* 函数 : void USART2_IRQHandler(void) 
* 功能 :  采用空闲中断的方法判断数据接收完成
* 参数 :  无
* 返回 :  无
* 依赖 :  底层读写函数
* 作者 :  li_qcxy@126.com
* 时间 :  2016-12-8
* 最后修改时间 : 
* 说明 : 
*************************************************************************************************************************/
void USART3_IRQHandler(void)                //串口2中断服务程序
{  
  u8 Res;
 if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)  //接收中断(接收到的数据必须是0x0d 0x0a结尾)
{
    Res =USART_ReceiveData(USART2);//(USART2->DR);//读取接收到的数据
  USART2_RX_BUF[TX2_no++]=Res;
}
else if((USART_GetITStatus(USART2, USART_IT_IDLE) != RESET))//使用空闲中断判断接收不定长数据完成
{  
USART3_RX_STA = 1;//数据接收完成标志位
//
}
}


/*************************************************************************************************************************
* 函数 : void USART2_IRQHandler(void) 
* 功能 :  采用状态机的方法判断数据接收完成
* 参数 :  无
* 返回 :  无
* 依赖 :  底层读写函数
* 作者 :  li_qcxy@126.com
* 时间 :  2016-12-8
* 最后修改时间 : 
* 说明 : 
*************************************************************************************************************************/
void USART2_IRQHandler(void)             
{
 u8 u8Temp;
 /*****************发送中断************************************/
 if (USART_GetITStatus(USART2, USART_IT_TC) == SET)
 { 
  if(TX2_cn >= (TX2_no))
  {
  EN_USART2_TX();
  USART_ITConfig(USART2, USART_IT_TC, DISABLE);
   USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);
   u8Uart2_FSM = U_FSM_ADR;
  }
  else
  {
  u8Temp = USART2_TX_BUF[TX2_cn++];
  USART2->DR = (u16)u8Temp;
  }
 }
 
 /******************接收中断*************************************/
 if (USART_GetITStatus(USART2, USART_IT_RXNE) == SET)
 {
  u8Temp = (u8)USART2->DR;
  switch(u8Uart2_FSM)
  {
   case U_FSM_ADR:
   {
    if(u8Temp == local_info.id)  //本地地址
    {
     USART2_RX_BUF[0] = u8Temp;
     u8Uart2_FSM = U_FSM_FUN;
    }
break;
   }
   case U_FSM_FUN:
   {
    if((u8Temp == 0x05)||(u8Temp == 0x01)||(u8Temp == 0x03)||(u8Temp == 0x04)) //本单元值接受0x05和0x01的指令,遥信和遥控
    {
     USART2_RX_BUF[1] = u8Temp;
     u8Uart2_FSM = U_FSM_DATA;
     RX2_no = 8; 
     RX2_cn = 2;
    }
else if(u8Temp == 0x10)
{
USART2_RX_BUF[1] = u8Temp;
     u8Uart2_FSM = U_FSM_FUN16;
//     RX2_no = 15; 
     RX2_cn = 2;
}
    else
{
     u8Uart2_FSM = U_FSM_ADR;
}
break;
}
case U_FSM_FUN16:
{
USART2_RX_BUF[RX2_cn++] = u8Temp;
if(RX2_cn == 6)
{
USART2_RX_BUF[6] = u8Temp;
u8Uart2_FSM = U_FSM_DATA16;
RX2_cn = 7;
RX2_no = 9 + USART2_RX_BUF[6];
}
// else
// {
// USART2_RX_BUF[RX2_cn++] = u8Temp;
// }
break;
}
   case U_FSM_DATA:
   {
    USART2_RX_BUF[RX2_cn++] = u8Temp;
    if(RX2_no <= RX2_cn)                 //数据接收完毕
    { 
    u8Uart2_FSM = U_FSM_ADR;  
USART_ITConfig(USART2, USART_IT_RXNE, DISABLE);  //一帧数据收完,不再接受数据
    USART2_RX_STA = 1;//置一帧数据接收完标志
//   GPIOA->ODR |= GPIO_Pin_8;
//   GPIO_SetBits(GPIOA,GPIO_Pin_11); 
    }
  break; 
   }
case U_FSM_DATA16:
{
USART2_RX_BUF[RX2_cn++] = u8Temp;
    if(RX2_no <= RX2_cn)                 //数据接收完毕
    { 
    u8Uart2_FSM = U_FSM_ADR;  
USART_ITConfig(USART2, USART_IT_RXNE, DISABLE);  //一帧数据收完,不再接受数据
    USART2_RX_STA = 1;//置一帧数据接收完标志
}
   break;
   }
default:{u8Uart2_FSM = U_FSM_ADR; break;}
  }
 } 
}

关键字:STM32  UART  中断接收 

『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
C51 特殊功能寄存器SFR的名称和地址