air724UG + Luat玩转物联网(二) console模式, GPIO控制, 第一个工程

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了air724UG + Luat玩转物联网(二) console模式, GPIO控制, 第一个工程相关的知识,希望对你有一定的参考价值。

参考技术A

console模式既是即时命令行模式, 也可以称之为交互模式, 就像micropython的交互模式一样

烧录console模式脚本, 烧录方法和第一篇中讲解的一样, 脚本是luattools v2自带的,在 \\resource\\8910_script\\script_LuaTask_V2.3.6\\demo\\console 目录下

烧录完成后, 我们需要用一条micro-USB数据线连接UART接口, 然后打开电脑上的串口调试助手, 我们可以看到串口调试助手进入了console

根据air724ug a13原理图: http://openluat-luatcommunity.oss-cn-hangzhou.aliyuncs.com/attachment/20210106210504049_EVB_Air724UG_A13_%E8%AE%BE%E8%AE%A1%E6%96%87%E4%BB%B6_20200723.pdf

我们可以看到: gpio1接到了 绿色LED灯上

现在我们想点亮这个灯, 方法就是在console中输入命令使得gpio1引脚拉高
具体操作步骤只有一步, 在控制台输入:

灯亮了。这里, 我们其实用了一个pins模块的setup函数。参考API: http://doc.openluat.com/wiki/3?wiki_page_id=1382

参考文档: http://doc.openluat.com/wiki/6?wiki_page_id=60
Air724UG模块引脚共支持29个GPIO,部分引脚上电前后状态不同,如使用这些管脚,需根据实际情况使用。
注意 : Air724UG没有GPIO8

对luat来说 GPIO控制只有以下两个方法:

首先要引入 pins模块

返回值
返回function
配置为输出模式时,返回的函数,可以设置IO的电平
配置为输入或者中断模式时,返回的函数,可以实时获取IO的电平

精彩的设计, 以下是举例:

我们可以初始化一个pin脚blue_led为输出.

此时blue_led这个变量是个function类型的数据

上面的配置是输出模式,所以返回的function可以设置IO的电平

明白了, setup以后,控制GPIO高低可以直接 blue_led(0) 这样了

以demo中的console为例:

通过看main文件,我们可以确定:

下面我们来一个LED闪烁程序,尝尝鲜

然后开始编写逻辑:

我们发现, 一个小小的闪灯并不简单, 涉及了任务等我们没有接触过的luat特性, 接下来, 我们会慢慢的越来越了解

下面, 尝试将闪烁函数抽取并开启多任务

根据上面的 pins.setup 函数,如果函数的第二个参数传入function的话,就会开启GPIO中断

下面我们来尝试一下:

由于开发板没有按键,我们使用GPIO15来模拟按键, GPIO15的位置如下图所示

开启中断模式, 我们首先要定义一个function作为中断函数, 这里还是使用了匿名函数
根据上面的 pins.setup 函数的返回值, 如果是中断模式时,返回的函数可以实时获取IO的电平, 所以我们可以看一下中断电平

合宙Luat | 看《射雕英雄传》,聊聊LuaTask延时那些事

武侠小说中,主人公之所以能纵横江湖,常常离不开一样可遇不可求的绝世法宝——武功秘籍。如今勇于尝试的开发者,笃定地告诉后来者:选Luat二次开发,就如同拥有了物联网开发的武功秘籍。

本期让我们通过《射雕英雄传》的一些小场景,聊聊LuaTask延时那些事儿~

不了解Luat开发的朋友,可参考学习:

http://doc.openluat.com/article/1719/0


http://doc.openluat.com/wiki/3?wiki_page_id=606




1


什么是协程?




首先我们来看下什么是协程:

提起协程的话,大多数时候都会跟多线程进行比较。两者之间是有些相似的地方,都是程序上下文切换执行,都有并发性,但更多的还是区别所在。

多线程——是发生在系统态的程序切换,可以模拟较为真实的并发性。因为本身执行顺序带有一定的随机性,不可预测,所以很容易因为竞争造成数据混乱。

协程——是发生在用户态上的程序切换,只是对多线程的一种模拟,并不能替代多线程。它把本该在一个地方实现的代码拆分到了不同任务,让逻辑表述看起来更加清晰。

合宙Luat | 看《射雕英雄传》,聊聊LuaTask延时那些事

在《射雕英雄传》第十五章神龙摆尾中,有关黄蓉与欧阳克的比试有这样一段描写:

