| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473 |
- --[[
- @module AirGPIO_1000
- @summary AirGPIO_1000应用功能模块
- @version 1.0
- @date 2025.10.21
- @author 沈园园
- @usage
- 本文件为AirGPIO_1000驱动配置文件,核心业务逻辑为:
- 1、配置主机和AirGPIO_1000之间的通信参数;
- 2、配置AirGPIO_1000上的扩展GPIO管脚功能;支持配置为输出,输入和中断三种模式;
- 本文件没有对外接口,直接require "AirGPIO_1000"就可以加载运行;
- ]]
- --本文件中的主机是指I2C主机,具体指Air8000
- --本文件中的从机是指I2C从机,具体指AirGPIO_1000配件板上的IO扩展芯片
- local AirGPIO_1000 =
- {
- -- i2c_id:主机的i2c id;
- -- gpio_int_id:主机的GPIO中断引脚id;
- -- slave_address:从机地址;
- -- ints = --从机各个扩展IO配置为中断时的处理函数以及上一次的输入电平
- -- {
- -- [0x00] = {cb_func=, old_level=},
- -- [0x01] = {cb_func=, old_level=},
- -- [0x02] = {cb_func=, old_level=},
- -- [0x03] = {cb_func=, old_level=},
- -- [0x04] = {cb_func=, old_level=},
- -- [0x05] = {cb_func=, old_level=},
- -- [0x06] = {cb_func=, old_level=},
- -- [0x07] = {cb_func=, old_level=},
- -- [0x10] = {cb_func=, old_level=},
- -- [0x11] = {cb_func=, old_level=},
- -- [0x12] = {cb_func=, old_level=},
- -- [0x13] = {cb_func=, old_level=},
- -- [0x14] = {cb_func=, old_level=},
- -- [0x15] = {cb_func=, old_level=},
- -- [0x16] = {cb_func=, old_level=},
- -- [0x17] = {cb_func=, old_level=},
- -- }
- }
- -- 从机硬件上有三个引脚A0 A1 A2可以配置I2C从设备的地址
- -- 当A0 A1 A2都接地时的从设备基地址为(0x40 >> 1)
- -- A0 A1 A2有0到7一共八种排序组合,基地址+0/1/2/3/4/5/6/7即为八种从设备的地址
- -- AirGPIO_1000默认A0 A1 A2都接地,所以AirGPIO_1000的从设备地址默认也为(0x40 >> 1)
- local SALVE_ADDRESS_HIGH_4BIT = (0x40 >> 1)
- -- 寄存器地址
- local REG_INPUT_PORT_0 = 0x00 -- 输入端口0
- local REG_INPUT_PORT_1 = 0x01 -- 输入端口1
- local REG_OUTPUT_PORT_0 = 0x02 -- 输出端口0
- local REG_OUTPUT_PORT_1 = 0x03 -- 输出端口1
- local REG_POL_INV_0 = 0x04 -- 极性反转端口0
- local REG_POL_INV_1 = 0x05 -- 极性反转端口1
- local REG_CONFIG_0 = 0x06 -- 配置端口0
- local REG_CONFIG_1 = 0x07 -- 配置端口1
- -- 写入AirGPIO_1000的寄存器
- --reg:number类型;
- -- 表示AirGPIO_1000上的寄存器地址;
- -- 取值范围:0x00到0x07,参考本文件上方的寄存器地址列表;
- -- 必须传入,不允许为空;
- --value:number类型;
- -- 表示要写入到AirGPIO_1000寄存器中的数据;
- -- 取值范围:0x00到0xFF,1个字节的长度;
- -- 必须传入,不允许为空;
- --返回值:成功返回true,失败返回false
- local function write_register(reg, value)
- local data = {reg, value}
- local result = i2c.send(AirGPIO_1000.i2c_id, AirGPIO_1000.slave_address, data)
- return result
- end
- -- 读取AirGPIO_1000的寄存器
- --reg:number类型;
- -- 表示AirGPIO_1000上的寄存器地址;
- -- 取值范围:0x00到0x07,参考本文件上方的寄存器地址列表;
- -- 必须传入,不允许为空;
- --返回值:成功返回1个字节的number类型,失败返回nil
- local function read_register(reg)
- i2c.send(AirGPIO_1000.i2c_id, AirGPIO_1000.slave_address, reg)
- local data = i2c.recv(AirGPIO_1000.i2c_id, AirGPIO_1000.slave_address, 1)
- if data and #data == 1 then
- return string.byte(data, 1)
- end
- return nil
- end
- --主机上的中断引脚处理函数
- local function gpio_int_callback()
- log.info("gpio_int_callback")
- --在中断处理函数中不能直接执行耗时较长的动作
- --所以在此处publish一个"AirGPIO_1000_INT"消息
- --在其他位置订阅这个消息,进行异步处理
- --异步处理这个消息的函数可以直接执行耗时较长的动作
- sys.publish("AirGPIO_1000_INT")
- end
- --遍历用户扩展GPIO中断函数表,进行处理
- local function user_gpio_int_callback()
- if AirGPIO_1000.ints then
- --遍历用户扩展GPIO中断函数表
- for k,v in pairs(AirGPIO_1000.ints) do
- if v then
- --读取扩展GPIO的输入电平
- local cur_level = AirGPIO_1000.get(k)
- --如果输入电平和上一次输入电平不一致
- --则执行用户扩展GPIO中断函数
- if v.old_level~=cur_level then
- v.old_level = cur_level
- if v.cb_func then v.cb_func(k, cur_level) end
- end
- end
- end
- end
- end
- --订阅"AirGPIO_1000_INT"消息的处理函数user_gpio_int_callback
- --当其他位置publish "AirGPIO_1000_INT"消息时,会执行user_gpio_int_callback
- sys.subscribe("AirGPIO_1000_INT", user_gpio_int_callback)
- --检查AirGPIO_1000上的扩展GPIO ID是否有效
- --gpio_id:number类型;
- -- 表示AirGPIO_1000上的扩展GPIO ID;
- -- 取值范围:0x00到0x07,0x10到0x17,一共16种,分别对应16个扩展GPIO引脚;
- -- 必须传入,不允许为空;
- --返回值:有效返回true,无效返回false
- local function check_gpio_id_valid(gpio_id)
- return (gpio_id>=0x00 and gpio_id<=0x07 or gpio_id>=0x10 and gpio_id<=0x17)
- end
- --配置主机和AirGPIO_1000之间的通信参数;
- --i2c_id:number类型;
- -- 主机使用的I2C ID,用来控制AirGPIO_1000;
- -- 取值范围:仅支持0和1;
- -- 如果没有传入此参数,则默认为0;
- --int_id:number类型;
- -- 主机使用的中断引脚GPIO ID,和AirGPIO_1000上的INT引脚相连;
- -- AirGPIO_1000可以扩展出来16个GPIO,这些GPIO支持配置为输入;
- -- AirGPIO_1000上的任意一个输入GPIO的状态发生上升沿或者下降沿变化时,会通过INT引脚通知到主机的int_id中断引脚;
- -- 此时主机可以通过I2C接口立即读取AirGPIO_1000上配置为输入模式的扩展GPIO的电平状态,从而判断是哪些扩展GPIO的输入电平发生了变化;
- -- 取值范围:nil或者空,或者0到9,或者12到55,注意不要使用已经复用为其他功能的引脚;nil或者空时,表示不使用中断通知功能;
- -- 如果没有传入此参数,则默认为空,表示不使用中断通知功能;
- --返回值:成功返回true,失败返回false
- function AirGPIO_1000.init(i2c_id, gpio_int_id)
- --检查参数的合法性
- if not (i2c_id == 0 or i2c_id == 1) then
- log.error("AirGPIO_1000.init", "invalid i2c_id", i2c_id)
- return false
- end
- if not (gpio_int_id==nil or gpio_int_id>=0 and gpio_int_id<=9 or gpio_int_id>=12 and gpio_int_id<=55) then
- log.error("AirGPIO_1000.init", "invalid gpio_int_id", gpio_int_id)
- return false
- end
- AirGPIO_1000.i2c_id = i2c_id
- AirGPIO_1000.gpio_int_id = gpio_int_id
- --初始化I2C
- if i2c.setup(i2c_id, i2c.FAST) ~= 1 then
- log.error("AirGPIO_1000.init", "i2c.setup error", i2c_id)
- return false
- end
- --自动识别从设备地址
- --AirGPIO_1000上使用的TCA9555芯片有三个引脚,A2 A1 A0,可以配置三个bit的I2C从设备地址
- --从 0 0 0 到 1 1 1,也就是十进制的0到7,一共可以配置8种;
- --依次读取这8个从设备地址上的一个寄存器地址数据
- --如果返回应答数据,则从设备地址自动识别成功
- for i=0,7 do
- i2c.send(i2c_id, SALVE_ADDRESS_HIGH_4BIT+i, REG_INPUT_PORT_0)
- local data = i2c.recv(i2c_id, SALVE_ADDRESS_HIGH_4BIT+i, 1)
- if data~=nil then
- AirGPIO_1000.slave_address = SALVE_ADDRESS_HIGH_4BIT+i
- log.error("AirGPIO_1000.init", "slave_address", SALVE_ADDRESS_HIGH_4BIT+i, data:byte())
- break
- end
- end
- --自动识别从设备地址失败
- if not AirGPIO_1000.slave_address then
- log.error("AirGPIO_1000.init", "slave_address unknown")
- i2c.close(i2c_id)
- return false
- end
- --配置主机上的中断GPIO,用来实时检测从机上扩展GPIO的输入电平变化
- if gpio_int_id then
- gpio.setup(gpio_int_id, gpio_int_callback, gpio.PULLUP, gpio.FALLING)
- end
- return true
- end
- --关闭主机和AirGPIO_1000之间的通信;
- --返回值:成功返回true,失败返回false
- function AirGPIO_1000.deinit()
- --关闭主机I2C
- if AirGPIO_1000.i2c_id then
- i2c.close(AirGPIO_1000.i2c_id)
- AirGPIO_1000.i2c_id = nil
- AirGPIO_1000.slave_address = nil
- end
- --关闭主机中断GPIO
- if AirGPIO_1000.gpio_int_id then
- gpio.close(AirGPIO_1000.gpio_int_id)
- AirGPIO_1000.gpio_int_id = nil
- end
- --清空用户注册的扩展GPIO中断处理表
- if type(AirGPIO_1000.ints)=="table" then
- for k,v in pairs(AirGPIO_1000.ints) do
- AirGPIO_1000.ints[k] = nil
- end
- AirGPIO_1000.ints = nil
- end
- end
- --[[
- 配置AirGPIO_1000上的扩展GPIO管脚功能;
- 支持配置为输出,输入和中断三种模式;
- @api AirGPIO_1000.setup(gpio_id, gpio_mode)
- @number
- gpio_id
- 表示AirGPIO_1000上的扩展GPIO ID;
- 取值范围:0x00到0x07,0x10到0x17,一共16种,分别对应16个扩展GPIO引脚;
- 必须传入,不允许为空或者nil;
- @number or function or nil or 空
- gpio_mode
- number类型时,表示输出模式,取值范围为0和1,0表示默认输出低电平,1表示默认输出高电平;
- nil或者空类型时,表示输入模式;
- function类型时,表示中断模式,此function为中断回调函数,函数的定义格式如下:
- function cb_func(id, level)
- --id:表示触发中断的AirGPIO_1000上的扩展GPIO ID,取值范围为0x00到0x07,0x10到0x17,一共16种,分别对应16个扩展GPIO引脚;
- --level:触发中断后,某一时刻,扩展GPIO输入的电平状态,高电平为1, 低电平为0;并不是指触发中断的电平状态;
- end
- @return bool
- 成功返回true,失败返回false
- @usage
- -- GPIO ID 0x00配置为输出模式,默认输出低电平
- AirGPIO_1000.setup(0x00, 0)
- -- GPIO ID 0x11配置为输入模式
- AirGPIO_1000.setup(0x11)
- --P04引脚中断处理函数
- --id:0x04
- --level:触发中断后,某一时刻,扩展GPIO输入的电平状态,高电平为1, 低电平为0
- local function P04_int_cbfunc(id, level)
- log.info("P04_int_cbfunc", id, level)
- end
- -- GPIO ID 0x04配置为中断模式,中断处理函数为P04_int_cbfunc
- AirGPIO_1000.setup(0x04, P04_int_cbfunc)
- ]]
- function AirGPIO_1000.setup(gpio_id, gpio_mode)
- --检查参数的合法性
- if not check_gpio_id_valid(gpio_id) then
- log.error("AirGPIO_1000.setup", "invalid gpio_id", gpio_id)
- return false
- end
- if not (gpio_mode==0 or gpio_mode==1 or gpio_mode==nil or type(gpio_mode)=="function") then
- log.error("AirGPIO_1000.setup", "invalid gpio_mode", type(gpio_mode), gpio_mode)
- return false
- end
- log.info("AirGPIO_1000.setup", "enter", gpio_id, type(gpio_mode), gpio_mode)
- --根据扩展GPIO ID识别当前扩展GPIO使用的配置寄存器地址
- --0x0x开头的ID为REG_CONFIG_0,0x01开头的ID为REG_CONFIG_1
- local reg_addr = ((gpio_id>>4) == 0) and REG_CONFIG_0 or REG_CONFIG_1
- --读取从机中输出寄存器当前的值
- local reg_data = read_register(reg_addr)
- if reg_data==nil then
- log.error("AirGPIO_1000.setup", "read config register error", reg_addr)
- return false
- end
- local mask = 1<<(gpio_id&0x0F)
- local value
- --GPIO配置为输出模式
- if gpio_mode==0 or gpio_mode==1 then
- value = reg_data & (~mask)
- --GPIO配置为输入模式
- elseif gpio_mode==nil or type(gpio_mode)=="function" then
- value = reg_data | mask
- end
- --如果寄存器新值和旧值相比,发生变化
- --写新值到从机的配置寄存器中
- if reg_data~=value then
- if not write_register(reg_addr, value) then
- log.error("AirGPIO_1000.setup", "config write error", reg_addr, value)
- return false
- end
- end
- log.info("AirGPIO_1000.setup", "config", reg_addr, reg_data, value)
- --如果是中断模式,并且用户注册了中断处理函数
- if type(gpio_mode)=="function" then
- if AirGPIO_1000.ints==nil then
- AirGPIO_1000.ints = {}
- end
- if AirGPIO_1000.ints[gpio_id]==nil then
- AirGPIO_1000.ints[gpio_id] = {}
- end
- --存储中断处理函数
- AirGPIO_1000.ints[gpio_id].cb_func = gpio_mode
- --读取当前时刻GPIO的输入电平状态
- AirGPIO_1000.ints[gpio_id].old_level = AirGPIO_1000.get(gpio_id)
- end
- --如果配置的是输入模式或者中断模式,可以直接返回了
- if gpio_mode~=0 and gpio_mode~=1 then return true end
- --如果配置的输出模式,初始化输出的电平为gpio_mode
- if not AirGPIO_1000.set(gpio_id, gpio_mode) then
- log.error("AirGPIO_1000.setup", "output set error")
- return false
- end
- log.info("AirGPIO_1000.setup", "output", reg_addr, reg_data, value)
- return true
- end
- --设置AirGPIO_1000上配置为输出模式的扩展GPIO的输出电平
- --gpio_id:number类型;
- -- 表示AirGPIO_1000上的扩展GPIO ID;
- -- 取值范围:0x00到0x07,0x10到0x17,一共16种,分别对应16个扩展GPIO引脚;
- -- 必须传入,不允许为空;
- --output_level:number类型;
- -- 表示配置为输出模式的扩展GPIO对外输出的电平;
- -- 取值范围:0和1,0表示输出低电平,1表示输出高电平;
- -- 必须传入,不允许为空;
- --返回值:成功返回true,失败返回false
- function AirGPIO_1000.set(gpio_id, output_level)
- --检查参数的合法性
- if not check_gpio_id_valid(gpio_id) then
- log.error("AirGPIO_1000.set", "invalid gpio_id", gpio_id)
- return false
- end
- if not (output_level==0 or output_level==1) then
- log.error("AirGPIO_1000.set", "invalid output_level", type(output_level), output_level)
- return false
- end
- log.info("AirGPIO_1000.set", "enter", gpio_id, output_level)
- --根据扩展GPIO ID识别当前扩展GPIO使用的输出寄存器地址
- --0x0x开头的ID为REG_OUTPUT_PORT_0,0x01开头的ID为REG_OUTPUT_PORT_1
- local reg_addr = ((gpio_id>>4) == 0) and REG_OUTPUT_PORT_0 or REG_OUTPUT_PORT_1
- --读取从机中输出寄存器当前的值
- local reg_data = read_register(reg_addr)
- if reg_data==nil then
- log.error("AirGPIO_1000.set", "read output register error", reg_addr)
- return false
- end
- local mask = 1<<(gpio_id&0x0F)
- local value
- --输出低电平
- if output_level==0 then
- value = reg_data & (~mask)
- --输出高电平
- elseif output_level==1 then
- value = reg_data | mask
- end
- --如果寄存器新值和旧值相比,发生变化
- --写新值到从机的输出寄存器中
- if reg_data~=value then
- if not write_register(reg_addr, value) then
- log.error("AirGPIO_1000.set", "output write error", reg_addr, value)
- return false
- end
- end
- log.info("AirGPIO_1000.set", "output", reg_addr, reg_data, value)
- return true
- end
- --读取AirGPIO_1000上配置为输入或者中断模式的扩展GPIO的输入电平
- --gpio_id:number类型;
- -- 表示AirGPIO_1000上的扩展GPIO ID;
- -- 取值范围:0x00到0x07,0x10到0x17,一共16种,分别对应16个扩展GPIO引脚;
- -- 必须传入,不允许为空;
- --返回值:number类型,表示输入的电平,0表示低电平,1表示高电平;如果读取失败,返回false
- function AirGPIO_1000.get(gpio_id)
- --检查参数的合法性
- if not check_gpio_id_valid(gpio_id) then
- log.error("AirGPIO_1000.get", "invalid gpio_id", gpio_id)
- return false
- end
- --根据扩展GPIO ID识别当前扩展GPIO使用的输入寄存器地址
- --0x0x开头的ID为REG_INPUT_PORT_0,0x01开头的ID为REG_INPUT_PORT_1
- local reg_addr = ((gpio_id>>4) == 0) and REG_INPUT_PORT_0 or REG_INPUT_PORT_1
- --读取从机中输入寄存器当前的值
- local value = read_register(reg_addr)
- if not value then
- log.error("AirGPIO_1000.get", "read_register error", reg_addr)
- return false
- end
- --返回输入寄存器的值和GPIO对应的bit位的值
- return ((value>>(gpio_id&0x0F)) & 0x01)
- end
- --关闭AirGPIO_1000上的扩展GPIO功能
- --实际上是恢复为默认状态(配置为输入)
- --gpio_id:number类型;
- -- 表示AirGPIO_1000上的扩展GPIO ID;
- -- 取值范围:0x00到0x07,0x10到0x17,一共16种,分别对应16个扩展GPIO引脚;
- -- 必须传入,不允许为空;
- --返回值:成功返回true,失败返回false
- function AirGPIO_1000.close(gpio_id)
- local result = AirGPIO_1000.setup(gpio_id)
- if not result then
- log.error("AirGPIO_1000.close", "error", gpio_id)
- end
- return result
- end
- return AirGPIO_1000
|