elua解析器开源文档第四章:4.1、添加OneWire库到elua模块中

目录

点击这里查看所有博文

第四章、为eLua添加自定义模块

  第四章内容迟迟没有迎来更新,小伙伴们估计都等不及了。距离上次elua文档正式发布也过了将近半个月的时间。当时在文末只留下了几个大字:未完待续。。。。你说看着正上瘾,刚准备动手实操下,突然就没了。

  我要是说结束了吧,各位也许还不会那么期待,可能只会觉得不够完美。这时候我偏偏来个未完待续,并且还写了第四章的标题为eLua添加自定义模块,这让人一看就知道后面还有干货,并且还是各位所期待的实操环节。

在这里插入图片描述

  正好前几天在csdk上发布了一个OneWire驱动库,这个库足够简单,就几个函数。今天正好就可以拿来练练手。

  进入正文之前我们先回顾下前三章讲了什么内容。前三章主要是讲了lua内核结构以及一些功能模块。并且举了两个现有的模块添加的例子,分别是adcjson,这些功能在现在的luat版本中都是已经存在的了,举例只是为了说明它们之间是什么样的关系。当时并没有讲编译的事情,对编译不熟悉的同学们,如果去自己尝试添加elua模块了,只看第三章的内容还真不一定能搞定。

  那么正好今天有点时间,我们就一起来看一下怎么自己注册一个自定义模块到elua中。

4.1、添加OneWire库到elua模块中

4.1.1、开始前准备

  正式开始前需要把OneWire软件包复制到elua下面的lib模块中。

在这里插入图片描述

在这里插入图片描述

  这时候有人会问了,既然OneWire是硬件模块,那就要和硬件打交道。为什么要放到lib目录下,第三章不是说了吗lib目录存放的是纯软驱动,不依赖外界环境吗。

  虽然OneWire是需要驱动硬件的,理论上讲就需要抽象层和外界硬件驱动库对接。但是又由于库函数不能满足使用的需求,代码中使用的是直接操作寄存器的方式控制的gpio,直接操作的内存地址。那就又不依赖外界代码库了了,看起来就像是一个纯软代码,那就又没必要抽象了。

  将elua/lib/OneWire目录下cmake文件修改成下面的代码:


set(target lua_OneWire)
add_library(${target} STATIC)
set_target_properties(${target} PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${out_lib_dir})



target_include_directories(${target} PUBLIC ./)
target_include_directories(${target} PUBLIC dht11)
target_include_directories(${target} PUBLIC ./ds18b20)
target_include_directories(${target} PRIVATE  ${PROJECT_SOURCE_DIR}/components/openat_inc)


target_sources(${target} PUBLIC
    ./OneWire.c
    dht11/dht11.c
    ds18b20/ds18b20.c
)


  将elua/lib目录下cmake文件修改成下面的代码:


add_subdirectory_if_exist(crypto)
add_subdirectory_if_exist(iconv)
add_subdirectory_if_exist(json)
add_subdirectory_if_exist(lzma)
add_subdirectory_if_exist(pbc)
add_subdirectory_if_exist(zlib)
add_subdirectory_if_exist(lpng)
add_subdirectory_if_exist(qr_encode)
add_subdirectory_if_exist(OneWire)#就添加了这么一行

4.1.2、注册函数

  打开elua/modules/include/auxmods.h,在文件中找个位置添加这么一段,增加声明OneWire模块的模块名和注册函数。

#define AUXLIB_OneWire    "OneWire"
LUALIB_API int ( luaopen_OneWire )( lua_State * L );

  别乱加哈。我建议和我一样,加在这个地方。

在这里插入图片描述

  打开elua/platform/openat/include/platform_conf.h,在文件中添加这么一段,完成将模块名和初始化函数注册到lua内核中。

    _ROM( AUXLIB_OneWire, luaopen_OneWire, OneWire_map) 

  这个就不能随便加了,大概加在这个地方。注意了要在上一条语句的结尾加上\

在这里插入图片描述

