当前位置:首页 > 公众号精选 > 嵌入式云IOT技术圈
[导读]今天分享的这个传感器驱动检测框架,也是我在副业里给客户做的那些项目里用得最多的骚技能,所以就拿出来说一说。

接上前面两篇文章:

基于事件型表驱动法菜单框架之小熊派简易气体探测器实战项目开发(上)

基于事件型表驱动法菜单框架之小熊派简易气体探测器实战项目开发(中)

今天这篇文章不作为气体探测器实战项目的最后一节,因为很多功能还在编写中,前两天在世伟兄的开源群里提到了传感器检测框架,群友反应说:杨工有空你要多搞点这种框架出来分享分享,感觉很有用啊!

今天分享的这个传感器驱动检测框架也是我在副业里给客户做的那些项目里用得最多的骚技能(但主业上的产品我几乎就没用过,还是我说的那句话:没有明确需求的产品,别提什么复用性和高逼格),所以今天就拿出来说一说。

看下之前这个项目里写的这个气体传感器MQ-2的检测流程:

void Test_CallBack(void)
{

    static uint8_t Count_AMI = 0;
    static uint8_t Refresh_flag = 0 ;
    int smoke_value = 0 ;
    static uint8_t display_result_flag = 0 ;

    if(Flow_Cursor.flow_cursor == TEST_PAGE && detect_logic.Start_Detect == 1)
    {
        switch(detect_logic.Detect_Step)
        {
            case BASE_LINE:
                Count_AMI++ ;

                if(Count_AMI > 2)
                    Count_AMI = 0 ;

                icon_reflash(Count_AMI);
                smoke_value = mq2_sensor_interface.get_smoke_value(&mq2_sensor_interface) ;

                if(smoke_value < ALARM_THRESHOLD / 2)
                {
                    display_smoke_value(smoke_value, GREEN, 1);
                    ++detect_logic.Count_Base ;
                }
                else
                {
                    display_smoke_value(smoke_value, RED, 1);
                }

                if(detect_logic.Count_Base > 10)
                {
                    detect_logic.Count_Base = 0 ;
                    display_result_flag = 0 ;
                    /*隐藏基准*/
                    display_base(0);
                    /*显示检测*/
                    display_detect(1);
                    /*显示进度条框*/
                    Display_Process_Bar_Frame(1);
                    /*切换到检测中*/
                    detect_logic.Detect_Step = DETECTING ;
                    break ;
                }

                break ;

            case DETECTING:
                Count_AMI++ ;

                if(Count_AMI > 2)
                    Count_AMI = 0 ;

                icon_reflash(Count_AMI);
                ++detect_logic.Test_Process ;

                /*测试安全*/
                if(detect_logic.Test_Process == 100 && mq2_sensor_interface.Smoke_Value < ALARM_THRESHOLD)
                {
                    detect_logic.Detect_Step = DETECT_SAFETY ;
                    Display_Process_Bar(0, 0);
                    display_smoke_value(smoke_value, BLACK, 0);
                    /*隐藏检测*/
                    display_detect(0);
                    /*显示安全*/
                    display_safety(1);
                    break ;
                }
                else
                {
                    smoke_value = mq2_sensor_interface.get_smoke_value(&mq2_sensor_interface) ;

                    if(mq2_sensor_interface.Smoke_Value < ALARM_THRESHOLD)
                    {
                        display_smoke_value(smoke_value, GREEN, 1);
                    }
                    else
                    {
                        display_smoke_value(smoke_value, RED, 1);
                        detect_logic.Count_Alarm++ ;

                        if(detect_logic.Count_Alarm > 5)
                        {
                            detect_logic.Detect_Step = DETECT_DANGER ;
                            detect_logic.Count_Alarm = 0 ;
                            display_smoke_value(smoke_value, BLACK, 0);
                            Display_Process_Bar(0, 0);
                            /*隐藏检测*/
                            display_detect(0);
                            /*显示危险*/
                            display_danger(1);
                            break ;
                        }
                    }

                    Display_Process_Bar(detect_logic.Test_Process, 1);
                }

                break ;

            case DETECT_SAFETY:
                detect_logic.Start_Detect = 0 ;

                if(display_result_flag == 0)
                {
                    display_result_flag = 1 ;
                    smoke_value = mq2_sensor_interface.get_smoke_value(&mq2_sensor_interface) ;
                    display_smoke_value(smoke_value, GREEN, 1);
                }

                break ;

            case DETECT_DANGER:
                /*危险闪烁*/
                Refresh_flag = !Refresh_flag ;
                display_danger(Refresh_flag);
                mq2_sensor_interface.led_control(&mq2_sensor_interface, Refresh_flag);
                mq2_sensor_interface.buzzer_control(&mq2_sensor_interface, Refresh_flag);

                if(display_result_flag == 0)
                {
                    display_result_flag = 1 ;
                    smoke_value = mq2_sensor_interface.get_smoke_value(&mq2_sensor_interface) ;
                    display_smoke_value(smoke_value, RED, 1);
                }

                break ;

            default:
                break ;
        }
    }
}

