将Lua解释器移植到STM32
2016-02-25 19:31
716 查看
这是我第一次写博客,当然在这之前已经学了会儿单片机和C语言,这两天突然有一个新想法:把Lua移植到STM32上去,网上搜了一下,好像非常简单,所以我就立马开始尝试。到Lua官网下载了Lua
5.3.2的代码,先是用GCC编译了一个Lua解释器试试手,熟悉下Lua语法,然后又在VS2015下建了工程(个人比较喜欢用VS的界面。。。),看看Lua源码的大概组织编排,折腾了一会儿后我就琢磨着移植到STM32了。
我用的KEIL 5.17,开发板是STM32F429I Discovery,刚好之前写了一个GUI库,就直接拿这个做显示了。移植的过程没有想象中的顺利,开始我按网上说的不使用MicroLib,编译是过了,但是单片机上根本不运行(实际上是缺少一些C标准库函数),折腾了大概一天才把这事解决。废话不多说,就直接上移植方法吧。
首先是吧Lua源码解压会得到一个src文件夹,把src下的源码添加到STM32的工程里,设置好包含路径,注意lua.c
和 luac.c 这两个文件是不包含的(它们包含PC上Lua解释器和编译器的main函数)。然后我写了一个简单的函数来实现解释器:
我还没有做文件方面的功能,直接把Lua脚本保存到字符串lua_test[]里。Lua脚本的运行就靠lua_main()函数来完成。由于单片机的IO系统不同于PC,我们需要重新实现print函数的底层,Lua的print函数的C语言实现部分是lbaselib.c文件的luaB_print()函数,我把底层的输出打印到了一个字符串LuaBuffer[](比较简单嘛
),代码如下:
此外我还修改了Lua内存管理的底层函数(在lauxlib.c中):
myfree()和myrealloc()函数是从正点原子的动态内存分配程序里来的,l_alloc()函数也可以不改,在使用MicroLib的时候是可以使用free()和realloc()函数的,这时就得在启动文件里把堆(Heap_Size)设置的足够大,我试过0x00008000(32KB)是没问题的,其实要不了这么多。建议把栈设置的大一点(1KB足够)。
到这里应该就可以编译了,下载到板子里会发现不能运行,程序根本没有进main()函数,联想起以前的一次经历知道这是因为Lua源码里调用了一些C标准库的输入输出(例如printf())函数导致的——STM32平台是不提供这些函数的,一开始我尝试修改源码,把system(),fwrite(),free()等函数统统改掉,无奈半天过后还是不能运行,然后我终于缴械,把MicroLib的勾打上了,如下图:
编译之后报错说time(), exit(), system()这三个标准库函数没有定义,这个好说,直接写三个不就完了。。。
这段Lua源码也贴出来:
最后说下题外话,其实移植脚本语言解释器并非我一时兴起,很久前就想做了,只是移植没找到合适的语言,以前用TI的nspire计算器听说过lua语言,lua虽然没去研究,却也听说过了lua的效率,后来我也做了些东西了,C语言有了点积累,造轮子的冲动慢慢在心里萌芽,去年暑假我开始写一个GUI,不过后来似乎有在抄uC/GUI之嫌了
,这两天无意间想起lua,于是我就花了点时间移植到了STM32,移植成功那一刻的心情当然是非常非常激动的。接下来我要接着完善我的GUI,Lua暂时就不折腾了,等到一切做妥当我可能会用STM32做一个可编程的设备(就像编程计算器),这因该会相当好玩。现在记下移植过程也方便以后用。第一次写博客比较啰嗦,还请看官见谅哈
。
卧槽,第一次写博客保存时还断网。。。人品真是爆了
!
5.3.2的代码,先是用GCC编译了一个Lua解释器试试手,熟悉下Lua语法,然后又在VS2015下建了工程(个人比较喜欢用VS的界面。。。),看看Lua源码的大概组织编排,折腾了一会儿后我就琢磨着移植到STM32了。
我用的KEIL 5.17,开发板是STM32F429I Discovery,刚好之前写了一个GUI库,就直接拿这个做显示了。移植的过程没有想象中的顺利,开始我按网上说的不使用MicroLib,编译是过了,但是单片机上根本不运行(实际上是缺少一些C标准库函数),折腾了大概一天才把这事解决。废话不多说,就直接上移植方法吧。
首先是吧Lua源码解压会得到一个src文件夹,把src下的源码添加到STM32的工程里,设置好包含路径,注意lua.c
和 luac.c 这两个文件是不包含的(它们包含PC上Lua解释器和编译器的main函数)。然后我写了一个简单的函数来实现解释器:
/* 测试的Lua代码字符串 */ const char lua_test[] = { "print(\"Hello,I am lua!\\n--this is newline printf\")\n" "function foo()\n" " local i = 0\n" " local sum = 1\n" " while i <= 10 do\n" " sum = sum * 2\n" " i = i + 1\n" " end\n" "return sum\n" "end\n" "print(\"sum =\", foo())\n" "print(\"and sum = 2^11 =\", 2 ^ 11)\n" "print(\"exp(200) =\", math.exp(200))\n" }; /* 运行Lua */ void lua_main(void) { lua_State *L; L = luaL_newstate(); /* 建立Lua运行环境 */ luaL_openlibs(L); luaopen_base(L); luaL_dostring(L, lua_test); /* 运行Lua脚本 */ lua_close(L); }
我还没有做文件方面的功能,直接把Lua脚本保存到字符串lua_test[]里。Lua脚本的运行就靠lua_main()函数来完成。由于单片机的IO系统不同于PC,我们需要重新实现print函数的底层,Lua的print函数的C语言实现部分是lbaselib.c文件的luaB_print()函数,我把底层的输出打印到了一个字符串LuaBuffer[](比较简单嘛
),代码如下:
char LuaBuffer[500] = ""; /* 输出缓存数组 */ static int luaB_print (lua_State *L) { int n = lua_gettop(L); /* number of arguments */ int i; char *Str = LuaBuffer + strlen(LuaBuffer); /* LuaBuffer直接接着上次的打印 */ lua_getglobal(L, "tostring"); for (i=1; i<=n; i++) { const char *s; size_t l; lua_pushvalue(L, -1); /* function to be called */ lua_pushvalue(L, i); /* value to print */ lua_call(L, 1, 1); s = lua_tolstring(L, -1, &l); /* get result */ if (s == NULL) return luaL_error(L, "'tostring' must return a string to 'print'"); if (i>1) { /* 这个是连续输出元素之间的空格,我用的1个空格 */ sprintf(Str, " "); Str += 1; /* 一个空格 */ } /* 我自己定义的输出(输出到字符串) */ sprintf(Str, "%s", s); Str += l; /* 跳过字符串的长度 */ lua_pop(L, 1); /* pop result */ } sprintf(Str, "\n"); /* 输出一个换行符 */ return 0; }
此外我还修改了Lua内存管理的底层函数(在lauxlib.c中):
/* 修改了free()和realloc()函数 */ static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) { (void)ud; (void)osize; /* not used */ if (nsize == 0) { myfree(SDRAMEX, ptr); /* 修改 */ return NULL; } else return myrealloc(SDRAMEX, ptr, nsize); /* 修改 */ }
myfree()和myrealloc()函数是从正点原子的动态内存分配程序里来的,l_alloc()函数也可以不改,在使用MicroLib的时候是可以使用free()和realloc()函数的,这时就得在启动文件里把堆(Heap_Size)设置的足够大,我试过0x00008000(32KB)是没问题的,其实要不了这么多。建议把栈设置的大一点(1KB足够)。
到这里应该就可以编译了,下载到板子里会发现不能运行,程序根本没有进main()函数,联想起以前的一次经历知道这是因为Lua源码里调用了一些C标准库的输入输出(例如printf())函数导致的——STM32平台是不提供这些函数的,一开始我尝试修改源码,把system(),fwrite(),free()等函数统统改掉,无奈半天过后还是不能运行,然后我终于缴械,把MicroLib的勾打上了,如下图:
编译之后报错说time(), exit(), system()这三个标准库函数没有定义,这个好说,直接写三个不就完了。。。
/* 定义MicroLib没有的函数 */ time_t time(time_t * time) { return 0; } void exit(int status) { } int system(const char * string) { return 0; }好,现在终于可以运行了,拍张照片,顺便演示一下我的GUI:
这段Lua源码也贴出来:
print("Hello,I am lua!\n--this is newline printf") function foo() local i = 0 local sum = 1 while i <= 10 do sum = sum * 2 i = i + 1 end return sum end print("sum =", foo()) print("and sum = 2^11 =", 2 ^ 11) print("exp(200) =", math.exp(200))照片上的运行结果跟PC上是一致的。
最后说下题外话,其实移植脚本语言解释器并非我一时兴起,很久前就想做了,只是移植没找到合适的语言,以前用TI的nspire计算器听说过lua语言,lua虽然没去研究,却也听说过了lua的效率,后来我也做了些东西了,C语言有了点积累,造轮子的冲动慢慢在心里萌芽,去年暑假我开始写一个GUI,不过后来似乎有在抄uC/GUI之嫌了
,这两天无意间想起lua,于是我就花了点时间移植到了STM32,移植成功那一刻的心情当然是非常非常激动的。接下来我要接着完善我的GUI,Lua暂时就不折腾了,等到一切做妥当我可能会用STM32做一个可编程的设备(就像编程计算器),这因该会相当好玩。现在记下移植过程也方便以后用。第一次写博客比较啰嗦,还请看官见谅哈
。
卧槽,第一次写博客保存时还断网。。。人品真是爆了
!
相关文章推荐
- protobuf-gen-lua 不能支持int64 的解决方法 !!
- lua获取当时时间
- Lua_热更新
- lua 取一个数字的整数部分
- Lua 5.2 视频教程
- Evaluation
- 模型评价和优化 Real-World Machine Learning: Model Evaluation and Optimization
- Lua Userdata
- lua 插入排序和谢尔排序
- Lua 5.1 常用时间函数以及一个字符串转时间的方法
- lua table 练习
- Lua 编写快速排序算法
- angluar根据链接的url参数的不同实现显示与隐藏
- Lua中的require(二)
- 43.Evaluate the following CREATE SEQUENCE statement:
- C++中的Lua 常用函数
- lua中的require机制
- lua 冒泡排序和选择排序
- LuaNote
- 39.Evaluate the following command:CREATE TABLE employees(employee_id NUMBER(2) PRIMARY KEY