黄蓉走进圈子,道:“咱们是文打还是武打?”

欧阳克心道:“偏你就有这许多古怪。”问道:“文打怎样?武打怎样?”

黄蓉道:“文打是我发三招,你不许还手;你还三招,我也不许还手。武打是乱打一气,你用死蛇拳也好,活耗子拳也好,都是谁先出圈子谁输。” 


这个比试所定的规则,跟我们说的协程和多线程的关系是比较像的:

协程就是文打,执行权在两人之间交替运行,同一时间只能有一人挥拳,A打完之后B才能打。

多线程就是武打,两个人可以同时挥拳,互不影响。

如果用程序表示协程的话,代码可能会像下面这样:

Luat协程使用示例





▼上下滚动,查看全部▼

function A()
   for i=1, 5 do

       coroutine.resume(co)  
       print("A\t"..i)

   end 

end


function B()

   for i=1, 5 do

       coroutine.yield()    

       print("B\t"..i)   

 end

end


co = coroutine.create(B)

A()

--[[ 

   A 1
   B 1
   A 2
   B 2
   A 3
   B 3
   A 4
   B 4
   A 5
]]



这是一种简单的使用场景,yield和resume只是负责切换控制,让控制权在两个任务之间来回切换,达到了使两个任务 “并行” 的目的。






2


协程的延时





合宙Luat | 看《射雕英雄传》,聊聊LuaTask延时那些事

协程的概念说完了,但是...这跟延时有什么关系? 

其实稍加思索的话,就会发现这个黄蓉与欧阳克约定的文打规则里有个BUG: 

黄蓉先打三拳,然后欧阳克还三招,但是如果黄蓉只打了两拳就停手了,欧阳克怎么办? 

这就反映出协程中一个很现实的问题:

各个协程之间的延时是会相互影响的,你打了一拳去睡觉了,那我也必须跟着等,我回一拳之后也去睡觉了,你也必须跟着等。 

 如果反映到程序上,代码就是这样:

▼上下滚动,查看全部▼

function wait(ms)

  -- 阻塞延时, 仅仅只做说明, 并不实现

end


function A()

  for i=1, 5 do

       coroutine.resume(co)    

       print("A\t"..i)

      wait(1000)   

   end 

end


function B()

  for i=1, 5 do

       coroutine.yield()   

       print("B\t"..i)

       wait(1000)   

    end

end


co = coroutine.create(B)

A()



我们期望两个协程都能以1000ms的延时打印输出,但是这种阻塞延时其实是会在两个协程之间相互影响的:

A 在延时的过程中其实是会加长 B 的延时,最终两个协程都会以2000ms的延时打印输出。

这当然是一件很不合理的情况,我们希望代码中的程序段都应该保持一定的独立性,不能在修改一段代码之后莫名其妙的影响了另一段代码的执行情况。






3


概念的偏差




合宙Luat | 看《射雕英雄传》,聊聊LuaTask延时那些事
人们常说,比喻都是跛脚的。

在学习一些概念的时候,我们常常会借助一些比喻描述,加深理解。但是例子并不能完全做到等同,仅仅只能帮助理解某一面特性而已。

如果完全类比,或者把这个例子当成是概念本身,那很多细节是经不起推敲的。

黄蓉与欧阳克约定文打之后,欧阳克为什么一定要遵守?黄蓉在打出一拳之后,欧阳克为什么不能动?他完全可以毁约啊。 

这就牵扯到协程和多线程的另一个重要概念了:执行权。

你可以把它想像成是一个令牌,只有拿到令牌的人才能指挥行动。

开始令牌在黄蓉手上,所以她可以行动,欧阳克手上没有令牌,所以只能站着挨打,黄蓉打完之后把令牌丢给了欧阳克,欧阳克才开始还手。

武打就是两人手上都有一个令牌,所以两个人才能乱打一气,同时挥拳。 


有了上面这些基础概念之后,我们可以开始尝试理解问题本身了。





4


真实的协程




那么真实的协程到底是什么样子?

在单任务系统,依靠切换控制权来模拟多线程的话,那延时必定不可能是真正“延时”。

一个任务的阻塞延时肯定会干扰到其他任务的计时,为了解决这个问题,我们一般会引入一个第三者来进行时间管理,也就是“时钟调度器”。 

合宙Luat | 看《射雕英雄传》,聊聊LuaTask延时那些事

其实A、B两个任务在执行时,总共有四个角色存在:Core(底层)、以及Lua中的A任务B任务,还有run (一段控制执行权的代码)。

