nodemcu中GPIO模块

一、基本介绍

请参考下面的GPIO引脚图以获取索引gpio映射。

IO index ESP8266 pin IO index ESP8266 pin
0[*] GPIO16 7 GPIO13
1 GPIO5 8 GPIO15
2 GPIO4 9 GPIO 3
3 GPIO0 10 GPIO1
4 GPIO2 11 GPIO9
5 GPIO14 12 GPIO10
6 GPIO12

[*] D0(GPIO16)只能用作gpio读/写。不支持漏极开路/中断/ pwm / i2c / ow。


引脚分布图

二、函数介绍

函数 功能
gpio.mode() 初始化引脚为GPIO模式,设置引脚的进/出方向,以及可选的内部弱上拉电路。
gpio.read() 读取数字GPIO引脚值。
gpio.serout() 根据一系列延迟时间(以µs为单位)对输出进行序列化。
gpio.trig() 建立或清除回调函数以在引脚的中断上运行。
gpio.write() 设置数字GPIO引脚值。
  • gpio.mode()
    初始化引脚为GPIO模式,设置引脚的进/出方向,以及可选的内部弱上拉电路。

    1. 句法
      gpio.mode(pin, mode [, pullup])
    2. 参数
    • pin 引脚进行配置,IO索引
    • mode gpio.OUTPUT, gpio.OPENDRAIN,gpio.INPUT或gpio.INT之一(中断模式)
    • pullup gpio.PULLUP使能弱上拉电阻;默认为gpio.FLOAT
    1. 返回
      nil

    4.例
    gpio.mode(0, gpio.OUTPUT)

  • gpio.read()
    读取数字GPIO引脚值。

    1. 句法
      gpio.read(pin)
    2. 参数
      pin 引脚读取,IO索引
    3. 返回
      一个数字,0=低,1=高

    4. -- read value of gpio 0.
      gpio.read(0)
  • gpio.trig()
    建立或清除回调函数以在引脚的中断上运行。
    如果在编译时未定义GPIO_INTERRUPT_ENABLE,则此功能不可用。

    1. 句法
      gpio.trig(pin, [type [, callback_function]])
    2. 参数
    • pin 1-12,引脚触发,IO索引。注意,引脚0不支持中断。
    • type“ up”,“ down”,“ both”,“ low”,“ high”分别代表上升沿,下降沿,两个沿,低电平和高电平触发模式。如果类型为“ none”或省略,则删除回调函数并禁用中断。
    • callback_function(level, when, eventcount)触发发生时的回调函数。中断时指定引脚的电平作为第一个参数传递给回调。事件的时间戳作为第二个参数传递。以微秒为单位,与tmr.now()。此时间戳是在中断级别获取的,比在回调函数中获取时间更一致。此时间戳通常是检测到的第一个中断,但是在过载情况下,可能是后一个。eventcount是此回调消除的中断数。这对于边沿触发的中断最有效,并且可以对边沿进行计数。但是,请注意开关弹跳-单个开关闭合可能会产生多个脉冲。以数字方式生成边缘时,计数效果最佳。如果省略该函数,则将使用前一个回调函数。
    1. 返回
      nil
do
  -- use pin 1 as the input pulse width counter
  local pin, pulse1, du, now, trig = 1, 0, 0, tmr.now, gpio.trig
  gpio.mode(pin,gpio.INT)
  local function pin1cb(level, pulse2)
    print( level, pulse2 - pulse1 )
    pulse1 = pulse2
    trig(pin, level == gpio.HIGH  and "down" or "up")
  end
  trig(pin, "down", pin1cb)
end
  • gpio.write()
    设置数字GPIO引脚值。

    1. 句法
      gpio.write(pin, level)
    2. 参数
    • pin 引脚写入,IO索引
    • level gpio.HIGH 要么 gpio.LOW
    1. 返回
      nil
-- set pin index 1 to GPIO mode, and set the pin to high.
pin=1
gpio.mode(pin, gpio.OUTPUT)
gpio.write(pin, gpio.HIGH)
  • gpio,serout()
    .serout函数,文档里面写得又长又臭的,只看懂一点,估计使用来让一个Pin翻转产生序列的,还提到了同步和异步(回调)。

三、实操

nodeMCU板子上面刚好有个LED,我们可以拿这个LED来测试。先来看下板子的电路图。其中的R10,板子上面没有焊。

LED电路图

也就是说LED1和GPIO16连接到一起,低电平就可以点亮。而GPIO16对应的编号则是0。先用.mode配置GPIO16为输出模式。使用.write可以设置电平,设置成gpio.LOW会看到板子上的蓝灯亮起了。使用.read可以得到pin状态,这里使用print把读到的值打印出来。lua没有printf函数,用起来真费劲。另外,为了能够看到灯亮,这里用了一下tmr.delay做一下延时。

gpio.mode(0, gpio.OUTPUT)
print(gpio.read(0),"\n")
gpio.write(0, gpio.LOW)
print(gpio.read(0),"\n")
tmr.delay(1000000)
gpio.write(0, gpio.HIGH)
print(gpio.read(0),"\n")

