物联网实战--入门篇之(四)嵌入式-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_OD
	GPIO_Init(GPIOA, &GPIO_InitStructure);    //TX

	GPIO_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); //初始化NVIC
 
	USART_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++;//接收长度加1
		if(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

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

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

相关文章

电商系列之风控安全

> 插&#xff1a;AI时代&#xff0c;程序员或多或少要了解些人工智能&#xff0c;前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站。 坚持不懈&#xff0c;越努力越幸运&#xff0c;大家…

Verilog语法回顾--用户定义原语

目录 用户定义原语 UDP定义 UDP状态表 状态表符号 组合UDP 电平敏感UDP 沿敏感时序UDP 参考《Verilog 编程艺术》魏家明著 用户定义原语 用户定义原语&#xff08;User-defined primitive&#xff0c;UDP&#xff09;是一种模拟硬件技术&#xff0c;可以通过设计新的原…

【北京迅为】《iTOP-3588开发板系统编程手册》第1章 系统编程初探

RK3588是一款低功耗、高性能的处理器&#xff0c;适用于基于arm的PC和Edge计算设备、个人移动互联网设备等数字多媒体应用&#xff0c;RK3588支持8K视频编解码&#xff0c;内置GPU可以完全兼容OpenGLES 1.1、2.0和3.2。RK3588引入了新一代完全基于硬件的最大4800万像素ISP&…

通过nvtx和Nsight Compute分析pytorch算子的耗时

通过nvtx和Nsight Compute分析pytorch算子的耗时 一.效果二.代码 本文演示了如何借助nvtx和Nsight Compute分析pytorch算子的耗时 一.效果 第一次执行,耗时很长 小规模的matmul,调度耗时远大于算子本身 大规模的matmul,对资源的利用率高小规模matmul,各层调用的耗时 二.代码…

болеть和заболеть的区别,柯桥俄语培训哪家好

动词болеть, заболеть是教学的重点&#xff0c;也是难点&#xff0c;在各个群里也是讨论频率极高的词汇&#xff0c;本期进行一下讲解。 请问&#xff1a;如何给学生讲解болеть和заболеть的区别&#xff1f; болеть和заболеть我是这…

1,static 关键字.Java

目录 1.概述 2.定义格式和使用 2.1 静态变量及其访问 2.2 实例变量及其访问 2.3 静态方法及其访问 2.4 实例方法及其访问 3.小结 1.概述 static表示静态&#xff0c;是Java中的一个修饰符&#xff0c;可以修饰成员方法&#xff0c;成员变量。被static修饰后的&#xff…

基于Eigen库的多项式曲线拟合实现(最小二乘法)

本文介绍基于Eigen库的多项式曲线拟合实现&#xff08;最小二乘法&#xff09;。 1.基础知识 1)范德蒙矩阵 范德蒙矩阵是一个n*m的矩阵&#xff0c;定义为 其第i 行、第j 列可以表示为。范德蒙矩阵可以应用于多项式的最小二乘法。 2)最小二乘法原理 给出n个点&#xff0c;求…

【智能算法】蜜獾算法(HBA)原理及实现

目录 1.背景2.算法原理2.1算法思想2.2算法过程 3.结果展示4.参考文献 1.背景 2021年&#xff0c;FA Hashim等人受到自然界中蜜獾狩猎行为启发&#xff0c;提出了蜜獾算法&#xff08;(Honey Badger Algorithm&#xff0c;HBA&#xff09;。 2.算法原理 2.1算法思想 蜜獾以其…

上传苹果IPA安装包的注意事项与技巧:确保顺利通过审核

目录 引言 摘要 第二步&#xff1a;打开appuploader工具 第二步&#xff1a;打开appuploader工具&#xff0c;第二步&#xff1a;打开appuploader工具 第五步&#xff1a;交付应用程序&#xff0c;在iTunes Connect中查看应用程序 总结 引言 在将应用程序上架到苹果应用商…

权限问题(Windows-System)

方法&#xff1a;用命令来写一个注册表的脚本 &#xff1f;System是最高级用户&#xff0c;但不拥有最高级权限 编写两文档&#xff1a;system.reg 和 remove.reg,代码如下&#xff1a; system.reg&#xff1a; Windows Registry Editor Version 5.00[-HKEY_CLASSES_ROOT\*…

[StartingPoint][Tier0]Dancing

Task 1 What does the 3-letter acronym SMB stand for? (3个字母的首字母缩略词SMB代表什么&#xff1f;) Server Message Block Task 2 What port does SMB use to operate at? (SMB 使用什么端口进行操作&#xff1f;) 445 Task 3 What is the service name for port…

redis持久化管理

目录 查看Redis内存使用 查看Redis内存使用 info memory 内存碎片率 内存碎片&#xff0c;如何产生 跟踪内存碎片率对理解Redis实例的资源性能是非常重要的&#xff1a; ●内存碎片率稍大于1是合理的&#xff0c;这个值表示内存碎片率比较低&#xff0c;也说明 Redis 没有发…

webapi 允许跨域

1.在Nuget安装webapi.cors 添加完会有这个包 然后在项目App_Start 目录下的WebApiConfig.cs里面添加 // Web API 配置和服务// 添加跨域设置config.EnableCors(new EnableCorsAttribute("*", "*", "*"));

前端跨页面通信方案介绍

在浏览器中&#xff0c;我们可以同时打开多个Tab页&#xff0c;每个Tab页可以粗略理解为一个“独立”的运行环境&#xff0c;即使是全局对象也不会在多个Tab间共享。然而有些时候&#xff0c;我们希望能在这些“独立”的Tab页面之间同步页面的数据、信息或状态。这就是本文说说…

从零开始为香橙派orangepi zero 3移植主线linux——2.linux kernel

从零开始为香橙派orangepi zero 3移植主线linux——2.linux kernel 0.环境搭建补档NFS服务TFTP服务 一、linux kernel编译二、运行 0.环境搭建补档 linux kernel验证时&#xff0c;使用tftp服务从ubuntu主机下载启动更加方便&#xff0c;等到验证无误后再一次性烧写到tf卡。所以…

使用 Docker 部署 Photopea 在线 PS 工具

1&#xff09;Photopea 介绍 GitHub&#xff1a;https://github.com/photopea/photopea 官方手册&#xff1a;https://www.photopea.com/learn/ Adobe 出品的「PhotoShop」想必大家都很熟悉啦&#xff0c;但是「PhotoShop」现在对电脑配置要求越来越高&#xff0c;体积越来越大…

中兴R5300 G4服务器BMC远程管理启用防火墙设置

中兴R5300 G4服务器启用了BMC远程管理&#xff0c;为保障设备安全配置启用防火墙只放通特定维护服务器可以访问。 一、设备初始登录信息 1、中兴R5300G4服务器&#xff0c;默认BMC管理地址https//192.168.5.7 2、中兴zteroot用户的默认密码为&#xff1a;Superuser9! 二、…

python文件处理:解析docx/word文件文字、图片、复选框

前言 因为一些项目原因&#xff0c;我需要提供解析docx内容功能。本来以为这是一件比较简单的工作&#xff0c;没想到在解析复选框选项上吃了亏&#xff0c;并且较长一段时间内通过各种渠道都没有真正解决这一问题&#xff0c;反而绕了远路。 终于&#xff0c;我在github pytho…

中颖51芯片学习1. 系统时钟及IO口输出操作

中颖51芯片学习1. 系统时钟及IO口输出操作 一、芯片介绍1. 规格2. 资源3. 中断源&#xff1a;4. 方框图5. 封装&#xff08;1&#xff09;32脚LQFP封装&#xff08;2&#xff09;28脚SOP封装&#xff08;3&#xff09;20脚SOP封装 二、开发环境搭建1. 安装keil2. 安装中颖keil插…

【管理咨询宝藏47】AA银行风险管理体系提升分析报告

本报告首发于公号“管理咨询宝藏”&#xff0c;如需阅读完整版报告内容&#xff0c;请查阅公号“管理咨询宝藏”。 【管理咨询宝藏47】AA银行风险管理体系提升分析报告 【格式】PPT版本&#xff0c;可编辑 【关键词】战略规划、商业分析、管理咨询 【强烈推荐】这是一套市面上…