正点原子串口例程解读

首先是串口初始化,这里初始化的是usart3

void esp8266_init(void)
{huart_wifi.Instance=ESP8266;    //uart3huart_wifi.Init.BaudRate=115200; // 设置波特率为115200huart_wifi.Init.WordLength=UART_WORDLENGTH_8B; // 设置数据位长度为8位huart_wifi.Init.StopBits=UART_STOPBITS_1; // 设置停止位为1位huart_wifi.Init.Parity=UART_PARITY_NONE; // 设置奇偶校验为无huart_wifi.Init.Mode=UART_MODE_TX_RX; // 设置模式为接收和发送huart_wifi.Init.HwFlowCtl=UART_HWCONTROL_NONE; // 设置硬件流控制为无huart_wifi.Init.OverSampling=UART_OVERSAMPLING_16; // 设置过采样为16if(HAL_UART_Init(&huart_wifi)!=HAL_OK){Error_Handler();}/* 该函数会开启接收中断:标志位UART_IT_RXNE,并且设置接收缓冲以及接收缓冲接收最大数据量 */HAL_UART_Receive_IT(&huart_wifi, (uint8_t *)uart_recv_it_buf, WIFI_IRQ_RECV_LEN);}

其中,HAL_UART_Receive_IT开启标志位UART_IT_RXNE后,我们就可以配置uart3的中断函数

void ESP8266_IRQHandler(void)
{HAL_UART_IRQHandler(&huart_wifi);
}

    函数中用的是hal库的中断函数代码,函数实现比较复杂,我们可以自己写一个中断函数,配合实现。

      这边是按照官方回调函数,在void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart),中定义何时结束数据传输。

        先讲一下调用结构 

由于   HAL_UART_Receive_IT开启接收中断,会调用我们写好的ESP8266_IRQHandler,进入到

HAL_UART_IRQHandler(&huart_wifi);   第一个if语句判断状态寄存器sr中的RXNE:读取数据寄存器不为空 (Read data register not empty)。和控制寄存器cr中的RXNEIERXNE 中断使能 (RXNE interrupt enable),当rxne不为空切使能rxne中断时候,进入UART_Receive_IT(huart);

点击跳转,找到如下

这个函数的实现官方是弱定义,我们可以重写。

调用结构: 调用  → 被调用

HAL_UART_IRQHandler   → UART_Receive_IT  →  HAL_UART_RxCpltCallback。

下面我们看一下正点原子是怎么实现自定义的串口通讯格式。

/*** @brief       Rx传输回调函数* @param       huart: UART句柄类型指针* @retval      无*/
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{//g_usart_rx_sta  0-13位表示交收到if(huart->Instance == ESP8266)             /* 如果是串口3 */{if((g_wifi_rx_sta & (1<<15)) == 0)      /* 接收未完成 */{if(g_wifi_rx_sta & (1<<14) )         /* 接收到了0x0d,换行符是由 2个字节组成:0x0D 和 0x0A */{if(uart_recv_it_buf[0] != 0x0a) {g_wifi_rx_sta = 0;         /* 接收错误,重新开始 */}else {g_wifi_rx_sta |= (1<<15);   /* 接收完成了 */}}else                                /* 还没收到0X0D */{if(uart_recv_it_buf[0] == 0x0d){g_wifi_rx_sta |= (1<<14);}else{rx_wifi_msg[g_wifi_rx_sta & 0X3FFF] = uart_recv_it_buf[0] ;g_wifi_rx_sta++;if(g_wifi_rx_sta > (WIFI_RX_LEN - 1)){g_wifi_rx_sta = 0;     /* 接收数据错误,重新开始接收 */}}}}HAL_UART_Receive_IT(&huart_wifi, (uint8_t *)uart_recv_it_buf, WIFI_IRQ_RECV_LEN);}}

打开正点原子f407开发指南,我们看到

        原子的开发手册对接收中断回调函数代码解读非常完整,清晰,大家可以去看下。

注意的是,用串口助手一定要勾选发送新行(结尾自动发送回车符号),因为代码涉及到对 回车的判断( 0x0d  + 0x0a 表示回车符 )。

g_wifi_rx_sta,表示接受状态标识符,uint16_t类型。

        下面我说一下我理解的代码思路

1.在回调函数中判断是否已经接收完成(bit 15 位为1)  g_wifi_rx_sta    &   (1<<15)    ==0

如果接收完成,调用接收中断函数HAL_UART_Receive_IT(&huart_wifi, (uint8_t *)uart_recv_it_buf, WIFI_IRQ_RECV_LEN);

2,如果已经接收到了 回车的前半部分 :0x0d                  g_wifi_rx_sta    &   (1<<14)    ==1

如果 后面接上的是后半部分 0x0a,那么就判定为接收完成(g_wifi_rx_sta |=(1<<15)),相反如果不是,那么g_wifi_rx_sta

置0,重新开始计数。

3,如果还没有接收到回车的前半部分,那么就先判定是否中断里面接受到的buffer:uart_recv_it_buf[0]已经是0x0d,如果是的话,那么将bit14置1,g_wifi_rx_sta    |=  (1<<14)

4,如果uart_recv_it_buf[0]不是是0x0d,那么就接收字符,原子在这里设置了一个 rx_wifi_msg[ buffer_len ] , buffer_len  是你设置的最大接受缓冲区长度,我这里设置最大128 。

前面我们在初始化esp8266已经开启了   HAL_UART_Receive_IT(&huart_wifi, (uint8_t *)uart_recv_it_buf, WIFI_IRQ_RECV_LEN);  意思是每次中断接收 1个字节的数据。

rx_wifi_msg[ g_wifi_rx_sta  & 0x3fff ]=uart_recv_it_buf[0] ,0x3fff因为是0-13位表示接受数据位数,

每次都接受1位数据,直到设定的最大接收值。

g_wifi_rx_sta ++(每次进入中断一次,而且没有接收到回车判定符号 0x0d,那么就会 自加)。

然后就是判定是否接收长度大于设定长度,如果大于,就将    g_wifi_rx_sta=0;。

main函数部分代码。

if (g_wifi_rx_sta & (1<<15) )         /* 接收到了数据? */{len = g_wifi_rx_sta & 0x3fff;  /* 得到此次接收到的数据长度 */printf("\r\n您发送的消息为:\r\n");HAL_UART_Transmit(&huart_wifi,(uint8_t*)rx_wifi_msg,len,1000);    /* 发送接收到的数据 */while(__HAL_UART_GET_FLAG(&huart_wifi,UART_FLAG_TC)!=SET);           /* 等待发送结束 */printf("\r\n\r\n");             /* 插入换行 */g_wifi_rx_sta = 0;}else{times++;if (times % 5000 == 0){printf("\r\n正点原子 STM32开发板 串口实验\r\n");printf("正点原子@ALIENTEK\r\n\r\n\r\n");}if (times % 200 == 0) printf("请输入数据,以回车键结束\r\n");if (times % 30  == 0) LED0_TOGGLE(); /* 闪烁LED,提示系统正在运行. */delay_ms(10);}}

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

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