写完后看了一下,逻辑上没有什么毛病,运行以后最终测试的结果也是我想要的结果就直接提交到Github和码云仓库上去了。所谓士别三日,非吴下阿蒙,过几天再看这代码,表示我已经看不下去了,居然一个函数能写这么长!看着不累不乱吗?于是吐槽了下自己:fuck me!,卧槽!这写的什么垃圾代码?不像我的个人风格,不应该更高逼格一点吗?于是就有了表驱动+状态机法传感器驱动检测框架的诞生。

1、核心传感器检测框架

上面那个写得很长的传感器检测流程,其实说白了就是两部分:

  • 1、当前到底是对应哪个传感器检测流程(状态机)?
  • 2、当前对应传感器检测流程的处理

于是我们就可以把这个过程抽象化成一个数据结构sensor_frame,将这两个部分相应的共同点提炼出来,这里就包括传感器检测流程sensor_detect_step,这里主要有基准、检测中、安全、危险;传感器检测流程处理函数handler_func是一个带形参的函数指针,这个参数在这里表示传感器数值,当然这个值可以是浮点型,也可以是其它类型,具体根据传感器的数据类型去定义,这里我把它定义成int型。

接下来我们还需要一个传感器的检测业务结构,用于实现检测流程切换(状态机)以及一些其它的逻辑操作,这里提供了一个Sensor_Cursor的数据结构。

/*检测流程*/
enum
{
    BASE_LINE_STEP = 0,
    DETECTING_STEP,
    DETECT_SAFETY_STEP,
    DETECT_DANGER_STEP
};

typedef void (*sensor_handler)(int);
typedef struct
{
    /*传感器检测流程*/
    uint8_t sensor_detect_step ;
    /*传感器检测流程处理*/
    sensor_handler handler_func ;
} sensor_frame;

/*传感器状态机+流程处理集*/
typedef struct
{
    uint8_t Detect_Step ; /*检测流程*/
    uint8_t Count_AMI  ; /*动画计数器*/
    uint8_t Start_Detect; /*开始测试标志*/
    uint8_t Count_Base  ; /*统计基准次数*/
    uint8_t Count_Alarm ; /*统计报警次数*/
    uint8_t Test_Process; /*测试进度*/
} Sensor_Cursor ;
extern Sensor_Cursor Sensor_Flow_Cursor ;

2、传感器驱动检测框架应用

有了这个最基本的框架结构,接下来照葫芦画瓢,把前面两篇文章介绍的菜单表驱动框架的代码复制粘贴然后稍微骚操作一下,于是我们就看到了以下的形态:

/*基准流程*/
void sensor_base_line_step(int adc);
/*检测中流程*/
void sensor_detecting_step(int adc);
/*检测安全*/
void sensor_detect_safety(int adc);
/*检测危险*/
void sensor_detect_danger(int adc);

/*传感器驱动表定义*/
static sensor_frame sensor_opStruct[] =
{
    {BASE_LINE_STEP,    sensor_base_line_step},  /*基准*/
    {DETECTING_STEP,    sensor_detecting_step},  /*检测中*/
    {DETECT_SAFETY_STEP, sensor_detect_safety},   /*安全*/
    {DETECT_DANGER_STEP, sensor_detect_danger},   /*危险*/
};

