嵌入式设计中对于只有两种状态的变量存储设计,如何高效的对循迹小车进行偏差量化

news2024/11/19 18:23:46

前言

(1)在嵌入式程序设计中,我们常常会要对各类传感器进行数据存储。大多时候的传感器,例如红外光传感器,返回的数据要么是0,要么是1。因此,只需要一bit就能够存储。而很多人却常常使用char型数组存储,这样真正申请到的内存只使用了八分之一。对于MCU这种空间宝贵的微型控制器而言,这是对内存的极大浪费。
(2)因此,我在此介绍一个初学C语言时候讲解的技术——位域,提高空间的利用率。
(3)在入门嵌入式开发的时候,大多数人都是做一个循迹小车,而进行循迹,就需要对光电传感器进行偏差量化。根据偏差量化的值进行输出相应的PWM。(如果是开环控制)进行偏差量化,使用联合体,无疑是最高效的方式。

优化两种状态变量存储

存储

(1)例如,我这个小项目,需要使用上一个12路循迹模块,一个红外遥控器,一个触摸模块(有一种触摸模块你手摸上去,就会返回指定电平)。
(2)为了高效存储这些只有两个状态的变量。我们可以按照下面方式进行存储。

/*--- 存储结构设计 ---*/
typedef struct
{
	uint8_t track_bit1	:1;
	uint8_t track_bit2	:1;
	uint8_t track_bit3	:1;
	uint8_t track_bit4	:1;
	uint8_t track_bit5	:1;
	uint8_t track_bit6	:1;
	uint8_t track_bit7	:1;
	uint8_t track_bit8	:1;
	uint8_t track_bit9	:1;
	uint8_t track_bit10	:1;
	uint8_t track_bit11	:1;
	uint8_t track_bit12	:1; //上面都是灰度传感器控制位
	uint8_t IRDS_bit13	:1; //红外遥控器控制位
	uint8_t Touch_bit14	:1; //触摸模块
	uint8_t bit15	:1;     //下面2bit保留
	uint8_t bit16	:1;
}Bit_field;  

访问

(1)现在我们知道如何存储这个如何访问呢?这个其实是C语言位域基础知识,但是为了防止有一些大学这部分不教,所以我还是讲一下。

Bit_field two_status_sensor;
two_status_sensor.track_bit1 = readpin(1); //使用你当前的MCU读取引脚电平函数
two_status_sensor.track_bit2 = readpin(2); //使用你当前的MCU读取引脚电平函数
two_status_sensor.IRDS_bit13 = readpin(13); //使用你当前的MCU读取引脚电平函数
if(two_status_sensor.IRDS_bit13 == 1) //假设遥控器被按下,引脚为高电平
{
	//...
}

利用共用体进行偏差量化

利用Excel可视化偏差量化

(1)现在我们使用位域对这种2值变量有了一个很好的存储了。但是我们都知道,想循迹模块需要对数据进行处理。而如何进行偏差量化又是一个问题。在此,我推荐使用excl表格,这样能够非常直观的对数据处理。
(2)我们有几路循迹,就需要写几格,一个16进制数据之后方便编程,最后是我们偏差量化值,2进制那一格是为了方便转换成16进制而写。
(3)美化表格

>

(4)将表格填充

在这里插入图片描述

(5)然后自己填写自己设定的偏差量化值,并且将传感器有反应的地方用蓝色填充,这样有利于阅读。

在这里插入图片描述

将偏差量化编程出来

大部分人写的垃圾代码

(1)用Excel将传感器的数值偏差量化出来了,但是如何编程了?想必很多同学使用下面这种非常低效方法进行偏差量化。

char deviation;  //存储偏差量化值
if(two_status_sensor.track_bit1 == 1) deviation = -11;
if(two_status_sensor.track_bit1 == 1 || two_status_sensor.track_bit2) deviation = -10;
if(two_status_sensor.track_bit1 == 1) deviation = -9;
//...

(2)这种方法,编写起来非常麻烦,而且不方便阅读,可以说,写的相当的垃圾!