相关文章

KVM虚拟机管理脚本

思路&#xff1a; 在/opt/kvm下创建一个磁盘文件&#xff0c;做差异镜像&#xff0c;创建一个虚拟机配置文件&#xff0c;做虚拟机模版 [rootnode01 ~]# ls /opt/kvm/ vm_base.qcow2 vm_base.xml创建虚拟机的步骤&#xff1a;首先创建虚拟机的差异镜像&#xff0c;然后复制虚…

Null value was assigned to a property of primitive type setter of 的原因与解决方案

Null value was assigned to a property of primitive type setter of 的原因与解决方案 org.hibernate.PropertyAccessException: Null value was assigned to a property of primitive type setter of com.xxx.xxx.DealerUser.dealerId数据库表结构 实体类 当数据库的dealer…

【数据结构与算法】排序算法(下)——计数排序与排序总结

写在前面 书接上文&#xff1a;【数据结构与算法】排序算法(中)——交换排序之快速排序 文章主要讲解计数排序的细节与分析源码。之后进行四大排序的总结。 文章目录 写在前面一、计数排序(非比较排序)代码的实现&#xff1a; 二、排序总结 2.1、稳定性 3.2、排序算法复杂度及…

Multi移动端开发

Multi移动端开发 安装环境 安装功能 VS2022安装 【ASP.NET和Web开发】、【.NET Multi-platform App UI开发】、【.NET桌面开发】 配置程序源 【工具】–>【选项】–>【NuGet包管理器】–>【程序包源】&#xff0c;添加如下&#xff1a; 名称&#xff1a;MES_APP 源&…

若依plus apifox导入接口显示为空

项目已经正常启动 访问接口有些没问题&#xff0c;有些有问题 其他模块都可以正常导入 解决&#xff1a;

音视频入门基础:AAC专题(13)——FFmpeg源码中,获取ADTS格式的AAC裸流音频信息的实现

音视频入门基础&#xff1a;AAC专题系列文章&#xff1a; 音视频入门基础&#xff1a;AAC专题&#xff08;1&#xff09;——AAC官方文档下载 音视频入门基础&#xff1a;AAC专题&#xff08;2&#xff09;——使用FFmpeg命令生成AAC裸流文件 音视频入门基础&#xff1a;AAC…

英文学术会议海报poster模板【可编辑】

英文学术会议海报poster模板【可编辑】 下载链接&#xff1a;学术会议海报poster模板【可编辑】 横版海报 竖版海报 下载链接&#xff1a;学术会议海报poster模板【可编辑】 提供了一套学术海报的PPT模板&#xff0c;适用于学术会议、研讨会等场合。 竖版&#xff0c;包含11…

机器学习之KNN算法预测数据和数据可视化

