物联网实战--入门篇之(四)嵌入式-UART驱动

        

目录

一、串口简介

二、串口驱动设计

三、串口发送

四、串口接收处理

五、PM2.5数据接收处理

六、printf重定义

七、总结


一、串口简介

        串口在单片机的开发中属于非常常用的外设,最基本的都会预留一个调试串口用来输出调试信息,串口时序这里就不谈了,主要来看看STM32中串口是怎么运行的。

void UART1_Init(void) 
{GPIO_InitTypeDef GPIO_InitStructure;USART_InitTypeDef USART_InitStructure;NVIC_InitTypeDef NVIC_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;// GPIO_Mode_AF_ODGPIO_Init(GPIOA, &GPIO_InitStructure);    //TXGPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;GPIO_Init(GPIOA, &GPIO_InitStructure);    //RX	USART_InitStructure.USART_BaudRate = BAUD_UART1;//波特率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); //初始化串口NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; //使能串口中断NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //主优先级NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //从优先级NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能外部中断通道NVIC_Init(&NVIC_InitStructure); //初始化NVICUSART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//接收中断USART_Cmd(USART1, ENABLE);                    //使能串口	g_sUART1.USARTx=USART1;g_sUART1.PortNum=1;g_sUART1.pBuff=g_u8UART1_Buff;//把数据指针指向接收缓冲区g_sUART1.total_len=UART1_LEN;
}

        先从初始化开始,基本上就是打开对应的时钟,初始化引脚,配置串口参数,配置接收中断,最后使能串口。

/*		
================================================================================
描述 :串口中断函数
输入 : 
输出 : 
================================================================================
*/
void USART1_IRQHandler(void)
{if(USART_GetITStatus(USART1, USART_IT_RXNE) == SET)//获取接收状态{g_sUART1.pBuff[g_sUART1.iRecv]=USART_ReceiveData(USART1);//缓存接收字节		USART_ClearITPendingBit(USART1, USART_IT_RXNE);//清理中断位USART_ClearFlag(USART1, USART_FLAG_RXNE);//清理标志位g_sUART1.iRecv++;//接收长度加1if(g_sUART1.iRecv>=UART1_LEN)g_sUART1.iRecv=0;}else if (USART_GetFlagStatus(USART1, USART_FLAG_ORE) != RESET)//接收错误{USART_ReceiveData(USART1);
//		USART_ClearITPendingBit(USART1, USART_IT_ORE);USART_ClearFlag(USART1, USART_FLAG_ORE);}	
}

        串口是接收一个字节产生一个中断,不要再中断函数里面有过多的操作,就是连续缓存数据就好,其他的操作在外部程序中去执行;另外,如果串口数据接收错误或者溢出经常会发生ORE错误,导致一直进中断,程序直接卡死,这里就要处理下这个错误,避免卡死。

二、串口驱动设计

        我这里要重点说明的是设计思想,根据下面的头文件可知,首先定义一个结构体,用来存放串口的配置信息;结合附图,在初始化阶段把串口地址、串口号、缓冲区指针和长度都赋值了;最后将定义的三个串口结构体用extern 暴露给外部文件使用。

#ifndef __DRV_UART_H__
#define __DRV_UART_H__#include "drv_common.h"typedef struct
{USART_TypeDef* USARTx;u8 PortNum;//串口号u8 *pBuff;//数据指针u16 iRecv;//已接收长度u16 iDone;//已处理长度u16 total_len;//总长度
}UART_Struct;extern UART_Struct g_sUART1;
extern UART_Struct g_sUART2;
extern UART_Struct g_sUART3;void UART_Init(void);
void UART1_Init(void); 
void UART2_Init(void); 
void UART3_Init(void);void UART_Send(u8 PortNum, u8 *buf, u16 len);
void UART_Clear(UART_Struct *pUART);void UART1_Send(u8 *buf, u16 len);
void UART2_Send(u8 *buf, u16 len);
void UART3_Send(u8 *buf, u16 len);#endif

三、串口发送

        串口发送较为简单,注意点就是while状态检测,一个字节发送完成才能发送下一个字节;还有就是最后的延时2ms,这个主要是在实际测试中发现有时候最后一个字节发送不完整,特别是RS485发送的时候,加个延时就能解决了。

/*		
================================================================================
描述 :串口1发送
输入 : 
输出 : 
================================================================================
*/
void UART1_Send(u8 *buf, u16 len)
{u16 i;for(i=0;i<len;i++){while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);	//发送完成USART_SendData(USART1,buf[i]);}while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);	//发送完成		delay_ms(2); 
}
四、串口接收处理

        串口在接收中断函数里不断缓存数据,在应用层只需要引用相应数据指针即可,这里以调试串口指令处理为例,具体代码如下。

        首先引用串口1指针,然后在while循环里不断检测是否有收到数据,如果iRecv>0,那么说明有数据,但是此时不一定已经接收完成了,所以定义了recv_len缓存当前的数据长度,经过5ms延时后,如果recv_len和iRecv相等,那么就说明接收完整了,可以做进一步的数据处理。

        接下来是数据处理,根据个人应用具体修改,这里我是复位、取消订阅和PWM设置指令,在开发过程中做调试使用,项目完成后可删除;具体就是使用strstr()函数去检索是否包含指定字符串,然后根据指令去执行对应的动作。

        最后就是要用UART_Clear(pUART);清理下缓冲区数据。

