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

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

前言

(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) //如果多次循迹错误,说明出现问题了,为了保护硬件,强制停车
{
  //停车
}


目录
相关文章
|
3月前
|
算法
【MFAC】基于全格式动态线性化的无模型自适应控制
【MFAC】基于全格式动态线性化的无模型自适应控制
|
3月前
|
SQL 开发框架 算法
【MFAC】基于偏格式动态线性化的无模型自适应控制
【MFAC】基于偏格式动态线性化的无模型自适应控制
|
2月前
|
算法 调度
基于变异混合蛙跳算法的车间调度最优化matlab仿真,可以任意调整工件数和机器数,输出甘特图
**摘要:** 实现变异混合蛙跳算法的MATLAB2022a版车间调度优化程序,支持动态调整工件和机器数,输出甘特图。核心算法结合SFLA与变异策略,解决Job-Shop Scheduling Problem,最小化总完成时间。SFLA模拟蛙群行为,分组进行局部搜索和全局信息交换。变异策略增强全局探索,避免局部最优。程序初始化随机解,按规则更新,经多次迭代和信息交换后终止。
配电网三相不平衡潮流计算【隐式Zbus高斯法】【可设定变压器数量、位置、绕组方式】
配电网三相不平衡潮流计算【隐式Zbus高斯法】【可设定变压器数量、位置、绕组方式】
|
3月前
|
数据安全/隐私保护 Perl
批量计算地震波PGA/PGV/PGD、PSA/PSV/PSD、特征周期、卓越频率、Arias强度、特征强度、能量密度、Housner强度等30+参数
地震波格式转换、时程转换、峰值调整、规范反应谱、计算反应谱、计算持时、生成人工波、时频域转换、数据滤波、基线校正、Arias截波、傅里叶变换、耐震时程曲线、脉冲波合成与提取、三联反应谱、地震动参数、延性反应谱、地震波缩尺、功率谱密度
|
3月前
|
数据可视化 测试技术
R语言线性混合效应模型(固定效应&随机效应)和交互可视化3案例
R语言线性混合效应模型(固定效应&随机效应)和交互可视化3案例
|
3月前
|
Windows
R语言有状态依赖强度的非线性、多变量跳跃扩散过程模型似然推断分析股票价格波动
R语言有状态依赖强度的非线性、多变量跳跃扩散过程模型似然推断分析股票价格波动
|
编解码 算法 数据可视化
【多重信号分类】超分辨率测向方法——依赖于将观测空间分解为噪声子空间和源/信号子空间的方法具有高分辨率(HR)并产生准确的估计(Matlab代码实现)
【多重信号分类】超分辨率测向方法——依赖于将观测空间分解为噪声子空间和源/信号子空间的方法具有高分辨率(HR)并产生准确的估计(Matlab代码实现)
|
12月前
|
机器学习/深度学习 传感器 算法
基于有限体积法 (FVM) 和 SIMPLE 算法求解平行板之间层流的速度、压力和温度附 MATLAB 代码
基于有限体积法 (FVM) 和 SIMPLE 算法求解平行板之间层流的速度、压力和温度附 MATLAB 代码
|
传感器 计算机视觉
多级式多传感器信息融合中的状态估计(Matlab代码实现)
多级式多传感器信息融合中的状态估计(Matlab代码实现)
103 0