当前位置:首页 > > 嵌入式云IOT技术圈
[导读]现在基本上每周末都要去上国硕的课提升自己的非技术技能,同时也希望两年后顺利拿到硕士学位,完成我人生第一阶段的目标;所以最近一段时间个人基本上忙得不可开支,既需要完成老师布置的课题,也需要完成课程总结等等。

现在基本上每周末都要去上国硕的课提升自己的非技术技能,同时也希望两年后顺利拿到硕士学位,完成我人生第一阶段的目标;所以最近一段时间个人基本上忙得不可开支,既需要完成老师布置的课题,也需要完成课程总结等等:

我也是个非常爱做笔记的人,所以我每次听完课都会肝一张思维导图,以作为课程的总结复习提纲,同时我也是个喜欢分享的人,每次肝完笔记都会第一时间分享给我的同学;我的同学也都是社会上的中流砥柱,基本上90%以上都是boss,不过说实话圈子是真的小,竟然还有前ST(意法半导体)的市场总监,能认识如此优秀的同学实属非常荣幸!跟着优秀的人一起慢慢也会变得优秀;后续我也会将我学习技术的思维导图分享给大家。

好了,话说再怎么忙,文章还是要更的,今天就来解决开源群里一位小伙伴的问题,我和这位小伙伴的聊天记录如下:

正好最近在工作中也遇到了这样的问题,但我的问题可能会比这位小伙伴更严重一些,但一样可以采用相同的方式来解决。

1、我自己遇到的问题

这个项目我上的是TencentOS tiny物联网操作系统,由于需要实时更新产品的一些状态,比如传感器、时间、电量、信号等等,更新这些我统一都放在一个任务里执行:

/*状态栏任务显示处理*/
void StartStatus_Bar_Task(void *argument);

我是如何完成这些状态的更新呢?采用状态机的模式,以下为伪代码:

void StartStatus_Bar_Task(void *argument)
{
    static uint8_t status = 0;
    while(1)
    {
        switch(status)
        {
          //更新时间
          case 0:
            //业务逻辑开始
            //....
            //业务逻辑结束
            //状态切换
            status = 1 ;  
            break ;
          //更新传感器状态
          case 1:
            //业务逻辑开始
            //....
            //业务逻辑结束
            //状态切换
            status = 2 ;
            break ;
          //更新电量
          case 2:
            //业务逻辑开始
            Update_Battery();
            //业务逻辑结束
            //状态切换
            status = 0 ;
            break ;
          default:
            break ;
        }
    
    }
    tos_sleep_ms(300);
}

那么这样做有什么好处呢?这样子就可以完成各个状态的间隔刷新了,个人经验使用感觉效率会高一些,当然如果你使用的MCU的主频够快,想一次性更新那也没问题。

好,这么做思路是对的,后面也配合硬件的充电模块完成了一些其它的逻辑:

  • 当插入充电器时,电池未充满电,显示充电红色图标
  • 当插入充电器时,电池充满电,显示充电绿色图标
  • 当没有插入充电器时,读取AD值,根据当前的AD值计算电压,然后分级显示

按照逻辑,我编写以下代码:

//更新电池
void Update_Battery(void)
{
    int level = 0;
    double Vol_value = 0.0;
    level = Get_Battery();
    Vol_value = level * 3.3 / 4096 ;

    //当前正在充电
    if(GPIO_PIN_RESET == HAL_GPIO_ReadPin(CHARG_0_GPIO_Port, CHARG_0_Pin))
        Display_Battery_Level(4);

    //当前电已充满
    if(GPIO_PIN_RESET == HAL_GPIO_ReadPin(CHARG_1_GPIO_Port, CHARG_1_Pin))
        Display_Battery_Level(5);

    //没插充电器
    if(GPIO_PIN_SET == HAL_GPIO_ReadPin(CHARG_1_GPIO_Port, CHARG_1_Pin)
            && GPIO_PIN_SET == HAL_GPIO_ReadPin(CHARG_0_GPIO_Port, CHARG_0_Pin))
    {
            if(Vol_value > 0.90)
                Display_Battery_Level(3);
            else if(Vol_value > 0.87 && Vol_value <= 0.90)
                Display_Battery_Level(2);
            else if(Vol_value > 0.84 && Vol_value <= 0.87)
                Display_Battery_Level(1);
            else
                Display_Battery_Level(0);
    }
}

