Lua作为目前最为流行的、免费轻量级嵌入式脚本语言,在很多工业级的应用程序中被广泛应用,如Adobe’s Photoshop,甚至是在一些著名的游戏程序中也被大量使用,如星际。不仅如此,由于Lua具备很多特殊的优点,如语法简单(基于过程)、高效稳定(基于字节码)、可以处理复杂的数据结构、动态类型、以及自动内存管理(基于垃圾收集)等,因此在很多嵌入式设备和智能移动设备中,为了提高程序的灵活性、扩展性和高可配置性,一般都会选择Lua作为它们的脚本引擎,以应对各种因设备不同而带来的差异。
Lua 是一个小巧的脚本语言。是巴西里约热内卢天主教大学(Pontifical Catholic University of Rio de Janeiro)里的一个研究小组,由Roberto Ierusalimschy、Waldemar Celes 和 Luiz Henrique de Figueiredo所组成并于1993年开发。 其设计目的是为了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能。Lua由标准C编写而成,几乎在所有操作系统和平台上都可以编译,运行。Lua并没有提供强大的库,这是由它的定位决定的。所以Lua不适合作为开发独立应用程序的语言。Lua 有一个同时进行的GIT项目,提供在特定平台上的即时编译功能。
Lua 可以说是目前嵌入式方案中,资源占用 最小 、运行效率 最高 、语法 最简洁 的一门脚本语言。对于编程小白来说,它适合作为你的编程入门语言,因为语法简单。对于会c语言的老手来说,它与c可以完美契合,再加上LuatOS本身就是开源,你可以轻松地使用c为其添加一套c库接口,享受它的高效。
Lua 是一种轻量小巧的脚本语言,它用标准C语言编写并以源代码形式开放。这意味着什么呢?这意味着Lua虚拟机可以很方便的嵌入别的程序里,从而为应用程序提供灵活的扩展和定制功能。而整个Lua虚拟机编译后仅仅一百余K,经过适当的裁剪还能做到更小,十分适合嵌入式的开发。
Lua脚本可以很容易的被C/C++ 代码调用,也可以反过来调用C/C++的函数,这使得Lua在应用程序中可以被广泛应用。不仅仅作为扩展脚本,也可以作为普通的配置文件,代替XML,ini等文件格式,并且更容易理解和维护。 Lua由标准C编写而成,代码简洁优美,几乎在所有操作系统和平台上都可以编译,运行。 一个完整的Lua解释器不过200k,;同时,在目前脚本引擎中,Lua的运行速度占有绝对优势。在目前所有脚本引擎中,Lua的速度是最快的。这一切都决定了Lua是作为嵌入式脚本的最佳选择。
主要优势
应用场景
几乎所有语言的第一行代码,都是输出hello world,本教程也不意外。
在Lua中,打印结果只需要使用print这个函数即可。同时,如果需要使用函数,只需要在函数名后加上双括号,同时传入你想传入的值即可。
所以,我们来执行下面的代码,打印出hello world吧!
print("hello world!")
上一部分,我们知道了,在Lua中,可以使用print函数来打印你想要得到的结果。
并且还知道了,函数是指可以实现某些功能的子程序,可以使用函数名(参数)来执行。
让我们试着输出一些其他东西吧!使用多个print函数,输出自己想输出的数据。
print("测试")
print("aabcdefg")
print("xxxxx","第二个参数","第三个参数")
代码注释就是在代码里,不会运行的部分。注释完全不会被运行。
这部分是为了在查看代码时,可以更好地立即现有代码含义用的。
我们可以用–开头,来写一段单行注释
也可以用–[[开头,]]结尾,写一段多行注释。
下面是注释的例子:
print("这段代码会运行")
--print("我被注释掉了,所以不会运行")
--[[
我是多行注释
不管我写多少行
都不会影响代码运行
]]
单行注释
使用两个减号表示注释的开始,一直延续到行末位置。相当于C语言中的"//"。
--这里是一行注释
print("Hello Lanou")
多行注释
使用"–[[“表示注释开始,使用”]]“表示注释结束。这种注释相当于C语言中的”/“和”/"。
--[[这里是第一行注释
这里是第二行注释]]
pring("Hello Lanou")
合宙Air101是一款QFN32 封装,4mm x 4mm 大小的mcu。注意:烧录前请设置波特率为921600。
Air101入门手册(示例程序)
示例程序
开发板所带的三个灯分别为PB8,PB8,PB10。使用GPIO接口控制开发板的LED灯进行闪烁,gpio - GPIO操作 - LuatOS 文档
PROJECT = "GPIO"
VERSION = "1.0.0"
sys = require("sys")
local LED1 = gpio.setup(pin.PB08, 0) -- PB08输出模式
local LED2 = gpio.setup(pin.PB09, 0) -- PB00输出模式
local LED3 = gpio.setup(pin.PB10, 0) -- PB10输出模式
sys.taskInit(function()
while 1 do
log.info("LED开启"); LED1(0); sys.wait(500)
log.info("LED关闭"); LED1(1); sys.wait(500)
log.info("LED开启"); LED2(0); sys.wait(500)
log.info("LED关闭"); LED2(1); sys.wait(500)
log.info("LED开启"); LED3(0); sys.wait(500)
log.info("LED关闭"); LED3(1); sys.wait(500)
end
end)
sys.run()
按键2接了BOOT,也就是PA0,
https://wiki.luatos.com/boardGuide/common/uart/air101.html
UART(Universal Asynchronous Receiver/Transmitter)通用异步收发传输器,UART 作为异步串口通信协议的一种,工作原理是将传输数据的每个字符一位接一位地传输。是在应用程序开发过程中使用频率最高的数据总线。
UART 串口的特点是将数据一位一位地顺序传送,只要 2 根传输线就可以实现双向通信,一根线发送数据的同时用另一根线接收数据。UART 串口通信有几个重要的参数,分别是波特率、起始位、数据位、停止位和奇偶检验位,对于两个使用 UART 串口通信的端口,这些参数必须匹配,否则通信将无法正常完成。
查看文档LuatOS 文档可以看到,Air101有4个uart,其中uart0做下载调试用,所以我们就选uart1吧。也就是PB6->TX然后PB7->RX把TX接串口线RX,RX接串口线TX,然后别忘了共地。
接好线以后开始写代码,根据UART 的API接口说明,首先我们初始化串口
PROJECT = "uart"
VERSION = "1.0.0"
sys = require("sys")
USE_ZBUFF = false
if USE_ZBUFF == true then
-- 创建1KB的发送缓冲区
sendBuff = zbuff.create(1024)
-- 创建1KB的接收缓冲区
receiveBuff = zbuff.create(1024)
-- 向发送缓冲区写入数据
sendBuff:write("Hi,I am Air101\n")
-- 将发送缓冲区的指针重新移到开头
sendBuff:seek(0)
end
uart.setup(1, 115200, 8, 1, uart.None)
if USE_ZBUFF == true then
uart.on(1, "receive", function(id, len)
-- 将数据读取到接收缓冲区
uart.read(id, len, receiveBuff)
-- 将接收缓冲区的指针重新移到开头
receiveBuff:seek(0)
-- 从接收缓冲区中读取数据
local data = receiveBuff:read(len)
-- 将接收缓冲区的指针重新移到开头
receiveBuff:seek(0)
log.info(PROJECT .. ".receive-" .. id, data)
end)
sys.timerLoopStart(function()
uart.write(1, sendBuff, 15)
end, 2000)
else
uart.on(1, "receive", function(id, len)
local data = uart.read(id, len)
log.info(PROJECT .. ".receive-" .. id, data)
end)
sys.timerLoopStart(function()
uart.write(1, "Hi,I am Air101\n")
end, 2000)
end
sys.run()
最新固件下载
原理图
硬件设计手册
Air101硬件设计教程
Air101开发板PCB
管脚映射表
GPIO编号 | 命名 | 默认功能及扩展功能 |
---|---|---|
0 | PA0 | BOOT |
1 | PA1 | I2C_SCL/ADC0 |
4 | PA4 | I2C_SDA/ADC1 |
7 | PA7 | GPIO/PWM4 |
16 | PB0 | GPIO/PWM0/UART3_TX |
17 | PB1 | GPIO/PWM1/UART3_RX |
18 | PB2 | SPI_SCK/PWM2/UART2_TX |
19 | PB3 | SPI_MISO/PWM3/UART2_RX |
20 | PB4 | SPI_CS/UART4_TX |
21 | PB5 | SPI_MOSI/UART4_RX |
22 | PB6 | UART1_TX |
23 | PB7 | UART1_RX |
24 | PB8 | GPIO |
25 | PB9 | GPIO |
26 | PB10 | GPIO |
27 | PB11 | GPIO |
35 | PB19 | UART0_TX |
36 | PB20 | UART0_RX |
开机时仅配置了BOOT和UART0_TX/RX,其他数字脚均为GPIO脚,状态为输入高阻。
ADC编号(LuatOS) | 功能 |
---|---|
0 | 模块ADC0-PA1 |
1 | 模块ADC1-PA4 |
10 | CPU温度 |
11 | 内部电压 |
合宙:
2023/04/17
串口程序:
-- LuaTools需要PROJECT和VERSION这两个信息
PROJECT = "uart_irq"
VERSION = "1.0.0"
log.info("main", PROJECT, VERSION)
-- 引入必要的库文件(lua编写), 内部库不需要require
sys = require("sys")
if wdt then
--添加硬狗防止程序卡死,在支持的设备上启用这个功能
wdt.init(9000)--初始化watchdog设置为9s
sys.timerLoopStart(wdt.feed, 3000)--3s喂一次狗
end
log.info("main", "uart demo")
local uartid = 1 -- 根据实际设备选取不同的uartid
--初始化
local result = uart.setup(
uartid,--串口id
115200,--波特率
8,--数据位
1--停止位
)
--循环发数据
sys.timerLoopStart(uart.write,1000, uartid, "test123")
-- 收取数据会触发回调, 这里的"receive" 是固定值
uart.on(uartid, "receive", function(id, len)
local s = ""
repeat
-- 如果是air302, len不可信, 传1024
-- s = uart.read(id, 1024)
s = uart.read(id, len)
if #s > 0 then -- #s 是取字符串的长度
-- 如果传输二进制/十六进制数据, 部分字符不可见, 不代表没收到
-- 关于收发hex值,请查阅 https://doc.openluat.com/article/583
log.info("uart", "receive", id, #s, s)
-- log.info("uart", "receive", id, #s, s:toHex())
end
if #s == len then
break
end
until s == ""
end)
-- 并非所有设备都支持sent事件
uart.on(uartid, "sent", function(id)
log.info("uart", "sent", id)
end)
-- sys.taskInit(function()
-- while 1 do
-- sys.wait(500)
-- end
-- end)
-- 用户代码已结束---------------------------------------------
-- 结尾总是这一句
sys.run()
-- sys.run()之后后面不要加任何语句!!!!!
uart.write(uartid, "Hi,I am Air101\n")
双向对发:https://wiki.luatos.com/boardGuide/common/uart/air101.html
PROJECT = "uart"
VERSION = "1.0.0"
sys = require("sys")
USE_ZBUFF = false
if USE_ZBUFF == true then
-- 创建1KB的发送缓冲区
sendBuff = zbuff.create(1024)
-- 创建1KB的接收缓冲区
receiveBuff = zbuff.create(1024)
-- 向发送缓冲区写入数据
sendBuff:write("Hi,I am Air101\n")
-- 将发送缓冲区的指针重新移到开头
sendBuff:seek(0)
end
uart.setup(1, 115200, 8, 1, uart.None)
if USE_ZBUFF == true then
uart.on(1, "receive", function(id, len)
-- 将数据读取到接收缓冲区
uart.read(id, len, receiveBuff)
-- 将接收缓冲区的指针重新移到开头
receiveBuff:seek(0)
-- 从接收缓冲区中读取数据
local data = receiveBuff:read(len)
-- 将接收缓冲区的指针重新移到开头
receiveBuff:seek(0)
log.info(PROJECT .. ".receive-" .. id, data)
end)
sys.timerLoopStart(function()
uart.write(1, sendBuff, 15)
end, 2000)
else
uart.on(1, "receive", function(id, len)
local data = uart.read(id, len)
log.info(PROJECT .. ".receive-" .. id, data)
end)
sys.timerLoopStart(function()
uart.write(1, "Hi,I am Air101\n")
end, 2000)
end
sys.run()