前面几篇文章我们基本上讲完了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输出高,13、14输出低
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(0, 0, 0, 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。
如下图:
原创不易,如果你喜欢我的公众号、觉得我 文章对你有所启发,
请务必“点赞、收藏、转发”,这对我很重要,谢谢!
欢迎订阅 嵌入式小书虫