32单片机移植LUA
前言:仅介绍Lua的使用,而不介绍内部运行原理,旨在快速上手移植并使用Lua。
移植
以Lua5.3.5为例,移植到Keil-MDK工程:
使用芯片:GD32F4(STM32同理)
操作系统:FreeRtos
Lua源码下载地址:https://download.youkuaiyun.com/download/SXD_SJJ/88273800
解压后文件夹下有文件:
我们打开src文件夹,这是我们需要的文件
将lua-5.3.5整个文件夹复制到我们的工程里,然后打开我们的keil工程,将lua-5.3.5/src文件夹下的c文件全部添加到我们的工程里:
使用
配置
我们明确几个关键的Lua的配置:
在luaconf.h:
此处配置Lua的最大堆栈大小,用来限制Lua可使用的堆栈大小
lua.h:
当然这些数值的单位并不是字节Byte,而是Lua堆栈的槽位数量,怎么理解槽位呢。我们可以认为是一个队列或者C++里的list,每一个槽位可以存放一个值,这个值可以是一个整形数字,可以是一个字符串甚至是一个列表。具体的内部的原理我们可以再深究,这里不再细说,通常情况下我们无需去配置这些参数,保持默认即可。
而我们需要的配置就是我们分配的堆空间,即在*.s的启动文件内分配的堆的大小,但是堆要分配多大的内存呢?
这个我们可以通过查看map文件来获取堆的起始地址,然后顺着堆的增长方向debug调试来确认堆到底使用了多少,当然,这些都是你已经运行了你的Lua的脚本文件的前提下,否则是看不到堆被使用的,而且因为脚本文件内的脚本是会被改动的,即堆的使用情况也是会变化的,所以我们需要预留足够的堆来保证Lua脚本的正确运行。
如果有小伙伴不明白MDK怎么查看堆的使用情况,可以参考博文:待补充
代码编写
那么前文提到Lua脚本,那这个脚本是什么呢?
我们可以在Windows下编写一个写了shutdown的test.bat脚本,那么运行这个test.bat,电脑就会关机,那么Windows是怎么认为这个shutdown就是关机呢,那肯定是Windows提供给了我们一个指令表或者函数表,告诉我们,这个shutdown对于Windows来说就是关机。
这个概念很重要,因为我们要在代码里去注册一个这种表,来提供给用户,让用户在编写脚本时去使用我们提供的表来写脚本,当然,对于Lua来说,我们提供的全是函数表。
那么现在开始,我们来编写底层的Lua注册代码
static int do_file_script(void)
{
L = luaL_newstate();
luaL_openlibs(L);
lua_register(L, "led_green", lua_green);
lua_register(L, "led_green_toggle", lua_led_green_toggle);
lua_sethook(L, &function_hook, LUA_MASKCALL, 0);
uint8_t* lp = lua_get_file();
int res = luaL_dostring(L, ( const char* )lp);
if (res) {
int type = lua_type(L, -1);
if (LUA_TSTRING == type) {
const char* str = lua_tostring(L, -1);
printf("%s", str);
}
}
lua_close(L);
return 0;
}
同样的我们用一个点灯实例来演示,luaL_newstate函数来为我们新建虚拟机(我们的脚本需要在这个虚拟机内运行),当然,他和文件系统的打开和关闭同理,新建一个虚拟机,在不用时或使用完毕后需要关闭这个虚拟机防止一致占用内存,我们可以使用lua_close函数关闭。
luaL_openlibs:我们需要为这个虚拟机去提供一些Lua的库。
lua_register:这个函数就很有意思了,这个就是我们注册的表,从上述代码来看,我们在这个表内注册了两个函数,一个是lua_green,一个是lua_led_green_toggle,这两个函数是我们底层实现的函数,而led_green和led_green_toggle就是我们提供给Lua脚本的函数表的项,脚本内调用led_green,底层就会执行lua_green函数。
lua_sethook:这个我们可以不必太多关心,这个大多是是调试调用,有兴趣的可以查查他的使用和原理
lua_get_file:这个是我自己定义的,他返回的是Lua脚本的存储地址,Lua脚本是在PC上编写的,但是下载到单片机内我们需要在单片机内找个地方(一段flash)把他存起来,那也就有了脚本地址。
luaL_dostring:这里就开始运行Lua脚本了
那么我们再来看看脚本怎么写,有意思的事Lua本身提供了一些关键词给我们使用,比如:
function:声明并定义函数
local:声明并定义变量
当然还有if else while 等等的关键词,有兴趣也可以问问度娘。
我们写一个简单的脚本,让灯闪起来:
local time=500
function led_green_flash() led_green_toggle(time) end
function main()
led_green_flash()
while true do
end
end
main()
我们在脚本内定义了一个变量time和函数led_green_flash,并在led_green_flash函数内调用了led_green_toggle,
那么我们把脚本下载进去脚本运行起来后,就会调用我们底层的lua_led_green_toggle函数。
那么会有刚接触的同学会问我该怎么下载Lua脚本文件到单片机内呢?
有很多通用的文件下载协议,例如YMODEM协议,也可以自己制定一些文件下载的协议,根本上来说文件本身也可以读取分解成一个大数组,而我们就是将这个大数组发送到单片机,这样理解后自己制定下载协议就很简单了。
当然我们也是自己定义的协议,编写了一个QT的上位机来下载Lua脚本,如果不想这样做的话网上有很多YMODEM的文件下载软件也可以的