4.1.3、编写实现函数

  4.1.2完成后,那就需要实现一下lua代码与c对接的部分了。在elua/modules/src目录下新建luaOneWire.c文件。

  编写OneWire注册函数。注册了OneWire基础函数:微秒延时函数、切换输入输出函数、读取和设置函数。还有应用层函数读取ds18b20函数以及读取dht11函数。

#include "lrodefs.h"
const LUA_REG_TYPE OneWire_map[] = {
    {LSTRKEY("Delay1us"), LFUNCVAL(Delay1us)},
    {LSTRKEY("IOIN"), LFUNCVAL(IOIN)},
    {LSTRKEY("IOOUT"), LFUNCVAL(IOOUT)},
    {LSTRKEY("DQIN"), LFUNCVAL(DQIN)},
    {LSTRKEY("DQOUT"), LFUNCVAL(DQOUT)},
    {LSTRKEY("GetDS18B20Data"), LFUNCVAL(GetDS18B20Data)},
    {LSTRKEY("GetDHT11Data"), LFUNCVAL(GetDHT11Data)},
    {LNILKEY, LNILVAL}};

LUALIB_API int luaopen_OneWire(lua_State *L)
{
    luaL_register(L, AUXLIB_OneWire, OneWire_map);
    return 1;
}

  基础函数的部分实现(除了微秒延时),这个直接调用C库就可以,啥都不用管。就只有四个函数,编写的流程就是读取传入参数--->调用c库运算--->返回运算结果。

static int IOIN(lua_State *L)
{
    uint8 pin = luaL_checkinteger(L, 1);
    lua_pushinteger(L, OneWire_IO_IN(pin));
    return 1;
}

static int IOOUT(lua_State *L)
{
    uint8 pin = luaL_checkinteger(L, 1);
    OneWire_IO_OUT(pin);
    lua_pushinteger(L, 1);
    return 1;
}

static int DQOUT(lua_State *L)
{
    uint8 pin = luaL_checkinteger(L, 1);
    uint8 level = luaL_checkinteger(L, 2);
    OneWire_DQ_OUT(pin, level);
    lua_pushinteger(L, 1);
    return 1;
}

static int DQIN(lua_State *L)
{
    uint8 pin = luaL_checkinteger(L, 1);
    lua_pushinteger(L, OneWire_DQ_IN(pin));
    return 1;
}

  基础函数的微秒延时函数,不能直接使用OneWire库中现有的c库代码。现有的c库代码,延时是很精准的,但是lua调用时会存在一个翻译的过程,我大概测试了下,翻译一条语句到执行c函数大约需要4us的时间。所以需要在现有的c库基础上另外重新实现做减法运算,减掉翻译的时间。lua调用的时候由于单语句翻译就需要4us,这就导致5us以下的延时不可能实现。开放给上层使用只能使用5us以上的延时。

#pragma GCC push_options
#pragma GCC optimize("O0")
static int Delay1us(lua_State *L)
{
    uint32 num = luaL_checkinteger(L, 1);
    if (num >= 5 && num < 20)
    {
        for (volatile int i = 60 * num - 70 * 4; i > 0; i--)
            ;
    }
    else if (num >= 20 && num < 100)
    {
        for (volatile int i = 60 * num - 90 * 4; i > 0; i--)
            ;
    }
    else if (num >= 100)
    {
        for (volatile int i = 63 * num - 90 * 4; i > 0; i--)
            ;
    }
    lua_pushinteger(L, 1);
    return 1;
}
#pragma GCC pop_options

  编写剩下的应用层代码,这个也需要做出小小的调整,我们需要根据返回的结果给上层推送不同的消息。不建议直接使用c库代码。

