?1.先初始化NVS,?nvs_open("WiFi_cfg", NVS_READWRITE, &wificfg_nvs_handler):打开配置文件读取wifi配置信息。
if(MY_WIFI_UPDATE == wifi_update ):首次运行时,从配置信息读取出来的wifi_update为0,
所以会将变量中的WiFi信息保存至NVS
接着led初始化,定时器闪烁初始化,wifi 初始化,串口初始化
static void app_init(void)
{
esp_log_level_set(TAG, ESP_LOG_INFO);
/* 初始化非易失性存储库 (NVS) */
esp_err_t err = nvs_flash_init();
if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
/* NVS分区被截断,需要删除,然后重新初始化NVS */
ESP_ERROR_CHECK(nvs_flash_erase());
err = nvs_flash_init();
}
ESP_ERROR_CHECK( err );
/* 定义一个NVS操作句柄 */
nvs_handle wificfg_nvs_handler;
/* 打开一个NVS命名空间 */
ESP_ERROR_CHECK( nvs_open("WiFi_cfg", NVS_READWRITE, &wificfg_nvs_handler) );
uint32_t wifi_update = 0;
err = nvs_get_u32(wificfg_nvs_handler,"wifi_update",&wifi_update);
if(MY_WIFI_UPDATE == wifi_update ) //最开始需要----是否更新wifi
printf("wifi_cfg needn't to update. \n");
else
{
printf("wifi_cfg update now... \n");
ESP_ERROR_CHECK( nvs_set_str(wificfg_nvs_handler,"wifi_ssid",MY_WIFI_SSID) );
ESP_ERROR_CHECK( nvs_set_str(wificfg_nvs_handler,"wifi_passwd",MY_WIFI_PASSWD) );
ESP_ERROR_CHECK( nvs_set_u32(wificfg_nvs_handler,"wifi_update",MY_WIFI_UPDATE) );
printf("wifi_cfg update ok. \n");
}
ESP_ERROR_CHECK( nvs_commit(wificfg_nvs_handler) ); /* 提交 */
nvs_close(wificfg_nvs_handler); /* 关闭 */
printf("ESP_WIFI_MODE_STA \n");
configure_led(); //led先初始化
esp_timer_init(); //使用定时器API函数,
err = esp_timer_create(&test_periodic_arg, &test_p_handle); // 开始创建一个重复周期的定时器并且执行先调用接口初始化
// err = esp_timer_start_periodic(test_p_handle, 1000 * 1000);
initialise_wifi();//初始化wifi
//串口初始化
uart_config_t uart_config = {
.baud_rate = 115200,
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
.source_clk = UART_SCLK_APB,
};
//Install UART driver, and get the queue.
uart_driver_install(EX_UART_NUM, BUF_SIZE * 2, BUF_SIZE * 2, 20, &uart0_queue, 0);
uart_param_config(EX_UART_NUM, &uart_config);
//Set UART pins (using UART0 default pins ie no changes.)
uart_set_pin(EX_UART_NUM, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
//uart_set_pin(EX_UART_NUM, TXD_PIN, RXD_PIN, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);//改变引脚
}
2.WiFi初始化,首先去读取NVS内部wifi_cfg信息,尝试去连接,如果能连接上:
?if (bits & WIFI_CONNECTED_BIT) ?/* WiFi连接成功事件 */
? ? {
? ? ? ? printf("connected to ap %s OK \n",wifi_ssid);
? ? ? ? vEventGroupDelete(wifi_event_group_handler); ? ?/* 删除WiFi连接事件标志组,WiFi连接成功后不再需要 */
? ? ? ? esp_timer_start_periodic(test_p_handle, 1000 * 1000);//
? ? ? ? xTaskCreate(tcp_client_task, "tcp_client", 4096, NULL, 5, NULL);? ?//?
? ? }
指示灯闪烁,连接tcp服务器
如果连接不上:smartconfig_init_start(); ? /* 开启智能配网 */
static void initialise_wifi(void)
{
ESP_ERROR_CHECK(esp_netif_init());/* 初始化底层TCP/IP堆栈。在应用程序启动时,应该调用此函数一次。*/
wifi_event_group_handler = xEventGroupCreate(); /* 创建一个事件标志组 */
ESP_ERROR_CHECK(esp_event_loop_create_default());/* 创建默认事件循环,*/
esp_netif_t *sta_netif = esp_netif_create_default_wifi_sta();/* 创建一个默认的WIFI-STA网络接口,如果初始化错误,此API将中止。*/
assert(sta_netif);
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); /* 使用WIFI_INIT_CONFIG_DEFAULT() 来获取一个默认的wifi配置参数结构体变量*/
ESP_ERROR_CHECK( esp_wifi_init(&cfg) ); /* 根据cfg参数初始化wifi连接所需要的资源 */
/* 将事件处理程序注册到系统默认事件循环,分别是WiFi事件、IP地址事件及smartconfig事件 */
ESP_ERROR_CHECK( esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL) );
ESP_ERROR_CHECK( esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL) );
ESP_ERROR_CHECK( esp_event_handler_register(SC_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL) );
nvs_handle wificfg_nvs_handler; /* 定义一个NVS操作句柄 */
char wifi_ssid[32] = { 0 }; /* 定义一个数组用来存储ssid*/
char wifi_passwd[64] = { 0 }; /* 定义一个数组用来存储passwd */
size_t len;
/* 打开一个NVS命名空间 */
ESP_ERROR_CHECK( nvs_open("WiFi_cfg", NVS_READWRITE, &wificfg_nvs_handler) );
len = sizeof(wifi_ssid); /* 从NVS中获取ssid */
ESP_ERROR_CHECK( nvs_get_str(wificfg_nvs_handler,"wifi_ssid",wifi_ssid,&len) );
len = sizeof(wifi_passwd); /* 从NVS中获取ssid */
ESP_ERROR_CHECK( nvs_get_str(wificfg_nvs_handler,"wifi_passwd",wifi_passwd,&len) );
ESP_ERROR_CHECK( nvs_commit(wificfg_nvs_handler) ); /* 提交 */
nvs_close(wificfg_nvs_handler); /* 关闭 */
/* 设置WiFi连接的ssid和password参数 */
wifi_config_t wifi_config;
bzero(&wifi_config, sizeof(wifi_config_t)); /* 将结构体数据清零 */
memcpy(wifi_config.sta.ssid, wifi_ssid, sizeof(wifi_config.sta.ssid));
memcpy(wifi_config.sta.password, wifi_passwd, sizeof(wifi_config.sta.password));
/* 设置WiFi的工作模式为 STA */
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA) );
/* 设置WiFi连接的参数,主要是ssid和password */
ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config));
/* 启动WiFi连接 */
ESP_ERROR_CHECK(esp_wifi_start());
printf("wifi_init_sta finished. \n");
/* 使用事件标志组等待连接建立(WIFI_CONNECTED_BIT)或连接失败(WIFI_FAIL_BIT)事件 */
EventBits_t bits; /* 定义一个事件位变量来接收事件标志组等待函数的返回值 */
bits = xEventGroupWaitBits( wifi_event_group_handler, /* 需要等待的事件标志组的句柄 */
WIFI_CONNECTED_BIT | WIFI_FAIL_BIT, /* 需要等待的事件位 */
pdFALSE, /* 为pdFALSE时,在退出此函数之前所设置的这些事件位不变,为pdFALSE则清零*/
pdFALSE, /* 为pdFALSE时,设置的这些事件位任意一个置1就会返回,为pdFALSE则需全为1才返回 */
portMAX_DELAY); /* 设置为最长阻塞等待时间,单位为时钟节拍 */
/* 根据事件标志组等待函数的返回值获取WiFi连接状态 */
if (bits & WIFI_CONNECTED_BIT) /* WiFi连接成功事件 */
{
printf("connected to ap %s OK \n",wifi_ssid);
vEventGroupDelete(wifi_event_group_handler); /* 删除WiFi连接事件标志组,WiFi连接成功后不再需要 */
esp_timer_start_periodic(test_p_handle, 1000 * 1000);
xTaskCreate(tcp_client_task, "tcp_client", 4096, NULL, 5, NULL);
}
else if (bits & WIFI_FAIL_BIT) /* WiFi连接失败事件 */
{
printf("Failed to connect to ap %s. \n",wifi_ssid);
smartconfig_init_start(); /* 开启智能配网 */
}
else
{
printf("UNEXPECTED EVENT \n"); /* 没有等待到事件 */
smartconfig_init_start(); /* 开启智能配网 */
}
}
3。智能配网:智能配网有多种type:?
typedef enum {
? ? SC_TYPE_ESPTOUCH = 0, ? ? ? /**< protocol: ESPTouch */
? ? SC_TYPE_AIRKISS, ? ? ? ? ? ?/**< protocol: AirKiss */
? ? SC_TYPE_ESPTOUCH_AIRKISS, ? /**< protocol: ESPTouch and AirKiss */
? ? SC_TYPE_ESPTOUCH_V2, ? ? ? ?/**< protocol: ESPTouch v2*/
} smartconfig_type_t;
配网过程产生事件,并置位标志位:
uxBits = xEventGroupWaitBits(wifi_event_group_handler, WIFI_CONNECTED_BIT | SMART_CONFIG_BIT,? ? ? ? ?true, false, portMAX_DELAY);
通过标志位结束配网,并开启指示灯闪烁,连接tcp服务器。
static void smartconfig_init_start(void)
{
/* 设置智能配网类型为 AirKiss */
ESP_ERROR_CHECK( esp_smartconfig_set_type(SC_TYPE_AIRKISS) );
/* 通过SMARTCONFIG_START_CONFIG_DEFAULT宏 来获取一个默认的smartconfig配置参数结构体变量*/
smartconfig_start_config_t cfg = SMARTCONFIG_START_CONFIG_DEFAULT();
/* 开始智能配网 */
ESP_ERROR_CHECK( esp_smartconfig_start(&cfg) );
printf("smartconfig start ....... \n");
/* 使用事件标志组等待连接建立(WIFI_CONNECTED_BIT)或连接失败(WIFI_FAIL_BIT)事件 */
EventBits_t uxBits; /* 定义一个事件位变量来接收事件标志组等待函数的返回值 */
/* 等待事件标志组,退出前清除设置的事件标志,任意置1就会返回*/
while(1){
uxBits = xEventGroupWaitBits(wifi_event_group_handler, WIFI_CONNECTED_BIT | SMART_CONFIG_BIT,
true, false, portMAX_DELAY);
if(uxBits & WIFI_CONNECTED_BIT)
{
printf("WiFi Connected to ap ok. \n");
esp_smartconfig_stop(); /* 关闭智能配网 */
}
if(uxBits & SMART_CONFIG_BIT)
{
printf("smartconfig over \n");
esp_smartconfig_stop(); /* 关闭智能配网 */
esp_timer_start_periodic(test_p_handle, 1000 * 1000); //指示灯闪烁
xTaskCreate(tcp_client_task, "tcp_client", 4096, NULL, 5, NULL); //连接tcp服务
}
}
}
4.配网事件??
event_base == WIFI_EVENT
WIFI_EVENT_STA_START:通过NVS内部配置信息进行sta连接路由器,连接不成功尝试十次。
event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP:ip事件获取ip并打印
event_base == SC_EVENT:智能配网事件,获取AP的ssid与passwd udp包,通过保存到NVS配置信息,尝试sta连接网络。
/* 系统事件循环处理函数 */
static void event_handler(void* arg, esp_event_base_t event_base,int32_t event_id, void* event_data)
{
static int retry_num = 0; /* 记录wifi重连次数 */
/* 系统事件为WiFi事件 */
if (event_base == WIFI_EVENT)
{
if(event_id == WIFI_EVENT_STA_START) /* 事件id为STA开始 */
esp_wifi_connect();
else if (event_id == WIFI_EVENT_STA_DISCONNECTED) /* 事件id为失去STA连接 */
{
esp_wifi_connect();
retry_num++;
printf("retry to connect to the AP %d times. \n",retry_num);
if (retry_num > 10) /* WiFi重连次数大于10 */
{
/* 将WiFi连接事件标志组的WiFi连接失败事件位置1 */
xEventGroupSetBits(wifi_event_group_handler, WIFI_FAIL_BIT);
}
/* 清除WiFi连接成功标志位 */
xEventGroupClearBits(wifi_event_group_handler, WIFI_CONNECTED_BIT);
}
}
/* 系统事件为ip地址事件,且事件id为成功获取ip地址 */
else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP)
{
ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data; /* 获取IP地址信息*/
printf("got ip:%d.%d.%d.%d \n" , IP2STR(&event->ip_info.ip)); /* 打印ip地址*/
retry_num = 0; /* WiFi重连次数清零 */
/* 将WiFi连接事件标志组的WiFi连接成功事件位置1 */
xEventGroupSetBits(wifi_event_group_handler, WIFI_CONNECTED_BIT);
}
/* 系统事件为智能配网事件 */
else if (event_base == SC_EVENT)
{
if(event_id == SC_EVENT_SCAN_DONE ) /* 开始扫描智能配网设备端 */
printf("Scan done\n");
else if(event_id == SC_EVENT_FOUND_CHANNEL) /* 得到了智能配网通道 */
printf("Found channel \n");
else if(event_id == SC_EVENT_GOT_SSID_PSWD) /* 得到了智能配网设备提供的ssid和password */
{
printf("smartconfig got SSID and password\n");
/* 获取智能配网设备端提供的数据信息 */
smartconfig_event_got_ssid_pswd_t *evt = (smartconfig_event_got_ssid_pswd_t *)event_data;
/* 定义WiFi配置结构体和用了结收ssid和password的数组 */
wifi_config_t wifi_config;
char ssid[32] = { 0 };
char password[64] = { 0 };
bzero(&wifi_config, sizeof(wifi_config_t)); /* 将结构体数据清零 */
/* 将智能配网设备发送来的WiFi的ssid、password及MAC地址复制到wifi_config */
memcpy(wifi_config.sta.ssid, evt->ssid, sizeof(wifi_config.sta.ssid));
memcpy(wifi_config.sta.password, evt->password, sizeof(wifi_config.sta.password));
wifi_config.sta.bssid_set = evt->bssid_set;
if (wifi_config.sta.bssid_set == true) {
memcpy(wifi_config.sta.bssid, evt->bssid, sizeof(wifi_config.sta.bssid));
}
/* 打印WiFi名称和密码 */
memcpy(ssid, evt->ssid, sizeof(evt->ssid));
memcpy(password, evt->password, sizeof(evt->password));
printf("SSID:%s \n", ssid);
printf("PASSWORD:%s \n", password);
/* 将得到的WiFi名称和密码存入NVS*/
nvs_handle wificfg_nvs_handler;
ESP_ERROR_CHECK( nvs_open("WiFi_cfg", NVS_READWRITE, &wificfg_nvs_handler) );
ESP_ERROR_CHECK( nvs_set_str(wificfg_nvs_handler,"wifi_ssid",ssid) );
ESP_ERROR_CHECK( nvs_set_str(wificfg_nvs_handler,"wifi_passwd",password) );
ESP_ERROR_CHECK( nvs_commit(wificfg_nvs_handler) ); /* 提交 */
nvs_close(wificfg_nvs_handler); /* 关闭 */
printf("smartconfig save wifi_cfg to NVS .\n");
/* 根据得到的WiFi名称和密码连接WiFi*/
ESP_ERROR_CHECK( esp_wifi_disconnect() );
ESP_ERROR_CHECK( esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config) );
ESP_ERROR_CHECK( esp_wifi_connect() );
}
else if (event_id == SC_EVENT_SEND_ACK_DONE) /* 智能配网成功,已经给智能配网设备发送应答*/
{
xEventGroupSetBits(wifi_event_group_handler, SMART_CONFIG_BIT);
}
}
}
5.tcp_client_task:使用的是IP_V4,绑定服务器IP端口号,建立socket来连接,
配置操作:
添加Kconfig.projbuild?
menu "Example Configuration"
choice BLINK_LED
prompt "Blink LED type"
default BLINK_LED_GPIO if IDF_TARGET_ESP32
default BLINK_LED_RMT
help
Defines the default peripheral for blink example
config BLINK_LED_GPIO
bool "GPIO"
config BLINK_LED_RMT
bool "RMT - Addressable LED"
endchoice
config BLINK_LED_RMT_CHANNEL
depends on BLINK_LED_RMT
int "RMT Channel"
range 0 7
default 0
help
Set the RMT peripheral channel.
ESP32 RMT channel from 0 to 7
ESP32-S2 RMT channel from 0 to 3
ESP32-S3 RMT channel from 0 to 3
ESP32-C3 RMT channel from 0 to 1
config BLINK_GPIO
int "Blink GPIO number"
range 0 48
default 8 if IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32H2
default 18 if IDF_TARGET_ESP32S2
default 48 if IDF_TARGET_ESP32S3
default 5
help
GPIO number (IOxx) to blink on and off or the RMT signal for the addressable LED.
Some GPIOs are used for other purposes (flash connections, etc.) and cannot be used to blink.
config BLINK_PERIOD
int "Blink period in ms"
range 10 3600000
default 1000
help
Define the blinking period in milliseconds.
choice EXAMPLE_IP_MODE
prompt "IP Version"
depends on EXAMPLE_SOCKET_IP_INPUT_STRING
help
Example can use either IPV4 or IPV6.
config EXAMPLE_IPV4
bool "IPV4"
config EXAMPLE_IPV6
bool "IPV6"
endchoice
config EXAMPLE_IPV4_ADDR
string "IPV4 Address"
default "192.168.0.165"
depends on EXAMPLE_IPV4
help
The example will connect to this IPV4 address.
config EXAMPLE_IPV6_ADDR
string "IPV6 Address"
default "FE80::30AD:E57B:C212:68AD"
depends on EXAMPLE_IPV6
help
The example will connect to this IPV6 address.
config EXAMPLE_PORT
int "Port"
range 0 65535
default 3333
help
The remote port to which the client example will connect to.
choice EXAMPLE_SOCKET_IP_INPUT
prompt "Socket example source"
default EXAMPLE_SOCKET_IP_INPUT_STRING
help
Selects the input source of the IP used in the example.
config EXAMPLE_SOCKET_IP_INPUT_STRING
bool "From string"
config EXAMPLE_SOCKET_IP_INPUT_STDIN
bool "From stdin"
endchoice
endmenu
?打开配置选Example Configuration:
重置 修改后保存 :
?接收到服务器消息,通过串口转发
? int len = recv(sock, rx_buffer, sizeof(rx_buffer) - 1, 0); ? ? ? ? ?
? ? ? ? ? ? if (len < 0) {
? ? ? ? ? ? ? ? ESP_LOGE(TAG, "recv failed: errno %d", errno); // Error occurred during receiving
? ? ? ? ? ? ? ? break;
? ? ? ? ? ? }
? ? ? ? ? ? // Data received
? ? ? ? ? ? else {
? ? ? ? ? ? ? ? rx_buffer[len] = 0; // Null-terminate whatever we received and treat like a string
? ? ? ? ? ? ? ? sendData(TAG, rx_buffer);//转发给串口
? ? ? ? ? ? }
//tcp通讯
static void tcp_client_task(void *pvParameters)
{
char rx_buffer[128];
char host_ip[] = HOST_IP_ADDR;
int addr_family = 0;
int ip_protocol = 0;
while (1) {
#if defined(CONFIG_EXAMPLE_IPV4)
struct sockaddr_in dest_addr;
dest_addr.sin_addr.s_addr = inet_addr(host_ip);
dest_addr.sin_family = AF_INET;
dest_addr.sin_port = htons(PORT);
addr_family = AF_INET;
ip_protocol = IPPROTO_IP;
#elif defined(CONFIG_EXAMPLE_IPV6)
struct sockaddr_in6 dest_addr = { 0 };
inet6_aton(host_ip, &dest_addr.sin6_addr);
dest_addr.sin6_family = AF_INET6;
dest_addr.sin6_port = htons(PORT);
dest_addr.sin6_scope_id = esp_netif_get_netif_impl_index(EXAMPLE_INTERFACE);
addr_family = AF_INET6;
ip_protocol = IPPROTO_IPV6;
#elif defined(CONFIG_EXAMPLE_SOCKET_IP_INPUT_STDIN)
struct sockaddr_in6 dest_addr = { 0 };
ESP_ERROR_CHECK(get_addr_from_stdin(PORT, SOCK_STREAM, &ip_protocol, &addr_family, &dest_addr));
#endif
sock = socket(addr_family, SOCK_STREAM, ip_protocol);
if (sock < 0) {
ESP_LOGE(TAG, "Unable to create socket: errno %d", errno);
break;
}
ESP_LOGI(TAG, "Socket created, connecting to %s:%d", host_ip, PORT);
int err = connect(sock, (struct sockaddr *)&dest_addr, sizeof(struct sockaddr_in6));
if (err != 0) {
ESP_LOGE(TAG, "Socket unable to connect: errno %d", errno);
break;
}
ESP_LOGI(TAG, "Successfully connected");
while (1) {
int len = recv(sock, rx_buffer, sizeof(rx_buffer) - 1, 0);
if (len < 0) {
ESP_LOGE(TAG, "recv failed: errno %d", errno); // Error occurred during receiving
break;
}
// Data received
else {
rx_buffer[len] = 0; // Null-terminate whatever we received and treat like a string
sendData(TAG, rx_buffer);//转发给串口
// ESP_LOGI(TAG, "Received %d bytes from %s:", len, host_ip);
// ESP_LOGI(TAG, "%s", rx_buffer);
}
vTaskDelay(2000 / portTICK_PERIOD_MS);
}
if (sock != -1) {
ESP_LOGE(TAG, "Shutting down socket and restarting...");
shutdown(sock, 0);
close(sock);
}
}
vTaskDelete(NULL);
}
5.串口事件 接收到串口消息转发给tcp服务端
static void rx_task(void *arg)
{
static const char *RX_TASK_TAG = "RX_TASK";
esp_log_level_set(RX_TASK_TAG, ESP_LOG_INFO);
uint8_t* data = (uint8_t*) malloc(BUF_SIZE+1);
while (1) {
const int rxBytes = uart_read_bytes(EX_UART_NUM, data, BUF_SIZE, 1000 / portTICK_RATE_MS);
if (rxBytes > 0) {
data[rxBytes] = 0;
//转发给tcp服务
int err = send(sock, (char *)data, rxBytes+1, 0);
if (err < 0) {
ESP_LOGE(TAG, "Error occurred during sending: errno %d", errno);
break;
}
// ESP_LOGI(RX_TASK_TAG, "Read %d bytes: '%s'", rxBytes, data);
// ESP_LOG_BUFFER_HEXDUMP(RX_TASK_TAG, data, rxBytes, ESP_LOG_INFO);
}
}
free(data);
}
最后,贴上完整代码
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "driver/gpio.h"
#include "esp_log.h"
#include "led_strip.h"
#include "driver/uart.h"
#include "sdkconfig.h"
#include "esp_timer.h"
#include "esp_spi_flash.h"
#include "esp_wifi.h"
#include "esp_wpa2.h"
#include "esp_event.h"
#include "esp_system.h"
#include "nvs_flash.h"
#include "esp_netif.h"
#include "esp_smartconfig.h"
#include "string.h"
#include <sys/param.h>
#include "protocol_examples_common.h"
#include "addr_from_stdin.h"
#include "lwip/err.h"
#include "lwip/sockets.h"
static const char *TAG = "care_robot";
#define BLINK_GPIO CONFIG_BLINK_GPIO
static uint8_t s_led_state = 0;
static led_strip_t *pStrip_a;
#define EX_UART_NUM UART_NUM_0 //串口号
#define BUF_SIZE (1024)
#define RD_BUF_SIZE (BUF_SIZE)
static QueueHandle_t uart0_queue;
/* 宏定义WiFi更新标识码、WiFi名称和密码 */
#define MY_WIFI_UPDATE 4096 /* 对数值进行修改表示更新NVS的WiFi名称和密码*/
#define MY_WIFI_SSID "Singhu_test"
#define MY_WIFI_PASSWD "123123123DESK"
static EventGroupHandle_t wifi_event_group_handler;
/* 宏定义WiFi连接事件标志位、连接失败标志位及智能配网标志位 */
#define WIFI_CONNECTED_BIT BIT0
#define WIFI_FAIL_BIT BIT1
#define SMART_CONFIG_BIT BIT2
int sock=0;
#if defined(CONFIG_EXAMPLE_IPV4)
#define HOST_IP_ADDR CONFIG_EXAMPLE_IPV4_ADDR
#elif defined(CONFIG_EXAMPLE_IPV6)
#define HOST_IP_ADDR CONFIG_EXAMPLE_IPV6_ADDR
#else
#define HOST_IP_ADDR ""
#endif
#define PORT CONFIG_EXAMPLE_PORT
float arr1[8][3] = { {0.5, 0.5, 0.5}, {0, 0, 1},{0, 1, 0},
{0, 1, 1},{1, 0, 0},{1, 0, 1},{1, 1, 0}, {1, 1, 1}};//七彩效果
static void blink_led(void)
{
/* If the addressable LED is enabled */
static int index=0;
if (s_led_state) {
index=(index+1)%8;
/* Set the LED pixel using RGB from 0 (0%) to 255 (100%) for each color */
pStrip_a->set_pixel(pStrip_a, 0, arr1[index][0]*255, arr1[index][1]*255, arr1[index][2]*255);
/* Refresh the strip to send data */
pStrip_a->refresh(pStrip_a, 100);
} else {
/* Set all LED off to clear all pixels */
pStrip_a->clear(pStrip_a, 50);
}
}
static void configure_led(void) //led初始化
{
ESP_LOGI(TAG, "Example configured to blink addressable LED!");
/* LED strip initialization with the GPIO and pixels number*/
pStrip_a = led_strip_init(CONFIG_BLINK_LED_RMT_CHANNEL, BLINK_GPIO, 1);
/* Set all LED off to clear all pixels */
pStrip_a->clear(pStrip_a, 50);
}
void test_timer_periodic_cb(void *arg) ;// 定义定时器句柄
esp_timer_handle_t test_p_handle = 0;// 定义一个周期重复运行的定时器结构体
esp_timer_create_args_t test_periodic_arg =
{
.callback = &test_timer_periodic_cb, // 设置回调函数
.arg = NULL, // 不携带参数
.name = "xjhPeriodicTimer" // 定时器名字
};
void test_timer_periodic_cb(void *arg) //定时器回调函数
{
blink_led();
s_led_state = !s_led_state;
//int64_t tick = esp_timer_get_time();
}
int sendData(const char* logName, const char* data)
{
const int len = strlen(data);
const int txBytes = uart_write_bytes(EX_UART_NUM, data, len);
ESP_LOGI(logName, "Wrote %d bytes", txBytes);
return txBytes;
}
static void rx_task(void *arg)
{
static const char *RX_TASK_TAG = "RX_TASK";
esp_log_level_set(RX_TASK_TAG, ESP_LOG_INFO);
uint8_t* data = (uint8_t*) malloc(BUF_SIZE+1);
while (1) {
const int rxBytes = uart_read_bytes(EX_UART_NUM, data, BUF_SIZE, 1000 / portTICK_RATE_MS);
if (rxBytes > 0) {
data[rxBytes] = 0;
//转发给tcp服务
int err = send(sock, (char *)data, rxBytes+1, 0);
if (err < 0) {
ESP_LOGE(TAG, "Error occurred during sending: errno %d", errno);
break;
}
// ESP_LOGI(RX_TASK_TAG, "Read %d bytes: '%s'", rxBytes, data);
// ESP_LOG_BUFFER_HEXDUMP(RX_TASK_TAG, data, rxBytes, ESP_LOG_INFO);
}
}
free(data);
}
//tcp通讯
static void tcp_client_task(void *pvParameters)
{
char rx_buffer[128];
char host_ip[] = HOST_IP_ADDR;
int addr_family = 0;
int ip_protocol = 0;
while (1) {
#if defined(CONFIG_EXAMPLE_IPV4)
struct sockaddr_in dest_addr;
dest_addr.sin_addr.s_addr = inet_addr(host_ip);
dest_addr.sin_family = AF_INET;
dest_addr.sin_port = htons(PORT);
addr_family = AF_INET;
ip_protocol = IPPROTO_IP;
#elif defined(CONFIG_EXAMPLE_IPV6)
struct sockaddr_in6 dest_addr = { 0 };
inet6_aton(host_ip, &dest_addr.sin6_addr);
dest_addr.sin6_family = AF_INET6;
dest_addr.sin6_port = htons(PORT);
dest_addr.sin6_scope_id = esp_netif_get_netif_impl_index(EXAMPLE_INTERFACE);
addr_family = AF_INET6;
ip_protocol = IPPROTO_IPV6;
#elif defined(CONFIG_EXAMPLE_SOCKET_IP_INPUT_STDIN)
struct sockaddr_in6 dest_addr = { 0 };
ESP_ERROR_CHECK(get_addr_from_stdin(PORT, SOCK_STREAM, &ip_protocol, &addr_family, &dest_addr));
#endif
sock = socket(addr_family, SOCK_STREAM, ip_protocol);
if (sock < 0) {
ESP_LOGE(TAG, "Unable to create socket: errno %d", errno);
break;
}
ESP_LOGI(TAG, "Socket created, connecting to %s:%d", host_ip, PORT);
int err = connect(sock, (struct sockaddr *)&dest_addr, sizeof(struct sockaddr_in6));
if (err != 0) {
ESP_LOGE(TAG, "Socket unable to connect: errno %d", errno);
break;
}
ESP_LOGI(TAG, "Successfully connected");
while (1) {
int len = recv(sock, rx_buffer, sizeof(rx_buffer) - 1, 0);
if (len < 0) {
ESP_LOGE(TAG, "recv failed: errno %d", errno); // Error occurred during receiving
break;
}
// Data received
else {
rx_buffer[len] = 0; // Null-terminate whatever we received and treat like a string
sendData(TAG, rx_buffer);//转发给串口
// ESP_LOGI(TAG, "Received %d bytes from %s:", len, host_ip);
// ESP_LOGI(TAG, "%s", rx_buffer);
}
vTaskDelay(2000 / portTICK_PERIOD_MS);
}
if (sock != -1) {
ESP_LOGE(TAG, "Shutting down socket and restarting...");
shutdown(sock, 0);
close(sock);
}
}
vTaskDelete(NULL);
}
/* 系统事件循环处理函数 */
static void event_handler(void* arg, esp_event_base_t event_base,int32_t event_id, void* event_data)
{
static int retry_num = 0; /* 记录wifi重连次数 */
/* 系统事件为WiFi事件 */
if (event_base == WIFI_EVENT)
{
if(event_id == WIFI_EVENT_STA_START) /* 事件id为STA开始 */
esp_wifi_connect();
else if (event_id == WIFI_EVENT_STA_DISCONNECTED) /* 事件id为失去STA连接 */
{
esp_wifi_connect();
retry_num++;
printf("retry to connect to the AP %d times. \n",retry_num);
if (retry_num > 10) /* WiFi重连次数大于10 */
{
/* 将WiFi连接事件标志组的WiFi连接失败事件位置1 */
xEventGroupSetBits(wifi_event_group_handler, WIFI_FAIL_BIT);
}
/* 清除WiFi连接成功标志位 */
xEventGroupClearBits(wifi_event_group_handler, WIFI_CONNECTED_BIT);
}
}
/* 系统事件为ip地址事件,且事件id为成功获取ip地址 */
else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP)
{
ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data; /* 获取IP地址信息*/
printf("got ip:%d.%d.%d.%d \n" , IP2STR(&event->ip_info.ip)); /* 打印ip地址*/
retry_num = 0; /* WiFi重连次数清零 */
/* 将WiFi连接事件标志组的WiFi连接成功事件位置1 */
xEventGroupSetBits(wifi_event_group_handler, WIFI_CONNECTED_BIT);
}
/* 系统事件为智能配网事件 */
else if (event_base == SC_EVENT)
{
if(event_id == SC_EVENT_SCAN_DONE ) /* 开始扫描智能配网设备端 */
printf("Scan done\n");
else if(event_id == SC_EVENT_FOUND_CHANNEL) /* 得到了智能配网通道 */
printf("Found channel \n");
else if(event_id == SC_EVENT_GOT_SSID_PSWD) /* 得到了智能配网设备提供的ssid和password */
{
printf("smartconfig got SSID and password\n");
/* 获取智能配网设备端提供的数据信息 */
smartconfig_event_got_ssid_pswd_t *evt = (smartconfig_event_got_ssid_pswd_t *)event_data;
/* 定义WiFi配置结构体和用了结收ssid和password的数组 */
wifi_config_t wifi_config;
char ssid[32] = { 0 };
char password[64] = { 0 };
bzero(&wifi_config, sizeof(wifi_config_t)); /* 将结构体数据清零 */
/* 将智能配网设备发送来的WiFi的ssid、password及MAC地址复制到wifi_config */
memcpy(wifi_config.sta.ssid, evt->ssid, sizeof(wifi_config.sta.ssid));
memcpy(wifi_config.sta.password, evt->password, sizeof(wifi_config.sta.password));
wifi_config.sta.bssid_set = evt->bssid_set;
if (wifi_config.sta.bssid_set == true) {
memcpy(wifi_config.sta.bssid, evt->bssid, sizeof(wifi_config.sta.bssid));
}
/* 打印WiFi名称和密码 */
memcpy(ssid, evt->ssid, sizeof(evt->ssid));
memcpy(password, evt->password, sizeof(evt->password));
printf("SSID:%s \n", ssid);
printf("PASSWORD:%s \n", password);
/* 将得到的WiFi名称和密码存入NVS*/
nvs_handle wificfg_nvs_handler;
ESP_ERROR_CHECK( nvs_open("WiFi_cfg", NVS_READWRITE, &wificfg_nvs_handler) );
ESP_ERROR_CHECK( nvs_set_str(wificfg_nvs_handler,"wifi_ssid",ssid) );
ESP_ERROR_CHECK( nvs_set_str(wificfg_nvs_handler,"wifi_passwd",password) );
ESP_ERROR_CHECK( nvs_commit(wificfg_nvs_handler) ); /* 提交 */
nvs_close(wificfg_nvs_handler); /* 关闭 */
printf("smartconfig save wifi_cfg to NVS .\n");
/* 根据得到的WiFi名称和密码连接WiFi*/
ESP_ERROR_CHECK( esp_wifi_disconnect() );
ESP_ERROR_CHECK( esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config) );
ESP_ERROR_CHECK( esp_wifi_connect() );
}
else if (event_id == SC_EVENT_SEND_ACK_DONE) /* 智能配网成功,已经给智能配网设备发送应答*/
{
xEventGroupSetBits(wifi_event_group_handler, SMART_CONFIG_BIT);
}
}
}
static void smartconfig_init_start(void)
{
/* 设置智能配网类型为 AirKiss */
ESP_ERROR_CHECK( esp_smartconfig_set_type(SC_TYPE_AIRKISS) );
/* 通过SMARTCONFIG_START_CONFIG_DEFAULT宏 来获取一个默认的smartconfig配置参数结构体变量*/
smartconfig_start_config_t cfg = SMARTCONFIG_START_CONFIG_DEFAULT();
/* 开始智能配网 */
ESP_ERROR_CHECK( esp_smartconfig_start(&cfg) );
printf("smartconfig start ....... \n");
/* 使用事件标志组等待连接建立(WIFI_CONNECTED_BIT)或连接失败(WIFI_FAIL_BIT)事件 */
EventBits_t uxBits; /* 定义一个事件位变量来接收事件标志组等待函数的返回值 */
/* 等待事件标志组,退出前清除设置的事件标志,任意置1就会返回*/
while(1){
uxBits = xEventGroupWaitBits(wifi_event_group_handler, WIFI_CONNECTED_BIT | SMART_CONFIG_BIT,
true, false, portMAX_DELAY);
if(uxBits & WIFI_CONNECTED_BIT)
{
printf("WiFi Connected to ap ok. \n");
esp_smartconfig_stop(); /* 关闭智能配网 */
}
if(uxBits & SMART_CONFIG_BIT)
{
printf("smartconfig over \n");
esp_smartconfig_stop(); /* 关闭智能配网 */
esp_timer_start_periodic(test_p_handle, 1000 * 1000); //指示灯闪烁
xTaskCreate(tcp_client_task, "tcp_client", 4096, NULL, 5, NULL); //连接tcp服务
}
}
}
static void initialise_wifi(void)
{
ESP_ERROR_CHECK(esp_netif_init());/* 初始化底层TCP/IP堆栈。在应用程序启动时,应该调用此函数一次。*/
wifi_event_group_handler = xEventGroupCreate(); /* 创建一个事件标志组 */
ESP_ERROR_CHECK(esp_event_loop_create_default());/* 创建默认事件循环,*/
esp_netif_t *sta_netif = esp_netif_create_default_wifi_sta();/* 创建一个默认的WIFI-STA网络接口,如果初始化错误,此API将中止。*/
assert(sta_netif);
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); /* 使用WIFI_INIT_CONFIG_DEFAULT() 来获取一个默认的wifi配置参数结构体变量*/
ESP_ERROR_CHECK( esp_wifi_init(&cfg) ); /* 根据cfg参数初始化wifi连接所需要的资源 */
/* 将事件处理程序注册到系统默认事件循环,分别是WiFi事件、IP地址事件及smartconfig事件 */
ESP_ERROR_CHECK( esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL) );
ESP_ERROR_CHECK( esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL) );
ESP_ERROR_CHECK( esp_event_handler_register(SC_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL) );
nvs_handle wificfg_nvs_handler; /* 定义一个NVS操作句柄 */
char wifi_ssid[32] = { 0 }; /* 定义一个数组用来存储ssid*/
char wifi_passwd[64] = { 0 }; /* 定义一个数组用来存储passwd */
size_t len;
/* 打开一个NVS命名空间 */
ESP_ERROR_CHECK( nvs_open("WiFi_cfg", NVS_READWRITE, &wificfg_nvs_handler) );
len = sizeof(wifi_ssid); /* 从NVS中获取ssid */
ESP_ERROR_CHECK( nvs_get_str(wificfg_nvs_handler,"wifi_ssid",wifi_ssid,&len) );
len = sizeof(wifi_passwd); /* 从NVS中获取ssid */
ESP_ERROR_CHECK( nvs_get_str(wificfg_nvs_handler,"wifi_passwd",wifi_passwd,&len) );
ESP_ERROR_CHECK( nvs_commit(wificfg_nvs_handler) ); /* 提交 */
nvs_close(wificfg_nvs_handler); /* 关闭 */
/* 设置WiFi连接的ssid和password参数 */
wifi_config_t wifi_config;
bzero(&wifi_config, sizeof(wifi_config_t)); /* 将结构体数据清零 */
memcpy(wifi_config.sta.ssid, wifi_ssid, sizeof(wifi_config.sta.ssid));
memcpy(wifi_config.sta.password, wifi_passwd, sizeof(wifi_config.sta.password));
/* 设置WiFi的工作模式为 STA */
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA) );
/* 设置WiFi连接的参数,主要是ssid和password */
ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config));
/* 启动WiFi连接 */
ESP_ERROR_CHECK(esp_wifi_start());
printf("wifi_init_sta finished. \n");
/* 使用事件标志组等待连接建立(WIFI_CONNECTED_BIT)或连接失败(WIFI_FAIL_BIT)事件 */
EventBits_t bits; /* 定义一个事件位变量来接收事件标志组等待函数的返回值 */
bits = xEventGroupWaitBits( wifi_event_group_handler, /* 需要等待的事件标志组的句柄 */
WIFI_CONNECTED_BIT | WIFI_FAIL_BIT, /* 需要等待的事件位 */
pdFALSE, /* 为pdFALSE时,在退出此函数之前所设置的这些事件位不变,为pdFALSE则清零*/
pdFALSE, /* 为pdFALSE时,设置的这些事件位任意一个置1就会返回,为pdFALSE则需全为1才返回 */
portMAX_DELAY); /* 设置为最长阻塞等待时间,单位为时钟节拍 */
/* 根据事件标志组等待函数的返回值获取WiFi连接状态 */
if (bits & WIFI_CONNECTED_BIT) /* WiFi连接成功事件 */
{
printf("connected to ap %s OK \n",wifi_ssid);
vEventGroupDelete(wifi_event_group_handler); /* 删除WiFi连接事件标志组,WiFi连接成功后不再需要 */
esp_timer_start_periodic(test_p_handle, 1000 * 1000);
xTaskCreate(tcp_client_task, "tcp_client", 4096, NULL, 5, NULL);
}
else if (bits & WIFI_FAIL_BIT) /* WiFi连接失败事件 */
{
printf("Failed to connect to ap %s. \n",wifi_ssid);
smartconfig_init_start(); /* 开启智能配网 */
}
else
{
printf("UNEXPECTED EVENT \n"); /* 没有等待到事件 */
smartconfig_init_start(); /* 开启智能配网 */
}
}
static void app_init(void)
{
esp_log_level_set(TAG, ESP_LOG_INFO);
/* 初始化非易失性存储库 (NVS) */
esp_err_t err = nvs_flash_init();
if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
/* NVS分区被截断,需要删除,然后重新初始化NVS */
ESP_ERROR_CHECK(nvs_flash_erase());
err = nvs_flash_init();
}
ESP_ERROR_CHECK( err );
/* 定义一个NVS操作句柄 */
nvs_handle wificfg_nvs_handler;
/* 打开一个NVS命名空间 */
ESP_ERROR_CHECK( nvs_open("WiFi_cfg", NVS_READWRITE, &wificfg_nvs_handler) );
uint32_t wifi_update = 0;
err = nvs_get_u32(wificfg_nvs_handler,"wifi_update",&wifi_update);
if(MY_WIFI_UPDATE == wifi_update ) //最开始需要----是否更新wifi
printf("wifi_cfg needn't to update. \n");
else
{
printf("wifi_cfg update now... \n");
ESP_ERROR_CHECK( nvs_set_str(wificfg_nvs_handler,"wifi_ssid",MY_WIFI_SSID) );
ESP_ERROR_CHECK( nvs_set_str(wificfg_nvs_handler,"wifi_passwd",MY_WIFI_PASSWD) );
ESP_ERROR_CHECK( nvs_set_u32(wificfg_nvs_handler,"wifi_update",MY_WIFI_UPDATE) );
printf("wifi_cfg update ok. \n");
}
ESP_ERROR_CHECK( nvs_commit(wificfg_nvs_handler) ); /* 提交 */
nvs_close(wificfg_nvs_handler); /* 关闭 */
printf("ESP_WIFI_MODE_STA \n");
configure_led(); //led先初始化
esp_timer_init(); //使用定时器API函数,
err = esp_timer_create(&test_periodic_arg, &test_p_handle); // 开始创建一个重复周期的定时器并且执行先调用接口初始化
// err = esp_timer_start_periodic(test_p_handle, 1000 * 1000);
initialise_wifi();//初始化wifi
//串口初始化
uart_config_t uart_config = {
.baud_rate = 115200,
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
.source_clk = UART_SCLK_APB,
};
//Install UART driver, and get the queue.
uart_driver_install(EX_UART_NUM, BUF_SIZE * 2, BUF_SIZE * 2, 20, &uart0_queue, 0);
uart_param_config(EX_UART_NUM, &uart_config);
//Set UART pins (using UART0 default pins ie no changes.)
uart_set_pin(EX_UART_NUM, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
//uart_set_pin(EX_UART_NUM, TXD_PIN, RXD_PIN, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);//改变引脚
}
void app_main(void)
{
app_init();//外设初始化
xTaskCreate(rx_task, "uart_rx_task", 1024*2, NULL, configMAX_PRIORITIES, NULL);//串口接收任务
// vTaskDelay(1000 / portTICK_PERIOD_MS);
}
编译:Makefile与CMakelist让添加外部依赖
?收发结果:
?
?
?
|