利用联合体管控标志位

(1)为了提高代码的观赏性,同时方便我们进行调试。我认为我们可以使用联合体的方法优化代码。这样之后,我们能够发现,对于偏差量化的值就能够进行非常好的管控。

/*--- 利用共用体优化偏差量化 ---*/
typedef union    //利用共用体优化偏差量化
{
	Bit_field sensor_value;
	uint16_t state;
}_two_status_sensor; 

/*--- 访问变量 ---*/
char deviation;  //存储偏差量化值的当前值
_two_status_sensor two_status_sensor;   //定义用于记录传感器的值
two_status_sensor.sensor_value.track_bit1 = readpin(1); //使用你当前的MCU读取引脚电平函数
//...  省略读取传感器的值过程

switch(two_status_sensor.state & 0x0FFF)//偏差量化,因为是12路循迹,所以只要低12位
{
	case 0x0001:deviation=-11;break; //000000000001b
	case 0x0003:deviation=-10;break; //000000000011b
	//... 省略其他偏差量化过程
	default://其它特殊情况单独判断
	{
		//...
	}
}

利用带参宏进行标志位判断

(1)但是这个还能不能再次进行优化呢?肯定可以,我们知道,这个2值联合体中,有一些是用于循迹,有些是用于遥控器,有些是用于触摸芯片的。为了提高代码的可阅读性。我们是不是可以用几个带参宏来进行定义呢?

/*--- 利用带参宏进行标志位判断 ---*/
#define track_state(x)  x & 0x0FFF
#define IRDS_state(x)   x & 0x1000
#define Touch_state(x)  x & 0x2000

利用?:和条件编译对提高代码对硬件的适配程度

(1)我们有没有发现一个问题,上面循迹代码,检测到黑线是1。那么肯定有人会说了,假如我硬件上检测到黑线是低电平怎么办呢?
(2)为了提高代码对硬件的适配能力,于是我认为可以使用条件编译。
(3)因为,不同的MCU读取电平返回的不一定是0和1,有可能读取到低电平是0,读取到高电平是一个其他的非0值,例如5。所以为了防止1bit存储不下导致溢出问题。我们可以使用?:来处理。

/*--- 提高代码对硬件的适配能力 ---*/
#define track_active_level  1 //高电平有效写1,低电平有效写0
#if     track_active_level
two_status_sensor.sensor_value.track_bit1 = readpin(1)!=0?0x01:0x00;
//... 其他11个同理
#else 
two_status_sensor.sensor_value.track_bit1 = readpin(1)==0?0x01:0x00;
//... 其他11个同理
#endif

进行错误判断,保护硬件,提高硬件的容错率

(1)看到上面的代码,肯定有骚年觉得已经很好了。但是,我们想想,如果循迹最终的结果返回的数据不是预期数据怎么办?例如小车跑出去了。
(2)为了防止这种异常情况,保护硬件,我们可以加一个标志位worse存储错误次数。如果次数超标就强制停车。
(3)因为小车循迹可能只是刚好偏离路线一点点,或者是硬件突然有点小问题,所以我们还可以建立一个标志位deviation_backup存储偏差量化值的以往值。让小车保持上一次的状态运行提高硬件容错率。

/*--- 提高代码对硬件的适配能力 ---*/
#define track_active_level  1 //高电平有效写1,低电平有效写0
#if     track_active_level
two_status_sensor.sensor_value.track_bit1 = readpin(1)!=0?0x01:0x00;
//... 其他11个同理
#else 
two_status_sensor.sensor_value.track_bit1 = readpin(1)==0?0x01:0x00;
//... 其他11个同理
#endif
/*--- 利用带参宏进行标志位判断 ---*/
#define track_state(x)  x & 0x0FFF
#define IRDS_state(x)   x & 0x1000
#define Touch_state(x)  x & 0x2000
/*--- 利用共用体优化偏差量化 ---*/
typedef union    //利用共用体优化偏差量化
{
	Bit_field sensor_value;
	uint16_t state;
}_two_status_sensor; 

