加载中…
正文 字体大小:

LUATASK教程之运行原理

(2018-03-23 10:47:25)
分类: GPRS模块

这一章讲解一下程序的运行原理,可能有的开发者一直在main.lua里面找main函数,一直没找到,然后就懵逼了。Luat采用的Lua语言,Lua 是一种轻量小巧的脚本语言。

先来看一下main.lua


--必须在这个位置定义PROJECT和VERSION变量
--PROJECT:ascii string类型,可以随便定义,只要不使用,就行
--VERSION:ascii string类型,如果使用Luat物联云平台固件升级的功能,必须按照"X.X.X"定义,X表示1位数字;否则可随便定义
PROJECT = "DEMO_TASK"
VERSION = "2.0.0"
-- 日志级别
require "log"
LOG_LEVEL = log.LOGLEVEL_TRACE
require "sys"
require "utils"
-- 加载GSM
require "net"
--8秒后查询第一次csq
net.startQueryAll(8 * 1000, 600 * 1000)
-- 控制台
require "console"
console.setup(1, 115200)
-- 系统工具
require "misc"
-- 看门狗
require "wdt"
wdt.setup(pio.P0_31, pio.P0_29)
-- 系統指示灯
require "led"
led.setup(pio.P0_28)
-- 测试任务
require "test"
-- 启动系统框架
sys.init(0, 0)
sys.run()

Lua提供了一个名为require的函数用来加载模块。要加载一个模块,只需要简单地调用就可以了。也就是说在main.lua里面加载了多个lua文件(简单粗暴的理解为require的文件内容复制到了main.lua),脚本语言顺序执行,所以执行顺序为:

  • 加载log.lua,sys.lua,utils.lua文件
  • 加载net.lua文件,执行net.startQueryAll函数设置第一次查询GSM信号时间(这个函数在net.lua里实现的,所以在使用前必须require"net")
  • 加载console.lua文件,执行console.setup函数设置控制台波特率
  • 加载misc.lua,wdt.lua,执行wdt.setup设置看门狗管脚
  • 加载led.lua,执行led.setup设置led灯管脚
  • 最后加载test.lua,也就是我们自己写的测试程序,执行test.lua里面的内容,输出信息
  • 执行sys.init函数,sys.init是什么呢?引用wiki上对sys.init的描述
    系统初始化

     

    • sys.init(mode, lprfnc)
    • mode:整数型。充电开机是否启动 GSM 协议栈,1 不启动,否则启动 。mode=1.
    • lprfnc:用户应用脚本中定义的“低电关机处理函数”,如果有函数名,则低电时,本文件中的run接口不会执行任何动作,否则,会延时1分钟自动关机
  • 执行sys.run函数,同样引用wiki上的描述
    主架构程序。一般情况下,这个程序是必须要有,而且必须要写在 main.lua 里。

     

    没有过多的描述,看一下这个函数的函数体

    ```lua
    ------------------------------------------ Luat 主调度框架 ------------------------------------------
    --- run()从底层获取core消息并及时处理相关消息,查询定时器并调度各注册成功的任务线程运行和挂起
    -- @return 无
    -- @usage sys.run()
    function run()
    while true do
    -- 分发内部消息
    dispatch()
    -- 阻塞读取外部消息
    local msg, param = rtos.receive(rtos.INF_TIMEOUT)
    -- 判断是否为定时器消息,并且消息是否注册
    if msg == rtos.MSG_TIMER and timerPool[param] then
    if param msg,msgpara = rtos.receive(timeout)
    >
    > 如果 msg 为 table 类型,msg 根据不同的消息 msg.id 会有不同的数据:
    >
    > 如果 msg 为 number 类型,msg 根据不同的消息 msg 会有不同的数据
    >
    > 1.rtos.MSG_TIMER 定时器超时消息 msg.timer_id 或者 msgpara 为超时的定时器 id
    >
    > 2.rtos.MSG_UART_RXDATA 串口 ATC 数据提醒 msg.uart_id 或者msgpara为收到的数据的串口id或者atc,收到该消息后可以通过uart.read 接口读取数据
    >
    > 3.rtos.MSG_KEYPAD 键盘消息,必须初始化按键(#rtos.init_module#)后才会有键盘消息
    >
    > msg.pressed 按键按下/弹起 msg.key_matrix_row 按键所在行值 msg.key_matrix_col 按键所在列值 4.rtos.WAIT_MSG_TIMEOUT 等待消息超时
    >
    > 5.rtos.MSG_INT 中断消息 msg.int_id 中断 id msg.int_resnum 中断 pin 脚编号
    >
    > 6.rtos.MSG_PMD 电源管理消息 msg.present 电池在位状态 msg.level 百分比 0-100 msg.voltage 电池电压 msg.charger 充电器在位状态 msg.state 充电状态:0-不在充电 1-充电中 2-充电停止

也就是说,通过不断的接收消息来判断发生了什么事件,应该做什么事情。

最后在分析一下test.lua。重构版采取的协程的方式。什么是协程?举个例子,有一盘菜,你和你女友两人吃。按照老的方法,顺序是这样的,女友先吃,吃饱了,然后自己吃。这样就不科学了,说好的男女平等了(emmmm....)。现在换一种方式:女友吃两分钟,自己吃两分钟,女友吃两分钟,自己吃两分钟...loop.....。这样是不是科学很多了。第一种方式就是我们常用的方式顺序执行,在单片机里面经常用while(1)来死循环控制流程。这样有个缺陷是,太死板,不能根据调整程序的执行时间,就比如,女友在吃菜的时候,自己已经饿得不行了,但是还是得等女友吃完(没人性啊!)。第二种方式就相对方便很多,可以控制程序运行的时间。比如:男生饭量大,需要吃三分钟,女生饭量小只吃一分钟,这样就可以合理分配时间。

回到test.lua里面的内容


module(..., package.seeall)                 --必须,目的是让其他文件能包含该文件

sys.taskInit(function()                 --任务1
    while true do
        print("Hello World")
        sys.wait(1000)
    end
end)
sys.taskInit(function()                 --任务2
    while true do
        print("Luat is esay")
        sys.wait(2000)
    end
end)

还记得上一章输出的内容吗?输出两次Hello World,输出一次Luat is esay。明明是while true的死循环,怎么会切换到其他任务?可以看到每个程序后都有sys.wait,程序执行sys.wait将自己挂起(说白一点,就是不在执行自己了),然后执行其他任务。第一个任务将自己挂起1000ms,也就是说每隔1000ms执行一次。第二个任务将自己挂起2000ms,也就是说将自己挂起2000ms。

希望这一章能让你明白Luat的运行原理

0

阅读 评论 收藏 转载 喜欢 打印举报
  • 评论加载中,请稍候...
发评论

    发评论

    以上网友发言只代表其个人观点,不代表新浪网的观点或立场。

      

    新浪BLOG意见反馈留言板 电话:4006900000 提示音后按1键(按当地市话标准计费) 欢迎批评指正

    新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 会员注册 | 产品答疑

    新浪公司 版权所有