static int GetDS18B20Data(lua_State *L)
{
    uint8 pin = luaL_checkinteger(L, 1);
    int TempNum = 0;
    int data1 = 0, data2 = 0;
    char str1[10] = {0};
    char str2[10] = {0};
    char TempStr[20] = {0};
    uint8 var = 0;
    var = DS18B20_GetTemp_Num(pin, &TempNum);
    switch (var)
    {
    case 0:
        data1 = TempNum / 10000;
        data2 = TempNum % 10000;
        itoa(data1, str1, 10);
        itoa(data2, str2, 10);
        sprintf(TempStr, "%s.%s C", str1, str2);
        lua_pushinteger(L, TempNum);
        lua_pushlstring(L, TempStr, strlen(TempStr) + 1);
        break;
    case 1:
        lua_pushinteger(L, 0xffff);
        lua_pushlstring(L, "[OneWire]TempStr=NULL", sizeof("[OneWire]TempStr=NULL"));
        break;
    case 2:
        lua_pushinteger(L, 0xffff);
        lua_pushlstring(L, "[OneWire]The pin passed in is not in the allowed range", sizeof("[OneWire]The pin passed in is not in the allowed range"));
        break;
    case 3:
        lua_pushinteger(L, 0xffff);
        lua_pushlstring(L, "[OneWire]DS18B20 was not detected", sizeof("[OneWire]DS18B20 was not detected"));
        break;
    }

    return 2;
}

static int GetDHT11Data(lua_State *L)
{
    uint8 pin = luaL_checkinteger(L, 1);

    uint8 HumNum = 0, TemNum = 0;
    char str1[10] = {0};
    char str2[10] = {0};
    char HumStr[20] = {0};
    char TemStr[20] = {0};
    uint8 var = 0;
    var = DHT11_GetData_Num(pin, &HumNum, &TemNum);
    switch (var)
    {
    case 0:
        itoa(HumNum, str1, 10);
        itoa(TemNum, str2, 10);
        char len = sprintf(HumStr, "%s%% RH", str1);
        HumStr[(int)len] = '\0';
        len = sprintf(TemStr, "%s C", str2);
        TemStr[(int)len] = '\0';
        lua_pushinteger(L, HumNum);
        lua_pushlstring(L, HumStr, strlen(HumStr) + 1);
        lua_pushinteger(L, TemNum);
        lua_pushlstring(L, TemStr, strlen(TemStr) + 1);
        break;
    case 1:
        lua_pushinteger(L, 0xffff);
        lua_pushlstring(L, "[OneWire]HumStr == NULL || TemStr == NULL", sizeof("[OneWire]HumStr == NULL || TemStr == NULL"));
        return 2;
    case 2:
        lua_pushinteger(L, 0xffff);
        lua_pushlstring(L, "[OneWire]The pin passed in is not in the allowed range", sizeof("[OneWire]The pin passed in is not in the allowed range"));
        return 2;
    case 3:
        lua_pushinteger(L, 0xffff);
        lua_pushlstring(L, "[OneWire]DHT11 was not detected", sizeof("[OneWire]DHT11 was not detected"));
        return 2;
    case 4:
        lua_pushinteger(L, 0xffff);
        lua_pushlstring(L, "[OneWire]Data verification error", sizeof("[OneWire]Data verification error"));
        return 2;
    }
    return 4;
}

  完整的c文件内容如下:



#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
#include "lplatform.h"
#include "auxmods.h"
#include "lrotable.h"
#include <string.h>
#include <stdlib.h>
#include <ctype.h>

#include "OneWire.h"
#include "ds18b20.h"
#include "dht11.h"