/*--- 访问变量 ---*/
char deviation;  //存储偏差量化值的当前值
char deviation_backup,worse;//存储偏差量化值的以往值,循迹错误次数
_two_status_sensor two_status_sensor;   //定义用于记录传感器的值
two_status_sensor.sensor_value.track_bit1 = readpin(1); //使用你当前的MCU读取引脚电平函数
//...  省略读取传感器的值过程

switch(track_state(two_status_sensor.state))//偏差量化,因为是12路循迹,所以只要低12位
{
	case 0x0001:deviation=-11;worse/2;break; //000000000001b
	case 0x0003:deviation=-10;worse/=2;break; //000000000011b
	//... 省略其他偏差量化过程
	default://其它特殊情况单独判断
	{
		deviation=deviation_backup;//如果是异常情况,就保持上一个状态
		worse++;
	}
}
if(worse == 10) //如果多次循迹错误,说明出现问题了,为了保护硬件,强制停车
{
	//停车
}

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

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

相关文章

Python中的“ @”

一、介绍 这是Python装饰器的语法,使用符号,表示将装饰器函数放在被装饰函数的上方。当调用被装饰函数时,实际上是调用了装饰器函数,装饰器函数可以在调用被装饰函数之前或之后执行一些额外的操作。 #funA 作为装饰器函数 def f…

慎用!澳洲留学生用ChatGPT写论文被控学术不端!AI论文漏洞百出,各高校已加强捡测!

自从进入ChatGPT时代以来,留学生们纷纷表示写作业,so easy。留学生们在用AI写论文时候没有预计到的是,ChatGPT存在杜撰文献的问题,并且学校已经在使用AI检测工具。 目前全澳大多数大学都可以选择使用现在很流行的反剽窃软件服务T…

【观察】戴尔科技:构建企业创新“韧性”,开辟数实融合新格局

过去几年,国家高度重视发展数字经济,将其上升为国家战略。其中,“十四五”规划中,就明确提出要推动数字经济和实体经济的深度融合,以数字经济赋能传统产业转型升级;而2023年年初正式发布的《数字中国建设整…

LangChain 手记 Conclusion结语

整理并翻译自DeepLearning.AILangChain的官方课程:Conclusion Conclusion 结语 本系列短课展示了大量使用LangChain构建的大语言模型应用,包括处理用户反馈、文档上的问答系统甚至使用LLM来决定发起外部工具的调用(比如搜索)来回答…

如何进行远程debug?

文章目录 前言一、使用步骤1.首先通过nohup在启动jar包的我们可以添加参数:2.具体参数的含义如下:3. 查询监听的端口: 前言 在工作中,排查问题我们经常需要进行debug,而远程debug能够方便的帮助我们排查线上的问题。 …

【C语言基础】宏定义的用法详解

📢:如果你也对机器人、人工智能感兴趣,看来我们志同道合✨ 📢:不妨浏览一下我的博客主页【https://blog.csdn.net/weixin_51244852】 📢:文章若有幸对你有帮助,可点赞 👍…

【无标题】WIN11下 ESP8266 _RTOS_SDK3.0以上开发环境搭建(记录及避坑必看)

前提参考文档 1、乐鑫官网: https://docs.espressif.com/projects/esp8266-rtos-sdk/en/latest/get-started/index.html 官网上有如何搭建windows linux macos 三种环境,以及如何配置Eclipse去编译和开发项目(如何安装Eclipse环境&#xff0…

高品质音乐下载命令行工具Musicn

又到了小苏同学的生日🎂,宝贝,生日快乐!祝永远健康、快乐、心想事成! 什么是 Musicn ? Musicn 是一个可播放及下载高品质🎵音乐🎵的命令行工具。支持咪咕、酷我、酷狗和网易云的服务…

《合成孔径雷达成像算法与实现》Figure3.10

代码复现如下: clc clear close all% 参数设置 TBP 100; % 时间带宽积 T 7.2e-6; % 脉冲持续时间 t_0 1e-6; % 脉冲回波时延% 参数计算 B TBP/T; …

