esp32型號:
環境搭建
安裝:就按這個來,別的試了好多次都不行,這個一次成功!!!!
vscode下ESP32開發環境配置(100%成功)_嗶哩嗶哩_bilibili
esp芯片的兩種模式:
ESP32 固件燒錄教程_嗶哩嗶哩_bilibili
1.運行模式
2.下載模式
esp32s3程序下載
1.數據線插在TTL的那個口,下載過程中不用按什么按鍵
2.
3.點擊小火花一鍵編譯下載
ESP32的啟動流程
ESP32_freeRTOS教程三:系統啟動流程_嗶哩嗶哩_bilibili
注意:app_main()是在一個任務中被調用的,它是任務的一部分,與所以里面沒有死循環,在執行app_main()之前就開啟了任務調度器了
任務的創建與刪除
實驗現象:首先創建my_task任務,系統會輸出十次my_task1這個任務的最小剩余堆棧大小,之后調用vTaskDelete()刪除m_task1這個任務
#include <stdio.h>
#include <inttypes.h>
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_chip_info.h"
#include "esp_flash.h"
#include "esp_system.h"
void my_task1(void *param)
{while (1){UBaseType_t stack_remain = uxTaskGetStackHighWaterMark(NULL);//顯示及最小棧大小printf("Stack remaining: %d\n", stack_remain);//fflush(stdout); // 手動刷新緩沖區vTaskDelay(50);}
}
void app_main(void)
{TaskHandle_t my_task1_handle=NULL;xTaskCreate(my_task1, "my_task1", 3000, NULL, 3, &my_task1_handle);vTaskDelay(500);if(my_task1_handle!=NULL){vTaskDelete(my_task1_handle);}}
注意:gcc的printf默認需要換行符\n才會輸出,或者等緩沖區滿了才輸出,keil沒有這個問題
任務創建時的輸入參數
傳給任務的參數類型時void *類型,void *類型它可以接收任何類型,
傳遞整數型
#include <stdio.h>
#include <inttypes.h>
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_chip_info.h"
#include "esp_flash.h"
#include "esp_system.h"int num=9;
void my_task1(void *param)
{int *tem=(int *)param;while (1){printf("get num: %d\n", *tem);vTaskDelay(100);}
}
void app_main(void)
{TaskHandle_t my_task1_handle=NULL;xTaskCreate(my_task1, "my_task1", 3000, (void *)&num, 3, &my_task1_handle);
}
傳遞數組:
傳遞結構體
傳遞字符串:?
vTaskList()的使用
static char pcWriteBuffer[512]={0};vTaskList(pcWriteBuffer);printf("%s",pcWriteBuffer);
輸出格式:
State表示:
?Stack表示:最小剩余的堆棧大小
#include <stdio.h>
#include <inttypes.h>
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_chip_info.h"
#include "esp_flash.h"
#include "esp_system.h"void my_task1(void *param)
{while (1){UBaseType_t stack_remain = uxTaskGetStackHighWaterMark(NULL);//顯示及最小棧大小printf("my_task1 Stack: %d\n", stack_remain);//fflush(stdout); // 手動刷新緩沖區vTaskDelay(500/portTICK_PERIOD_MS);}
}
void my_task2(void *param)
{while (1){UBaseType_t stack_remain = uxTaskGetStackHighWaterMark(NULL);//顯示及最小棧大小printf("my_task2 Stack: %d\n", stack_remain);//fflush(stdout); // 手動刷新緩沖區vTaskDelay(500/portTICK_PERIOD_MS);}
}
void app_main(void)
{TaskHandle_t my_task1_handle=NULL;TaskHandle_t my_task2_handle=NULL;xTaskCreate(my_task1, "my_task1", 3000, NULL, 10, &my_task1_handle);xTaskCreate(my_task2, "my_task2", 3000, NULL, 10, &my_task2_handle);static char pcWriteBuffer[512]={0};vTaskList(pcWriteBuffer);printf("%s",pcWriteBuffer);vTaskDelay(2000/portTICK_PERIOD_MS);}
看門狗
中斷看門狗:
? ? ? ? 當中斷程序執行過長時間時可能會觸發中斷看門狗
任務看門狗:
? ? ? ? 任務看被狗是今天重點;
使用任務看門狗需要包含頭文件: #include "esp_task_wdt.h"
#include "esp_task_wdt.h"
void my_task1(void *param)
{//將任務添加到任務看門狗所監控的列表esp_task_wdt(NULL);while (1){//喂狗esp_task_wdt_reset();vTaskDelay(500 / portTICK_PERIOD_MS);}
}void app_main(void)
{TaskHandle_t my_task1_handle = NULL;xTaskCreate(my_task1, "my_task1", 3000, NULL, 1, &my_task1_handle);
}
點亮一顆LED?
led的引腳連接在了G19引腳?
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"#define LED_GPIO GPIO_NUM_19void task_led(void *param)
{int gpio_level = 0;while(1){gpio_level=gpio_level?0:1;gpio_set_level(GPIO_NUM_19,gpio_level);vTaskDelay(pdMS_TO_TICKS(500));}}
void app_main(void)
{gpio_config_t led_cfg;led_cfg.pin_bit_mask=(1<<GPIO_NUM_19);led_cfg.mode=GPIO_MODE_OUTPUT;led_cfg.intr_type=GPIO_INTR_DISABLE;led_cfg.pull_down_en=GPIO_PULLDOWN_DISABLE;led_cfg.pull_up_en=GPIO_PULLUP_DISABLE;gpio_config(&led_cfg);xTaskCreatePinnedToCore(task_led,"task_led",3000,NULL,2,NULL,1);}
LEDC-(PWM)?
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "driver/gpio.h"
#include "driver/ledc.h"#define LED_GPIO GPIO_NUM_19#define FULL_EV_BIT BIT0 //
#define EMPTY_EV_BIT BIT1static EventGroupHandle_t ledc_event_handle; // 修正變量名bool IRAM_ATTR ledc_flish_cb(const ledc_cb_param_t *param, void *user_arg) {BaseType_t xHigherPriorityTaskWoken = pdFALSE;if (param->event == LEDC_FADE_END_EVT) {if (param->duty == 0) {xEventGroupSetBitsFromISR(ledc_event_handle, EMPTY_EV_BIT, &xHigherPriorityTaskWoken);} else {xEventGroupSetBitsFromISR(ledc_event_handle, FULL_EV_BIT, &xHigherPriorityTaskWoken);}}portYIELD_FROM_ISR(xHigherPriorityTaskWoken);return (xHigherPriorityTaskWoken == pdTRUE);
}void task_led(void *param) {EventBits_t ev;while (1) {ev = xEventGroupWaitBits(ledc_event_handle, FULL_EV_BIT | EMPTY_EV_BIT, pdTRUE, pdFALSE, pdMS_TO_TICKS(5000));if (ev & FULL_EV_BIT) {ledc_set_fade_with_time(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, 0, 2000);ledc_fade_start(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, LEDC_FADE_NO_WAIT);}if (ev & EMPTY_EV_BIT) {ledc_set_fade_with_time(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, 8191, 2000);ledc_fade_start(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, LEDC_FADE_NO_WAIT);}}
}void app_main(void) {// 1. 初始化事件組ledc_event_handle = xEventGroupCreate();// 2. 配置LEDC定時器和通道ledc_timer_config_t timer_cfg = {.speed_mode = LEDC_LOW_SPEED_MODE,.timer_num = LEDC_TIMER_0,.duty_resolution = LEDC_TIMER_13_BIT,.freq_hz = 5000,.clk_cfg = LEDC_AUTO_CLK};ESP_ERROR_CHECK(ledc_timer_config(&timer_cfg));ledc_channel_config_t channel_cfg = {.speed_mode = LEDC_LOW_SPEED_MODE,.channel = LEDC_CHANNEL_0,.timer_sel = LEDC_TIMER_0,.intr_type = LEDC_INTR_DISABLE,.gpio_num = LED_GPIO,.duty = 0,.hpoint = 0};ESP_ERROR_CHECK(ledc_channel_config(&channel_cfg));// 3. 安裝漸變功能并注冊回調ledc_fade_func_install(0);ledc_cbs_t cbs = { .fade_cb = ledc_flish_cb };ledc_cb_register(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, &cbs, NULL);// 4. 啟動初始漸變ledc_set_fade_with_time(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, 8191, 2000);ledc_fade_start(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, LEDC_FADE_NO_WAIT);// 5. 創建任務xTaskCreatePinnedToCore(task_led, "task_led", 3000, NULL, 2, NULL, 1);
}
WS2812?
單個WS2812?
ws2812的0碼和1碼都是由高低電平組成的????????
RES為復位電平:表示一幀數據傳輸結束
數據幀,RGB格式
?多個WS2812
通常情況下,電路中會有不止一個WS2812串聯起來,串聯方式如下
?
第一個燈的輸出連接到第二個燈的輸入引腳上,第二個燈的輸出連接到第三個燈的輸入引腳上,以此類推
那么任何才能控制每一個燈珠的顏色呢?
這就得益于ws2812的獨特控制方式:當我們發生一個24位數據幀后,第一個ws2812會記錄并且鎖存起來,當我們發生第二個24位數據幀時,第一個ws2812內部以及鎖存了數據,此時會將數據通過out引腳輸出給第二個ws2812燈,第二個ws2812燈會錄并且鎖存起來,當我們發生第三個24位數據幀時繼續向下遞交數據,直到我們發生了一個rest信號,本次傳輸才會結束,后續發送的數據又會從第一個ws2812開始記錄
WIFI?
WIFI模型:
AP:路由器,所有的設備和電腦通過ap熱點進行數據交換
WIFI熱點的啟動流程
? ? wifi driver被啟動之后, 會發送WIFI_EVENT_AP_START這個事件到event Task中,如果有處理這個事件的回調函數,就會再這個回調函數中進行處理;?如果有設備進行連接,就會發送WIFI_EVENT_AP_STACONNECTED這個事件到event Task,?之后再wifi_event_handler中進行處理(實例代碼中只是打印了相應的信息)如果有斷開連接的事件WIFI_EVENT_AP_STADISCONNECTED,也會發送到event Task,event Task調用wifi_event_handler進行處理
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_mac.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "nvs_flash.h"#include "lwip/err.h"
#include "lwip/sys.h"/* The examples use WiFi configuration that you can set via project configuration menu.If you'd rather not, just change the below entries to strings withthe config you want - ie #define EXAMPLE_WIFI_SSID "mywifissid"
*/
#define EXAMPLE_ESP_WIFI_SSID CONFIG_ESP_WIFI_SSID
#define EXAMPLE_ESP_WIFI_PASS CONFIG_ESP_WIFI_PASSWORD
#define EXAMPLE_ESP_WIFI_CHANNEL CONFIG_ESP_WIFI_CHANNEL
#define EXAMPLE_MAX_STA_CONN CONFIG_ESP_MAX_STA_CONNstatic const char *TAG = "wifi softAP";static void wifi_event_handler(void* arg, esp_event_base_t event_base,int32_t event_id, void* event_data)
{if (event_id == WIFI_EVENT_AP_STACONNECTED) {//有設備連接到我們的軟件熱點時會觸發這個事件 wifi_event_ap_staconnected_t* event = (wifi_event_ap_staconnected_t*) event_data;ESP_LOGI(TAG, "station "MACSTR" join, AID=%d",MAC2STR(event->mac), event->aid);} else if (event_id == WIFI_EVENT_AP_STADISCONNECTED) {//斷開連接時wifi_event_ap_stadisconnected_t* event = (wifi_event_ap_stadisconnected_t*) event_data;//打印斷開設備的信息,如ipESP_LOGI(TAG, "station "MACSTR" leave, AID=%d, reason=%d",MAC2STR(event->mac), event->aid, event->reason);}
}void wifi_init_softap(void)
{//通過調用esp_netif_init()來啟動LWIPtaskESP_ERROR_CHECK(esp_netif_init());//通過esp_event_loop_create_default()來啟動時間task--eventtask ESP_ERROR_CHECK(esp_event_loop_create_default());esp_netif_create_default_wifi_ap();wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();//esp_wifi_init() 初始化WIFI driverESP_ERROR_CHECK(esp_wifi_init(&cfg));//4.對我們所需處理的一些事件注冊了一個回調函數wifi_event_handlerESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,ESP_EVENT_ANY_ID,&wifi_event_handler,NULL,NULL));//配置driverwifi_config_t wifi_config = {.ap = {.ssid = EXAMPLE_ESP_WIFI_SSID,//熱點的名字.ssid_len = strlen(EXAMPLE_ESP_WIFI_SSID),.channel = EXAMPLE_ESP_WIFI_CHANNEL,.password = EXAMPLE_ESP_WIFI_PASS,//熱點的密碼.max_connection = EXAMPLE_MAX_STA_CONN,//熱點的最大連接數目
#ifdef CONFIG_ESP_WIFI_SOFTAP_SAE_SUPPORT.authmode = WIFI_AUTH_WPA3_PSK,//授權的模式,登錄的加密模式 .sae_pwe_h2e = WPA3_SAE_PWE_BOTH,
#else /* CONFIG_ESP_WIFI_SOFTAP_SAE_SUPPORT */.authmode = WIFI_AUTH_WPA2_PSK,
#endif.pmf_cfg = {.required = true,},},};if (strlen(EXAMPLE_ESP_WIFI_PASS) == 0) {wifi_config.ap.authmode = WIFI_AUTH_OPEN;}//使用esp_wifi_set_mode()對driver進行配置ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_AP));ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_AP, &wifi_config));//啟動driverESP_ERROR_CHECK(esp_wifi_start());ESP_LOGI(TAG, "wifi_init_softap finished. SSID:%s password:%s channel:%d",EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS, EXAMPLE_ESP_WIFI_CHANNEL);
}
/*wifi driver被啟動之后, 會發送WIFI_EVENT_AP_START這個事件到event Task中,如果有處理這個事件的回調函數,就會再這個回調函數中進行處理;如果有設備進行連接,就會發送WIFI_EVENT_AP_STACONNECTED這個事件到event Task,之后再wifi_event_handler中進行處理(實例代碼中只是打印了相應的信息)如果有斷開連接的事件WIFI_EVENT_AP_STADISCONNECTED,也會發送到event Task,event Task調用wifi_event_handler進行處理
*/
void app_main(void)
{//初始化存儲空間esp_err_t ret = nvs_flash_init();if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {ESP_ERROR_CHECK(nvs_flash_erase());ret = nvs_flash_init();}ESP_ERROR_CHECK(ret);ESP_LOGI(TAG, "ESP_WIFI_MODE_AP");wifi_init_softap();
}
NVS分區:主要是保存一些配置參數,即使設備重啟之后,NVS中的數據仍然可以保存,比如說wifi的ssid和密碼?
socket編程流程?
TCP與UDP對比
TCP是基于連接的,是可靠的,但傳輸速度慢,UDP是不基于連接的,?不可靠,傳輸速度快
UDP可以進行廣播和組播
UDP沒有建立連接的過程,所有recvfrom()與sendto()這兩個函數在發生數據的時候會包含IP地址等信息,而TCP的recv()與send()不包含IP地址等信息?