# ESP32 學習筆記 # Introduction the ESP32 Board ESP32是一系列由中國上海樂鑫科技(Espressif)推出的晶片、模組、開發板,採用Tensilica Xtensa LX6微處理器,包括雙核心和單核變體,支援Arduino開放性架構,內建WiFi及低功率藍芽,可用腳位也擴增到約26根,大部分腳位同時支援類比及數位,內建霍爾、溫度、觸控感測器,主頻高達240mHz的雙核心CPU,傳輸界面SPI、I2C、UART等強大的功能。 ## Features * ESP32本身帶有WiFi與藍芽的功能 * 只能吃與輸出DC 3.3V * 板子上有兩個按鈕,ENABLE與BOOT, ![](https://i.imgur.com/LE4x0xm.jpg) 按下ENABLE,會重啟ESP32。 而當常壓BOOT以及按下ENABLE,ESP32會重啟編輯模式(Programming mode) ## Specification * ESP32為雙核心,意味著可以同時處理兩件事(但需要在programe中激活) * 可以執行32 bit的程式 * 時脈(Clock frequency):240MHz * 記憶體(RAM):512 kB * 30隻腳位(也有30隻腳位的版本) ![](https://i.imgur.com/hgrJIuX.jpg) ## 各個開發板的比較 | 類型 | Arduino UNO | Arduino Mega | STM32 | ESP32 | | --------| -------- | -------- | | Text | Text | Text | ## Arduino IDE添加ESP32開發板 點選File,選擇Prefences,在Additional boards manager URLS輸入https://dl.espressif.com/dl/package_esp32_index.json即可。 ![](https://i.imgur.com/US7tgFC.png) ## 利用ESP32來計算馬達轉速 由於馬達的Encoder頻率太高,導致普通的Arduino在使用中斷函式時,會出現其他程式無法使用的窘境,因此需要使用ESP32的雙核心分區計算。 ## 遭遇問題 ### **<font color="bull">系統重啟</font>** ``` Arduino #define PWM1 13 #define INA1 12 #define INB1 14 #define Encoder_A 32 #define Encoder_B 33 hw_timer_t *timer = NULL; // 建立計時器物件 /* 宣告任務變數 */ TaskHandle_t Task_Motorcontrol; TaskHandle_t Task_Encoder; volatile long Encoder_R; int Vel_Right; unsigned long RightMotor_Speed; void EncoderISR(){ sei(); Vel_Right = Encoder_R; RightMotor_Speed = Vel_Right / 13 * 60; Encoder_R = 0; Serial.print("Right motor:"); Serial.println(RightMotor_Speed); } void READ_ENCODER_R(){ if(digitalRead(Encoder_A) == LOW){ if(digitalRead(Encoder_B) == LOW) Encoder_R++; else Encoder_R--; } else{ if(digitalRead(Encoder_B) == LOW) Encoder_R--; else Encoder_R++; } } void Motor_control(void * pvParameters){ Serial.print("Task_Motorcontrol running on core"); Serial.println(xPortGetCoreID()); int i; for(;;){ digitalWrite(INA1, LOW); digitalWrite(INB1, HIGH); for(i=80 ; i<=255 ; i++){ ledcWrite(0, i); // Serial.print("Motor PWM: "); // Serial.println(i); delay(2000); } } } void Encoder_process(void * pvParameters){ Serial.print("Task_Encoder running on core"); Serial.println(xPortGetCoreID()); for(;;){ attachInterrupt(Encoder_A, READ_ENCODER_R, CHANGE); timer = timerBegin(0, 80, true); timerAttachInterrupt(timer, &EncoderISR, true); timerAlarmWrite(timer, 5000, true); timerAlarmEnable(timer); } } void setup() { Serial.begin(115200); setCpuFrequencyMhz(240); pinMode(PWM1, OUTPUT); pinMode(INA1, OUTPUT); pinMode(INB1, OUTPUT); pinMode(Encoder_A, INPUT); pinMode(Encoder_B, INPUT); delay(200); digitalWrite(INA1, HIGH); digitalWrite(INB1, HIGH); digitalWrite(PWM1, LOW); delay(100); ledcSetup(0, 5000, 8); ledcAttachPin(PWM1, 0); xTaskCreatePinnedToCore(Motor_control, "Motor Control", 10000, NULL, 1, &Task_Motorcontrol, 1); delay(500); xTaskCreatePinnedToCore(Encoder_process, "Encoder", 10000, NULL, 1, &Task_Encoder, 0); delay(500); } void loop() { } ``` Solution: 1. 在 EncoderISR() 函數中,不應該使用 sei(),因為該函數已經在中斷上下文中調用。sei() 用於允許中斷,而在中斷上下文中,中斷是已經被允許的。因此,可以直接刪除 sei()。 3. 在 Motor_control() 函數中,應該使用 vTaskDelay() 函數來替代 delay() 函數,因為 delay() 函數會阻塞程式執行,導致其他任務無法執行,進而導致系統不穩定。可以將 delay(2000) 替換為 vTaskDelay(pdMS_TO_TICKS(2000))。 5. 在 Encoder_process() 函數中,由於一直進入中斷處理函數,可能會導致中斷佔滿 CPU 資源,從而導致系統不穩定。建議使用 Timer 來設定定時器中斷,而不是在 for(;;) 迴圈中重複註冊中斷。 ### **<font color="bull">核心恐慌</font>** ``` arduino #define PWM1 13 #define INA1 12 #define INB1 14 #define Encoder_A 32 #define Encoder_B 33 hw_timer_t *timer = NULL; // 建立計時器物件 /* 宣告任務變數 */ TaskHandle_t Task_Motorcontrol; volatile long Encoder_R, Vel_Right, Vel_Left; long RightMotor_RPM, LeftMotor_RPM; int PPR = 13; // Encoder 1圈pulse數 int interval = 1000; // 計數時間 unit:ms void Motor_control(void * pvParameters){ Serial.print("Task_Motorcontrol running on core"); Serial.println(xPortGetCoreID()); int i; for(;;){ digitalWrite(INA1, LOW); digitalWrite(INB1, HIGH); // for(i=80 ; i<=255 ; i++){ ledcWrite(0, 255); // Serial.print("Motor PWM: "); // Serial.println(i); vTaskDelay(200); // } } } void setup() { Serial.begin(115200); setCpuFrequencyMhz(240); pinMode(PWM1, OUTPUT); pinMode(INA1, OUTPUT); pinMode(INB1, OUTPUT); pinMode(Encoder_A, INPUT); pinMode(Encoder_B, INPUT); delay(200); digitalWrite(INA1, HIGH); digitalWrite(INB1, HIGH); digitalWrite(PWM1, LOW); delay(100); ledcSetup(0, 5000, 8); ledcAttachPin(PWM1, 0); xTaskCreatePinnedToCore(Motor_control, "Motor Control", 10000, NULL, 1, &Task_Motorcontrol, 1); delay(500); attachInterrupt(Encoder_A, READ_ENCODER_R, CHANGE); timer = timerBegin(0, 80, true); // timerBegin(定時器編號, 分頻數, 是否是累加模式) timerAttachInterrupt(timer, &EncoderISR, true); timerAlarmWrite(timer, 5000, true); // timerAlarmWrite(目標定時器, 計數上限, 是否重裝載) 第二個參數單位(us) timerAlarmEnable(timer); } void loop() { Serial.print("Encoder count:"); Serial.print(Vel_Right); Serial.print(" ,Right motor:"); Serial.println(RightMotor_RPM); vTaskDelay(200); } ``` ``` ets Jun 8 2016 00:22:57 rst:0xc (SW_CPU_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT) configsip: 0, SPIWP:0xee clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00 mode:DIO, clock div:1 load:0x3fff0018,len:4 load:0x3fff001c,len:1044 load:0x40078000,len:10124 load:0x40080400,len:5856 entry 0x400806a8 Task_Motorcontrol running on core1 Encoder count:0 ,Right motor:0 Encoder count:0 ,Right motor:0 Encoder count:0 ,Right motor:0 Encoder count:0 ,Right motor:0 Encoder count:0 ,Right motor:0 Encoder count:0 ,Right motor:0 Guru Meditation Error: Core 1 panic'ed (Coprocessor exception) Core 1 register dump: PC : 0x400d0ca3 PS : 0x00060031 A0 : 0x80081270 A1 : 0x3ffbea80 A2 : 0x3ffbdc5c A3 : 0x00000001 A4 : 0x00000400 A5 : 0x00000000 A6 : 0x00000000 A7 : 0x00000000 A8 : 0x00000000 A9 : 0x00000000 A10 : 0x00000000 A11 : 0x3ffbfe90 A12 : 0x00000020 A13 : 0x80000020 A14 : 0x00000003 A15 : 0x00000000 SAR : 0x00000012 EXCCAUSE: 0x00000004 EXCVADDR: 0x00000000 LBEG : 0x00000000 LEND : 0x00000000 LCOUNT : 0x00000000 Core 1 was running in ISR context: EPC1 : 0x400d0ca3 EPC2 : 0x00000000 EPC3 : 0x00000000 EPC4 : 0x40083ecb ELF file SHA256: 0000000000000000 Backtrace: 0x400d0ca3:0x3ffbea80 0x4008126d:0x3ffbeb60 0x40083cb1:0x3ffbeb80 0x400e9a47:0x3ffbc6b0 0x400e1dfb:0x3ffbc6d0 0x40087a4e:0x3ffbc6f0 0x400865b9:0x3ffbc710 Rebooting... ``` Solution: ```timerAlarmWrite()```函式的第二個參數修正 ### **<font color="bull">無法燒入program</font>** ``` Sketch uses 208046 bytes (15%) of program storage space. Maximum is 1310720 bytes. Global variables use 14016 bytes (4%) of dynamic memory, leaving 313664 bytes for local variables. Maximum is 327680 bytes. esptool.py v3.0-dev Serial port COM5 Traceback (most recent call last): File "esptool.py", line 3682, in <module> File "esptool.py", line 3675, in _main File "esptool.py", line 3329, in main File "esptool.py", line 263, in __init__ File "site-packages\serial\__init__.py", line 88, in serial_for_url File "site-packages\serial\serialwin32.py", line 62, in open serial.serialutil.SerialException: could not open port 'COM5': WindowsError(5, '\xa6s\xa8\xfa\xb3Q\xa9\xda\xa1C') Failed to execute script esptool Failed uploading: uploading error: exit status 0xffffffff ```