接下来,我们来看看.trig函数是怎么工作的,直接上代码。板子上面的flash按键(接在3号IO上)在上电后是可以用来当做普通按键使用的,不一定要外接按键。

gpio.mode(0, gpio.OUTPUT)
gpio.mode(3, gpio.INT, gpio.PULLUP)
function ledTrg()
    local i = gpio.read(0)
    if (i == 0) then
        gpio.write(0, gpio.HIGH)
    else
        gpio.write(0, gpio.LOW)
    end
end
gpio.trig(3, "low", ledTrg)

.serout函数可以用来让IO输出特定电平。直接看一个例子

time = 0
time = tmr.now()
gpio.mode(1, gpio.OUTPUT, PULLUP)
gpio.serout(1,1,{3,7},8)
print(tmr.now() - time)
time = tmr.now()
gpio.serout(1,1,{5000,5000},8, 1)
print(tmr.now() - time)

不过这个例子,需要示波器来配合,才能看出效果。


gpio.serout(1,1,{3,7},8)

gpio.serout(1,1,{5000,5000},8, 1)

或者把后面的5ms改成500ms,接上LED。会看到灯闪了几下。

四、综合例子

结合上一篇的tmr模块,实现呼吸灯效果。函数ledPWM用来改变LED状态,同时,修改高低电平的持续时间。不过.interval的最小单位是ms,所以,效果不是特别好。一个周期的时间不要大于50HZ(20ms),不然会有明显的闪烁。changePWM函数用来调节占空比。最后启动两个静态定时器。把程序send到nodeMCU里面就可以看到效果了~

ledState = 0
pwm = 1
flag = 0
gpio.mode(0, gpio.OUTPUT)

function ledPWM() 
    if (ledState == 1) then
        ledState = 0
        gpio.write(0, gpio.HIGH)
        tmr.interval(0, 20 - pwm)
    else 
        ledState = 1
        gpio.write(0, gpio.LOW)
        tmr.interval(0, pwm)
    end
end
function changePWM()
    if(flag == 0) then
        if(pwm == 12) then
            pwm = 11
            flag = 1
        else
            pwm = pwm + 1
        end 
    else
        if(pwm == 1) then
            pwm = 2
            flag = 0
        else
            pwm = pwm - 1
        end         
    end
end

tmr.alarm(0, 1, tmr.ALARM_AUTO, ledPWM)
tmr.alarm(1, 80, tmr.ALARM_AUTO, changePWM)

一个例子,估计你看着不过瘾。上面使用.trig来做按键扫描效果不是特别理想。这里,使用定时器扫描的方式来做按键扫描。

gpio.mode(0, gpio.OUTPUT)
gpio.mode(1, gpio.INPUT, gpio.PULLUP)
keyScanTime = tmr.create()
keyCnt = 0
function ledCtrl() 
    local i = gpio.read(0)
    if(i == 0) then
        gpio.write(0, gpio.HIGH)
    else
        gpio.write(0, gpio.LOW)
    end
end
function keyScan() 
    local key = gpio.read(1)
    if (key == 0) then
        keyCnt = keyCnt + 1
    else
        if(keyCnt > 10) then
            ledCtrl()
            keyCnt = 0
        end
    end
end
tmr.alarm(keyScanTime, 10, tmr.ALARM_AUTO, keyScan)

keyScan函数以10ms的扫描周期扫描按键的电平状态,当按键按下足够长的时间后松手,则调用ledCtrl函数。赶紧send to esp后,按一下按键看看效果吧,调试过程中,不要重复send代码。可以先按ESPlorer上面的Reset按钮,重启模块。不然可以会导致模块重启。猜测是,重复注册定时器导致的。使用静态定时器,还可以在右边发送tmr.stop(定时器序号)来暂停。动态创建的,估计就比较麻烦了。

五、引用

https://www.jianshu.com/p/c3ef61c9c59b

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 闲言碎语 今天的主角是gpio模块。nodeMCU总共有12个GPIO,这些IO中只有两个是纯粹的IO,其他的都可...
    谢mingmin阅读 24,613评论 51 17
  • 其实这篇文章主要是介绍自己为其写的GPIO库,自己借鉴了原子写的STM32,野火写的K60,还有LPC官方库,然后...
    杨奉武阅读 806评论 0 0
  • 姓名:朱小鹏 学号:16010130023 转载:STM32输入输出模式理解 http://www.opened...
    小鵬_956f阅读 1,284评论 0 0
  • 重新投入学习是痛苦的,就连生物钟都因为几天的休息又回到了原来的时间。 上午玩了好久的手机,没有做什么事情,英语做了...
    吾家小女阅读 223评论 0 0
  • 其实永远不可能再在一起的两个人,应该是什么都没有牵扯的两个个体,你给于我绝望之后,是真的不想在有什么牵扯,尽管是真...
    你凭什么说阅读 385评论 0 0