细说STM32单片机DMA中断收发RTC实时时间并改善其鲁棒性的另一种方法

目录

一、工程配置

二、软件代码

1、软件代码

2、usart.h

3、usart.c

4、rtc.c

三、运行与调试        

1、合规的指令

2、proBuffer[0]不是 ‘#’ 或proBuffer[4]不是 ‘;’ 

3、指令长度小于5

4、proBuffer[2]或proBuffer[3]至少一个不是数字

5、';' 位于proBuffer[2]或proBuffer[3]位置

6、proBuffer[2]和proBuffer[3]数字超范围

7、输入的指令字符串长度>5,且不含有 '#' 和 ':'

8、以 '#' 开头且长度=5,或包含有 '#' 且 '#' 后的字符数=5。都不含有 ‘;’

9、以 '#' 开头且长度<5,或包含有 '#' 且 '#' 后的字符数<5。都不含有 ‘;’


        在本文作者的文章中:细说STM32单片机DMA中断收发RTC实时时间并改善其鲁棒性的方法-CSDN博客  https://wenchm.blog.csdn.net/article/details/143844395 曾总结过“当输入的指令的长度不等于5时,程序容错能力是比较弱的,鲁棒性并不明显。这是因为串口接收设置数据长度=5导致的,rxBuffer[5]以后内容并不能被memset()清空,残余的数据影响了紧邻的下一次接收。”

        在本文中,作者设置DMA每次只能接受1个字节的指令字符,然后在程序里判断数据起始字符和结束字符。当接收到起始字符 ‘#’ 时,位索引值 = 0,当接收到结束字符 ‘;’ 时,显示并更新RTC时间。每次更新RTC时间后,清空缓存。

        当输入的字符长度>5时,且不包含有结束字符 ';' ,限制位索引值 = 5,并显示和处理指令字符。无论输入何种类型的错误指令,程序的容错能力显著提高,并能正确响应再次输入正确的指令。鲁棒性得到极大的改善。

        特殊情况1, 以 '#' 开头或包含 '#' 但 '#' 后面的字符数量<4,且不含有 ';' 时,每次发送指令后,串口助手没有显示改变,貌似没有响应,实际后台是有响应的,只是每次读到 '#' 时,都有rxBufPos = 0,又因 '#' 后面的字符数量<4,程序不满足任何跳转。按任意 “#***;” 格式的字符串,程序就可以跳出。

        特殊情况2,输入任意长度的指令字符串,但不含有起始字符 '#' 和结束字符 ';' ,累计发送的字符的长度为5的倍数时,或输入任意 “#***;” 格式的字符串,程序就可以跳出。

        特殊情况1、2是可以编程解决并变得更完美的,从而完美解决程序的容错能力。这项工作,就留给感兴趣的网友吧。

一、工程配置

         同参考文章。

二、软件代码

1、软件代码

        同参考文章。 

2、usart.h

/* USER CODE BEGIN Includes */
#define	RX_CMD_LEN	1		    // Only accept one character at a timeextern uint8_t rxBuffer[];   	// Serial port receiving data buffer
extern	uint8_t	isUploadTime;	// upload RTCtime switch
/* USER CODE END Includes */
/* USER CODE BEGIN Prototypes */
void updateRTCTime();
/* USER CODE END Prototypes */

3、usart.c