Core本身带一个系统时钟,用来记录当前时间,同时维护了一个表格,用来记录在什么时间,把控制权交给谁。

A、B在睡觉前都把自己的唤醒时间告诉Core,把自己的控制权交给run。run在获取到唤醒时间之后交给指定任务执行,指定任务执行完毕之后交还控制权。 


当然,这里其实还有另外一个疑问,为什么要有 run 这个角色的存在? 

按照我们直观的理解,为了防止AB在睡觉时霸占控制权,仅仅只需要一个管理者就可以了。时间到达之后,管理者可以自行调用A 或B,它们在执行完毕之后交还控制权,这样看起来似乎更简单。 

这样做其实有两方面原因: 

一是因为除了时钟消息,Core还有其他消息需要传递给Lua,程序中不光是有 A 和 B 提交的时钟消息,所以需要有一个角色来处理这些其他信息。 

二是因为Core和 A、B 两个任务所属在不同层,Core在C 层,而任务A、B是在Lua层。为了简化两个层之间的交互,Core 把消息传递给Lua之后由Lua自行处理调度。所以是Core处理时钟调度信息,Lua负责调度。





5


完整演示





最后,我们再看一遍整个过程的完整演示:

延时运行图示说明





合宙Luat | 看《射雕英雄传》,聊聊LuaTask延时那些事

从上图可以看到,控制权首先是在 Core,Core 完成初始化工作之后把控制权交给任务A执行。


A任务在执行到延时 wait(100) 时会把当前延时时间加上系统时钟时间的数值,连同自身ID,添加进Core的时间链表。也就是告诉 Core,在130这个时间点,把控制权交给A任务。如下图所示:

合宙Luat | 看《射雕英雄传》,聊聊LuaTask延时那些事

然后到了任务B——任务B在执行到 wait(80) 时,也会向 Core 中添加消息, 在110这个时间点,把控制权交给B任务:

合宙Luat | 看《射雕英雄传》,聊聊LuaTask延时那些事

接着会按顺序执行到run,run把控制权交给 Core:

合宙Luat | 看《射雕英雄传》,聊聊LuaTask延时那些事

然后,Core会以1ms的间隔独自计时,每过1ms,Core都会检查链表第一项时间是否达到。当时钟计时达到时间,控制权会交还给run,并且告诉 run,B的计时时间到了。

合宙Luat | 看《射雕英雄传》,聊聊LuaTask延时那些事
之后run会把控制权交给B,B执行完返还控制权。当然 B 在执行过程中依然会向Core中添加消息。

点击放大查看:

合宙Luat | 看《射雕英雄传》,聊聊LuaTask延时那些事

接着就开始下一轮循环,如此往复…

点击放大查看:

合宙Luat | 看《射雕英雄传》,聊聊LuaTask延时那些事



通过上面的分析我们也不难发现,Lua层当中的所有代码几乎都是瞬时完成的,所有延时操作都是把控制权移交到了Core。


以上就是关于LuaTask延时的一些事,更多开发应用问题,欢迎加入技术群共同探讨交流。

合宙Luat | 看《射雕英雄传》,聊聊LuaTask延时那些事

合宙Luat | 看《射雕英雄传》,聊聊LuaTask延时那些事

合宙Luat交流群04:877164555

合宙Luat交流群03:1092305811

合宙Luat交流群18(LuatOS):1061642968  

合宙Luat交流群17(iRTU):1027923658


每个建议都值得关注

每个技能都值得分享

合宙Luat | 看《射雕英雄传》,聊聊LuaTask延时那些事

- 更多精彩等你参与 -

了解更多相关内容






合宙Luat | 看《射雕英雄传》,聊聊LuaTask延时那些事


以上是关于air724UG + Luat玩转物联网(二) console模式, GPIO控制, 第一个工程的主要内容,如果未能解决你的问题,请参考以下文章

001-STM32+Air724UG基本控制篇(华为云物联网平台)--测试STM32+Air724UG(4G模组),Android,微信小程序等连接华为云物联网平台

04-STM32+Air724UG(4G模组)远程升级篇OTA(自建物联网平台)-STM32+Air724UG实现利用http或https远程更新STM32程序(TCP指令,单片机程序检查更新,精简内

手把手教你玩转物联网

手把手教你玩转物联网

玩转物联网外设之步进电机

Luat Air201 Air202 Air800 script 1.1.5,core V0019发布