思路是对的,看上去也完全没有问题;但是实际操作过程中问题就来了,当电压值计算到了临界点,假设在没插充电器时,电量其实一直在消耗中,电压计算在0.87边界范围左右跳动,这样出现问题的现象就和刚刚聊天那位小伙伴描述的现象基本一致了:

后来根据我个人分析问题的经验,电池格数跳动它不是一个一直在发生的事件,它可能是几秒钟跳一次,隔几秒钟再跳一次,等到电压降下来了,就又不跳了,又保持在一个稳定的状态,所谓的这种跳动的状态,只有可能发生在格数临界点的地方。

2、解决方案

适当给显示电量的地方延时,不要频繁的更新电池电量的显示;以上面状态栏任务的更新频率是每300ms的频率更新每个显示状态,其它的可以保持不变,但是电量这块可以做一下处理,我们把代码稍微改一下:

//更新电池
void Update_Battery(void)
{
    int level = 0;
    double Vol_value = 0.0;
    /*延时计数器*/
    static uint8_t count_delay = 0 ;
    /*拔插充电器时候实时更新当前电量状态*/
    static uint8_t update_flag = 0 ;
    level = Get_Battery();
    Vol_value = level * 3.3 / 4096 ;

    //当前正在充电
    if(GPIO_PIN_RESET == HAL_GPIO_ReadPin(CHARG_0_GPIO_Port, CHARG_0_Pin))
    {
        /*解锁刷新标志,当拔掉充电器时候需要更新一次电量显示*/
        update_flag = 0 ;
        Display_Battery_Level(4);
    }

    //当前电已充满
    if(GPIO_PIN_RESET == HAL_GPIO_ReadPin(CHARG_1_GPIO_Port, CHARG_1_Pin))
    {
        /*解锁刷新标志,当拔掉充电器时候需要更新一次电量显示*/
        update_flag = 0 ;
        Display_Battery_Level(5);
    }

    //没插充电器
    if(GPIO_PIN_SET == HAL_GPIO_ReadPin(CHARG_1_GPIO_Port, CHARG_1_Pin)
            && GPIO_PIN_SET == HAL_GPIO_ReadPin(CHARG_0_GPIO_Port, CHARG_0_Pin))
    {
        /*当更新标志解锁时,更新一次电量显示*/
        if(update_flag == 0)
        {
            if(Vol_value > 0.90)
                Display_Battery_Level(3);
            else if(Vol_value > 0.87 && Vol_value <= 0.90)
                Display_Battery_Level(2);
            else if(Vol_value > 0.84 && Vol_value <= 0.87)
                Display_Battery_Level(1);
            else
                Display_Battery_Level(0);
            /*更新完毕后上锁,直到下一次插入充电器的时候再解锁*/
            update_flag = 1 ;
        }

        /*持续计数,一次是300ms,那么计数60次就是18s,也就是18s才更新一次电量*/
        ++count_delay;
        if(count_delay >= 60)
        {
            count_delay = 0 ;

            if(Vol_value > 0.90)
                Display_Battery_Level(3);
            else if(Vol_value > 0.87 && Vol_value <= 0.90)
                Display_Battery_Level(2);
            else if(Vol_value > 0.84 && Vol_value <= 0.87)
                Display_Battery_Level(1);
            else if(Vol_value > 0.80 && Vol_value <= 0.84)
                Display_Battery_Level(0);
        }
    }
}

在这里,代码主要解决了两个问题:

  • 当拔插充电器时,需要完成状态切换,并更新一次电量显示
  • 在没有插充电器时,每18s完成一次电量更新

我改完以后再去测试的时候就不会再有电池格数频繁跳动的问题了,当然项目里还有其它的一些业务问题,比如处理休眠唤醒时,状态栏的更新问题,所有的处理方式也是类似的;如果有些还是会有明显跳动现象的话,我们可以考虑把计数时间继续拉长,比如1分钟就只更新一次电量;这样也是合理的。

