嵌入式系统与单片机|技术阅读
登录|注册

您现在的位置是:嵌入式系统与单片机 > 技术阅读 > ESP8266入门(十二)SDK编程注意事项与GPIO中断

ESP8266入门(十二)SDK编程注意事项与GPIO中断

前面几篇文章我们基本上讲完了8266的联网操作,在开始讲连接互联网上传云平台之前,有必要讲一下8266 GPIO的操作,这样我们就可以读取传感器的值,方便我们上传云平台。这一篇顺便把SDK编程的注意事项也简单讲一下。


1、GPIO输出高低电平

打开编程指南,找到GPIO的介绍,如下图:

  • 参考文件也告诉我们了,在/user/user_plug.c文件中。


好了,那我们也来个点灯的程序,实现这样的功能:3个LED灯,每秒点亮一个,其他两个熄灭,如此循环就是一个简单的流水灯了。

有过单片机 编程基础的都应该会写吧,写个while(1)循环就可以了。

好,我也写了一个,程序如下:

void user_init() //程序入口{ uart_init(115200,115200); ||初始化GPIO PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDI_U, FUNC_GPIO12); PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTCK_U, FUNC_GPIO13); PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTMS_U, FUNC_GPIO14); ||循环点亮LED while(1){ syp_LED_disply(NULL); os_delay_us(10000); }}
  • 程序下载运行后,直接就重启了,串口打印如下图:


那是 因为SDK编程不能使用while(1)死循环,否则会进入看门狗中断。

想想也是,他好像没有main函数?

那我们该怎么实现流水灯呢?

这就需要开软件定时器,每隔1秒修改一下LED灯的亮灭。

修改后用定时器的代码如下:

ETSTimer syp_LED_timer;
void user_init() //程序入口{ uart_init(115200,115200); ||初始化GPIO PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDI_U, FUNC_GPIO12); PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTCK_U, FUNC_GPIO13); PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTMS_U, FUNC_GPIO14); ||开启定时器 os_timer_disarm(&syp_LED_timer); os_timer_setfn(&syp_LED_timer,syp_LED_disply,NULL); os_timer_arm(&syp_LED_timer,1000,1);//定1秒钟发送一次
}||定时器回调函数void ICACHE_FLASH_ATTR syp_LED_disply(void *arg){ static char num = 0; ||用case实现流水灯 switch(num){ case 0: ||GPIO12输出高,1314输出低 gpio_output_set(BIT12, BIT13|BIT14, BIT12|BIT13|BIT14, 0);//12high num++; break; case 1: ||GPIO13输出高 gpio_output_set(BIT13, BIT12|BIT14, BIT12|BIT13|BIT14, 0);//13high num++; break; case 2: ||GPIO14输出高 gpio_output_set(BIT14, BIT13|BIT12, BIT12|BIT13|BIT14, 0);//14high num=0; break; default : num = 0;    break; }}

程序下载后流水灯正常显示。(* ̄︶ ̄)


2、GPIO输入


设置GPIO的输入输出函数为gpio_output_set,编程指南中的介绍如下图:

那我们也简单读取一下按键的值,如果有按键按下,就串口输出“Key Down”

按键程序如下:

ETSTimer syp_KEY_timer;
void user_init() //程序入口{ uart_init(115200,115200);  ||初始化GPIO12 PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDI_U, FUNC_GPIO12);  ||设置上拉使能 PIN_PULLUP_EN(PERIPHS_IO_MUX_MTDI_U); ||设置为输入  gpio_output_set(000, BIT12); ||开启定时器 os_timer_disarm(&syp_KEY_timer);//定个时发送 os_timer_setfn(&syp_KEY_timer,syp_KEY_scanf,NULL);  os_timer_arm(&syp_KEY_timer,100,1);//定100毫秒发送一次}
||定时器回调函数void ICACHE_FLASH_ATTR syp_KEY_scanf(void *arg){ ||检测有按键按下 if(GPIO_INPUT_GET(12) == 0){ uart0_sendStr("KEY Down\r\n"); }}
  • 程序下载后,按下按键 输出"KEY Down"

  • 注意定时器 为100毫秒检测一次按键。


3、GPIO输入中断


上面的按键程序每隔一段时间都要进行扫描按键是否按下,是不是感觉有点麻烦,因为在没有按键按下的时候也要去扫描。为了解决这个问题,我们可以给按键扫描程序修改成中断触发的方式,当有按键按下时,我们就输出“Key Down”,没有按键按下我们就去干其他事情。


给8266的GPIO开中断步骤如下:

初始化GPIO管脚
设置中断回调函数
关闭GPIO中断
将GPIO设置为输入模式
设置中断触发方式(下降沿触发)
开启GPIO中断


中断回调函数设计如下:

关闭GPIO中断
清除中断标志位

中断处理

设置中断触发方式(一定要重新设置,否则下次不会进入中断处理函数
打开GPIO中断


按键的中断函数实现如下:

void user_init(//程序入口{ uart_init(115200,115200); ||GPIO脚选择GPIO12  PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDI_U,FUNC_GPIO12);  ||设置中断回调函数  ETS_GPIO_INTR_ATTACH(syp_key_handle,NULL);  ||关闭GPIO中断  ETS_GPIO_INTR_DISABLE();  ||将GPIO12设置为输入 gpio_output_set(0,0,0,BIT12); ||设置中断触发方式 gpio_pin_intr_state_set(GPIO_ID_PIN(12),GPIO_PIN_INTR_NEGEDGE); ||开启GPIO中断  ETS_GPIO_INTR_ENABLE();}
LOCAL void syp_key_handle(void *arg){ uint16 gpio_status=0; ||关闭GPIO12中断 gpio_pin_intr_state_set(GPIO_ID_PIN(12),GPIO_PIN_INTR_DISABLE);  ||清除中断标志 gpio_status = GPIO_REG_READ(GPIO_STATUS_ADDRESS);//判断IO口状态 GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, gpio_status);  ||按键延时去抖动 os_delay_us(10000); if(GPIO_INPUT_GET(12)==0){ uart0_sendStr("KEY Down\r\n"); } ||设置中断触发方式 gpio_pin_intr_state_set(GPIO_ID_PIN(12),GPIO_PIN_INTR_NEGEDGE);  ||打开中断  ETS_GPIO_INTR_ENABLE();}
  • 在中断回调函数中要加入10毫秒延时,防止按键抖动,否则会多次发送"KEY Down\r\n"


4、总结

SDK编程不能使用while(1)死循环,否则会进入看门狗中断。
循环控制的实现一般用软件定时器的回调函数。
中断回调函数中要重新设置中断触发方式(否则下次不会进入中断处理函数)。


补充                                                        

上一篇的smartconfig程序还有一点需要注意,如果用官方的例子程序测试编译是没问题的,如果用helloworld程序修改的,编译会报错误,找不到lib文件,此时需要在makefile文件中加入-lsmartconfig。

如下图:




原创不易,如果你喜欢我的公众号、觉得我 文章对你有所启发,

请务必“点赞、收藏、转发”,这对我很重要,谢谢!

欢迎订阅    嵌入式小书虫