• Arduino ESP8266编程深入要点


            Arduino for ESP8266的话,如果不修改代码,默认没有办法进入轻睡眠的省电模式,只能进入Modem Sleep,也就是说Wifi可以暂时睡眠但是CPU没法睡,Modem Sleep最低功耗在15mA-16mA,轻睡眠的最低功耗在1mA-2mA左右

           如果要在Arduino中再腾出几KB内存的话,我这晨还有一个方法,就是去到esp8266 arduino的开发包中,找到一个叫"cont.h"的头文件,里边有一个栈大小的宏定义常量叫“CONT_STACKSIZE",他的值默认是4096,我试着将他改成1024,这样就省了3KB内存,具体稳定的话,我用一个程序目前测试了一下,还是可以顺利腾出3KB的内存的,因为刚好我应要用把这将近50K的内存用完,所以特此贡献这个方法
    我先看看他的调度的汇编来确定一下是否有其他的隐患,目前是测得可以正常工作的

           如果你用过SDK就会发现,有将近50K的内存,你用Arduino会少了几K,不好奇是去了哪里吗?有4K至少,是被用来做保存是上下文用的,什么是上下文?就是内核调度器的一个概念,你可以理解为,一个MCU要实现不同的线程,他就要为单个线程保存单独的现场环境,而这个现场环境就用掉了4K多一点的内存了

           如果有空可以将试着去官网下载一个最新版的SDK文件夹,然后将"lib"中的文件替换至现在的2.0.0版的"lib"文件夹中,这样的话,可以使用一些SDK1.5.0的一些最新的特性(不知道的可以暂时不升级),记得替换前要进行好备份原来的文件夹,如果替换后编译时出错,则可以在这个旧的文件夹中找至具体出错的文件进行找旧版的覆盖上去用,目前我大部份测试Arduino 2.0.0将SDK 1.3.0替换成SDK1.5.0(最新版的)也是可以正常工作的

           另外发现Arduino的一个问题就是在使用TCP(注意仅是TCP)发送一个内存缓冲区(大小是1450左右)函数的时候速度很慢(表现为TCP这个write函数执行时间较久),暂时我还没有办法找到内部的原因,但是使用SDK就没有这个问题,但是为了使用Arduino良好的编译环境,以及一堆的函数库(比如SD卡库),我在Ardiuno中使用了SDK的代码(可以直接编译成功,改动不大)

           我查看过这个write函数内部的源代码,发现里边有进行调度的迹象,因此有可能是因为这个Arduino内部的调度所产生的问题,这样的话比如你要做一个实时性要求很高的串口透传就会有受影响

           但如果对这个实时性要求不高的话,暂时Arduino也可以满足要求,我的话,是在Arduino上采用SDK编程的方法,使用异步回调的接口(而不是像Arduino一样必须在一个大循环里执行所有的逻辑)

            同时也要注意,由于esp8266的省电模式中,有三种,其中有一种是叫Modem Sleep,这种是默认开启的(你可能在一买回来就ping这个esp8266会觉得慢,其实不是他慢,根据我的测试,只要关掉这个默认的省电模式,esp8266的响应非常快,可以达到小于1毫秒的时间)理论分析也是可以做到小于1毫秒的,实测也可以。这种模式对于Arduino来讲是可以轻易进入的,他的功耗大概是省电模式进入后是15mA左右,但是对于第二种比较好用的更省电的模式,大概是1mA左右,是15分之一

           但是这种模式,你首先要理解为什么省电能再省14mA?原因是这个CPU可以被暂停!但由于是由系统自己判断如何进入省电模式的,其中有一个重要的条件,则是,CPU要保持空闲,才会被检测到,这是系统内部的逻辑来实现的,其中有一点重要的条件就是,CPU上的程序不能有一个循环定时,它的间隔是不能小于路由器上的两个DITM Beacon帧中设定的间隔的,通常我们家用的一般是100毫秒,你可以抓包看看便知具体数值,一般是这个
    如果有一个定时他总是小于100毫秒去执行的
    那么CPU便不能被判定为空闲状态,换言之,他省电也只能做到15mA了,即使你调用了API将系统设定为轻睡眠模式

    用Arduino的结论就是默认不能进入轻睡眠模式,那就是说默认情况下你用Arduino做的东西的最低的功耗可能只能到15mA了,一个1500mAh的电池,可以跑80个小时,因为中间还会醒来接收一下是否有数据要发给自己的,所以不会跑足100个小时的,而接收时的平均电流一般是60-70mA左右,这是比15mA还要大几倍的

    好了,那是不是就彻底没办法了?

    有的

    那就是想办法将这个阻碍系统判定Arduino进入省电模式的东西去掉

    core_esp8266_main.cpp

    在这个核心的文件中,你打开就会发现刚才我讲的,那个“Arduino利用SDK的函数来创建一个SDK上的任务(注意不是RTOS)”的函数

    我现在的推测就是可能是这个创建的任务导致Arduino不能进入轻睡模式的,因为他这个任务的时间片可能就是15mS左右,15mS当然是小了100mS的了!所以这又怎么会能进入轻睡眠模式呢?CPU怎么可能知道他啥时候要睡呢?一睡要是影响了你的15mS的时间片,人家罪就大了不是?
    15mS这个时间值是经详细研读乐鑫的esp8266手册推测得出的,官方特么的没有任何说法给出来这些重要的数值

    所以啊,要让Arduino不要被阻碍进入轻睡眠模式,从而让CPU可以顺利被暂停的关键就在于要去掉这个创建的任务了

    着重来看这个函数

    core_esp8266_main.cpp中的"loop_wraper()"

    static void loop_wrapper() {
        static bool setup_done = false;
        if(!setup_done) {
            setup();
            setup_done = true;
        }
        preloop_update_frequency();
        loop();
        esp_schedule();
    }

    他就是Arduino中的loop函数那个大循环的“包在外边”的代码了

    一者是setup(),一者是loop(),setup使用了一个静态变量来判断为只执行一次

    loop()则是你实际的loop函数的代码,在编译时,这个函数会和在ino文件中的loop函数对应链接起来

    所以有了这个不断在执行的循环啊

    系统不能让它睡这个也完全可以理解了吧?

    那么问题来了,是不是只要简单的不要创建这几个任务就行了呢?

    是的,如果你不使用Serial等内部封装了Arduino本身的这套调度系统的话,是没有大问题的

    但是啊,问题是这些平时用得很爽的封装过的类啊,他内部或多或少都是使用了Arduino的这套调度系统的

    你不相信可以自己使用VS的跳转功能来查看这些函数的源代码,就知道了
    所以啊,换言之啊,可以总结为

    如果你想在Arduino中找到一些不使用这些调度系统的函数的话, 那用之,则没问题

    但是很可惜很多都不行

    要用轻睡眠省电模式就最好不要用Arduino

    不要觉得奇怪,看起来低效的东西,逻辑上往往很好理解!

    这就是Arduino的封装者为什么一定要强行加一个setup和loop的原因,内部的逻辑就是为了简化入门者的门槛,同时引导你快速形成一种编程的思想习惯,也就是西乡一样所强调的“编程框架”

    虽然它不是异步的,但显然是简单而又可以让你动脑筋去实现复杂的结构的一种好的切入点

    只要我们不满足于这种编程的方式,我们总能找到更有效的异步回调的方式的,但,那时的你也不是一个新手级别的人了

    自然而言掌握回调这样的方法来解决业务逻辑,这是轻而易举的事

    所以Arduino他并不是低效(虽然我本人也比较喜欢用异步的方式,看起来比较“高效”)

    好了,只要注重几个重要的点,其实Arduino也没啥的,他的执行速度就是SDK的执行速度,C++和C语言之间的这点点执行差别,我们根本就很难体现得出来的!





  • 相关阅读:
    BZOJ 2299 向量
    BZOJ 1237 配对
    BZOJ 2226 LCMSum
    BZOJ 1876 SuperGCD
    查漏补缺:C++STL简述(容器部分)
    查漏补缺:Linux进程与线程的区别
    码海拾遗:常用的其中排序算法
    码海拾遗:简述C++(一)
    码海拾遗:简单的链表类
    码海拾遗:位运算实现加减乘除
  • 原文地址:https://www.cnblogs.com/lanzhi/p/6467331.html
Copyright © 2020-2023  润新知