#pragma GCC push_options
#pragma GCC optimize("O0")
static int Delay1us(lua_State *L)
{
    uint32 num = luaL_checkinteger(L, 1);
    if (num >= 5 && num < 20)
    {
        for (volatile int i = 60 * num - 70 * 4; i > 0; i--)
            ;
    }
    else if (num >= 20 && num < 100)
    {
        for (volatile int i = 60 * num - 90 * 4; i > 0; i--)
            ;
    }
    else if (num >= 100)
    {
        for (volatile int i = 63 * num - 90 * 4; i > 0; i--)
            ;
    }
    lua_pushinteger(L, 1);
    return 1;
}
#pragma GCC pop_options
static int GetDS18B20Data(lua_State *L)
{
    uint8 pin = luaL_checkinteger(L, 1);
    int TempNum = 0;
    int data1 = 0, data2 = 0;
    char str1[10] = {0};
    char str2[10] = {0};
    char TempStr[20] = {0};
    uint8 var = 0;
    var = DS18B20_GetTemp_Num(pin, &TempNum);
    switch (var)
    {
    case 0:
        data1 = TempNum / 10000;
        data2 = TempNum % 10000;
        itoa(data1, str1, 10);
        itoa(data2, str2, 10);
        sprintf(TempStr, "%s.%s C", str1, str2);
        lua_pushinteger(L, TempNum);
        lua_pushlstring(L, TempStr, strlen(TempStr) + 1);
        break;
    case 1:
        lua_pushinteger(L, 0xffff);
        lua_pushlstring(L, "[OneWire]TempStr=NULL", sizeof("[OneWire]TempStr=NULL"));
        break;
    case 2:
        lua_pushinteger(L, 0xffff);
        lua_pushlstring(L, "[OneWire]The pin passed in is not in the allowed range", sizeof("[OneWire]The pin passed in is not in the allowed range"));
        break;
    case 3:
        lua_pushinteger(L, 0xffff);
        lua_pushlstring(L, "[OneWire]DS18B20 was not detected", sizeof("[OneWire]DS18B20 was not detected"));
        break;
    }

    return 2;
}

static int GetDHT11Data(lua_State *L)
{
    uint8 pin = luaL_checkinteger(L, 1);

    uint8 HumNum = 0, TemNum = 0;
    char str1[10] = {0};
    char str2[10] = {0};
    char HumStr[20] = {0};
    char TemStr[20] = {0};
    uint8 var = 0;
    var = DHT11_GetData_Num(pin, &HumNum, &TemNum);
    switch (var)
    {
    case 0:
        itoa(HumNum, str1, 10);
        itoa(TemNum, str2, 10);
        char len = sprintf(HumStr, "%s%% RH", str1);
        HumStr[(int)len] = '\0';
        len = sprintf(TemStr, "%s C", str2);
        TemStr[(int)len] = '\0';
        lua_pushinteger(L, HumNum);
        lua_pushlstring(L, HumStr, strlen(HumStr) + 1);
        lua_pushinteger(L, TemNum);
        lua_pushlstring(L, TemStr, strlen(TemStr) + 1);
        break;
    case 1:
        lua_pushinteger(L, 0xffff);
        lua_pushlstring(L, "[OneWire]HumStr == NULL || TemStr == NULL", sizeof("[OneWire]HumStr == NULL || TemStr == NULL"));
        return 2;
    case 2:
        lua_pushinteger(L, 0xffff);
        lua_pushlstring(L, "[OneWire]The pin passed in is not in the allowed range", sizeof("[OneWire]The pin passed in is not in the allowed range"));
        return 2;
    case 3:
        lua_pushinteger(L, 0xffff);
        lua_pushlstring(L, "[OneWire]DHT11 was not detected", sizeof("[OneWire]DHT11 was not detected"));
        return 2;
    case 4:
        lua_pushinteger(L, 0xffff);
        lua_pushlstring(L, "[OneWire]Data verification error", sizeof("[OneWire]Data verification error"));
        return 2;
    }
    return 4;
}

static int IOIN(lua_State *L)
{
    uint8 pin = luaL_checkinteger(L, 1);
    lua_pushinteger(L, OneWire_IO_IN(pin));
    return 1;
}

static int IOOUT(lua_State *L)
{
    uint8 pin = luaL_checkinteger(L, 1);
    OneWire_IO_OUT(pin);
    lua_pushinteger(L, 1);
    return 1;
}

static int DQOUT(lua_State *L)
{
    uint8 pin = luaL_checkinteger(L, 1);
    uint8 level = luaL_checkinteger(L, 2);
    OneWire_DQ_OUT(pin, level);
    lua_pushinteger(L, 1);
    return 1;
}

