ESP8266 SDK开发入坑3 — 触摸控制继电器通断-软件、PCB制作
【入坑1】http://www.straka.cn/blog/starting-with-esp8266-light-a-led/
【入坑2】http://www.straka.cn/blog/starting-with-esp8266-touch-relay/
原博客:http://www.straka.cn/blog/starting-with-esp8266-touch-relay-code/
里简单说了下软件,这里还是贴上代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 |
#include "ets_sys.h" #include "osapi.h" #include "gpio.h" #include "user_interface.h" #include "eagle_soc.h" #include "spi_flash.h"
#define LED_PIN 1 #define RELAY_PIN 0 #define TOUCH_PIN 2
LOCAL os_timer_t timer; char LEDStatus = 1; //light when low level char TimerCounter = 0; char RelayStatus = 1;
static void GPIO_INTR_Handler(void* arg){ u32 GPIOStatus = GPIO_REG_READ(GPIO_STATUS_ADDRESS); GPIO_REG_WRITE( GPIO_STATUS_W1TC_ADDRESS, GPIOStatus);//clear interrupt status ETS_GPIO_INTR_DISABLE(); if ( GPIOStatus & BIT( TOUCH_PIN )){ //judge whether interrupt source is TOUCH_PIN RelayStatus = !RelayStatus; GPIO_OUTPUT_SET(GPIO_ID_PIN(RELAY_PIN), RelayStatus); } ETS_GPIO_INTR_ENABLE(); }
void ICACHE_FLASH_ATTR Touch_INTR_init(){ ETS_GPIO_INTR_DISABLE(); ETS_GPIO_INTR_ATTACH( GPIO_INTR_Handler, NULL );
gpio_pin_intr_state_set( GPIO_ID_PIN(TOUCH_PIN), GPIO_PIN_INTR_POSEDGE ); //DISABLE\POSEDGE\NEGEDGE\LOLEVEL\HILEVEL
GPIO_REG_WRITE( GPIO_STATUS_W1TC_ADDRESS, BIT(TOUCH_PIN)); //remove the GPIO interrupt mark of this pin ETS_GPIO_INTR_ENABLE(); }
void timer_cb(){ TimerCounter++; GPIO_OUTPUT_SET(GPIO_ID_PIN(LED_PIN), LEDStatus); TimerCounter %= 2; if(TimerCounter==0){ LEDStatus = !LEDStatus; } }
void ICACHE_FLASH_ATTR Timer_init(){ os_timer_disarm(&timer); os_timer_setfn(&timer,(os_timer_func_t *)timer_cb,NULL); //set callback func os_timer_arm(&timer,100,1); //set timer interval 1000ms }
void ICACHE_FLASH_ATTR user_rf_pre_init(){ }
uint32 ICACHE_FLASH_ATTR user_rf_cal_sector_set(void) { enum flash_size_map size_map = system_get_flash_size_map(); uint32 rf_cal_sec = 0;
switch (size_map) { case FLASH_SIZE_4M_MAP_256_256: rf_cal_sec = 128 - 5; UserParamStartSect = 0x6C; break; case FLASH_SIZE_8M_MAP_512_512: rf_cal_sec = 256 - 5; UserParamStartSect = 0xCC; break; case FLASH_SIZE_16M_MAP_512_512: rf_cal_sec = 512 - 5; UserParamStartSect = 0xD0; break; case FLASH_SIZE_16M_MAP_1024_1024: rf_cal_sec = 512 - 5; UserParamStartSect = 0xD0; break; case FLASH_SIZE_32M_MAP_512_512: rf_cal_sec = 1024 - 5; UserParamStartSect = 0xD0; break; case FLASH_SIZE_32M_MAP_1024_1024: rf_cal_sec = 1024 - 5; UserParamStartSect = 0xD0; break; case FLASH_SIZE_64M_MAP_1024_1024: rf_cal_sec = 2048 - 5; UserParamStartSect = 0xD0; break; case FLASH_SIZE_128M_MAP_1024_1024: rf_cal_sec = 4096 - 5; UserParamStartSect = 0xD0; break; default: rf_cal_sec = 0; UserParamStartSect = 0; break; } return rf_cal_sec; }
void ICACHE_FLASH_ATTR user_init(void) { PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO0_U,FUNC_GPIO0); PIN_PULLUP_DIS(PERIPHS_IO_MUX_GPIO0_U); GPIO_OUTPUT_SET(GPIO_ID_PIN(RELAY_PIN), 0);
PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U,FUNC_GPIO1); GPIO_OUTPUT_SET(GPIO_ID_PIN(LED_PIN), 1);
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U,FUNC_GPIO2); PIN_PULLUP_DIS(PERIPHS_IO_MUX_GPIO2_U); GPIO_DIS_OUTPUT(TOUCH_PIN); //config to input mode
Timer_init(); Touch_INTR_init(); } |
其实就这一个文件,写完感觉比较简单,但是没写的时候也是困惑的很,反复看了代码和官方文档才慢慢明白。
尤其开始不是很习惯官方搞了这么这么这么多的宏还不怎么解释清楚,一下子没看明白,思维没有跟上,比如GPIO相关的宏就很多,PIN_FUNC_SELECT这个宏,开始的时候怎么都没想明白是干啥的,同一个GPIO有多种引用方式,GPIO_ID_PN(*),PERIPHS_IO_MUX_****_U,而层层溯源才能看到这些宏的真正含义,其中GPIO_ID_PIN 是通过GPIO标号(注意不是引脚号)得到对应的GPIO,,,ID?,反正宏定义这个转换不明白啥意思,名字上也看不出来
1 2 |
#define GPIO_ID_PIN0 0 #define GPIO_ID_PIN(n) (GPIO_ID_PIN0+(n)) |
还有这些定义在eagle_soc.h里,
PIN_FUNC_SELECT宏:
1 2 3 4 5 6 |
#define PIN_FUNC_SELECT(PIN_NAME, FUNC) do { \ WRITE_PERI_REG(PIN_NAME, \ (READ_PERI_REG(PIN_NAME) \ & (~(PERIPHS_IO_MUX_FUNC< |( (((FUNC&BIT2)<<2)|(FUNC&0x3))< } while (0) |
就是根据PIN_NAME选择GPIO功能寄存器PERIPHS_IO_MUX对应于该管脚的寄存器字节,而用FUNC选择对应字节的位,具体宏实现就是根据FUNC将对应位清除并置位。而do{}while(0)是常用的宏代码的隔离方法,防止宏代码被误用导致出错。
1 2 3 |
#define PERIPHS_IO_MUX 0x60000800 //这里是管脚功能选择寄存器基址定义 #define PERIPHS_IO_MUX_MTDI_U (PERIPHS_IO_MUX + 0x04) //对应管脚在寄存器的字节地址 #define FUNC_GPIO12 3 //对应管脚功能在字节中的位 |
所以呢,PIN_FUNC_SELECT宏的参数 PIN_NAME 和 FUNC也并不一定要对应,只需要FUNC所代表的值是对应的就行。
类似的很多宏都只能慢慢去啃代码了,我是啃不下了,就做个探路者看看罢了。
写完代码自然是画PCB了???。。。心太急,刚学PCB画板还比较兴奋,还没测试就先把板子拿去打样了,结果提交完就发现画的有问题,没办法了。。。。
等板子期间烧录然后在面包板上测试,结果又发现了上篇说的选型上的小问题。
自己还是默默的焊上了错的板子。
本来应该是这样
结果只能这么用:
恩,主要问题就是一时兴奋,覆了个铜,导致220AC的安全电气距离、爬电距离不够了。。。
不过当低压电路使还是没问题的。