博客
关于我
安信可ESP32-C3模组阿里云远程控制WS2812RGB灯条(基于ESP-IDF的SDK)
阅读量:389 次
发布时间:2019-03-05

本文共 9194 字,大约阅读时间需要 30 分钟。

前言

       ESP32-C3模组是4月初发布上线的一款双模(2.4GWiFi+BLE5.0)的通信模块,博主手上的是一款外置2M Flash的型号ESP32-C3F:

在这里插入图片描述
本文是在Linux 开发环境用的是乐鑫的ESP-IDF的master分 支的SDK基础上做的二次开发。 所以需要准备的软件:
               Linux 开发环境(当然Windos也是可以的,请参考: .)
               ESP-IDF: .(ESP-IDF的使用请参考 .)
注意: 在进行配置menuconifg 的时候需要把 Revision 设置为Rev2在这里插入图片描述
硬件准备:
              1、ESP32-C3F小开发板
              2、VB01离线语音模块
              3、WS2812 RGB灯条

一、新建工程文件

        把ESP-IDF中的一个空例程复制到自己工程目录中,空例程在ESP-IDF中的路径如下:

.../esp=idf/examples/get-started/sample_project

主函数文件就在该目录下的:main文件夹中的main.c

在这里插入图片描述

二、WS2812RGB驱动

        WS2812的驱动其实乐鑫的ESP-IDF中就做有相关的例程:…/examples/peripherals/rmt/led_strip,这个例程使用了RMT红外驱动,还连接了les_strip 驱动库(库路径:…/examples/common_components/led_strip)。但是那个例程无法驱动WS2812灯条,但是它的库却可以使用,所以要移植一下这个库。

1.led_strip 驱动库移植

       在main文件夹的同级目录下创建一个名为compornents的文件夹:

mkidr compornents

在这里插入图片描述

然后把/examples/common_components/ 下的 led_strip 文件夹全部复制到刚刚创建的compornents文件夹中 。并且在main.c中引用以下头文件:

#include "driver/rmt.h"#include "led_strip.h"#include "esp_system.h"#include "esp_log.h"

2.初始化WS2812 灯条

定义RMT发送管脚和频道及灯珠个数的宏