/*传感器流程处理*/
int Sensor_Handler(int8_t op, int adc_value)
{
    assert(op >= sizeof(sensor_opStruct) / sizeof(sensor_opStruct[0]));
    assert(op < 0);
    sensor_opStruct[op].handler_func(adc_value);
    return 0 ;
}

这样看起来舒服多了有木有??在程序后期调试中,如果想增加传感器检测流程,或者说发现传感器检测哪个流程有BUG,那这不就直接就可以找到了吗?整个框架组成清晰明了,我们只需要分别去实现如上的基准、检测中、安全、危险四个流程对应的处理函数就可以了。

在进入检测页面时还需要实现并调用传感器检测初始化函数,这个初始化函数主要是对一些原始数据(比如检测流程中用到的一些计数变量)进行清0操作,然后将检测流程设置为最开始的基准流程。

/*传感器检测初始化*/
void Sensor_Detect_Init(void)
{
    Sensor_Flow_Cursor.Count_AMI = 0 ;
    Sensor_Flow_Cursor.Count_Base = 0 ;
    Sensor_Flow_Cursor.Count_Alarm = 0 ;
    Sensor_Flow_Cursor.Test_Process = 0 ;
    Sensor_Flow_Cursor.Start_Detect = 1 ;
    Sensor_Flow_Cursor.Detect_Step = BASE_LINE_STEP ;
}

我们可以来看下其中有关基准流程的处理:

/*基准流程*/
void sensor_base_line_step(int adc)
{
    Sensor_Flow_Cursor.Count_AMI++ ;

    if(Sensor_Flow_Cursor.Count_AMI > 2)
        Sensor_Flow_Cursor.Count_AMI = 0 ;

    /*刷新动画*/
    icon_reflash(Sensor_Flow_Cursor.Count_AMI);

    /*判断是否满足基准条件*/
    if(adc < ALARM_THRESHOLD / 2)
    {
        display_smoke_value(adc, GREEN, 1);
        ++Sensor_Flow_Cursor.Count_Base ;
    }
    else
    {
        display_smoke_value(adc, RED, 1);
    }

    if(Sensor_Flow_Cursor.Count_Base > 10)
    {
        Sensor_Flow_Cursor.Count_Base = 0 ;
        /*隐藏基准*/
        display_base(0);
        /*显示检测*/
        display_detect(1);
        /*显示进度条框*/
        Display_Process_Bar_Frame(1);
        /*切换到检测中*/
        Sensor_Flow_Cursor.Detect_Step = DETECTING_STEP ;
    }
}

满足通过基准的条件,此时在该函数里写了这么一句代码:

Sensor_Flow_Cursor.Detect_Step = DETECTING_STEP ;

这一句代码就是检测流程的切换(状态机),后面的几个流程也是类似的,满足条件则切换到下一个检测流程。

最后我们只需要在原来传感器定时后调函数Test_CallBack里这么写就可以了:

/*测试回调*/
void Test_CallBack(void)
{
  int smoke_value = 0 ;
  /*如果当前在测试页面 && 开始检测标志为1,则进入传感器数据处理*/
  if(Flow_Cursor.flow_cursor == TEST_PAGE && Sensor_Flow_Cursor.Start_Detect == 1)
  {
   smoke_value = mq2_sensor_interface.get_smoke_value(&mq2_sensor_interface) ;
   Sensor_Handler(Sensor_Flow_Cursor.Detect_Step,smoke_value);
  }
}

这才是我们想要的高逼格嘛!嘿嘿嘿!

表驱动其实还有很多更骚的操作,今晚就分享到这里了,期待杨工下期精彩分享!

其余功能:后续还可以做报警记录存储、数据上传到OneNet或者华为云等平台、参数设置等等,总之这个项目可拓展性非常强,这些功能将在本项目开发的下一章节持续进行拓展并分享,欢迎及时关注我的码云仓库与微信公众号文章更新。

本节代码已同步到码云的代码仓库中:

获取方法如下:

1、新建一个文件夹

2、使用git clone远程获取小熊派所有案例代码

我还将之前做的一些项目以及练习例程在近期内全部上传完毕,与大家一起分享交流:

公众号粉丝福利时刻

这里我给大家申请到了福利,本公众号读者购买小熊派开发板可享受9折优惠,有需要购买小熊派以及腾讯物联网开发板的朋友,淘宝搜索即可,跟客服说你是公众号:嵌入式云IOT技术圈 的粉丝,立享9折优惠!

往期精彩

STM32系统bootloader应用

GitHub上最励志的计算机自学教程

"结构体"和"共用体"在单片机中的妙用

STM32硬核DIY机械键盘|蓝牙USB双模|灯控

觉得本次分享的文章对您有帮助,随手点[在看]并转发分享,也是对我的支持。

免责声明:本文内容由21ic获得授权后发布,版权归原作者所有,本平台仅提供信息存储服务。文章仅代表作者个人观点,不代表本平台立场,如有问题,请联系我们,谢谢!

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

2024年3月26日 – 提供超丰富半导体和电子元器件™的业界知名新品引入 (NPI) 代理商贸泽电子 (Mouser Electronics) 即日起开售Melexis的MLX90830 Triphibian™ MEM...

关键字: 传感器 电动汽车 热管理系统 膨胀阀

传感器的原理基于将一种形式的信号或物理量转换为另一种可测量或可处理的信号。这通常涉及敏感元件和转换元件的协同工作。敏感元件负责感受或检测被测信号或物理量,如力、温度、光、声、化学成分等,而转换元件则将这些非电学量按照一定...

关键字: 传感器 敏感元件

香港 - Media OutReach Newswire - 2024年3月21日 - 全球领先的工程硬件解决方案供应商索斯科推出一款带内置式传感器和密封式电子驱动装置R4-50重载型电子转动式门锁,为旗下的转动式门锁系...

关键字: 转动式门锁 传感器

3月21日消息,近日,杭州镓仁半导体有限公司宣布,公司联合浙江大学杭州国际科创中心先进半导体研究院、硅及先进半导体材料全国重点实验室。

关键字: 半导体 传感器 人工智能 电动汽车

【2024年3月21日,德国慕尼黑讯】英飞凌科技股份公司(FSE代码:IFX / OTCQX代码:IFNNY)近日宣布推出最新款蓝牙模块CYW20822-P4TAI040,在低功耗与覆盖范围等方面实现了新的突破,推动物联...

关键字: 蓝牙模块 智能家居 传感器

现在,OEM和一级供应商可以更轻松地获取价格合理且性能可靠的成像雷达传感器技术。恩智浦和赛恩领动联合开发的入门级量产4D成像雷达为这项技术提供了有力证明。

关键字: 4D成像雷达 传感器

中国,2024年3月20日,–全球领先的胶粘剂专家Bostik波士胶将在2024慕尼黑上海电子生产设备展(Productronica China 2024)上展示其针对消费电子行业的全系列创新工程胶粘剂解决方案。

关键字: 传感器 机器人 智能仓储

新的IEEE汽车以太网标准不断涌现,10BASE-T1S是最新的以太网标准之一。本文讨论汽车行业影响汽车电子/电气(E/E)架构变化的发展趋势,以及新10BASE-T1S标准如何支持和推动这种新架构的部署。

关键字: 以太网 汽车电子 传感器

新竹,台湾,2024年3月13日 -工业5.0注重智慧化、感测能力和高度自动化,代表着智慧工业领域的新一波革命,在这个背景下,工业自动化和物联网应用在多个领域对高精准、小型化传感器的需求不断增加。NuMicro M091...

关键字: 运算放大器 模拟数字转换器 传感器

随着科技的不断进步,传感器技术在工业、农业、医疗、环保等领域的应用越来越广泛。BF350传感器作为一种高精度、高稳定性的传感器,被广泛应用于各种测量和控制系统中。本文将详细介绍BF350传感器的使用方法,帮助读者更好地理...

关键字: 传感器 BF350 控制系统
关闭
关闭