# ESP32-s
by Tseng
* [Raspberry pi pico w參考](https://hackmd.io/@9FlBS64-RXuEYo-jZ-hMBw/SyOu0sF8i)
* [ESP32線上模擬器](https://wokwi.com/)
# GPIO
* 
* **GPIO注意事項**
* 1. GPIO 34,35,36,39:僅能input,不能作為output
* 2. GPIO 0,6,7,8,9,10,11:系統使用
* 3. GPIO 12, 2 燒錄時不可接任何裝置,燒錄完成後再接回,否則會upload失敗。
* 4. WiFi 模式啟動後,2,4,12,13,14,15,25,26,27僅能digital讀取,不可analog
* 5. DHT11: 不可以用GPIO 5、26
# Arduino IDE 設定
* 將下列網址貼上 arduino ide的Preferences
* https://dl.espressif.com/dl/package_esp32_index.json




## SHT31 溫溼度感測器
* ### 基本測試 
* 
* ## [github 程式碼](https://github.com/chiangyih/ESP32/blob/a513df02b1705df2cfa3223cbda4f09cce75951c/SHT31_%E6%BA%AB%E6%BA%BC%E5%BA%A6/sht31-basic/sht31-basic.ino)
---
## SHT31使用OLED顯示

### [git程式碼](https://github.com/chiangyih/ESP32/blob/c4999b8d835a2e469cc4d05d0ff8f347779c9a3b/oled_sht31/oled_sht31.ino)
### 透過串列埠,在電腦端顯示溫溼度值

labview code

---
## 土壤溼度感測器


* ### 完全乾燥時讀取值=0,濕度達100%時=4095
* ### 上面照片範例,小盆栽加20cc水後值約1000~2000間
* ## [github](https://github.com/chiangyih/ESP32/tree/master/%E5%9C%9F%E5%A3%A4%E6%BF%95%E5%BA%A6sensor/test1)
---
## GP2Y1014AU(灰塵感測)



## [程式碼](https://github.com/chiangyih/ESP32/tree/master/%E7%81%B0%E5%A1%B5%E6%84%9F%E6%B8%AC%E5%99%A8/GP2Y1014AU/test1)
#### 測得值
3000 + = 很差
1050-3000 = 差
300-1050 = 一般
150-300 = 好
75-150 = 很好
0-75 = 非常好
---
## L298N DC motor 基本控制

| motor | IN1/IN3 | IN2/IN4 |
| -------- | -------- | -------- |
| 正轉 | High | Low |
| 逆轉 | Low | High |
| 停止 | Low | Low |

[程式碼](https://github.com/chiangyih/ESP32/tree/master/vscode-L298N/)
## L298N DC motor PWM
pwm訊號接至L298N上的en接腳

## 類比轉數位(ADC)練習
* [線上模擬](https://wokwi.com/projects/349650657658012244) 含程式碼
## WS2818b模擬(使用可變電阻調整顏色)
* [線上模擬](https://wokwi.com/projects/349646102033597012) 含程式碼
## WS2818(以8顆燈燈串測試)
* 基本測試(流水燈來回一次)
* [程式碼Git](https://github.com/chiangyih/ESP32/tree/master/ws2812/ws2812-basic-test0-esp32)
* 
* 按鈕切換顯示模式
* [程式碼git](https://github.com/chiangyih/ESP32/blob/master/ws2812/buttoncycler-esp32/)
* 
* {%youtube HflxMedMLqU%}
## 8X8LED矩陣(使用MAX7219)
### 1.定點顯示
```
#include <MD_Parola.h>
#include <MD_MAX72xx.h>
#include <SPI.h>
// Uncomment according to your hardware type
#define HARDWARE_TYPE MD_MAX72XX::FC16_HW
//#define HARDWARE_TYPE MD_MAX72XX::GENERIC_HW
#define MAX_DEVICES 4 //連接8X8LED數量
#define CS_PIN 5
MD_Parola Display = MD_Parola(HARDWARE_TYPE, CS_PIN, MAX_DEVICES);
void setup() {
Display.begin();
Display.setIntensity(0);
Display.displayClear();
}
void loop() {
Display.setTextAlignment(PA_LEFT); //靠左
Display.print("Arduino test");
delay(2000);
Display.setTextAlignment(PA_CENTER); //置中
Display.print("ESP32");
delay(2000);
Display.setTextAlignment(PA_RIGHT); //靠右
Display.print("ESP32");
delay(2000);
Display.setTextAlignment(PA_CENTER);
Display.setInvert(true); //反相顯示
Display.print("ESP32");
delay(2000);
Display.setInvert(false);
delay(2000);
}
```
### 2.使用串列埠輸入顯示(可變電阻改變捲動速度)
```
#include <MD_MAX72xx.h>
#include <SPI.h>
#define IMMEDIATE_NEW 0 // if 1 will immediately display a new message
#define USE_POT_CONTROL 1
#define PRINT_CALLBACK 0
#define PRINT(s, v) { Serial.print(F(s)); Serial.print(v); }
// Define the number of devices we have in the chain and the hardware interface
// NOTE: These pin numbers will probably not work with your hardware and may
// need to be adapted
//#define HARDWARE_TYPE MD_MAX72XX::PAROLA_HW
#define HARDWARE_TYPE MD_MAX72XX::FC16_HW
#define MAX_DEVICES 4
#define CLK_PIN 18 // or SCK
#define DATA_PIN 23 // or MOSI
#define CS_PIN 5 // or SS
// SPI hardware interface
MD_MAX72XX mx = MD_MAX72XX(HARDWARE_TYPE, CS_PIN, MAX_DEVICES);
// Arbitrary pins
//MD_MAX72XX mx = MD_MAX72XX(HARDWARE_TYPE, DATA_PIN, CLK_PIN, CS_PIN, MAX_DEVICES);
// Scrolling parameters
#if USE_POT_CONTROL
#define SPEED_IN A5
#else
#define SCROLL_DELAY 1000 // in milliseconds
#endif // USE_POT_CONTROL
#define CHAR_SPACING 1 // pixels between characters
// Global message buffers shared by Serial and Scrolling functions
#define BUF_SIZE 75
uint8_t curMessage[BUF_SIZE] = { "Hello! " };
uint8_t newMessage[BUF_SIZE];
bool newMessageAvailable = false;
uint16_t scrollDelay; // in milliseconds
void readSerial(void)
{
static uint8_t putIndex = 0;
while (Serial.available())
{
newMessage[putIndex] = (char)Serial.read();
if ((newMessage[putIndex] == '\n') || (putIndex >= BUF_SIZE-3)) // end of message character or full buffer
{
// put in a message separator and end the string
newMessage[putIndex++] = ' ';
newMessage[putIndex] = '\0';
// restart the index for next filling spree and flag we have a message waiting
putIndex = 0;
newMessageAvailable = true;
}
else if (newMessage[putIndex] != '\r')
// Just save the next char in next location
putIndex++;
}
}
void scrollDataSink(uint8_t dev, MD_MAX72XX::transformType_t t, uint8_t col)
// Callback function for data that is being scrolled off the display
{
#if PRINT_CALLBACK
Serial.print("\n cb ");
Serial.print(dev);
Serial.print(' ');
Serial.print(t);
Serial.print(' ');
Serial.println(col);
#endif
}
uint8_t scrollDataSource(uint8_t dev, MD_MAX72XX::transformType_t t)
// Callback function for data that is required for scrolling into the display
{
static uint8_t* p = curMessage;
static enum { NEW_MESSAGE, LOAD_CHAR, SHOW_CHAR, BETWEEN_CHAR } state = LOAD_CHAR;
static uint8_t curLen, showLen;
static uint8_t cBuf[15];
uint8_t colData = 0; // blank column is the default
#if IMMEDIATE_NEW
if (newMessageAvailable) // there is a new message waiting
{
state = NEW_MESSAGE;
mx.clear(); // clear the display
}
#endif
// finite state machine to control what we do on the callback
switch(state)
{
case NEW_MESSAGE: // Load the new message
memcpy(curMessage, newMessage, BUF_SIZE); // copy it in
newMessageAvailable = false; // used it!
p = curMessage;
state = LOAD_CHAR;
break;
case LOAD_CHAR: // Load the next character from the font table
showLen = mx.getChar(*p++, sizeof(cBuf)/sizeof(cBuf[0]), cBuf);
curLen = 0;
state = SHOW_CHAR;
// if we reached end of message, opportunity to load the next
if (*p == '\0')
{
p = curMessage; // reset the pointer to start of message
#if !IMMEDIATE_NEW
if (newMessageAvailable) // there is a new message waiting
{
state = NEW_MESSAGE; // we will load it here
break;
}
#endif
}
// !! deliberately fall through to next state to start displaying
case SHOW_CHAR: // display the next part of the character
colData = cBuf[curLen++];
if (curLen == showLen)
{
showLen = CHAR_SPACING;
curLen = 0;
state = BETWEEN_CHAR;
}
break;
case BETWEEN_CHAR: // display inter-character spacing (blank columns)
colData = 0;
curLen++;
if (curLen == showLen)
state = LOAD_CHAR;
break;
default:
state = LOAD_CHAR;
}
return(colData);
}
void scrollText(void)
{
static uint32_t prevTime = 0;
// Is it time to scroll the text?
if (millis()-prevTime >= scrollDelay)
{
mx.transform(MD_MAX72XX::TSL); // scroll along - the callback will load all the data
prevTime = millis(); // starting point for next time
}
}
uint16_t getScrollDelay(void) //設定捲動速度
{
#if USE_POT_CONTROL
uint16_t t;
//t = analogRead(SPEED_IN); //使用可變電阻調整捲動速度(此處直接給定常數180)
//t = map(t, 0, 1023, 25, 250); //0~1023對應至25~250
t=180;
return(t);
#else
return(SCROLL_DELAY);
#endif
}
void setup()
{
mx.begin();
mx.setShiftDataInCallback(scrollDataSource);
mx.setShiftDataOutCallback(scrollDataSink);
#if USE_POT_CONTROL
pinMode(SPEED_IN, INPUT);
#else
scrollDelay = SCROLL_DELAY;
#endif
newMessage[0] = '\0';
Serial.begin(57600);
Serial.print("\n[MD_MAX72XX Message Display]\nType a message for the scrolling display\nEnd message line with a newline");
}
void loop()
{
scrollDelay = getScrollDelay();
readSerial();
scrollText();
}
```
### 3.使用按鈕切換顯示變化
```
// Program to exercise the MD_MAX72XX library
//
// Test the library transformation functions
//藉由按鈕切換顯示的文字變換模式
#include <MD_MAX72xx.h>
#include <SPI.h>
// Use a button to transfer between transformations or just do it on a timer basis
#define USE_SWITCH_INPUT 1
#define SWITCH_PIN 8 // switch pin if enabled - active LOW 切換按鈕
// We always wait a bit between updates of the display
#define DELAYTIME 500 // in milliseconds
// Number of times to repeat the transformation animations
#define REPEATS_PRESET 16
// Define the number of devices we have in the chain and the hardware interface
// NOTE: These pin numbers will probably not work with your hardware and may
// need to be adapted
//#define HARDWARE_TYPE MD_MAX72XX::PAROLA_HW
#define HARDWARE_TYPE MD_MAX72XX::FC16_HW
#define MAX_DEVICES 4
#define WRAPAROUND_MODE MD_MAX72XX::ON
#define CLK_PIN 18 // or SCK
#define DATA_PIN 23 // or MOSI
#define CS_PIN 5 // or SS
// SPI hardware interface
MD_MAX72XX mx = MD_MAX72XX(HARDWARE_TYPE, CS_PIN, MAX_DEVICES);
// Arbitrary pins
//MD_MAX72XX mx = MD_MAX72XX(HARDWARE_TYPE, DATA_PIN, CLK_PIN, CS_PIN, MAX_DEVICES);
bool changeState(void)
{
bool b = false;
#if USE_SWITCH_INPUT
static int8_t lastStatus = HIGH;
int8_t status = digitalRead(SWITCH_PIN);
b = (lastStatus == HIGH) && (status == LOW);
lastStatus = status;
#else
static uint32_t lastTime = 0;
static uint8_t repeatCount = 0;
if (repeatCount == 0)
repeatCount = REPEATS_PRESET;
if (millis()-lastTime >= DELAYTIME)
{
lastTime = millis();
b = (--repeatCount == 0);
}
#endif
return(b);
}
void transformDemo(MD_MAX72XX::transformType_t tt, bool bNew)
{
static uint32_t lastTime = 0;
if (bNew)
{
mx.clear();
for (uint8_t i=0; i<MAX_DEVICES; i++)
mx.setChar(((i+1)*COL_SIZE)-1, 'o'+i);
lastTime = millis();
}
if (millis() - lastTime >= DELAYTIME)
{
mx.transform(0, MAX_DEVICES-1, tt);
lastTime = millis();
}
}
void setup()
{
mx.begin();
// use wraparound mode
mx.control(MD_MAX72XX::WRAPAROUND, WRAPAROUND_MODE);
#if USE_SWITCH_INPUT
pinMode(SWITCH_PIN, INPUT_PULLUP);
#endif
Serial.begin(57600);
Serial.println("[Transform Test]");
}
void loop()
{
static int8_t tState = -1;
static bool bNew = true;
if (bNew)
{
tState = (tState+1) % 8;
Serial.print("State: "); Serial.println(tState);
}
switch (tState) //依據GPIO8按鈕輸入切換顯示模式
{
case 0: transformDemo(MD_MAX72XX::TSL, bNew); break;
case 1: transformDemo(MD_MAX72XX::TSR, bNew); break;
case 2: transformDemo(MD_MAX72XX::TSU, bNew); break;
case 3: transformDemo(MD_MAX72XX::TSD, bNew); break;
case 4: transformDemo(MD_MAX72XX::TFUD, bNew); break;
case 5: transformDemo(MD_MAX72XX::TFLR, bNew); break;
case 6: transformDemo(MD_MAX72XX::TRC, bNew); break;
case 7: transformDemo(MD_MAX72XX::TINV, bNew); break;
default: tState = 0; // just in case
}
bNew = changeState();
}
```
## 藍芽初始化
* ## 程式碼:[Github](https://github.com/chiangyih/VScode_esp32-bt/blob/81160369fb815c74c17ce579c3df8219678032ac/src/main.cpp)
* ## 使用藍芽控制LED
* ### 程式碼:[github](https://github.com/chiangyih/ESP32-Bluetooth1_vscode/blob/d728935bf2d1f2c7dc54bb5e2d0e37439b97b115/src/main.cpp)
* 
## 雙核心工作任務
* xTaskCreate建立的任務都是運行在核心0
* 主程式 loop()運行在核心1 *
* 範例:使用3顆LED,2顆綠燈分別為任務1與任務2,由核心0負責,1顆藍燈閃爍於主程式(核心1)負責
* 
* {%youtube 1bU1GBATItw%}
* ## 程式碼:[GitHub](https://github.com/chiangyih/ESP32/blob/c3f48f632971189888bea5bbe6fdcd67ceff967e/multiTask/2Task_test_2led/2Task_test_2led.ino)
## 連線WiFi範例
* ## 程式碼:[GitHub](https://github.com/chiangyih/ESP32-Wifi_connect/blob/master/WiFi_connect.ino)
* json資料格式解析
* [資料解析](http://jsonpath.com/)
* [json資料線上瀏覽1](http://jsonviewer.stack.hu/)
* [json資料線上瀏覽2](https://jsoneditoronline.org/)
---
## sht31溫溼度感測與土壤濕度感測寫入Google Sheet
[Google Sheet紀錄](https://docs.google.com/spreadsheets/d/1g23kwsH2B62oTP40rE4PSNd_TnGrqWhFCQBy6fhzACE/edit?usp=sharing)
[程式碼Github](https://github.com/chiangyih/ESP32/blob/master/%E8%87%AA%E5%8B%95%E5%8C%96%E8%BE%B2%E6%A5%AD/wifi-sht31-moisture-pump/wifi-sht31-moisture-pump.ino)
**這裡使用google form介接寫入,簡化使用google sheet的程式**(有關介接方式請參閱[App inventor 使用 Google Sheet](https://hackmd.io/qtYVwfNIQu2SBz5jd318hg?view#App-inventor-%E4%BD%BF%E7%94%A8-Google-Sheet))


### 上述程式加上傳送至MQTT broker(使用broker.emqx.io)
(每秒偵測天氣溫溼度及土壤濕度並上傳MQTT Broker已顯示於MQTT DASH,另每30分鐘寫入Google Sheet一筆紀錄)
[Node-red Dashboard](http://210.60.50.184:1880/ui/#!/7?socketid=UIfdhIprM6GNhAxRAAAD)
[程式碼github](https://github.com/chiangyih/ESP32/blob/master/%E8%87%AA%E5%8B%95%E5%8C%96%E8%BE%B2%E6%A5%AD/wifi-sht31-moisture-pump-MultiTask-mqtt/wifi-sht31-moisture-pump-MultiTask-mqtt.ino)
Android MQTT Dash

---
## 環境溫溼度、人體紅外線監測範例
* 溫溼度與人體紅外驗監測、上傳MQTT Broker,Node-red顯示結果,有人員進入時發送line-notify(node-red上設定)
* [環境現況監看](http://210.60.50.184:1880/ui/#!/1?socketid=JFpB7o6MUPnfURMqAAAH)
* 線路圖 
* node-red 流程設定 
程式碼[github](https://github.com/chiangyih/ESP32/blob/master/DHT22_mqtt_computer-center/DHT22_mqtt_computer-center.ino)
---
## 使用Arduino IOT Cloud
[Arduino Cloud](https://cloud.arduino.cc/)