#define RMT_TX_NUM 3  //发送口#define RMT_TX_CHANNEL RMT_CHANNEL_0//发送频道#define LED_STRIP_NUM 24//灯珠数量
void init_led(){   	rmt_config_t config = RMT_DEFAULT_CONFIG_TX(RMT_TX_NUM, RMT_TX_CHANNEL);	// set counter clock to 40MHz	config.clk_div = 2;	ESP_ERROR_CHECK(rmt_config(&config));	ESP_ERROR_CHECK(rmt_driver_install(config.channel, 0, 0));	// install ws2812 driver	led_strip_config_t strip_config = LED_STRIP_DEFAULT_CONFIG(24, (led_strip_dev_t)config.channel);	strip = led_strip_new_rmt_ws2812(&strip_config);	if (!strip)	{   		ESP_LOGE(TAG, "install WS2812 driver failed");	}	// Clear LED strip (turn off all LEDs)	ESP_ERROR_CHECK(strip->clear(strip, 100));}

3.设置RGB颜色的函数

缓存颜色的结构体

struct WS2812_COLOR{   uint32_t red;uint32_t green ;uint32_t blue;};struct WS2812_COLOR WS2812_RGB;
void set_rgb(uint16_t Red, uint16_t Green, uint16_t Blue){   	for (int i = 0; i < LED_STRIP_NUM; i++)	{   		strip->set_pixel(strip, i, Red, Green, Blue);//设置颜色	}	WS2812_RGB.red = Red;	WS2812_RGB.green = Green;	WS2812_RGB.blue = Blue;	strip->refresh(strip, 10);}

三、UART 串口驱动与VB01通信

       UART通信同样也可以使用ESP-IDF的example,参考的例程在:examples/peripherals/uart/uart_async_rxtxtasks 目录之下。这个例程使用了FreeRTOS来管理UART的发送函数和接收函数,博主也照样使用了freeRTOSUART驱动这里只是使用了FreeRTOS 创建任务,并没有使用太多FreeRTOS的各种功能,所以对于不太熟悉FreeRTOS 的同学也不要怕。

1.串口初始化配置

同样的,先要引用一下相关头文件

/*********RTOS Handle-file****************/#include "freertos/FreeRTOS.h"#include "freertos/task.h"#include "freertos/event_groups.h"/*********UART Handle-file*****************/#include "driver/gpio.h"#include "driver/uart.h"

串口初始化配置函数:

void UART_Init(void){   	const uart_config_t uart_config = {   		.baud_rate =38400,  //波特率		.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,//时钟	};	// We won't use a buffer for sending data.	uart_driver_install(UART_NUM_1, RX_BUF_SIZE * 2, 0, 0, NULL, 0);	uart_param_config(UART_NUM_1, &uart_config);	uart_set_pin(UART_NUM_1, TXD_PIN, RXD_PIN, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);}

2.串口接收任务创建

       在主函数中初始化UART之后,就创建串口的接收数据的任务,提高数据接收的速度:

//开启串口接收任务xTaskCreate(uartRxTask, "uart_rx_task", 1024*3, NULL, 4, NULL);

任务函数:

static void uartRxTask(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(RX_BUF_SIZE+1);		while (1) {   		const int rxBytes = uart_read_bytes(UART_NUM_1, data, RX_BUF_SIZE, 1000 / portTICK_RATE_MS);		if (rxBytes > 0) {   			data[rxBytes] = 0;			ESP_LOGI(RX_TASK_TAG, "Read %d bytes: '%s'", rxBytes, data);			memset(cJson_data, 0, sizeof(cJson_data));			uartControlLedStrip(uartDataHandle(data));	//设置灯条颜色				ESP_LOG_BUFFER_HEXDUMP(RX_TASK_TAG, data, rxBytes, ESP_LOG_INFO);		}	}	free(data);}

说明

       uartControlLedStrip函数和uartDataHandle函数是博主自己写一个串口数据处理函数,目的是把串口接收的数据中提取控制RGB的指令或者数据,各位同学可通过自己的需求去写这样的函数,比如提取指令ID号,只是用一些字符串操作的函数就可以了。

四、WiFi 配置连接

       WiFi的配置连接极为简单,不需要些配置函数,也不需要写初始化函数,需要连接的WiFi名称和密码都可以通过menuconfig来配置。因为ESP-IDF的例程中,已经写好了相关的配置文件,只需要简单的修改就可以配置连接WiFi。

1.引入头文件并使用几个函数

(1)头文件的引用

/**********WiFI Handle-file**************/#include "esp_netif.h"#include "protocol_examples_common.h"#include "esp_wifi.h"#include "nvs_flash.h"

(2)在main()中使用以下函数

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_ERROR_CHECK(esp_netif_init());	/* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.	 * Read "Establishing Wi-Fi or Ethernet Connection" section in	 * examples/protocols/README.md for more information about this function.	 */	ESP_ERROR_CHECK(example_connect());

2.修改CMakefile.txt 文件

       在工程文件目录下,打开CMakefile文件并加入以下内容:

set(EXTRA_COMPONENT_DIRS $ENV{   IDF_PATH}/examples/common_components/protocol_examples_common)

在这里插入图片描述

3.运行idf.py menuconfig

在这里插入图片描述

在这里插入图片描述

idf.py flash //烧录程序进ESP32C3idf.py monitor //监控串口

获取到IP地址,连接成功。

在这里插入图片描述

五、MQTT 配置连接阿里云

1.阿里云接入要点

       本项目是使用阿里云远程控制RGB灯条,所以需要在阿里云物联网平台创建响应的产品和设备。创建方式请参考: .

       除此之外,还需要了解阿里云连接所需要的三元组与MQTT客户端和密码的关系。这个请参考:.中的一机一密接入

2.配置MQTT接入阿里云物联网平台

       博主是使用创建RTOS任务的方式来配置MQTT,因为在配置的过程中需要引入MQTT事件回调函数,该函数可以负责处理各个事件所要执行的动作,比如MQTT连接成功事件:MQTT_EVENT_CONNECTED;订阅成功事件:MQTT_EVENT_SUBSCRIBED等。当然收到数据事件也在其中。

       当MQTT有一个事件被触发的时候,就会跳到事件回调函数去执行相关事件下的动作。所以创建任务来管理是很有必要的。

(1)头文件

/***********MQTT Handle-file************/#include "mqtt_client.h"#include "lwip/sockets.h"#include "lwip/dns.h"#include "lwip/netdb.h"

(2) MQTT配置

void TaskXMqttRecieve(void *p){   	//连接的配置参数#if MQTT_LINK_Aliyum	sprintf(MQTT_LINK_USERNAME,"%s&%s",MQTT_DeviceName,MQTT_ProductKey);#endif	esp_mqtt_client_config_t mqtt_cfg = {   		.host = MQTT_LINK_HOST, 		//连接的域名 ,请务必修改为您的		.port = MQTT_LINK_PORT,              //端口,请务必修改为您的		.username = MQTT_LINK_USERNAME,       //用户名,请务必修改为您的		.password = MQTT_LINK_PASS,   //密码,请务必修改为您的		.client_id = MQTT_LINK_CLIENT_ID,		.event_handle = MqttCloudsCallBack, //设置回调函数		.keepalive = 120,                   //心跳		.disable_auto_reconnect = false,    //开启自动重连		.disable_clean_session = false,     //开启 清除会话	};	client = esp_mqtt_client_init(&mqtt_cfg);	esp_mqtt_client_start(client);	vTaskDelete(NULL);}

博主自己定义的宏

#define MQTT_LINK_HOST 		"www.baidu.com" //域名:改成自己的域名#define MQTT_LINK_PORT 		1883//端口//是否开启发布 1 为开启发布 0:关闭发布/***** 阿里云设备三元组 ************/#define MQTT_DeviceName "xxxxx"//设备名:改成你们自己的域名#define MQTT_ProductKey "xxxx"//char MQTT_LINK_USERNAME[128];#define MQTT_LINK_PASS 		"xxxxxxxxxxxxx"  //加过hmacmd5加密后的密码#define MQTT_LINK_CLIENT_ID	"改成自己的设备名|securemode=3,signmethod=hmacmd5|"//客户端ID 阿里云

域名查看方式:注意看鼠标箭头

在这里插入图片描述只有用户名,密码,MQTT客户端及域名都正确才能连上阿里云,物联网平台的设备才会是在线状态
在这里插入图片描述
如果一直不在线,请仔细阅读:.中的一机一密接入
在这里插入图片描述

3.主题订阅

       如果通过阿里云控制设备,就必须订阅阿里云的设备Topic

先查看以下阿里云的产品 ——>Topic类列表——>属性Topic 中的属性设置
在这里插入图片描述

Topic:/sys/g6oroz0VLBN/${deviceName}/thing/service/property/set

        这个Topic中,

                     “g6oroz0VLBN” 是产品的:ProductKey
                     “${deviceName}” 是设备名:DeviceName
比如现有有以下设备信息:ProductKey = abcdf12;DeviceName=asdvsa。那么该Topic就是:/sys/abcdf12/asdvsa/thing/service/property/set。
       
       订阅主题的代码:

sprintf(MqttTopicSub, "/sys/%s/%s/thing/service/property/set",MQTT_ProductKey,MQTT_DeviceName);	ESP_LOGI(TAG, "MqttTopicSub: %s", MqttTopicSub);	//ESP_LOGI(TAG, "MqttTopicPub: %s", MqttTopicPub);	ESP_ERROR_CHECK(esp_event_loop_create_default());

4.事件回调函数中的数据接收事件

case MQTT_EVENT_DATA:			{   				printf("TOPIC=%.*s \r\n", event->topic_len, event->topic);				printf("DATA=%.*s \r\n\r\n", event->data_len, event->data);				//发送数据到队列				struct __User_data *pTmper;				memset(&user_data,0,sizeof(struct __User_data));				sprintf(user_data.allData, "%.*s",event->data_len,event->data);				pTmper = &user_data;				user_data.dataLen = event->data_len;				//把数据发送到消息队列				xQueueSend(ParseJSONQueueHandler, (void *)&pTmper, portMAX_DELAY);				break;			}

5.消息队列处理函数

void Task_ParseJSON(void *pvParameters){   	printf("[SY] Task_ParseJSON_Message creat ... \n");	while (1)	{   		struct __User_data *pMqttMsg;		printf("Task_ParseJSON_Message xQueueReceive wait [%d] ... \n", esp_get_free_heap_size());		xQueueReceive(ParseJSONQueueHandler, &pMqttMsg, portMAX_DELAY);		printf("Task_ParseJSON_Message xQueueReceive get [%s] ... \n", pMqttMsg->allData);		首先整体判断是否为一个json格式的数据		cJSON *pJsonRoot = cJSON_Parse(pMqttMsg->allData);		//如果是否json格式数据		if (pJsonRoot == NULL)		{   			printf("[SY] Task_ParseJSON_Message xQueueReceive not json ... \n");			goto __cJSON_Delete;		}		cJSON *pJsonParams = cJSON_GetObjectItem(pJsonRoot,"params");		if(pJsonParams==NULL){   			printf("pJsonParams NULL\r\n");			goto __cJSON_Delete;		}		cJSON *pJsonGRB =cJSON_GetObjectItem(pJsonParams,"RGB");		if(pJsonGRB==NULL) goto __cJSON_Delete;		cJSON *pJSON_Item_Red = cJSON_GetObjectItem(pJsonGRB, "R");		cJSON *pJSON_Item_Gree = cJSON_GetObjectItem(pJsonGRB, "G");		cJSON *pJSON_Item_Blue = cJSON_GetObjectItem(pJsonGRB, "B");		//设置RGB颜色		set_rgb(pJSON_Item_Red->valueint, pJSON_Item_Gree->valueint, pJSON_Item_Blue->valueint);		//播放提示音		if(WS2812_RGB.red!=0&&WS2812_RGB.green!=0&&WS2812_RGB.blue!=0);		else uart_write_bytes(UART_NUM_1,"AT+PLAY=21\r\n",13);//播放:已经打开灯了		if(WS2812_RGB.red!=254&&WS2812_RGB.green!=254&&WS2812_RGB.blue!=254)goto __cJSON_Delete;		else uart_write_bytes(UART_NUM_1,"AT+PLAY=22\r\n",13);//播放:已经关灯了		__cJSON_Delete:		cJSON_Delete(pJsonRoot);	}}

六、相关文档

感谢

1.的.

2. .

3.:https://github.com/espressif/esp-idf.git

4.本文源码地址:.

转载地址:http://ltlwz.baihongyu.com/

你可能感兴趣的文章
Mysql 会导致锁表的语法
查看>>
mysql 使用sql文件恢复数据库
查看>>
mysql 修改默认字符集为utf8
查看>>
Mysql 共享锁
查看>>
MySQL 内核深度优化
查看>>
mysql 内连接、自然连接、外连接的区别
查看>>
mysql 写入慢优化
查看>>
mysql 分组统计SQL语句
查看>>
Mysql 分页
查看>>
Mysql 分页语句 Limit原理
查看>>
MySql 创建函数 Error Code : 1418
查看>>
MySQL 创建新用户及授予权限的完整流程
查看>>
mysql 创建表,不能包含关键字values 以及 表id自增问题
查看>>
mysql 删除日志文件详解
查看>>
mysql 判断表字段是否存在,然后修改
查看>>
MySQL 到底能不能放到 Docker 里跑?
查看>>
mysql 前缀索引 命令_11 | Mysql怎么给字符串字段加索引?
查看>>
MySQL 加锁处理分析
查看>>
mysql 协议的退出命令包及解析
查看>>
mysql 参数 innodb_flush_log_at_trx_commit
查看>>