机器学习及KNN算法 目录 机器学习及KNN算法机器学习基本概念概念理解步骤为什么要学习机器学习需要准备的库 KNN算法概念算法导入常用距离公式算法优缺点优点&#xff1a;缺点︰ 数据可视化二维界面三维界面 KNeighborsClassifier 和KNeighborsRegressor理解查看KNeighborsRegr…

Jmeter自学【8】- 使用JMeter模拟设备通过MQTT发送数据

今天使用jmeter推送数据到MQTT&#xff0c;给大家分享一下操作流程。 一、安装JMeter 参考文档&#xff1a;Jmeter自学【1】- Jmeter安装、配置 二、安装MQTT插件 1、下载插件 我的Jmeter版本是5.6.3&#xff0c;用到的插件是&#xff1a;mqtt-xmeter-2.0.2-jar-with-depe…

若依框架中的上传图片后如何实现回显到页面的

在日常开发中&#xff0c;总会遇到上传文件、图片等功能&#xff0c;然后本地开发的话&#xff0c;又没有像OSS、七牛等网络存储&#xff0c;这个时候通常将文件上传到本地&#xff0c;那么上传之后拿到的是本地的路径&#xff0c;存储到数据库中&#xff0c;查询的时候如何将本…

Linux 文件 I/O 基础

目录 前言 一、文件描述符&#xff08;File Descriptor&#xff09; 二、打开文件&#xff08;open 函数&#xff09; 三、读取文件&#xff08;read 函数&#xff09; 四、写入文件&#xff08;write 函数&#xff09; 五、关闭文件&#xff08;close 函数&#xff09; …

【CSS in Depth 2 精译_091】15.4:让 CSS 高度值过渡到自动高度 + 15.5:自定义属性的过渡设置(全新)+ 15.6:本章小结

当前内容所在位置&#xff08;可进入专栏查看其他译好的章节内容&#xff09; 第五部分 添加动效 ✔️【第 15 章 过渡】 ✔️ 15.1 状态间的由此及彼15.2 定时函数 15.2.1 定制贝塞尔曲线15.2.2 阶跃 15.3 非动画属性 15.3.1 不可添加动画效果的属性15.3.2 淡入与淡出 15.4 过…

路由器的原理

✍作者&#xff1a;柒烨带你飞 &#x1f4aa;格言&#xff1a;生活的情况越艰难&#xff0c;我越感到自己更坚强&#xff1b;我这个人走得很慢&#xff0c;但我从不后退。 &#x1f4dc;系列专栏&#xff1a;网路安全入门系列 目录 路由器的原理一&#xff0c;路由器基础及相关…

spring专题笔记(七):spring如何引入外部属性文件?spring在xml配置bean时如何引入外部的properties属性文件内容?

目录 1、spring在xml配置bean时引入外部的properties属性文件内容作用是什么&#xff1f; 2、引入配置文件步骤 2.1、首先创建一个java类MyDataSource&#xff0c;主要包含四个属性。 2.2、准备一个myDataConfig.properties属性文件&#xff0c;里面配置MyDataSource类中需…

梳理你的思路(从OOP到架构设计)_认识框架(Framework) 01

目录 1、 是框架的核心要素​编辑&i> 范例1&#xff1a; 范例2&#xff1a; 范例3&#xff1a; 1、 <E&I>是框架的核心要素 在特定领域(Domain)里&#xff0c;将EIT造形的<E&I>部份有意义地组合起来&#xff0c;就成为框架(Framework)了。基本…

邮件白名单是什么?

邮件白名单是一种电子邮件过滤规则&#xff0c;用于指定哪些发件人、域名或IP地址的邮件被允许通过过滤系统&#xff0c;不受任何限制地进入收件人的邮箱。与黑名单&#xff08;用于阻止特定发件人的邮件&#xff09;相反&#xff0c;白名单确保了来自受信任来源的邮件能够畅通…

Maven项目中不修改 pom.xml 状况下直接运行OpenRewrite的配方

在Java 的Maven项目中&#xff0c;可以在pom.xml 中配置插件用来运行OpenRewrite的Recipe&#xff0c;但是有一些场景是希望不修改pom.xml 文件就可以运行Recipe&#xff0c;比如&#xff1a; 因为不需要经常运行 OpenRewrite&#xff0c;所以不想在pom.xml 加入不常使用的插件…

JVM实战—2.JVM内存设置与对象分配流转

大纲 1.JVM内存划分的原理细节 2.对象在JVM内存中如何分配如何流转 3.部署线上系统时如何设置JVM内存大小 4.如何设置JVM堆内存大小 5.如何设置JVM栈内存与永久代大小 6.问题汇总 1.JVM内存划分的原理细节 (1)背景引入 (2)大部分对象的存活周期都是极短的 (3)少数对象…

kong网关使用pre-function插件,改写接口的返回数据

一、背景 kong作为api网关&#xff0c;除了反向代理后端服务外&#xff0c;还可对接口进行预处理。 比如本文提及的一个小功能&#xff0c;根据http header某个字段的值&#xff0c;等于多少的时候&#xff0c;返回一个固定的报文。 使用到的kong插件是pre-function。 除了上…