lua移植到STM32F4全过程
基于之前了解到的Lua脚本开发功能,尝试过多次都没有很认真的做打底。之前的尝试都没能很好的应用到自己的工程里。
elua东西太多并且是在linux下编译的,我很不适应,当然liunx涉及的不深。
本次移植的条件及目标:
本次的目标是能精简移植最纯洁版的lua框架,能够实现多文件(.lua)的联合调用 require / dofile。
开发工具:Keil V5.29
硬件平台:STM32F4探索者开发版
移植下来发现lua和平台真的关系不大,就内存上面我还没搞懂他需要多少合适。
单纯加入了一个测试lib,具体编译空间MAP如下:
Total RO Size (Code + RO Data) 157208 ( 153.52kB)
Total RW Size (RW Data + ZI Data) 36904 ( 36.04kB)
Total ROM Size (Code + RO Data + RW Data) 157256 ( 153.57kB)
工作内容有:
1、lua库移植
2、FatFs文件系统的移植
3、多文件.lua的相互调用测试测试
这次捣鼓花了3天的时间,对lua语言和和lua库的函数库有初步了解。整个过程就不是很顺利,几经自闭。
程序源码会附件提供大家学习,以免大家少走弯路。欢迎下载。
整体参考博客,在此感谢给了很多的帮助
https://blog.csdn.net/zlm_space/article/details/50379980
工程整体能容:
移植步骤:
到gethub下载lua源码,当前使用版本 This is Lua 5.4.0, released on 18 Jun 2020.
解压并添加到自己的工程里,除lua.c和luac.c外全部添加。
添加后编译会出现几个未定义的函数,可以找到并实现一个空函数,实际用到的时候再补充。
不用文件的话不出意外都能跑起来。
大概描述一下几个地方,方便以后快速上手。
1、添加预编译LUA_32BITS
2、注意此处不打勾
文件系统重定向
3、这里坑我比较久
#pragma import(__use_no_semihosting)
不加入这一句会出现一个很郁闷的问题。程序进入DEBUG模式时能正常运行,真机运行就崩溃起不来。
4、lua搜索路径
根据自己挂载的路径修改lua搜索路径,主要提供 require查找文件。dofile默认可以查找到当前路径,可以不需要设置该路径。reuqire不行,需要指定。
5、在此处添加自己的驱动
6、文件系统配置
文件系统我使用的是系统RAM,分配了10k空间。自己可随意调整为内部FLASH或者存储卡等存储介质。
#define FF_MIN_SS 1024 // 扇区大小
7、注意屏蔽掉fputc的实现
int fputc(int ch, FILE *f)该函数就不需要在外部实现,会造成发送混乱。重定向的功能已经在stdio.c里面实现了。
8、这几个实现文件系统的必要文件
收尾
至此,没有什么要特别注意的了。附上main.c文件,是不是你需要的东西,自行评估。
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "beep.h"
#include "key.h"
#include "string.h"
//ALIENTEK 探索者STM32F407开发板 实验4
//串口通信实验 -库函数版本
//技术支持:www.openedv.com
//淘宝店铺:http://eboard.taobao.com
//广州市星翼电子科技有限公司
//作者:正点原子 @ALIENTEK
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
#include <ff.h>
static FATFS fatfs;
//文件系统挂
static int file_system_init(void)
{
char buffer[FF_MIN_SS];
FRESULT fr;
fr = f_mount(&fatfs, "0:/", 1); // 挂载磁盘
if (fr == FR_OK)
{
printf("f_mount OK!\n");
return 1;
}
if (fr == FR_NO_FILESYSTEM)
{
// 若磁盘没有格式化, 则格式化磁盘
fr = f_mkfs("0:/", FM_FAT, 0, buffer, sizeof(buffer));
if (fr == FR_OK)
{
printf("Disk is formatted!\n");
return 1;
}
else
{
printf("Disk cannot be formatted! fr=%d\n", fr);
return 0;
}
}
else
{
printf("f_mount error! fr=%d\n", fr);
return 0;
}
}
const char LUA_SCRIPT_HELLO[] = " \
print('this is hello.lua')\
gloabl_param = 'this is gloabl param' \
function say_hello()\
print('this is function:say hello')\
end \
";
const char LUA_SCRIPT_GLOBAL[] = " \
print('this is main.lua') \
off = 500 \
on = 500 \
require('module')\
print(module.constant)\
print('into while')\
while true do \
led.led_on() \
led.delay(off) \
led.led_off() \
led.delay(on) \
end";
const char LUA_SCRIPT_GLOBAL_STR[] = " \
print('this is main.lua') \
off = 500 \
on = 500 \
print('into while')\
while true do \
led.led_on() \
led.delay(off) \
led.led_off() \
led.delay(on) \
end";
const char LUA_SCRIPT_MODULE[] = " \
module ={} \
module.constant='这是一个模块常量'\
return module";
void file_write_string(const char *filename,const char *strdata)
{
FILE *fp = NULL;
fp = fopen(filename, "w");
if(fp)
{
fputs(strdata, fp);
fclose(fp);
printf("file %s create success\r\n",filename);
}
else
{
printf("file %s create err\r\n",filename);
}
}
static void file_create_test(void)
{
file_write_string("main.lua",LUA_SCRIPT_GLOBAL);
file_write_string("hello.lua",LUA_SCRIPT_HELLO);
file_write_string("module.lua",LUA_SCRIPT_MODULE);
}
FRESULT scan_files(char *path)
{
FRESULT res; //定义结果对象
DIR dir; //定义目录对象
UINT i; //定义变量
static FILINFO fno; //定义静态文件信息结构对象
res = f_opendir(&dir, path); //打开目录,返回状态 和 目录对象的指针
char pathBuff[256]; //定义路径数组
if (res == FR_OK) //打开成功
{
for (;;) //遍历
{
res = f_readdir(&dir, &fno); //读取目录,返回状态 和 文件信息的指针
if (res != FR_OK || fno.fname[0] == 0)
break; //若打开失败 或 到结尾,则退出
if (fno.fattrib & AM_DIR) //是目录
{
i = strlen(path); //获取原目录长度
sprintf(&path[i], "/%s", fno.fname); //将新目录添加在原目录后面
printf("是目录::%s\r\n", path);
res = scan_files(path); //将新目录进行递归调用
if (res != FR_OK)
break; //打开失败则退出
path[i] = 0;
}
else
{
printf("是文件:%s/%s\r\n", path, fno.fname); //是文件
//strcpy(pathBuff, fno.fname); //将文件目录存储起来
}
}
}
else
{
printf("失败 - %s", &res); //打开失败
}
f_closedir(&dir); //关闭目录
return res; //返回状态
}
int main(void)
{
uart_init(115200);
delay_init(168); //延时初始化
LED_Init(); //初始化与LED连接的硬件接口
file_system_init();//加载文件系统
file_create_test();//创建lua脚本文件
scan_files("0:");
lua_State *L = luaL_newstate();
if (L == NULL)
{
printf("LUA ERR\r\n");
}
else
{
printf("Lua init ok\r\n");
luaL_openlibs(L);//加载Lua库
//重复写文件测试
file_write_string("autorun.lua","print('autorun file <1> 2')");
luaL_dofile(L,"autorun.lua");
file_write_string("autorun.lua","print('autorun file <2> s ')");
luaL_dofile(L,"autorun.lua");
luaL_dofile(L, "main.lua");
}
printf("exit\r\n");
}
运行结果:
led灯正产闪烁
其他:
启动文件再执行 __main 和 mian()函数之间会执行 __rt_entry函数,还函数会加载和执行
_sys_open 函数,配置STDIN STDOUT STDERR等相关初始化工作。
上一篇: 普洱茶要放冰箱吗?你不知道的都在这里