STM32和国民技术(N32)单片机串口中断接收数据及数据解析

一、串口配置

根据单片机不同,串口IO口配置也不同,像STM32单片机,RX脚可以配置为复用输出,也可以配置为浮空输入模式。但是国民技术单片机(N32)的RX是不能配置为复用输出模式的,这样是收不到数据的,只能配置为浮空输入模式。其他的单片机情况也不一样。使用时候需要注意。

STM32单片机串口接收中断配置代码如下:

c 复制代码
 void uart_init(u32 bound)
{
  GPIO_InitTypeDef GPIO_Initstructure;
	USART_InitTypeDef USART_Initstructure;
	NVIC_InitTypeDef NVIC_Initstrcuture;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE );
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA ,ENABLE );
	
	GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_USART1);
	GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_USART1);
	
  GPIO_Initstructure.GPIO_Pin = GPIO_Pin_9;
	GPIO_Initstructure.GPIO_Mode = GPIO_Mode_AF;
	GPIO_Initstructure.GPIO_OType = GPIO_OType_PP;
	GPIO_Initstructure.GPIO_PuPd = GPIO_PuPd_UP;
	GPIO_Initstructure.GPIO_Speed = GPIO_Speed_100MHz;
	GPIO_Init(GPIOA,&GPIO_Initstructure);
	GPIO_Initstructure.GPIO_Pin = GPIO_Pin_10;
	GPIO_Initstructure.GPIO_Mode = GPIO_Mode_AF;
	GPIO_Initstructure.GPIO_OType = GPIO_OType_PP;
	GPIO_Initstructure.GPIO_PuPd = GPIO_PuPd_UP;
	GPIO_Initstructure.GPIO_Speed = GPIO_Speed_100MHz;
	GPIO_Init(GPIOA,&GPIO_Initstructure);
	
	USART_Initstructure.USART_BaudRate = bound;
	USART_Initstructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
	USART_Initstructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
	USART_Initstructure.USART_Parity = USART_Parity_No;
	USART_Initstructure.USART_StopBits = USART_StopBits_1;
	USART_Initstructure.USART_WordLength = USART_WordLength_8b;
	USART_Init(USART1,&USART_Initstructure);
	
	NVIC_Initstrcuture.NVIC_IRQChannel = USART1_IRQn;
	NVIC_Initstrcuture.NVIC_IRQChannelPreemptionPriority=3;
	NVIC_Initstrcuture.NVIC_IRQChannelSubPriority =3;		
	NVIC_Initstrcuture.NVIC_IRQChannelCmd = ENABLE;		
	NVIC_Init(&NVIC_Initstrcuture);	
	
	USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);	//串口接收中断
	//USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);	//串口空闲中断
  USART_Cmd(USART1, ENABLE);
}

N32单片机串口接收中断配置如下:

c 复制代码
   void Uart_Init(u32 band)
   {
    RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_GPIOA|RCC_APB2_PERIPH_AFIO,ENABLE);
    RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_USART1,ENABLE);
    GPIO_InitType GPIO_InitStructure;
	USART_InitType USART_InitStructure;
	NVIC_InitType NVIC_InitStructure;
	
     GPIO_InitStructure.Pin  = GPIO_PIN_10;
     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
     GPIO_InitPeripheral(UART_GPIO_INIT, &GPIO_InitStructure);
	
	 GPIO_InitStructure.Pin = GPIO_PIN_9;
	 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	
	 GPIO_InitPeripheral(USART1, &GPIO_InitStructure);
  
   USART_InitStructure.BaudRate = band;
	 USART_InitStructure.Parity = USART_PE_NO;
	 USART_InitStructure.StopBits = USART_STPB_1;
	 USART_InitStructure.WordLength = USART_WL_8B;
	 USART_InitStructure.HardwareFlowControl = USART_HFCTRL_NONE;
	 USART_InitStructure.Mode = USART_MODE_RX | USART_MODE_TX;
	
	 USART_Init(USART1, &USART_InitStructure);
   
    NVIC_InitStructure.NVIC_IRQChannel                   = USART1_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority        = 2;
    NVIC_InitStructure.NVIC_IRQChannelCmd                = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
  
    USART_ConfigInt(USART1, USART_INT_RXDNE, ENABLE);
	
	 USART_Enable(USART1, ENABLE);
	}

这个中断就是串口缓冲区有数据时候就会产生中断,也就是接收到一个字节就中断一次。如果是那种数据量很大且需要持续发的情况可以选择使用DMA结合串口空闲中断使用比较方便。串口空闲中断就是发完一整包数据才进行中断。

二、串口中断解析

以0x12 ,0x13 0x0a 0x01 0x02 0x03,0x04,0x05,0xab,0xac这帧简单数据为例子讲解。

前两个字节为头和功能码

第三个字节为总长度

最后两个字节为尾

没有校验

c 复制代码
volatile u32 Buff_Num; //全局变量
u32 Buff_Len;
//正取写法
void USART1_IRQHandler(void)
{
    if(USART_GetIntStatus(USART1,USART_INT_RXDNE))
   {
      Rece_Buff[Buff_Num++] =USART_ReceiveData(USART1);
      USART_ClrIntPendingBit(USART1,USART_INT_RXDNE); //先取数据后清标准正确写法
          
      if(Buff_Num ==1)       
      {
         if(Rece_Buff[0]!=0xfe)
         {
            Buff_Num=0;
         }
      }
      else if(Buff_Num ==2)
      {
         if(Rece_Buff[1]!=0x54)
         {
            Buff_Num=0;
         }
      }  //逐一字节对齐正确写法
      else if(Buff_Num ==3)
      {
        Buff_Len = Rece_Buff[2];
      }
      else
      {
        if(Buff_Num==Buff_Len)
         { 
            Buff_Num=0;
            if(Rece_Buff[Buff_Len-2]==0xab&&Rece_Buff[Buff_Len-1]==0xac)
            {
             //取出数据使用
            }
            else
            {
              //尾不对
            }
        }
     }
  }
}