static int DQIN(lua_State *L)
{
    uint8 pin = luaL_checkinteger(L, 1);
    lua_pushinteger(L, OneWire_DQ_IN(pin));
    return 1;
}
#include "lrodefs.h"
const LUA_REG_TYPE OneWire_map[] = {
    {LSTRKEY("Delay1us"), LFUNCVAL(Delay1us)},
    {LSTRKEY("IOIN"), LFUNCVAL(IOIN)},
    {LSTRKEY("IOOUT"), LFUNCVAL(IOOUT)},
    {LSTRKEY("DQIN"), LFUNCVAL(DQIN)},
    {LSTRKEY("DQOUT"), LFUNCVAL(DQOUT)},
    {LSTRKEY("GetDS18B20Data"), LFUNCVAL(GetDS18B20Data)},
    {LSTRKEY("GetDHT11Data"), LFUNCVAL(GetDHT11Data)},
    {LNILKEY, LNILVAL}};

LUALIB_API int luaopen_OneWire(lua_State *L)
{
    luaL_register(L, AUXLIB_OneWire, OneWire_map);
    return 1;
}

4.1.4、最后一步

  函数实现后,还剩下三件事,分别是:

  在modules下面的cmake文件中加入如下代码,将自己写的luaOneWire.c加入编译:

src/luaOneWire.c

在这里插入图片描述

  那就是链接OneWire库,在链接文件的后面加上库名称:

在这里插入图片描述

  添加OneWire头文件路径:

target_include_directories(${target} PRIVATE ../lib/OneWire)
target_include_directories(${target} PRIVATE ../lib/OneWire/ds18b20)
target_include_directories(${target} PRIVATE ../lib/OneWire/dht11)

  大概就加在这个地方,就行了。

在这里插入图片描述

4.1.5、编译一下看看

  没有错误,皆大欢喜 ̑̑ฅ( ˃̶˙ω˙˂̶ ฅ) ​​​

在这里插入图片描述

4.1.6、来跑一下

  来写一个脚本,跑一下看看,从gpio0读取ds18b20,从gpio1读取dht11。代码如下:

--必须在这个位置定义PROJECT和VERSION变量
--PROJECT:ascii string类型,可以随便定义,只要不使用,就行
--VERSION:ascii string类型,如果使用Luat物联云平台固件升级的功能,必须按照"X.X.X"定义,X表示1位数字;否则可随便定义
PROJECT = "LED"
VERSION = "0.0.1"
require "sys"
--加载日志功能模块,并且设置日志输出等级
--如果关闭调用log模块接口输出的日志,等级设置为log.LOG_SILENT即可
require "log"

LOG_LEVEL = log.LOGLEVEL_TRACE
--[[
如果使用UART输出日志,打开这行注释的代码"--log.openTrace(true,1,115200)"即可,根据自己的需求修改此接口的参数
如果要彻底关闭脚本中的输出日志(包括调用log模块接口和Lua标准print接口输出的日志),执行log.openTrace(false,第二个参数跟调用openTrace接口打开日志的第二个参数相同),例如:
1、没有调用过sys.opntrace配置日志输出端口或者最后一次是调用log.openTrace(true,nil,921600)配置日志输出端口,此时要关闭输出日志,直接调用log.openTrace(false)即可
2、最后一次是调用log.openTrace(true,1,115200)配置日志输出端口,此时要关闭输出日志,直接调用log.openTrace(false,1)即可
]]
--log.openTrace(true,1,115200)

local function ds18b20_Task()
    local TempNum, TempStr = 0, 0
    while true do
        TempNum, TempStr = OneWire.GetDS18B20Data(0)
		if TempNum~=0xffff then
			log.info("ds18b20的值:", TempNum, TempStr)
		else
			log.info("ds18b20读取出错:", TempStr)
		end
        sys.wait(1000)
    end
end

local function dht11_Task()
    local  HumNum, HumStr, TemNum, TemStr = 0, 0, 0, 0
    while true do
        HumNum, HumStr, TemNum, TemStr = OneWire.GetDHT11Data(1)
		if HumNum~=0xffff then
			log.info("dht11:HumNum", HumNum)
			log.info("dht11:HumStr", HumStr)
			log.info("dht11:TemNum", TemNum)
			log.info("dht11:TemStr", TemStr)
		else
			log.info("dht11读取出错:", HumStr)
		end
        sys.wait(3000)
    end
end
local function user_main()
	sys.wait(10000)
    sys.taskInit(ds18b20_Task)
	sys.taskInit(dht11_Task)