这里透露一些产品研发上的潜规则,比如我要让客户感觉这个设备的续航时间够长,其实我可以在电池分级分少一些,不要分那么多状态,只有满电、低电、充电、充满四种状态,这样从用户的使用角度上来说,只要客户看着产品的电量指示有电,那么它就是有电,这也是一种研发产品上的商务手段,我们简称这种手段叫投机取巧;当然作为一个刚直的技术人员,我其实是非常反对这种为了迎合资本市场而去做的这种不道德的行为!这是需要被公众所谴责的;希望我们技术人员都要有一颗不投机取巧的心,努力把产品做好!

3、其它

感谢前天汪哥在分享的TencentOS tiny的会议上提到了我的开源项目:

TencentOS tiny危险气体探测仪产品级开发

并且TencetOS官方号也做了一次转发表示支持:

这个项目会继续维护,后面会将代码做得更优雅,界面做得更漂亮;功能做得更完善,并且在做完一次迭代更新的同时会及时通过本公众号告诉大家。

我的开源之路会一直坚持不懈的继续走下去,如下,手上的东西还有很多,比如手持PDA扫码器、4G DTU、智能小车,还有超多的各种各样的开发板;接下来期待我的持续分享:

往期精彩

TencentOS tiny RTOS快速入门

分批读取文件中数据的程序流程及其C代码实现

C语言表驱动法编程实践(精华帖,建议收藏并实践)

分享一个在Keil开发环境中配置代码格式化工具Astyle(美化代码风格)

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

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

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

LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: 驱动电源

在工业自动化蓬勃发展的当下,工业电机作为核心动力设备,其驱动电源的性能直接关系到整个系统的稳定性和可靠性。其中,反电动势抑制与过流保护是驱动电源设计中至关重要的两个环节,集成化方案的设计成为提升电机驱动性能的关键。

关键字: 工业电机 驱动电源

LED 驱动电源作为 LED 照明系统的 “心脏”,其稳定性直接决定了整个照明设备的使用寿命。然而,在实际应用中,LED 驱动电源易损坏的问题却十分常见,不仅增加了维护成本,还影响了用户体验。要解决这一问题,需从设计、生...

关键字: 驱动电源 照明系统 散热

根据LED驱动电源的公式,电感内电流波动大小和电感值成反比,输出纹波和输出电容值成反比。所以加大电感值和输出电容值可以减小纹波。

关键字: LED 设计 驱动电源

电动汽车(EV)作为新能源汽车的重要代表,正逐渐成为全球汽车产业的重要发展方向。电动汽车的核心技术之一是电机驱动控制系统,而绝缘栅双极型晶体管(IGBT)作为电机驱动系统中的关键元件,其性能直接影响到电动汽车的动力性能和...

关键字: 电动汽车 新能源 驱动电源

在现代城市建设中,街道及停车场照明作为基础设施的重要组成部分,其质量和效率直接关系到城市的公共安全、居民生活质量和能源利用效率。随着科技的进步,高亮度白光发光二极管(LED)因其独特的优势逐渐取代传统光源,成为大功率区域...

关键字: 发光二极管 驱动电源 LED

LED通用照明设计工程师会遇到许多挑战,如功率密度、功率因数校正(PFC)、空间受限和可靠性等。

关键字: LED 驱动电源 功率因数校正

在LED照明技术日益普及的今天,LED驱动电源的电磁干扰(EMI)问题成为了一个不可忽视的挑战。电磁干扰不仅会影响LED灯具的正常工作,还可能对周围电子设备造成不利影响,甚至引发系统故障。因此,采取有效的硬件措施来解决L...

关键字: LED照明技术 电磁干扰 驱动电源

开关电源具有效率高的特性,而且开关电源的变压器体积比串联稳压型电源的要小得多,电源电路比较整洁,整机重量也有所下降,所以,现在的LED驱动电源

关键字: LED 驱动电源 开关电源

LED驱动电源是把电源供应转换为特定的电压电流以驱动LED发光的电压转换器,通常情况下:LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: LED 隧道灯 驱动电源
关闭