//错误写法
void USART1_IRQHandler(void)
{
    if(USART_GetIntStatus(USART1,USART_INT_RXDNE))
   { 
      USART_ClrIntPendingBit(USART1,USART_INT_RXDNE);
      Rece_Buff[Buff_Num++] =USART_ReceiveData(USART1); //先清标志后取数据错误写法
       
      if(Buff_Num ==2)       
      {
         if(Rece_Buff[0]!=0xfe&&Rece_Buff[1]!=0x54)
         {
            Buff_Num=0;
         }
      }  //不逐一字节进行对齐错误写法
      
      else if(Buff_Num ==3)
      {
        Buff_Len = Rece_Buff[2];
      }
      else
      {
        if(Buff_Num==Buff_Len)
         { 
            Buff_Num=0;
            if(Rece_Buff[Buff_Len-2]==0xab&&Rece_Buff[Buff_Len-1]==0xac)
            {
             //取出数据使用
            }
            else
            {
              //尾不对
            }
        }
     }
  }
}

串口接收中断和数据解析需要注意两个问题:

1.应该先取数据后清标志。

如果先清标志位,在取数据。会出现,数据还没有取出来就告诉单片机我数据已经取出来,然后下一个数据过来了,而寄存器上一个数据还在,没有读出去无法接收下一个数据就会导致触发溢出中断。如果没有清除溢出中断标志位,会一直触发溢出中断卡在中断出不去。

这就好比,碗里成满饭,还没开始吃,就告诉盛饭的人你的碗空了,那下一碗饭过来,碗装不下就会溢出。但是先取数据再清标志位就是碗里有饭,先吃完饭再告诉盛饭的人碗空了,那下一碗饭来才能正常装。

2.数据从头对齐时候必须一个一个字节进行对齐

我平时习惯那种错误写法,头两个字节一起去对,这样只有没有其他数据,或者刚好数据长度是对的时候才能对齐。有其他数据包或者长度不对的时候,除了第一包可以对齐,后面永远对不齐。就不能正常接收数据包了。

三,需要接收多包数据并解析

只需要在判断头那里或上其他的头就可以。

例如:

1 . 接收0xa1 0xa2为头的数据包。

2 . 接收0xb1 0xb2为头的数据包。

3 . 接收0xc1 0xc2为头的数据包。

c 复制代码
//中断接收多包数据
void USART1_IRQHandler(void)
{
    if(USART_GetIntStatus(USART1,USART_INT_RXDNE))
   {
      Rece_Buff[Buff_Num++] =USART_ReceiveData(USART1);
      USART_ClrIntPendingBit(USART1,USART_INT_RXDNE); //先取数据后清标准正确写法
          
      if(Buff_Num ==1)       
      {
         if(Rece_Buff[0]!=0xa1||Rece_Buff[0]!=0xb1||Rece_Buff[0]!=0xc1)
         {
            Buff_Num=0;
         }
      }
      else if(Buff_Num ==2)
      {
         if(Rece_Buff[1]!=0xa2||Rece_Buff[1]!=0xb2||Rece_Buff[1]!=0xc2)
         {
            Buff_Num=0;
         }
      }  //正确写法
      else if(Buff_Num ==3)
      {
        Buff_Len = Rece_Buff[2];  //各包长度不一样这里会取
      }
      else
      {
        if(Buff_Num==Buff_Len)
         { 
            Buff_Num=0;
            if(Rece_Buff[Buff_Len-2]==0xab&&Rece_Buff[Buff_Len-1]==0xac)
            {
             //取出数据使用
            }
            else
            {
              //尾不对
            }
        }
     }
  }
}
相关推荐
沐欣工作室_lvyiyi1 小时前
基于物联网技术的电动车防盗系统设计(论文+源码)
单片机·嵌入式硬件·毕业设计·单片机毕业设计·nbiot
厉昱辰3 小时前
一文读懂单片机的串口
单片机·嵌入式硬件
沐欣工作室_lvyiyi3 小时前
基于STM32的智能生态水族箱系统设计(论文+源码)
stm32·单片机·嵌入式硬件·物联网·毕业设计·水族箱
7yewh4 小时前
自制红外热像仪(二) MLX90640移植 RP2040 STM32 ESP32
驱动开发·stm32·单片机·嵌入式硬件·mcu·计算机视觉
冰糖雪莲IO5 小时前
【江协STM32】10-2/3 MPU6050简介、软件I2C读写MPU6050
stm32·单片机·嵌入式硬件
1101 11015 小时前
STM32-笔记39-SPI-W25Q128
笔记·stm32·嵌入式硬件
Leiditech__5 小时前
汽车氛围灯静电浪涌的难点
嵌入式硬件·汽车·硬件工程
云山工作室7 小时前
基于单片机的客车载客状况自动检测系统(论文+源码)
单片机·嵌入式硬件·毕业设计·毕设
2301_805962939 小时前
NRF24L01模块STM32通信-发送端
stm32·单片机·嵌入式硬件
LeoZY_11 小时前
CH348结合开源ModBus协议组成串口温度采集服务器
运维·笔记·嵌入式硬件·开源