end

--启动系统框架
sys.taskInit(user_main)
sys.init(0, 0)
sys.run()

  下架编译的固件和脚本后,打印结果如下。三秒采集一次dht11,一秒采集一次ds18b20,看起来还是很稳定的。没出现什么错误。

[2020-08-07 13:24:57.396] [I]-[dht11:HumNum] 78
[2020-08-07 13:24:57.396] [I]-[dht11:HumStr] 78RH
[2020-08-07 13:24:57.396] [I]-[dht11:TemNum] 28
[2020-08-07 13:24:57.396] [I]-[dht11:TemStr] 28 C
[2020-08-07 13:24:58.027] [I]-[ds18b20的值:] 271250 27.1250 C
[2020-08-07 13:24:59.035] [I]-[ds18b20的值:] 271250 27.1250 C
[2020-08-07 13:25:00.042] [I]-[ds18b20的值:] 270625 27.625 C
[2020-08-07 13:25:00.419] [I]-[dht11:HumNum] 78
[2020-08-07 13:25:00.419] [I]-[dht11:HumStr] 78RH
[2020-08-07 13:25:00.419] [I]-[dht11:TemNum] 28
[2020-08-07 13:25:00.419] [I]-[dht11:TemStr] 28 C
[2020-08-07 13:25:01.028] [I]-[ds18b20的值:] 271250 27.1250 C
[2020-08-07 13:25:02.048] [I]-[ds18b20的值:] 271250 27.1250 C
[2020-08-07 13:25:03.058] [I]-[ds18b20的值:] 271250 27.1250 C
[2020-08-07 13:25:03.445] [I]-[dht11:HumNum] 78
[2020-08-07 13:25:03.445] [I]-[dht11:HumStr] 78RH
[2020-08-07 13:25:03.849] [I]-[dht11:TemNum] 28
[2020-08-07 13:25:03.849] [I]-[dht11:TemStr] 28 C
[2020-08-07 13:25:04.048] [I]-[ds18b20的值:] 271250 27.1250 C
[2020-08-07 13:25:05.069] [I]-[ds18b20的值:] 271250 27.1250 C
[2020-08-07 13:25:06.063] [I]-[ds18b20的值:] 271250 27.1250 C
[2020-08-07 13:25:06.497] [I]-[dht11:HumNum] 78
[2020-08-07 13:25:06.500] [I]-[dht11:HumStr] 78RH
[2020-08-07 13:25:06.500] [I]-[dht11:TemNum] 28
[2020-08-07 13:25:06.500] [I]-[dht11:TemStr] 28 C
[2020-08-07 13:25:07.088] [I]-[ds18b20的值:] 271250 27.1250 C
[2020-08-07 13:25:08.076] [I]-[ds18b20的值:] 271250 27.1250 C
[2020-08-07 13:25:09.122] [I]-[ds18b20的值:] 271250 27.1250 C
[2020-08-07 13:25:09.528] [I]-[dht11:HumNum] 78
[2020-08-07 13:25:09.528] [I]-[dht11:HumStr] 78RH
[2020-08-07 13:25:09.528] [I]-[dht11:TemNum] 28
[2020-08-07 13:25:09.528] [I]-[dht11:TemStr] 28 C
[2020-08-07 13:25:10.095] [I]-[ds18b20的值:] 271250 27.1250 C
[2020-08-07 13:25:11.104] [I]-[ds18b20的值:] 271250 27.1250 C
[2020-08-07 13:25:12.114] [I]-[ds18b20的值:] 271250 27.1250 C
[2020-08-07 13:25:12.548] [I]-[dht11:HumNum] 78
[2020-08-07 13:25:12.548] [I]-[dht11:HumStr] 78RH
[2020-08-07 13:25:12.548] [I]-[dht11:TemNum] 28
[2020-08-07 13:25:12.548] [I]-[dht11:TemStr] 28 C
[2020-08-07 13:25:13.113] [I]-[ds18b20的值:] 271250 27.1250 C
[2020-08-07 13:25:14.121] [I]-[ds18b20的值:] 270625 27.625 C

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

遇雪长安

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值