springboot整合websocker启动失败

在工作的时候,准备使用websocker建立长连接来统计网站在线人数,但是在配置好所有东西后,发现springboot启动失败 详细错误 java.lang.IllegalStateException: Failed to register ServerEndpoint class: class com.example.pipayshopapi.co…

【算法题解】54. 树的冗余连接

这是一道 中等难度 的题 https://leetcode.cn/problems/redundant-connection/ 题目 树可以看成是一个连通且 无环 的 无向 图。 给定往一棵 n n n 个节点 (节点值 1 ~ n 1~n 1~n) 的树中添加一条边后的图。添加的边的两个顶点包含在 1 …

Python可视化在量化交易中的应用(11)_Seaborn折线图

举个栗子,用seaborn绘制折线图。 Seaborn中折线图的绘制方法 在seaborn中,我们一般使用sns作为seaborn模块的别名,因此,在下文中,均以sns指代seaborn模块。 seaborn中绘制折线图使用的是sns.plot()函数: …

【算法学习】两数之和II - 输入有序数组

题目描述 原题链接 给你一个下标从 1 开始的整数数组 numbers &#xff0c;该数组已按 非递减顺序排列 &#xff0c;请你从数组中找出满足相加之和等于目标数 target 的两个数。如果设这两个数分别是 numbers[index1] 和 numbers[index2] &#xff0c;则 1 < index1 < …

JavaScript中的作用域(scope)是什么?以及有哪些类型的作用域?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 作用域&#xff08;Scope&#xff09;是什么&#xff1f;1. 全局作用域&#xff08;Global Scope&#xff09;2. 局部作用域&#xff08;Local Scope&#xff09;3. 块级作用域&#xff08;Block Scope&#xff09; ⭐ 写在最后 ⭐ 专栏简…

MPLAB X IDE 中的查找方式

1.第一种选择到变量&#xff0c;然后按ctrlf&#xff0c;这种方式只能在单个文件中查找&#xff1b; 2.第二种&#xff0c;按ctrlshiftf&#xff0c;前提必须在英文模式下&#xff0c; 对于普通用户来说&#xff0c;只需要知道Containing Text是搜索对象&#xff1b;最下面的F…

stm32红绿灯源代码示例(附带Proteus电路图)

本代码不能直接用于红路灯&#xff0c;只是提供一个思路 #include "main.h" #include "gpio.h" void SystemClock_Config(void); void MX_GPIO_Init(void) {GPIO_InitTypeDef GPIO_InitStruct {0};/* GPIO Ports Clock Enable */__HAL_RCC_GPIOB_CLK_ENAB…

JavaScript中的变量声明方式有哪些?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 变量声明方式var 声明&#xff08;ES5及以前&#xff09;let 声明&#xff08;ES6以后&#xff09;const 声明&#xff08;ES6以后&#xff09; ⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 记得点击上方或者…

【算法学习】平方数之和

title: 【力扣】633.平方数之和 cover: ‘https://storage.bummon.com/image/202308171051399.png’ tags: 算法LeetCode双指针法二分查找法 categories:算法笔记 abbrlink: 2911343079 date: 2023-08-17 10:49:52 mathjax: true 【力扣】633.平方数之和 题目 原题链接 给定…

Vue 2 计算属性与侦听器

计算属性 vs 方法 vs 侦听器 计算属性的出现是为了解决模板内表达式太过复杂而变得难以维护。 假设我们知道长和宽&#xff0c;要计算一个矩形的面积&#xff0c;如果没有计算属性&#xff0c;我们可能像下面这样处理&#xff1a; <div id"app"><input t…

functools.wrap的使用

一、介绍 functools.wraps 是 Python 标准库中的一个函数&#xff0c;用于帮助创建装饰器时保留被装饰函数的元数据&#xff08;如函数名、文档字符串等&#xff09;。在使用装饰器时&#xff0c;如果不使用 functools.wraps&#xff0c;则被装饰函数的一些元数据可能会丢失或…