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

一、串口配置

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

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

 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单片机串口接收中断配置如下:

   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这帧简单数据为例子讲解。
前两个字节为头和功能码
第三个字节为总长度
最后两个字节为尾
没有校验

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为头的数据包。

//中断接收多包数据
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
            {
              //尾不对
            }
        }
     }
  }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/953113.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Github Copilot学习笔记

(一)Prompt Engineering 利用AI工具生成prompt设计好的prompt结构使用MarkDown语法,按Role, Skills, Constrains, Background, Requirements和Demo这几个维度描述需求。然后收输入提示词:作为 [Role], 拥有 [Skills], 严格遵守 […

在 Rider 中使用 C# 创建 Windows 窗体应用 Winforms

1,创建项目 new solution 创建一个解决方案 2,打开设计器 在 Form1.cs 上右键打开设计器 认识一下 Rider 的界面 参考微软官方的例子,添加如下属性:注:这里 Listbox 的大小设置成 120, 94 失败,默认的是 12…

R数据分析:多分类问题预测模型的ROC做法及解释

有同学做了个多分类的预测模型,结局有三个类别,做的模型包括多分类逻辑回归、随机森林和决策树,多分类逻辑回归是用ROC曲线并报告AUC作为模型评估的,后面两种模型报告了混淆矩阵,审稿人就提出要统一模型评估指标。那么肯定是统一成ROC了,刚好借这个机会给大家讲讲ROC在多…

#Java-集合进阶-Map

1.Map 声明1 1.1 双列集合的特点 单列集合一次只能添加一个元素,双列集合一次可以添加一对元素 例: 小米手机2000华为手机5000苹果手机9000 这三对元素,左边的我们称之为键,右边的称为值。他们是一一对应的关系 所以双列集合中…

IntelliJ IDEA和MAVEN基本操作:项目和缓存存储到非C盘

为了将 IntelliJ IDEA 的所有项目和缓存存储到 C 盘以外的地方,以下是你需要调整的设置和步骤: 1. 更改项目默认存储位置 打开 IntelliJ IDEA。点击顶部菜单的 File > Settings (Windows)或 IntelliJ IDEA > Preferences &…

【Linux系列】`find / -name cacert.pem` 文件搜索

💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

RabbitMQ基础(简单易懂)

RabbitMQ高级篇请看: RabbitMQ高级篇-CSDN博客 目录 什么是RabbitMQ? MQ 的核心概念 1. RabbitMQ 的核心组件 2. Exchange 的类型 3. 数据流向说明 如何安装RabbitQueue? WorkQueue(工作队列): Fa…

《Spring Framework实战》5:Spring Framework 概述

欢迎观看《Spring Framework实战》视频教程 Spring 使创建 Java 企业应用程序变得容易。它为您提供一切 需要在企业环境中采用 Java 语言,并支持 Groovy 和 Kotlin 作为 JVM 上的替代语言,并且可以灵活地创建许多 类型的架构。从 Spring Framework 6.0 开…

有限元分析学习——Anasys Workbanch第一阶段笔记(10)桌子载荷案例分析_实际载荷与均布载荷的对比

目录 0 序言 1 桌子案例 2 模型简化 3 方案A 前处理 1)分析类型选择 2)材料加载 3)约束、载荷及接触 4)控制网格(网格大小需要根据结果不断调整) 初始计算结果 加密后计算结果 4 方案B、C 前处理 1)分析…

Git 基础——《Pro Git》

⭐获取 Git 仓库 获取 Git 仓库有两种方式: 将未进行版本控制的本地目录转换为 Git 仓库。从其他服务器克隆一个已存在的 Git 仓库。 在已存在目录中初始化 Git 仓库 进入目标目录 在 Linux 上:$ cd /home/user/my_project在 macOS 上:$ c…

Java 将RTF文档转换为Word、PDF、HTML、图片

RTF文档因其跨平台兼容性而广泛使用,但有时在不同的应用场景可能需要特定的文档格式。例如,Word文档适合编辑和协作,PDF文档适合打印和分发,HTML文档适合在线展示,图片格式则适合社交媒体分享。因此我们可能会需要将RT…

R语言在森林生态研究中的魔法:结构、功能与稳定性分析——发现数据背后的生态故事!

森林生态系统结构、功能与稳定性分析与可视化研究具有多方面的重要意义,具体如下: 一、理论意义 ●深化生态学理论 通过研究森林生态系统的结构、功能与稳定性,可以深化对生态系统基本理论的理解。例如,生物多样性与生态系统稳定性…

Delphi+SQL Server实现的(GUI)户籍管理系统

1.项目简介 本项目是一个户籍管理系统,用于记录住户身份信息,提供新户登记(增加)、户籍变更(修改)、户籍注销(删除)、户籍查询、曾用名查询、迁户记录查询以及创建备份、删除备份共8…

第2课 “Hello World” 与 print

1 Hello World 2 print 函数解析 2.1 基本用法 2.2 输出多个对象 2.3 使用sep参数 2.4 使用flush参数 2.5 输出到文件 3 格式化输出 3.1 格式化输出整数 3.2 格式化输出16进制整数 3.3 格式化输出浮点数(float) 3.4 格式化输出字符串(string) 3.5 输出列表与字典 …

计算机网络(四)网络层

4.1、网络层概述 简介 网络层的主要任务是实现网络互连,进而实现数据包在各网络之间的传输 这些异构型网络N1~N7如果只是需要各自内部通信,他们只要实现各自的物理层和数据链路层即可 但是如果要将这些异构型网络互连起来,形成一个更大的互…

qt 窗口(window/widget)绘制/渲染顺序 QPainter QPaintDevice Qpainter渲染 失效 无效 原因

qt窗体布局 窗体渲染过程 qt中窗体渲染逻辑顺序为 本窗体->子窗体/控件 递归,也就是说先渲染父窗体再渲染子窗体。其中子窗体按加入时的先后顺序进行渲染。通过下方的函数调用堆栈可以看出窗体都是在widget组件源码的widgetprivate::drawwidget中进行渲染的&am…

网络安全-kail linux 网络配置(基础篇)

一、网络配置 1.查看网络IP地址, 我的kail:192.168.15.128 使用ifconfig查看kail网络连接情况,ip地址情况 又复制了一台kail计算机的IP地址。 再看一下windows本机:使用ipconfig进行查看: 再看一下虚拟机上的win7I…

Edge浏览器内置的截长图功能

Edge浏览器内置截图功能 近年来,Edge浏览器不断更新和完善,也提供了长截图功能。在Edge中,只需点击右上角的“...”,然后选择“网页捕获”->“捕获整页”,即可实现长截图。这一功能的简单易用,使其成为…

【NLP】语言模型的发展历程 (1)

语言模型的发展历程系列博客主要包含以下文章: 【NLP】语言模型的发展历程 (1)【NLP】大语言模型的发展历程 (2) 本篇博客是该系列的第一篇,主要讲讲 语言模型(LM,Language Model) 的发展历程。 文章目录 一、统计语…

【ASP.NET学习】ASP.NET MVC基本编程

文章目录 ASP.NET MVCMVC 编程模式ASP.NET MVC - Internet 应用程序创建MVC web应用程序应用程序信息应用程序文件配置文件 用新建的ASP.NET MVC程序做一个简单计算器1. **修改视图文件**2. **修改控制器文件** 用新建的ASP.NET MVC程序做一个复杂计算器1.创建模型(…