五、PM2.5数据接收处理

        以下是PM2.5传感器的说明书,波特率是9600,传感器每隔1秒主动输出数据,其数据流的第一字节固定是0xA5,中间两字节是浓度值,最后一个字节是校验码。先思考下这种数据流应该如何解析?

        因为我们对PM2.5的实时性要求不会很高,三四秒更新一次即可,也就是三四秒处理一次串口的缓冲数据即可,代码如下所示。判断下接收长度是否大于等于4个字节,是的话进入校验环节,校验通过后再根据说明书组合浓度值,这里要注意的是,原始浓度值只是粉尘浓度,并不是PM2.5,根据XM净化器的数值大概标定下,乘以系数0.04;最后就是清理下缓冲区即可。

        主程序或任务线程调用时就四秒调用一次,如下图所示,就是在每次上报时更新下数据即可。

六、printf重定义

        printf是一个很有用的格式化输出函数,在PC端编写C语言的时候经常会用到,它会将数据打印到控制台上。那么,在单片机上,我们要如何把它的内容输出到指定的串口呢?这里就涉及到了重定义函数了,具体如下所示:

        其中UART_DEBUG在user_opt.h中定义,这样可以决定是否需要输出、用哪个串口输出。

七、总结

        至此,串口驱动也就差不多了,串口作为常用外设,几乎在每个项目中都会用到,这里通过驱动函数的形式保证了代码的重复利用的能力,再利用宏定义的方式对具体参数进行自定义配置,从而保证了通用型和灵活性。

本项目的交流QQ群:701889554

   写于2024-3-30

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

洛谷-P1706 全排列问题(DFS)

目录 题目链接&#xff1a; 思路&#xff1a; 代码&#xff1a; 题目链接&#xff1a; P1706 全排列问题 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 思路&#xff1a; 如果n比较小&#xff0c;可以写n个for循环输出全排列。但是这种简单方法只能用于较小的n&#xff0…

代码随想录算法训练营第三十六天|435. 无重叠区间,763. 划分字母区间

435. 无重叠区间 题目 给定一个区间的集合 intervals &#xff0c;其中 intervals[i] [starti, endi] 。返回 需要移除区间的最小数量&#xff0c;使剩余区间互不重叠 。 示例 1: 输入: intervals [[1,2],[2,3],[3,4],[1,3]] 输出: 1 解释: 移除 [1,3] 后&#xff0c;剩下…

基于opencv的SVM算法的车牌识别系统设计与实现

基于opencv的SVM算法的车牌识别系统设计与实现 车牌识别技术是智能交通系统中的一项关键技术&#xff0c;它能够自动识别车辆的车牌号码。本文将详细介绍如何使用Python编程语言结合OpenCV库和SVM算法来实现车牌识别系统。 系统架构 车牌识别系统主要包括以下几个模块&…

提高生产力!这10个Lambda表达式必须掌握,开发效率嘎嘎上升!

在Java8及更高版本中&#xff0c;Lambda表达式的引入极大地提升了编程的简洁性和效率。本文将围绕十个关键场景&#xff0c;展示Lambda如何助力提升开发效率&#xff0c;让代码更加精炼且易于理解。 集合遍历 传统的for-each循环对集合进行遍历虽然直观&#xff0c;但在处理大…

Python(乱学)

字典在转化为其他类型时&#xff0c;会出现是否舍弃value的操作&#xff0c;只有在转化为字符串的时候才不会舍弃value 注释的快捷键是ctrl/ 字符串无法与整数&#xff0c;浮点数&#xff0c;等用加号完成拼接 5不入&#xff1f;&#xff1f;&#xff1f; 还有一种格式化的方法…

jupyter notebook 配置默认文件路径

Jupyter是一种基于Web的交互式计算环境&#xff0c;支持多种编程语言&#xff0c;如Python、R、Julia等。使用Jupyter可以在浏览器中编写和运行代码&#xff0c;同时还可以添加Markdown文本、数学公式、图片等多种元素&#xff0c;非常适合于数据分析、机器学习等领域。 安装 …

理解VAE,可视化

引言 本文主要摘抄自&#xff1a;Understanding Variational Autoencoders (VAEs), Joseph Rocca, Sep 24, 2019&#xff0c;同时会加一些自己的理解和对原文的解释。 关于数据生成&#xff0c;目前深度生成模型中主流的有&#xff1a; 生成对抗网络——GANs&#xff0c;这是…

超市销售数据-python数据分析项目

Python数据分析项目-基于Python的销售数据分析项目 文章目录 Python数据分析项目-基于Python的销售数据分析项目项目介绍数据分析结果导出数据查阅 数据分析内容哪些类别比较畅销?哪些商品比较畅销?不同门店的销售额占比哪个时间段是超市的客流高封期?查看源数据类型计算本月…

