• [基础篇]ESP8266-SDK教程(四)之GPIO操作(按键、LED、中断、定时器)


    本篇文章我们再回到基础篇,难道你还以为我会讲UDP?啊哈哈哈,UDP肯定是会讲的,但是应用场景不是很多,我们放到后面再讲,不过也是简单一讲,毕竟熟悉UDP协议的人来说,都知道UDP一种不可靠的传输协议,可以这样形容“我(Client)只管发,你(Server)爱收不收”,所以在一些实际应用场景中是不多见的,大多数时候我们还是要保证数据传输的可靠性,准确性!好了,不多扯了,开始今天的简单却很重要的知识学习~

    我们先来了解一下什么是GPIO吧,虽然经常说GPIO,但是你有没有真正的去深入了解一下呢?随着知识的不断积累,有些时候去深入的了解某些东西,会让你有很多新的收获。

    • 什么是GPIO

    简单来说就是通用输入输出端口,英文全称:General Purpose Input Output。通俗地说,就是一些引脚,可以通过它们输出高低电平,或者通过它们读入引脚的状态是高电平或是低电平。GPIO是个比较重要的概念,用户可以通过GPIO口和硬件进行数据交互(如UART),控制硬件工作(如LED、蜂鸣器等),读取硬件的工作状态信号(如中断信号)等。

    • GPIO的八种模式

    这里说的八种模式并不是指ESP8266的八种模式,据我所知ESP8266的GPIO口并没有这么多模式,这里给大家说的是STM32 GPIO的八种模式,STM32单片机的八种模式相对来说是非常全的了,我们这里可以了解一下。

    1. 模拟输入(GPIO_Mode_AIN)
    2. 浮空输入(GPIO_Mode_IN_FLOATING)
    3. 下拉输入(GPIO_Mode_IPD)
    4. 上拉输入(GPIO_Mode_IPU)
    5. 开漏输出(GPIO_Mode_Out_OD)
    6. 推挽输出(GPIO_Mode_Out_PP)
    7. 复用开漏输出(GPIO_Mode_Out_PP)
    8. 复用推挽输出(GPIO_Mode_AF_PP)

    这里就不再详细展开叙述了,因为要把这八种模式都搞明白,一两句话是说不完了,有时间在跟大家分享。

    • GPIO可以用来做什么

    我们去学一个东西,最重要是知道这个东西可以做什么,最终要落实到实际使用嘛,如果这个GPIO没有实际使用价值,那我们也肯定不会去好好琢磨它了,简单来说,实际使用场景非常多,比如我们常见的只有开关状态的电子器件都可以用GPIO控制,或者间接使用GPIO去控制,举个栗子!LED灯,纳尼?怎么老是说一些跟灯有关的东西,啊哈哈哈哈,因为我还是比较喜欢闪闪发光的小玩意,我们都知道灯只有两种状态,开或者关(不要跟我讲还有坏了这种状态!),开跟关的状态其实就是有无电流经过它,而有无电流经过LED,最重要的是LED两端要有一个电压差,所以我们可以让某一个管脚输出高电平,这样就会在LED两端形成一定的电压差,自然而然的灯就亮了,大家可以暂时这么理解(这里只是讲给不怎么懂电子的人的~)。又比如还可以控制继电器、还可以获取按键状态,复杂一点的还可以模拟I2C总线,总之GPIO是很通用,但是也是非常重要的!

    • ESP8266GPIO接口函数

    其实单就ESP8266的GPIO口操作来说,我起初是很不适应的,如果你之前接触的是STM32单片机开发的话,你会感到不适应,但是慢慢的熟悉一下,会发现其实很简单,所以学习最重要的是摒弃固有思维,要能够思维活跃一些。我们先看一下手册当中对GPIO接口的说明,只有这个读懂了,我们才能更好的去使用它。

    我这里把几个常用的给圈出来了,基本上我们使用这几个就足够了,GPIO中断这块大家可以好好看一下,有时候我们会用到外部中断的,我们使用管脚去控制一个LED灯的基本流程就是先PIN_FUNC_SELECT(PIN_NAME, FUNC),然后就可以输出高低电平或者设置为输入,或者去读取管脚状态,但是有一点我们需要注意的就是gpio16这个管脚,在官方的技术参考手册中有说明,给大家截图看一下:

    什么意思呢?就是gpio16这个管脚不是GPIO这一伙里,使用它人家有自己的接口函数,不跟其他管脚使用同样的接口函数,这里大家需要注意一些,那么为什么这个管脚这么特殊呢?其实主要时为了低功耗,要知道Wi-Fi的功耗是很大,但是我们如果拿ESP8266做一些便携的设备,靠电池供电是不足以支撑很久的,所以在它没有什么事情的时候,我们需要它进入睡眠模式,这时候整个芯片会关闭除RTC以外的所有模块,此时工作电流是在μA级别,可以说是非常省电的,下面我们看一下官方是如何介绍的低功耗模式:

    可以看出在深度睡眠模式下功耗是极低的,所以我们是可以利用ESP8266做一些可穿戴设备的,但是戴着出去的时候,我们要去连接哪一个Wi-Fi呢?这是很值得思考的,很显然不能手机开热点,那样我们手机的功耗可就大大提高了,不过最近据说有家国内公司叫连尚网络的公司发布了自家的Wi-Fi卫星,据说明年将会搭载长征系列火箭升空,估计到那时候可穿戴Wi-Fi设备才有真正的应用场景,目前还是基于BLE的居多。详情戳卡片:

    连尚Wi-Fi卫星

    我们看一下三种模式睡眠模式的功耗对比吧!

    不对,好像又有点扯多了?怎么睡眠模式又写了这么多,好吧,转回正题,大家对低功耗感兴趣的话可以留言,改天我单独整理一篇文章详细介绍一下,要是没有那就先不整理了,啊哈哈哈哈~

    我们正式开始我们的点灯、按键点灯、定时器点灯等点灯之旅,不过还有个问题,我们这里如果是使用的NodeMCU(默认大家是使用的NodeMCU)话,我们还需要了解一下管脚定义,因为NodeMCU采用的管脚命名与ESP8266的默认管脚命名是不一样的,所以我们需要对应起来,直接给大家上个图片看一下,建议大家收藏一下,省的以后找起来麻烦。

    话不多说?上代码?得嘞,客官您里边请~

     1 /************************
     2  *   STATIC VARIABLES   *
     3  ************************/
     4 os_timer_t blue_led_timer;
     5 os_timer_t key_read_timer;
     6 
     7 /************************
     8  *   STATIC FUNCTIONS   *
     9  ************************/
    10 
    11 /**
    12  * LED定时反转函数,1s状态反转一次
    13  */
    14 static void ICACHE_FLASH_ATTR
    15 blue_led_timer_toggle(void){
    16     os_timer_disarm(&blue_led_timer);//取消定时器
    17     uint32 status = GPIO_INPUT_GET(GPIO_ID_PIN(2));//获取蓝灯管脚状态
    18     GPIO_OUTPUT_SET(GPIO_ID_PIN(2),!status);//取反实现蓝灯管脚电平反转,从而实现亮灭操作
    19     os_timer_arm(&blue_led_timer, 1000, true);//使能定时器
    20 }
    21 
    22 /**
    23  * 按键定时状态读取函数,10ms获取一次按键状态
    24  */
    25 static void ICACHE_FLASH_ATTR
    26 key_read_value(void){
    27     os_timer_disarm(&key_read_timer);//取消定时器
    28     if(GPIO_INPUT_GET(GPIO_ID_PIN(14)) == 0x00){//如果按键按下,低电平
    29         os_delay_us(20000);//延时20ms消抖
    30         if(GPIO_INPUT_GET(GPIO_ID_PIN(14)) == 0x00){//再次判断状态,防止误触
    31             uint32 status = GPIO_INPUT_GET(GPIO_ID_PIN(4));//获取当前管脚状态
    32             GPIO_OUTPUT_SET(GPIO_ID_PIN(4),!status);//取反实现管脚电平反转
    33             while(GPIO_INPUT_GET(GPIO_ID_PIN(14)));//等待按键松开
    34         }
    35     }
    36     os_timer_arm(&key_read_timer, 10, true);//使能定时器
    37 }
    38 
    39 /**
    40  *按键中断服务函数,高电平触发
    41  */
    42 static void ICACHE_FLASH_ATTR
    43 key_intr_handler(void){
    44     uint32 gpio_status = GPIO_REG_READ(GPIO_STATUS_ADDRESS);//读取GPIO寄存器状态,获取中断信息
    45     uint8 level = 0;
    46     GPIO_REG_WRITE(GPIO_STATUS_ADDRESS,gpio_status);//清楚中断信息
    47     if(gpio_status & (BIT(15))){//判断是否是gpio15
    48         if(GPIO_INPUT_GET(15)){//如果是高电平
    49             GPIO_OUTPUT_SET(GPIO_ID_PIN(5),0);//熄灭红灯
    50             GPIO_OUTPUT_SET(GPIO_ID_PIN(12),1);//熄灭黄灯
    51             GPIO_OUTPUT_SET(GPIO_ID_PIN(4),0);//熄灭绿灯
    52             GPIO_OUTPUT_SET(GPIO_ID_PIN(2),0);//熄灭蓝灯
    53             os_timer_disarm(&key_read_timer);//取消按键定时器
    54             os_timer_disarm(&blue_led_timer);//取消蓝灯定时反转定时器
    55         }else{//如果是低电平
    56             //不做处理
    57         }
    58     }else{//如果不是gpio15
    59         //不做处理
    60     }
    61 }
    62 
    63 /************************
    64  *   GLOBAL FUNCTIONS   *
    65  ************************/
    66 void ICACHE_FLASH_ATTR
    67 gpio_test(void){
    68 
    69     gpio_init();//初始化GPIO
    70 
    71     PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO5_U,FUNC_GPIO5);//红灯
    72     GPIO_OUTPUT_SET(GPIO_ID_PIN(5),1);//高电平点亮,常亮
    73 
    74     PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDI_U,FUNC_GPIO12);//黄灯
    75     GPIO_OUTPUT_SET(GPIO_ID_PIN(12),0);//低电平点亮,常亮
    76 
    77     PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U,FUNC_GPIO2);//蓝灯
    78     os_timer_disarm(&blue_led_timer);
    79     os_timer_setfn(&blue_led_timer, (os_timer_func_t *) blue_led_timer_toggle,NULL);//定时回调函数
    80     os_timer_arm(&blue_led_timer, 1000, true);//设置时间为1s
    81 
    82     PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO4_U,FUNC_GPIO4);//绿灯,按键触发,反转
    83     PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTMS_U,FUNC_GPIO14);//按键
    84     GPIO_DIS_OUTPUT(GPIO_ID_PIN(14));//按键设置为输入模式
    85     PIN_PULLUP_EN(PERIPHS_IO_MUX_MTMS_U);//引脚上拉使能
    86     os_timer_disarm(&key_read_timer);
    87     os_timer_setfn(&key_read_timer, (os_timer_func_t *) key_read_value,NULL);//定时回调函数
    88     os_timer_arm(&key_read_timer, 10, true);//设置时间为10ms
    89 
    90     PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U,FUNC_GPIO15);//中断按键
    91     GPIO_DIS_OUTPUT(GPIO_ID_PIN(15));//设置为输入模式
    92     PIN_PULLUP_DIS(PERIPHS_IO_MUX_MTDO_U);//下拉使能
    93     ETS_GPIO_INTR_DISABLE();//禁止所有GPIO中断
    94     ETS_GPIO_INTR_ATTACH((void *)key_intr_handler,NULL);//注册GPIO中断处理函数
    95     gpio_pin_intr_state_set(GPIO_ID_PIN(15),GPIO_PIN_INTR_HILEVEL);//设置高电平触发中断
    96     ETS_GPIO_INTR_ENABLE();//使能所有GPIO中断
    97 
    98 }

    代码不是很多,都有注释,大家可以自己看一下,最后我们来看一下实际运行效果,请原谅我这不标准的普通话,应该不用给大家加字幕吧?啊哈哈哈,请大家谅解~

    视频还在找托管方~

    再附上一张手画原理图,电路连接相对简单,就简单一画,应该很好看懂的。

    源码可以在这里下载:

    makingfunxyz-esp8266

    欢迎大家Star,您的鼓励是我最大的动力,有问题可以私信我,或者提交issues~

    本系列文章在知乎同步更新,知乎搜索专栏:IAMLIUBO的神奇物联网之旅

    QQ交流群:592587184

    唯有爱与科技不可辜负。
  • 相关阅读:
    Maven 跳过测试的几种方式
    Java Optional 初始为空
    Java 8 中的设计模式策略
    Java 8 开始新增的 Optional 类 Optional 对象中的返回
    关于AWSIAMcertificate证书的说明
    VUE 常规截取和特殊字符之前之后截取
    vue判断字符串中是否包含某个字符串
    图片文字居中显示
    获取Java对象中所有的属性名称和属性值
    12注册中心consul
  • 原文地址:https://www.cnblogs.com/imliubo/p/10090874.html
Copyright © 2020-2023  润新知