Lua学习笔记(2023-2)

  

Lua简介

  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是作为嵌入式脚本的最佳选择。

主要优势

  1. 高效性:作为一种脚本语言,Lua的高效是众所周知的,因此在实际应用中,很多大型程序都会考虑将代码中易变的部分用Lua来编写。这不但没有明显降低系统的运行效率,反而使程序的稳定性和可扩展性得到了显著的提升。
  2. 可移植性:在官方网站中提供了基于多种平台的发布包,如Linux/Unix、Windows、Symbian和Pocket PC等。
  3. 可嵌入性:在语言设计之初,Lua就被准确的定位为嵌入式脚本语言,因此Lua的设计者们为Lua提供了与其他编程语言之间的良好交互体验,这特别体现在和C/C++之间的交互上。对于其他语言,如Java和C#,也可以将Lua作为其嵌入式脚本引擎,并在代码中进行直接的交互。
  4. 简单强大:尽管是过程化脚本语言,但由于Lua的设计者们为Lua提供了meta-mechanisms机制,这不仅使Lua具备了一些基本的面向对象特征,如对象和继承,而且仍然保持了过程化语言所具有的语法简单的特征。
  5. 小巧轻便:在最新版本(5.2.0)的Lua中,仅仅包含了大约20000行的C语言代码,编译后的库文件大小约为240K左右,因此这对于很多资源有限的平台有着极强的吸引力。
  6. 免费开源:MIT Licence可以让Lua被免费的用于各种商业程序中。

应用场景

  1. 在很多时候,我们可以将Lua直接嵌入到我们的应用程序中,如游戏、监控服务器等。这样的应用方式对于程序的最终用户而言是完全透明的,但是对于程序本身,其扩展性将会得到极大的增强。
  2. 将Lua视为一种独立的脚本语言,通过它来帮助我们完成一些软件产品的辅助性工具的开发。比如在我们之前的数据分析产品中,我们通过编写Lua脚本,将每个用户不同格式的数据重新格式化为我们的软件平台能够读取的格式,之后再将格式化的后的数据加载到数据库中,或者是写入我们的分析引擎可以识别的数据分析文件中。这其中Lua仅仅用于文件格式的规格化过程,至于此后的操作,都是通过Lua调用我们的C语言导出函数来完成的。
  3. 将Lua应用于应用程序的动态配置部分。比如移动智能设备或嵌入式设备,它们的显示分辨率在很多情况下都是非标准的,如果我们为每一款设备都维护一套相关的配置信息,这无疑会加大我们程序的维护开销,如果我们将这段动态配置逻辑交由Lua脚本完成,那么这对于程序配置的灵活性而言,将会得到很大的提高。甚至可以是这样,运行在移动终端设备上的应用程序,在启动主窗体之前先和服务器建立连接,在服务器确认设备的各种参数后,再将和该设备显示相关的Lua脚本发送给设备客户端,这样客户端在得到Lua脚本之后,就可以立刻执行它以得到最新的动态配置信息。
      在我们编写代码之前,需要做一下准备,就是:确保你输入标点符号时,用的不是中文输入法。

基础知识

第一个 Lua 程序

  几乎所有语言的第一行代码,都是输出hello world,本教程也不意外。
  在Lua中,打印结果只需要使用print这个函数即可。同时,如果需要使用函数,只需要在函数名后加上双括号,同时传入你想传入的值即可。
  所以,我们来执行下面的代码,打印出hello world吧!

print("hello world!")

输出数据

  上一部分,我们知道了,在Lua中,可以使用print函数来打印你想要得到的结果。
并且还知道了,函数是指可以实现某些功能的子程序,可以使用函数名(参数)来执行。
让我们试着输出一些其他东西吧!使用多个print函数,输出自己想输出的数据。

print("测试")
print("aabcdefg")
print("xxxxx","第二个参数","第三个参数")

Lua代码注释

  代码注释就是在代码里,不会运行的部分。注释完全不会被运行。
  这部分是为了在查看代码时,可以更好地立即现有代码含义用的。
  我们可以用–开头,来写一段单行注释
  也可以用–[[开头,]]结尾,写一段多行注释。
  下面是注释的例子:

print("这段代码会运行")
--print("我被注释掉了,所以不会运行")
--[[
    我是多行注释
    不管我写多少行
    都不会影响代码运行
]]

  单行注释
  使用两个减号表示注释的开始,一直延续到行末位置。相当于C语言中的"//"。

--这里是一行注释
print("Hello Lanou")

  多行注释

  使用"–[[“表示注释开始,使用”]]“表示注释结束。这种注释相当于C语言中的”/“和”/"。

--[[这里是第一行注释
这里是第二行注释]]
pring("Hello Lanou")

基础语法

芯片资料

Air101芯片

合宙Air101是一款QFN32 封装,4mm x 4mm 大小的mcu。注意:烧录前请设置波特率为921600。

Air101入门手册(示例程序)
示例程序

GPIO输出(点灯)

开发板所带的三个灯分别为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()
GPIO输入-按键

按键2接了BOOT,也就是PA0,

在这里插入图片描述

UART串口通讯

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编号命名默认功能及扩展功能
0PA0BOOT
1PA1I2C_SCL/ADC0
4PA4I2C_SDA/ADC1
7PA7GPIO/PWM4
16PB0GPIO/PWM0/UART3_TX
17PB1GPIO/PWM1/UART3_RX
18PB2SPI_SCK/PWM2/UART2_TX
19PB3SPI_MISO/PWM3/UART2_RX
20PB4SPI_CS/UART4_TX
21PB5SPI_MOSI/UART4_RX
22PB6UART1_TX
23PB7UART1_RX
24PB8GPIO
25PB9GPIO
26PB10GPIO
27PB11GPIO
35PB19UART0_TX
36PB20UART0_RX

开机时仅配置了BOOT和UART0_TX/RX,其他数字脚均为GPIO脚,状态为输入高阻。

ADC编号(LuatOS)功能
0模块ADC0-PA1
1模块ADC1-PA4
10CPU温度
11内部电压

在这里插入图片描述
在这里插入图片描述在这里插入图片描述

参考网页

  1. 博客园
  2. Lua入门教程
  3. Step By Step(Lua目录)

合宙:

  1. 合宙 Lua社区
  2. 合宙 LuatOS
  3. 合宙 MCU资料
  4. 合宙 air101

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()
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值