嵌入式设计中对于只有两种状态的变量存储设计,如何高效的对循迹小车进行偏差量化
前言
(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; //000000000001bcase 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; //000000000001bcase 0x0003:deviation=-10;worse/=2;break; //000000000011b//... 省略其他偏差量化过程default://其它特殊情况单独判断{deviation=deviation_backup;//如果是异常情况,就保持上一个状态worse++;}
}
if(worse == 10) //如果多次循迹错误,说明出现问题了,为了保护硬件,强制停车
{//停车
}
相关文章:

嵌入式设计中对于只有两种状态的变量存储设计,如何高效的对循迹小车进行偏差量化
前言 (1)在嵌入式程序设计中,我们常常会要对各类传感器进行数据存储。大多时候的传感器,例如红外光传感器,返回的数据要么是0,要么是1。因此,只需要一bit就能够存储。而很多人却常常使用char型数…...
day53 第九章 动态规划part14● 1143.最长公共子序列 ● 1035.不相交的线 ● 53. 最大子序和 动态规划
1143. 最长公共子序列 class Solution {public int longestCommonSubsequence(String text1, String text2) {int m text1.length();int n text2.length();int[][] dp new int[m 1][n 1];for (int i 1; i < m; i) {for (int j 1; j < n; j) {if (text1.charAt(i …...

shell编程 基础
将content.txt文件中的内容输出到控制台上 将content.txt中有tom的行输出到控制台 将$2文件中含有gree的行输出到控制台 case语法 简易计算器 查找有root的行 查找以root开头的行 查询时忽略大小写 grep -E 则适用于复杂的正则表达式,可以使用多项选择、重复和子表达…...

人工智能在网络安全中的应用: 分析人工智能、机器学习和深度学习等技术在预测、检测和应对网络攻击中的作用
第一章:引言 随着信息技术的迅猛发展,网络安全已成为当今社会不容忽视的重要议题。网络攻击手法日益复杂,传统的防御方法已经不再足够。在这一背景下,人工智能(AI)技术正逐渐崭露头角,为网络安…...
使用 Redis 实现异步队列
使用 Redis 实现异步队列 一、简介1 异步队列2 异步队列与同步队列 二、Redis 实现异步队列1 利用 Redis 的 List 数据类型实现异步队列2 利用 Redis 的 Pub/Sub 功能实现异步队列3 利用 Redis 的 Sorted Set 数据类型实现延迟队列 三、Redis 异步队列的实际应用场景4.1 异步任…...

RocketMQ、Dashboard部署以及安全设置
RocketMQ、dashboard部署以及安全设置 一、启动RocketMQ1.1 下载RocketMQ1.2 修改配置文件1.2.1 修改nameServer Jvm内存配置1.2.2 修改broker参数 1.3 启动1.3.1 启动NameServer1.3.2 启动Broker1.3.3 测试是否启动成功1.3.3.1 测试消息发送1.3.3.2 测试消息接收1.3.3.3 Java程…...
Android AlarmManager设置闹钟
官网镇楼:设置重复闹铃时间 闹钟具有以下特征: 它们可让您按设定的时间和/或间隔触发 intent。您可以将它们与广播接收器结合使用,以启动服务以及执行其他操作。它们在应用外部运行,因此即使应用未运行,或设备本身处…...

【C# 基础精讲】LINQ to XML查询
LINQ to XML 是 C# 中用于查询和操作 XML 数据的强大工具。它允许您使用 LINQ 查询语法对 XML 文档进行查询、过滤、投影等操作,从而更加方便地处理 XML 数据。本文将详细介绍 LINQ to XML 的基本概念、常见操作以及示例,帮助您了解如何在 C# 中使用 LIN…...
Java学习笔记——(20)标识符命名规则和规范
什么叫标识符 Java 对各种变量、方法和类等命名时使用的字符序列成为标识符凡是自己可以起名字的地方都叫标识符 标识符的命名规则(必须遵守) 由26个英文字母大小写,0-9,_ 或 $ 组成数字不可以开头不可以使用关键字和保留字Jav…...
过滤字符,绕过
构造不包含字母和数字的webshell <?phpecho "A"^""; ?>运行结果为! 代码中对字符"A"和字符”"进行了异或操作。在PHP中,两个变量进行异或时,先会将字符串转换成ASCII值,再将ASCII值转换成二进制…...
Apache Doris 入门教程32:物化视图
物化视图 物化视图是将预先计算(根据定义好的 SELECT 语句)好的数据集,存储在 Doris 中的一个特殊的表。 物化视图的出现主要是为了满足用户,既能对原始明细数据的任意维度分析,也能快速的对固定维度进行分析查询。 …...
PHP substr()函数详解,PHP截取字符串。
「作者主页」:士别三日wyx 「作者简介」:CSDN top100、阿里云博客专家、华为云享专家、网络安全领域优质创作者 「推荐专栏」:对网络安全感兴趣的小伙伴可以关注专栏《网络安全入门到精通》 substr 一、截取字符串二、截取中文字符串三、leng…...
关于flink-sql-connector-phoenix的重写逻辑
目录 重写意义 代码结构 调用链路 POM文件配置 代码解析 一、PhoenixJdbcDynamicTableFactory...

Django进阶:DRF(Django REST framework)
什么是DRF? DRF即Django REST framework的缩写,官网上说:Django REST framework是一个强大而灵活的工具包,用于构建Web API。 简单来说:通过DRF创建API后,就可以通过HTTP请求来获取、创建、更新或删除数据(…...
Flink CDC系列之:Oracle CDC 导入 Elasticsearch
Flink CDC系列之:Oracle CDC 导入 Elasticsearch 一、深入理解Flink Oracle CDC Connector二、创建docker-compose.yml文件三、启动容器四、下载Flink Oracle CDC的jar包五、启动 Flink 集群,再启动 SQL CLI六、检查 ElasticSearch 中的结果七、在 Oracl…...

Linux忘记root密码解决方法
当我们忘记root密码进不去服务器怎么办?不要担心,可以进入到linux的救援模式修改root密码。 下面直接上干货,流程如下: 1.重启电脑,按上下键滑动,保证不进入开机流程,然后按e键 2.出现此页面…...

AR/VR眼镜转接器方案,实现同时传输视频快充方案
简介 虚拟现实头戴显示器设备,简称VR头显VR眼镜,是利用仿真技术与计算机图形学人机接口技术多媒体技术传感技术网络技术等多种技术集合的产品,是借助计算机及最新传感器技术创造的一种崭新的人机交互手段。VR头显VR眼镜是一个跨时代的产品。不…...
ASP.NET Core中路由规则匹配
RESTful约束,如果在一个控制器里面有多个Get、Post...的操作 1、在一个控制器里面可以定义多个API方法 2、通过路由规则来区分 /// <summary> /// 获取用户信息 /// </summary> /// <param name"user"></param> /// <returns…...

IDEA:Error running,Command line is too long. 解决方法
报错如下: Error running SendSmsUtil. Command line is too long. Shorten the command line via JAR manifest or via a classpath file and rerun.原因是启动命令过长。 解决方法: 1、打开Edit Configurations 2、点击Modify options设置&#x…...
什么是反射机制?为什么反射慢?
目录 面试回答 知识扩展 反射常见的使用方式 反射和 Class 的关系 面试回答 反射指的是程序在运行时能够获取自身的信息。在 java 中,只要给定类的名字,那么就可以通过反射机制来获得类的所有属性和方法。 Java 的反射可以: 在运行时判断…...

地震勘探——干扰波识别、井中地震时距曲线特点
目录 干扰波识别反射波地震勘探的干扰波 井中地震时距曲线特点 干扰波识别 有效波:可以用来解决所提出的地质任务的波;干扰波:所有妨碍辨认、追踪有效波的其他波。 地震勘探中,有效波和干扰波是相对的。例如,在反射波…...
Ubuntu系统下交叉编译openssl
一、参考资料 OpenSSL&&libcurl库的交叉编译 - hesetone - 博客园 二、准备工作 1. 编译环境 宿主机:Ubuntu 20.04.6 LTSHost:ARM32位交叉编译器:arm-linux-gnueabihf-gcc-11.1.0 2. 设置交叉编译工具链 在交叉编译之前&#x…...

stm32G473的flash模式是单bank还是双bank?
今天突然有人stm32G473的flash模式是单bank还是双bank?由于时间太久,我真忘记了。搜搜发现,还真有人和我一样。见下面的链接:https://shequ.stmicroelectronics.cn/forum.php?modviewthread&tid644563 根据STM32G4系列参考手…...
三维GIS开发cesium智慧地铁教程(5)Cesium相机控制
一、环境搭建 <script src"../cesium1.99/Build/Cesium/Cesium.js"></script> <link rel"stylesheet" href"../cesium1.99/Build/Cesium/Widgets/widgets.css"> 关键配置点: 路径验证:确保相对路径.…...
DockerHub与私有镜像仓库在容器化中的应用与管理
哈喽,大家好,我是左手python! Docker Hub的应用与管理 Docker Hub的基本概念与使用方法 Docker Hub是Docker官方提供的一个公共镜像仓库,用户可以在其中找到各种操作系统、软件和应用的镜像。开发者可以通过Docker Hub轻松获取所…...
Java 8 Stream API 入门到实践详解
一、告别 for 循环! 传统痛点: Java 8 之前,集合操作离不开冗长的 for 循环和匿名类。例如,过滤列表中的偶数: List<Integer> list Arrays.asList(1, 2, 3, 4, 5); List<Integer> evens new ArrayList…...

基于uniapp+WebSocket实现聊天对话、消息监听、消息推送、聊天室等功能,多端兼容
基于 UniApp + WebSocket实现多端兼容的实时通讯系统,涵盖WebSocket连接建立、消息收发机制、多端兼容性配置、消息实时监听等功能,适配微信小程序、H5、Android、iOS等终端 目录 技术选型分析WebSocket协议优势UniApp跨平台特性WebSocket 基础实现连接管理消息收发连接…...
Java - Mysql数据类型对应
Mysql数据类型java数据类型备注整型INT/INTEGERint / java.lang.Integer–BIGINTlong/java.lang.Long–––浮点型FLOATfloat/java.lang.FloatDOUBLEdouble/java.lang.Double–DECIMAL/NUMERICjava.math.BigDecimal字符串型CHARjava.lang.String固定长度字符串VARCHARjava.lang…...
Nginx server_name 配置说明
Nginx 是一个高性能的反向代理和负载均衡服务器,其核心配置之一是 server 块中的 server_name 指令。server_name 决定了 Nginx 如何根据客户端请求的 Host 头匹配对应的虚拟主机(Virtual Host)。 1. 简介 Nginx 使用 server_name 指令来确定…...
AI编程--插件对比分析:CodeRider、GitHub Copilot及其他
AI编程插件对比分析:CodeRider、GitHub Copilot及其他 随着人工智能技术的快速发展,AI编程插件已成为提升开发者生产力的重要工具。CodeRider和GitHub Copilot作为市场上的领先者,分别以其独特的特性和生态系统吸引了大量开发者。本文将从功…...