/* USER CODE BEGIN 0 */
#include "rtc.h"
#include "dma.h"
#include <string.h>
#include <ctype.h>uint8_t	proBuffer[10];		//用于处理数据, #H12; #M23; #S43;
uint8_t	rxBuffer[10];		//接收缓存数据, #H12; #M23; #S43;
uint8_t	isUploadTime = 1;	//是否上传时间数据unsigned char hello1[]="Invalid command\n";
unsigned char hello2[]="Invalid data\n";/* 新增的两句用于接收不定长数据 */
#define PRO_CMD_LEN 5	    // String length must be 5.
uint8_t rxBufPos = 0;		// Receive buffer bit index
/* 新增的两句用于接收不定长数据 *//* USER CODE END 0 */
/* USER CODE BEGIN 1 */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)  //DMA
{if (huart->Instance == USART2){uint8_t ch = rxBuffer[0];// If # is received, the instruction header position is 0if(ch == '#')rxBufPos = 0;// When the length of the input string is greater than 5 and does not contain';',// the index value is cleared to zero,// and the unfinished string can continue to be received until it encounters';'.if (rxBufPos < PRO_CMD_LEN){proBuffer[rxBufPos] = ch;rxBufPos++;// The input command string must start with # and contain ';',// whether or not ';' is at the end,// ';' represents the end of the command.if(ch == ';' ){// Upload the received command string, less than or equal to 5 char, and must be delayed,// otherwise, the command string displayed on the serial port will be incomplete.// HAL_UART_Transmit(huart,proBuffer, strlen((char*)(proBuffer)), 200);HAL_UART_Transmit_DMA(&huart2,proBuffer,PRO_CMD_LEN);HAL_Delay(10);// Update the RTC time with the received command.updateRTCTime();// Clear the cache after each command is sent to the serial port assistant.memset(rxBuffer, '\0', sizeof(rxBuffer));memset(proBuffer, '\0', sizeof(proBuffer));// Bit index reset,// this operation is particularly useful when the correct format of the input contains erroneous data.rxBufPos = 0;return;}// When the length of the input string is greater than 5 and does not contain';',// the index value is cleared to zero,// and the unfinished string can continue to be received until it encounters';'.//if((strchr((const char *)proBuffer, ';') == NULL) || (rxBufPos == PRO_CMD_LEN))if(rxBufPos == PRO_CMD_LEN){rxBufPos = 0;HAL_UART_Transmit_DMA(&huart2,proBuffer,PRO_CMD_LEN);HAL_Delay(10);HAL_UART_Init(&huart2);HAL_UART_Transmit(&huart2,hello1,sizeof(hello1),200);memset(rxBuffer, '\0', sizeof(rxBuffer));memset(proBuffer, '\0', sizeof(proBuffer));return;}}}
}// Update according to the command string received by the serial port.
void updateRTCTime()
{uint8_t	timeSection=proBuffer[1];	// type characters, such as "#H12;"uint8_t	tmp10=proBuffer[2]-0x30;	// tens digitsuint8_t	tmp1 =proBuffer[3]-0x30;	// single digitsuint8_t	val=10*tmp10+tmp1;// Identify the start_bit is '#' and the end_bit is ';'or not.// Determine whether the number of characters received is equal to 5.if (proBuffer[0] != '#' ||  proBuffer[PRO_CMD_LEN -1] != ';'){HAL_UART_Init(&huart2);	// Restart serial portHAL_UART_Transmit(&huart2,hello1,sizeof(hello1),200);memset(rxBuffer, '\0', sizeof(rxBuffer));memset(proBuffer, '\0', sizeof(proBuffer));return;	//An error has occurred, so it will naturally jump out of this callback.}// Identify the data_bit is digits or notif (isalpha(proBuffer[2])  || isalpha(proBuffer[3])){HAL_UART_Init(&huart2);HAL_UART_Transmit(&huart2,hello2,sizeof(hello2),200);memset(rxBuffer, '\0', sizeof(rxBuffer));memset(proBuffer, '\0', sizeof(proBuffer));return;}//update RTCtimeRTC_TimeTypeDef sTime;RTC_DateTypeDef sDate;if (HAL_RTC_GetTime(&hrtc, &sTime, RTC_FORMAT_BIN) == HAL_OK){// After calling HAL_RTC_GetTime(),// you must call HAL_RTC_GetDate() to continuously update Date and Time.HAL_RTC_GetDate(&hrtc, &sDate, RTC_FORMAT_BIN);switch (timeSection){case 'H': // Modify hours{if(val <= 24)sTime.Hours = val;else{HAL_UART_Init(&huart2);HAL_UART_Transmit(&huart2,hello2,sizeof(hello2),200);memset(proBuffer, '\0', sizeof(proBuffer));return;}}break;case 'M': // Modify minutes{if(val <= 60)sTime.Minutes = val;else{HAL_UART_Init(&huart2);HAL_UART_Transmit(&huart2,hello2,sizeof(hello2),200);memset(proBuffer, '\0', sizeof(proBuffer));return;}}break;case 'S': // Modify seconds{if(val <= 60)sTime.Seconds = val;else{HAL_UART_Init(&huart2);HAL_UART_Transmit(&huart2,hello2,sizeof(hello2),200);memset(proBuffer, '\0', sizeof(proBuffer));return;}}break;case 'U':{if( tmp1 == 0){isUploadTime = 0;//pausereturn;}elseisUploadTime = 1; //resume}break;default: // If it is not H, M, S, U then return{HAL_UART_Init(&huart2);HAL_UART_Transmit(&huart2,hello1,sizeof(hello1),200);memset(proBuffer, '\0', sizeof(proBuffer));}return;}	//switch//Set the RTC time and will affect the next RTC wake-up interrupt.HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BIN);}	//if GetTime
}
/* USER CODE END 1 */

4、rtc.c

         同参考文章。

三、运行与调试        

        下载,运行,首先显示字符串“Hello,DMA transmit”,然后连续显示时间,间隔1s。下面根据不同的指令输入情况,展示运行结果。

1、合规的指令

        输入正确格式的指令,修改时分秒、暂停、恢复、及再次输入正确格式的指令。

 

2、proBuffer[0]不是 ‘#’ 或proBuffer[4]不是 ‘;’ 

        输入字符串长度=5,但首字符≠#或结束字符≠;时,能正常进行容错处理并消息提示,可以继续输入正确的指令:

 

3、指令长度小于5

        输入字符串的长度<5,但包含有 ‘#’ 和 ‘;’ 。程序能自动处理并跳出纠错循环,此后输入正确的指令后,执行并显示正确的结果。

4、proBuffer[2]或proBuffer[3]至少一个不是数字

        程序能自动执行错误处理,并跳出纠错循环。此后输入正确的指令后,执行并显示正确的结果。

 

5、';' 位于proBuffer[2]或proBuffer[3]位置

        程序能自动执行错误处理,并跳出纠错循环。此后输入正确的指令后,执行并显示正确的结果。 

6、proBuffer[2]和proBuffer[3]数字超范围

        程序能自动执行错误处理,并跳出纠错循环。此后输入正确的指令后,执行并显示正确的结果。 

7、输入的指令字符串长度>5,且不含有 '#' 和 ':'

        程序能自动执行错误处理,并跳出纠错循环。此后输入正确的指令后,执行并显示正确的结果。 

8、以 '#' 开头且长度=5,或包含有 '#' 且 '#' 后的字符数=5。都不含有 ‘;’

         程序能自动执行错误处理,并跳出纠错循环。此后输入正确的指令后,执行并显示正确的结果。

9、以 '#' 开头且长度<5,或包含有 '#' 且 '#' 后的字符数<5。都不含有 ‘;’

         以 '#' 开头且长度<5,串口助手没有任何显示,无论你输入多少次,这是因为每次读入 '#' 时,都有rxBufPos = 0。但程序并没有进入死循环,再次输入任意的正确指令,都能正确执行。

        而含有 '#' 且 '#' 后的字符数<5时,视具体的字符组合情况,可能和上面的情况一样,也可能连续输入几次以后,串口助手就有错误信息提示。但无论如何,程序并没有进入死循环,再次输入任意的正确指令,都能正确执行。

        这两种特殊情况下,通过编写更完整的程序,自然可以让处理结果更简洁。

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

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

相关文章

离散数学---概率, 期望

本文根据 MIT 计算机科学离散数学课程整理&#xff08;Lecture 22 ~ Lecture 24&#xff09;。 1 非负整数期望性质 用 N 表示非负整数集合&#xff0c;R 是 N 上的随机变量&#xff0c;则 R 的期望可以表示成&#xff1a; 证明&#xff1a; 换一个形式&#xff0c;把每一列…

AI一键生成原创花卉印花图案——创新与效率的结合

引言 在时尚界&#xff0c;印花图案一直是设计师们表达创意和个性的重要手段。随着人工智能技术的发展&#xff0c;AI在设计领域的应用越来越广泛&#xff0c;其中就包括了一键生成原创花卉印花图案。本文将探讨AI如何帮助设计师们提高效率&#xff0c;同时保持设计的创新性和…

QT实操中遇到的一些(C++)疑惑点汇总

QT实操中 遇到的一些C疑惑点汇总 1.实例化对象的两种方法及其访问方式 1.1 示例 1.2 总结 2.基类成员的访问 2.1 直接访问继承的基类成员 2.1.1示例代码 2.1.2 输出结果 2.2 使用作用域解析符来显式调用基类成员函数 2.2.1 示例代码 2.2.2 输出结果 2.3 使用 this 指针访问基类…

图形学笔记 - 4. 几何 -网格操作和阴影映射

文章目录 网格操作&#xff1a;几何处理细分Loop细分Catmull-Clark细分&#xff08;一般网格&#xff09;网格简化 阴影 Shadows可视化阴影映射阴影映射阴影贴图的问题 网格操作&#xff1a;几何处理 网格细分网格简化网格正则化 网格细分&#xff08;上采样&#xff09; 网…

OBOO鸥柏车载广告屏:28.6寸液晶一体机的技术革新与应用前景

在数字化迅速发展的今天&#xff0c;OBOO鸥柏推出的28.6寸车载长条形液晶广告屏一体机成为了市场的一大亮点。这款产品不仅具有超窄边框的高亮设计&#xff0c;还利用异形激光切割技术&#xff0c;支持多种形状如圆形、方形及三角形展示&#xff0c;极大地提升了商用和工业屏幕…

Spring Cloud Alibaba、Spring Cloud 与 Spring Boot各版本的对应关系

参考spring-cloud-alibaba github wiki说明&#xff1a;版本说明 下面截取说明&#xff1a; 2022.x 分支 2021.x 分支 2.2.x 分支 组件版本关系

Springboot + vue 健身房管理系统项目部署

1、前言 ​ 许多人在拿到 Spring Boot 项目的源码后&#xff0c;不知道如何运行。我以 Spring Boot Vue 健身房管理系统的部署为例&#xff0c;详细介绍一下部署流程。大多数 Spring Boot 项目都可以通过这种方式部署&#xff0c;希望能帮助到大家。 ​ 2、项目查看 ​ 首…

SOL链上的 Meme 生态发展:从文化到创新的融合#dapp开发#

一、引言 随着区块链技术的不断发展&#xff0c;Meme 文化在去中心化领域逐渐崭露头角。从 Dogecoin 到 Shiba Inu&#xff0c;再到更多细分的 Meme 项目&#xff0c;这类基于网络文化的加密货币因其幽默和社区驱动力吸引了广泛关注。作为近年来备受瞩目的区块链平台之一&…

基于大数据爬虫数据挖掘技术+Python的网络用户购物行为分析与可视化平台(源码+论文+PPT+部署文档教程等)

#1024程序员节&#xff5c;征文# 博主介绍&#xff1a;CSDN毕设辅导第一人、全网粉丝50W,csdn特邀作者、博客专家、腾讯云社区合作讲师、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和学生毕业项目实战,高校老…

主机管理工具 WGCLOUD v3.5.6 更新了哪些特性

WGCLOUD-v3.5.6 更新说明&#xff0c;2024-11-20发布 1. 新增&#xff0c;个性化采集&#xff0c;查看 2. 新增&#xff0c;支持达梦数据库做数据源来存贮监控数据&#xff0c;查看说明(8) 3. 新增&#xff0c;日志监控支持配置自动处理指令&#xff0c;当发现日志出现告警关键…

设计模式之 享元模式

享元模式&#xff08;Flyweight Pattern&#xff09;是一种结构型设计模式&#xff0c;用于减少系统中对象的数量&#xff0c;从而节省内存和提升性能。它通过共享相同的对象来避免重复创建类似的对象。该模式尤其适用于对象数量庞大、且重复内容较多的场景。 核心思想&#x…

yolov5 数据集分享:纯干货

数据集分享&#xff1a;纯干货 1. 遇见数据集&#xff1a;这是一个国内的数据集搜索引擎&#xff0c;索引了国内外的大部分网站&#xff0c;提供最新的数据集推荐。[遇见数据集网站](https://www.selectdataset.com/) 2. Kaggle&#xff1a;一个领先的数据科学和机器学习爱好者…

如何实现3D模型在线展示、互动和分享?

实现3D模型在线展示、互动和分享&#xff0c;可以通过多种途径和技术手段来完成。以下是一些具体的方法和步骤&#xff1a; 一、选择适合的3D模型展示平台 首先&#xff0c;你需要选择一个支持3D模型在线展示、互动和分享的平台。这些平台通常提供用户友好的界面和工具&#x…

大数据-227 离线数仓 - Flume 自定义拦截器(续接上节) 采集启动日志和事件日志

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; Java篇开始了&#xff01; 目前开始更新 MyBatis&#xff0c;一起深入浅出&#xff01; 目前已经更新到了&#xff1a; Hadoop&#xff0…

CANoe录制和回放CAN报文

目录 1、录制报文 2、离线回放 3、在线回放 3.1、在线回放设置 CANoe是一款用于汽车电子测试的工具&#xff0c;它可以模拟CAN网络中的各种设备&#xff0c;并支持CAN报文的录制和回放功能&#xff0c;方便我们远程调试。 1、录制报文 在Measurement Setupk面板点击Loggi…

大数据调度组件之Apache DolphinScheduler

Apache DolphinScheduler 是一个分布式易扩展的可视化 DAG 工作流任务调度系统。致力于解决数据处理流程中错综复杂的依赖关系&#xff0c;使调度系统在数据处理流程中开箱即用。 主要特性 易于部署&#xff0c;提供四种部署方式&#xff0c;包括Standalone、Cluster、Docker和…

XCode Build时遇到 .entitlements could not be opened 的问题

遇到错误 在构建成功的XCode工程上&#xff0c;手动打开XCode并Build&#xff0c;遇到以下问题&#xff1a; The file .entitlements could not be opened. Did you forget to declare this file as an output of a script phase or custom build rule which produces it 打…

关于一次开源java spring快速开发平台项目RuoYi部署的记录

关于一次开源java spring快速开发平台项目RuoYi部署的记录 本次因为需要一些练习环境&#xff0c;想要快速搭建一个javaweb 项目作为练习环境&#xff0c;经过查询和实验找到一个文档详细&#xff0c;搭建简单&#xff0c;架构也相对比较新的开源项目RuoYi。 项目介绍&#xf…

原生微信小程序在顶部胶囊左侧水平设置自定义导航兼容各种手机模型

无论是在什么手机机型下&#xff0c;自定义的导航都和右侧的胶囊水平一条线上。如图下 以上图iphone12&#xff0c;13PRo 以上图是没有带黑色扇帘的机型 以下是调试器看的wxml的代码展示 注意&#xff1a;红色阔里的是自定义导航&#xff08;或者其他的logo啊&#xff0c;返回之…

列出D3的所有交互方法,并给出示例

D3.js 提供了丰富的交互方法&#xff0c;可以用来增强图表的用户交互体验。以下是一些常用的交互方法及其示例&#xff1a; 1. 鼠标事件 on("mouseover", function) 用途: 当鼠标悬停在元素上时触发。示例:svg.selectAll(".bar").on("mouseover&qu…