LH
发布于 2018-05-02 / 670 阅读 / 0 评论 / 0 点赞

Nodemcu创建自定义C模块

填坑

上一年学校开了门IOT的课程,看了下ESP8266相关的信息,当时候由于赶时间,就把里面的固件刷成了MicroPython,然后在里面随便调用了几个传感器的库,然后定时上报给服务器就拿去答辩了

然后最近去买电子原件顺手买了两片来玩,顺便把Lua简单语法过了一遍,填上了Lua的坑。ESP8266的社区生态挺完善的,很多的传感器直接调库就好了,但是有一些传感器需要自己写驱动来控制和读取。

又一坑

我在写驱动GP2Y1010AU0F的时候,需要产生一个0.32ms的高电平,但是我试了一下Nodemcu最短只能延时1ms……所以需要自己编写C语言库来实现更加短的延时和其他更底层的控制

编写C语言库:

本文基于ESP8266芯片的nodemcu-firmware

头文件

在源码中添加如下头文件:

#include "lualib.h"
#include "lauxlib.h" //导入lua相关数据类型
#include "platform.h" //导入Nodemcu的gpio相关操作(uart,i2c,spi,pwd,adc...)
#include "module.h" //用于导出C语言函数
#include "c_types.h"
#include "c_string.h" //移植到ESP8266的C语言标准库

自定义函数

Lua 使用一个 虚拟栈 来和 C 互传值。 栈上的的每个元素都是一个 Lua 值 (nil,数字,字符串,等等)。
自定义的函数返回值必须为整型,并且返回的数字等于函数返回到Lua的返回值的个数
自定义函数参数列表只需要定义一个lua_State *L

The L is a Lua State and you can read about it in the Extending your Application,
Calling C from Lua, and Manual

int example_function(lua_State *L)
{
    //从栈中获取函数参数
    double a=luaL_checknumber(L,1); //从栈中取出一个double
    int b=(int)luaL_checkinteger(L,2);
    const char *c=luaL_checklstring(L,3,NULL); //从栈中取出一个字符串

    os_printf("From C Library:%s\n",c); //esp8266_non_os_sdk_api
    char rc[100];
    int index=0;
    for(int i=c_strlen(c)-1;i>=0;i--)
        rc[index++]=c[i];
    rc[index]='\0';

    //压栈传返回值到Lua
    lua_pushnumber(L,(a+b)/(a-b)); //往栈中压入一个浮点型数
    lua_pushstring(L,rc); //往栈中压入一个字符串

    return 2; //返回了一个浮点数,一个字符串,所以应该返回2
}

导出函数

导出函数根据官方样例的格式,把自定义的函数导出以便Lua调用:

const LUA_REG_TYPE example_map[]=
{
    {LSTRKEY("calc"),LFUNCVAL(example_function)},
    {LNILKEY,LNILVAL}
};
NODEMCU_MODULE(EXAMPLE,"example",example_map,NULL);

整合C模块到Nodemcu

app/include/user_modules.h中插入:#define LUA_USE_MODULES_EXAMPLE

编译&烧写

$ make
$ sudo make flash4m //根据不同ESP8266版本而定

测试

{% asset_img 1.png %}


评论