QT 实现无边框可伸缩变换有阴影的QDialog弹窗

实现无标题栏窗口的拖拽移动、调节窗口大小以及边框阴影效果。初始化时进行位或操作&#xff0c;将这些标志合并为一个值&#xff0c;并将其设置为窗口的标志。这些标志分别表示这是一个对话框、无边框窗口、有标题栏、有最小化按钮和最大化按钮。 setWindowFlags(Qt::Dialog |…

MCU配置的1106模块与1102模块功能差异分析

在现代工业自动化和智能控制领域&#xff0c;微控制器(MCU)扮演着至关重要的角色。而在MCU的配置中&#xff0c;选择适合的传感器采集模块是确保数据采集准确性和多样性的关键。其中&#xff0c;1106模块和1102模块作为两种常见的采集模块&#xff0c;各自具有独特的功能特点和…

sdrangel使用说明

使用说明 首先找一个usrp设备&#xff0c;我找到的是b205进行连接。打开生成的sdrangel.exe&#xff0c;第一次打开会出现空白界面 点击Add Rx Device按钮。 然后会弹出一个设备刷新窗口&#xff0c;选择你需要的设备 点击OK后&#xff0c;会响应一段时间&#xff0c;然后弹…

孙崧-回归祖国的数学天才谈国外学习研究感受

孙崧&#xff0c;这位37岁的美国加州大学伯克利分校数学系教授&#xff0c;今年正式回归祖国&#xff0c;担任浙江大学数学高等研究院杜建英讲席教授、博士生导师。在此&#xff0c;知识人网小编就经历过国外就读、从事博士后研究及任教的这位数学天才是怎么说的&#xff0c;或…

【三十二】【算法分析与设计】深搜(2),98。 验证二叉搜索树,不同方式定义递归函数,230。 二叉搜索树中第 K 小的元素,257。 二叉树的所有路径

98. 验证二叉搜索树 给你一个二叉树的根节点 root &#xff0c;判断其是否是一个有效的二叉搜索树。 有效 二叉搜索树定义如下&#xff1a; 节点的左 子树 只包含 小于 当前节点的数。 节点的右子树只包含 大于 当前节点的数。 所有左子树和右子树自身必须也是二叉搜索树。…

小程序 两页面间数据传递

页面1 页面2 实现效果&#xff1a;点击页面1 可以直接跳进页面2 实现过程&#xff1a; xhtml <view class"rank" wx:for"{{rankList}}" data-ids"{{item.id}}" data-names"{{item.name}}" data-description"{{item.descri…

行测——言语分析

行测——言语分析 1. 全文概括题1.1 做题思路1.2 例子1.2.1 概括内容1.2.2 标题类 2.中心理解题2.1 做题思路2.2 例子2.2.1 关键词清晰2.2.2 关键词不清晰 3. 逻辑顺序题3.1 做题思路3.2 例子3.2.1 划线部分填什么句子3.2.2 句子排序3.2.3 下一段讲什么3.2.4 细节分析题 4. 逻辑…

Oracle基础-PL/SQL编程 备份

1、PL/SQL简介 PL/SQL块结构 约定&#xff1a;为了方便&#xff0c;本文后面把PL/SQL简称PL。 PL程序都是以块&#xff08;BLOCK&#xff09;为基本单位&#xff0c;整个PL块分三部分&#xff1a;声明部分&#xff08;使用DECLARE开头&#xff09;、执行部分(以BEGIN开头)和异…

数字人视频合成平台推荐

数字人讲解视频和全景作品的结合是一种全新的数字交互方式&#xff0c;可为用户提供更加直观和具有沉浸感的内容展示和交互体验&#xff0c;从而适用于诸如旅游、展览、博物馆、教育培训、泛房地产、以及娱乐和文化等应用场景。 当前数字人合成视频技术已经发展至日益成熟的阶…

SSL通配符证书怎么选?看这里

通配符证书&#xff0c;作为一种特殊的数字证书类型&#xff0c;以其独特的优势在网络安全领域扮演着重要角色。相较于传统的单一域名证书&#xff0c;通配符证书能够为同一主域名下的所有子域名提供安全保护&#xff0c;显著提升管理效率&#xff0c;简化证书部署流程&#xf…

LandCover数据介绍与下载

一、LC介绍 土地覆盖&#xff08;Land Cover&#xff0c;LC&#xff09;是自然营造物和人工建筑物所覆盖的地表诸多要素的综合体。土地覆盖指地表所属的植被覆盖物(森林、草原、耕作植被等)或非植被覆盖物(冰雪、建筑物等)的具体类型&#xff0c;侧重描述地球表面的自然属性&a…

02 - 全加器和加法器

---- 整理自B站UP主 踌躇月光 的视频 1. 全加器 用门电路实现两个二进制数相加并求出和的组合线路&#xff0c;称为一位全加器。一位全加器可以处理低位进位&#xff0c;并输出本位加法进位。全加器比半加器多了一位进位。 1.1 实验 1&#xff1a;通过两个半加器设计全加器 1.…