原料及工具
正点原子水星开发板一套(含H743核心板)、JLINK仿真器一套、装有Keil5的电脑一台。
开始
主要过程参考文章:
STM32嵌入LUA开发(控制小灯闪耀)
原文是移植到STM32F103,我们使用的H743,大体流程是一样的。
- 使用STM32CubeMX软件配置并生成Keil工程。
- 下载LUA源码,并将所需文件添加到之前创建的Keil工程中。
- 修改源码并编译。
- 在主函数添加LUA初始化、运行脚本的功能。
- 编译、下载。
- 验证。
配置并生成工程
此处参考正点原子《STM32H743 开发指南 (水星版)V1.0 – HAL 库版本》,根据水星板的硬件进行配置H743功能、针脚等。主要用到的硬件有LED、USART1。相应配置内容主要包括Clock、GPIO、SYS等。
配置完成后点击“GENERATE CODE”生成工程。
下载LUA源码,并添加到工程中
- 下载地址我下载的是5.3.5版本,目前已经到5.4.4,可以自己选择需要的版本下载。
- 下载后解压,然后在工程文件夹下新建“Lua”文件夹,把源码中的".c"文件和".h"文件分别放在Lua下新建的“Src”和“Inc”文件夹。
- 使用Keil打开工程,在Projec面板上右击工程–>Add Group,并命名为“LUA”,双击LUA,定位到刚刚新建的“Lua/Src”文件夹,添加“.c”文件,这里可以排除“lua.c”、“luac.c”这2个文件。
- 添加头文件目录“Lua/Inc”。
修改源码
- 修改栈和堆的大小
修改“startup_stm32h743xx.s”文件
Stack_Size EQU 0x00001000 ;0x400
AREA STACK, NOINIT, READWRITE, ALIGN=3
Stack_Mem SPACE Stack_Size
__initial_sp
; <h> Heap Configuration
; <o> Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>
; </h>
Heap_Size EQU 0x00015000 ;0x200
AREA HEAP, NOINIT, READWRITE, ALIGN=3
__heap_base
Heap_Mem SPACE Heap_Size
__heap_limit
- 在main.c添加如下代码
此处参考单片机脚本语言-移植lua到stm32-MDK
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
#include "time.h"
typedef int FILEHANDLE;
#pragma import(__use_no_semihosting_swi)
#pragma import(_main_redirection)
const char __stdin_name[150];
const char __stdout_name[150];
const char __stderr_name[150];
FILEHANDLE _sys_open(const char *name, int openmode)
{
return 0;
}
int _sys_close(FILEHANDLE fh)
{
return 0;
}
int _sys_write(FILEHANDLE fh, const unsigned char *buf, unsigned len, int mode)
{
return 0;
}
int _sys_read(FILEHANDLE fh, unsigned char*buf, unsigned len, int mode)
{
return 0;
}
//检查句柄是否为终端
int _sys_istty(FILEHANDLE fh)
{
return 0;
}
int _sys_seek(FILEHANDLE fh, long pos)
{
return 0;
}
//刷新句柄关联的缓冲区
int _sys_ensure(FILEHANDLE fh)
{
return 0;
}
//返回文件当前长度
long _sys_flen(FILEHANDLE fh)
{
return 0;
}
void _sys_exit(int status)
{
//while(1);
}
int _sys_tmpnam(char *name, int fileno, unsigned maxlength)
{
return 0;
}
//将一个字符写入控制台
void _ttywrch(int ch)
{
}
int remove(const char *filename)
{
return 0;
}
char *_sys_command_string(char *cmd, int len)
{
return NULL;
}
time_t time(time_t * time)
{
return 0;
}
//重定义fputc函数
int fputc(int ch, FILE *f)
{
while((USART1->ISR&0X40)==0);//循环发送,直到发送完毕
USART1->TDR=(u8)ch;
return ch;
}
这一步非常重要,作用是重写一些底层的函数,如果不重写会导致运行时一直卡在汇编的BEAB BKPT 0xAB位置。
- 添加lua功能函数实现,包括LED0的亮、灭,延时函数,代码如下:
static int lua_led_on(lua_State *L)
{
LED0(1);
printf("LED0->1\r\n");
return 1;
}
static int lua_led_off(lua_State *L)
{
LED0(0);
printf("LED0->0\r\n");
return 1;
}
static int lua_delay(lua_State *L)
{
int num;
num= lua_tointeger(L, 1);
delay_ms(num);
return 1;
}
- 注册lua功能函数,并初始化一个简单的脚本:
static const struct luaL_Reg mylib[]=
{
{"led_on",lua_led_on},
{"led_off",lua_led_off},
{"delay",lua_delay},
{NULL,NULL}
};
const char LUA_SCRIPT_Test[] =
" \
off = 500 \
on = 500 \
led_on() \
delay(off) \
led_off() \
delay(on) \
";
修改主函数
//lua初始化部分
lua_State *L;
L=luaL_newstate(); //创建LUA状态机
luaopen_base(L);
luaL_setfuncs(L,mylib,0);
while (1)
{
luaL_dostring(L,LUA_SCRIPT_Test); //运行LUA脚本
}
编译、下载
运行、验证
如图