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<<PERIPHS_IO_MUX_FUNC_S))) \ |( (((FUNC&BIT2)<<2)|(FUNC&0x3))<<PERIPHS_IO_MUX_FUNC_S) ); \ } 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的安全電氣距離、爬電距離不夠了。。。
不過當低壓電路使還是沒問題的。