首页
统计
壁纸
友链
关于
留言
Search
1
我的博客终于正式上线了!
360 阅读
2
ESP32_I2C通讯协议的SHT40温湿度传感器
309 阅读
3
Joe — 一款个人类型Typecho主题
188 阅读
4
使用 VS Code 快速搭建 ESP-IDF 开发环境
157 阅读
5
ESP32_定时器的简单使用
154 阅读
心情日记
建站笔记
软件资源
ESP32
VsCode
Arduino
登录
Search
冇雨
累计撰写
13
篇文章
累计收到
0
条评论
首页
栏目
心情日记
建站笔记
软件资源
ESP32
VsCode
Arduino
页面
统计
壁纸
友链
关于
留言
搜索到
13
篇与
的结果
2024-12-04
ESP32_RMT驱动DHT11
DHT.c文件#include <freertos/FreeRTOS.h> #include <freertos/task.h> #include <driver/rmt_rx.h> #include <driver/rmt_tx.h> #include <soc/rmt_reg.h> #include "esp_log.h" #include "driver/gpio.h" #include "esp_system.h" #include "esp32/rom/ets_sys.h" #define TAG "DHT11" int DHT11_IO =25; //rmt接收通道句柄 static rmt_channel_handle_t rx_chan_handle = NULL; //数据接收队列 static QueueHandle_t rx_receive_queue = NULL; // 将RMT读取到的脉冲数据处理为温度和湿度 static int parse_items(rmt_symbol_word_t *item, int item_num, int *humidity, int *temp_x10); //接收完成回调函数 static bool IRAM_ATTR example_rmt_rx_done_callback(rmt_channel_handle_t channel, const rmt_rx_done_event_data_t *edata, void *user_data) { BaseType_t high_task_wakeup = pdFALSE; QueueHandle_t rx_receive_queue = (QueueHandle_t)user_data; // send the received RMT symbols to the parser task xQueueSendFromISR(rx_receive_queue, edata, &high_task_wakeup); return high_task_wakeup == pdTRUE; } /** DHT11初始化 * @param DHT11_IO GPIO引脚 * @return 无 */ void DHT11_Init() { rmt_rx_channel_config_t rx_chan_config = { .clk_src = RMT_CLK_SRC_APB, // 选择时钟源 .resolution_hz = 1000 * 1000, // 1 MHz 滴答分辨率,即 1 滴答 = 1 µs .mem_block_symbols = 64, // 内存块大小,即 64 * 4 = 256 字节 .gpio_num = DHT11_IO, // GPIO 编号 .flags.invert_in = false, // 不反转输入信号 .flags.with_dma = false, // 不需要 DMA 后端(ESP32S3才有) }; //创建rmt接收通道 ESP_ERROR_CHECK(rmt_new_rx_channel(&rx_chan_config, &rx_chan_handle)); //新建接收数据队列 rx_receive_queue = xQueueCreate(20, sizeof(rmt_rx_done_event_data_t)); assert(rx_receive_queue); //注册接收完成回调函数 ESP_LOGI(TAG, "register RX done callback"); rmt_rx_event_callbacks_t cbs = { .on_recv_done = example_rmt_rx_done_callback, }; ESP_ERROR_CHECK(rmt_rx_register_event_callbacks(rx_chan_handle, &cbs, rx_receive_queue)); //使能RMT接收通道 ESP_ERROR_CHECK(rmt_enable(rx_chan_handle)); } // 将RMT读取到的脉冲数据处理为温度和湿度(rmt_symbol_word_t称为RMT符号) static int parse_items(rmt_symbol_word_t *item, int item_num, int *humidity, int *temp_x10) { int i = 0; unsigned int rh = 0, temp = 0, checksum = 0; if (item_num < 41){ // 检查是否有足够的脉冲数 //ESP_LOGI(TAG, "item_num < 41 %d",item_num); return 0; } if(item_num > 41) item++; // 跳过开始信号脉冲 for (i = 0; i < 16; i++, item++) // 提取湿度数据 { uint16_t duration = 0; if(item->level0) duration = item->duration0; else duration = item->duration1; rh = (rh << 1) + (duration < 35 ? 0 : 1); } for (i = 0; i < 16; i++, item++) // 提取温度数据 { uint16_t duration = 0; if(item->level0) duration = item->duration0; else duration = item->duration1; temp = (temp << 1) + (duration < 35 ? 0 : 1); } for (i = 0; i < 8; i++, item++){ // 提取校验数据 uint16_t duration = 0; if(item->level0) duration = item->duration0; else duration = item->duration1; checksum = (checksum << 1) + (duration < 35 ? 0 : 1); } // 检查校验 if ((((temp >> 8) + temp + (rh >> 8) + rh) & 0xFF) != checksum){ ESP_LOGI(TAG, "Checksum failure %4X %4X %2X\n", temp, rh, checksum); return 0; } // 返回数据 rh = rh >> 8; temp = (temp >> 8) * 10 + (temp & 0xFF); //判断数据合法性 if(rh <= 100) *humidity = rh; if(temp <= 600) *temp_x10 = temp; return 1; } /** 获取DHT11数据 * @param temp_x10 温度值 * @return 无 */ int DHT11_StartGet(int *temp_x10, int *humidity) { //发送20ms开始信号脉冲启动DHT11单总线 gpio_set_direction(DHT11_IO, GPIO_MODE_OUTPUT); gpio_set_level(DHT11_IO, 1); ets_delay_us(1000); gpio_set_level(DHT11_IO, 0); ets_delay_us(20000); //拉高20us gpio_set_level(DHT11_IO, 1); ets_delay_us(20); //信号线设置为输入准备接收数据 gpio_set_direction(DHT11_IO, GPIO_MODE_INPUT); gpio_set_pull_mode(DHT11_IO,GPIO_PULLUP_ONLY); //启动RMT接收器以获取数据 rmt_receive_config_t receive_config = { .signal_range_min_ns = 100, //最小脉冲宽度(0.1us),信号长度小于这个值,视为干扰 .signal_range_max_ns = 1000*1000, //最大脉冲宽度(1000us),信号长度大于这个值,视为结束信号 }; static rmt_symbol_word_t raw_symbols[128]; //接收缓存 static rmt_rx_done_event_data_t rx_data; //实际接收到的数据 ESP_ERROR_CHECK(rmt_receive(rx_chan_handle, raw_symbols, sizeof(raw_symbols), &receive_config)); // wait for RX done signal if (xQueueReceive(rx_receive_queue, &rx_data, pdMS_TO_TICKS(1000)) == pdTRUE) { // parse the receive symbols and print the result return parse_items(rx_data.received_symbols, rx_data.num_symbols,humidity, temp_x10); } return 0; }DHT.h文件#ifndef _DHT11_H_ #define _DHT11_H_ #include <stdint.h> /** DHT11初始化 * @param dht11_pin GPIO引脚 * @return 无 */ void DHT11_Init(); /** 获取DHT11数据 * @param temp_x10 温度值X10 * @param humidity 湿度值 * @return 无 */ int DHT11_StartGet(int *temp_x10, int *humidity); #endif
2024年12月04日
23 阅读
0 评论
0 点赞
2024-11-22
ESP32_UART串口通讯
#include <stdio.h> #include <inttypes.h> #include "sdkconfig.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "driver/ledc.h" #include "driver/uart.h" #include "driver/gpio.h" #include "string.h" //UART1 #define RX1_BUF_SIZE 1024 #define TX1_BUF_SIZE 512 #define RXD1_PIN 16 #define TXD1_PIN 17 //串口配置函数 void uart_init() { //UART1结构体配置 uart_config_t uart1_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,//硬件流控 }; //绑定串口 uart_param_config(UART_NUM_0,&uart1_config); //映射IO口 uart_set_pin(UART_NUM_0,UART_PIN_NO_CHANGE,UART_PIN_NO_CHANGE,UART_PIN_NO_CHANGE,UART_PIN_NO_CHANGE); //注册串口服务即使能+设置缓存区大小 uart_driver_install(UART_NUM_0, RX1_BUF_SIZE * 2, TX1_BUF_SIZE * 2, 0, NULL, 0); } /* * 串口1接收任务 */ void uart1_rx_task() { uint8_t* data = (uint8_t*) malloc(RX1_BUF_SIZE+1);//分配内存,用于串口接收 while (1) { //获取串口1接收的数据 const int rxBytes = uart_read_bytes(UART_NUM_0, data, RX1_BUF_SIZE, 10 / portTICK_PERIOD_MS); if (rxBytes > 0) { data[rxBytes] = 0;//在串口接收的数据增加结束符 //将接收到的数据发出去 uart_write_bytes(UART_NUM_0, (char *)data, rxBytes); } } free(data);//释放申请的内存 } void app_main(void) { uart_init(); //创建串口1接收任务 xTaskCreate(uart1_rx_task, "uart1_rx_task", 1024*2, NULL, 1, NULL); //串口1数据发送测试 uart_write_bytes(UART_NUM_0, "uart1 test OK ", strlen("uart1 test OK ")); }
2024年11月22日
45 阅读
0 评论
0 点赞
2024-11-14
ESP32_PWM驱动SG90舵机
#include <stdio.h> #include <sdkconfig.h> #include <driver/ledc.h> #include <driver/gpio.h> #include <esp_log.h> #include <freertos/FreeRTOS.h> #include <freertos/task.h> #define LED_IO 2 //pwm1引脚 #define LED_IO2 4 //pwm2引脚 #define LEDC_MAX_DUTY (1023) //最大占空比,2的13次方 #define LEDC_FADE_TIME 300 //渐变时间 ledc_channel_config_t ledc_con; //声明结构体函数 void ledc_init(void) { //设置LED定时器 ledc_timer_config_t ledc_timer = { .duty_resolution = LEDC_TIMER_10_BIT, //设置PWM分辨率 .freq_hz = 50 , //设置频率 .speed_mode = LEDC_HIGH_SPEED_MODE,//设置为高速模式 .timer_num = LEDC_TIMER_0,//选择定时器 }; //启动定时器的PWM模式 ledc_timer_config(&ledc_timer); //LED 灯结构体配置 ledc_con.channel = LEDC_CHANNEL_0;//pwm通道 ledc_con.duty = 0;//占空比 ledc_con.gpio_num = LED_IO; //选择IO口 ledc_con.speed_mode = LEDC_HIGH_SPEED_MODE; //选择高速通道 ledc_con.timer_sel = LEDC_TIMER_0; //选择定时器 ledc_channel_config(&ledc_con); //安装LED渐变 ledc_fade_func_install(0); //初始化给舵机默认位置为0度 ledc_set_duty_and_update(LEDC_HIGH_SPEED_MODE,LEDC_CHANNEL_0,77,0); vTaskDelay(LEDC_FADE_TIME / portTICK_PERIOD_MS); } void app_main(void) { //选择IO口 esp_rom_gpio_pad_select_gpio(LED_IO); esp_rom_gpio_pad_select_gpio(LED_IO2); //设置IO口 gpio_set_direction(LED_IO,GPIO_MODE_OUTPUT); gpio_set_direction(LED_IO2,GPIO_MODE_OUTPUT); gpio_set_level(LED_IO2,1); //定时器、LED灯初始化 ledc_init(); while (1) { //逆时针旋转45度 ledc_set_duty_and_update(LEDC_HIGH_SPEED_MODE,LEDC_CHANNEL_0,51,0); vTaskDelay(LEDC_FADE_TIME / portTICK_PERIOD_MS); //顺时针时针旋转45度 ledc_set_duty_and_update(LEDC_HIGH_SPEED_MODE,LEDC_CHANNEL_0,102,0); vTaskDelay(LEDC_FADE_TIME / portTICK_PERIOD_MS); } }
2024年11月14日
23 阅读
0 评论
1 点赞
2023-10-26
ESP32_I2C通讯协议的SHT40温湿度传感器
I2C通讯协议简介 I2C 通讯协议(Inter-Integrated Circuit)是由 Phiilps 公司开发的,由于它引脚少,硬件实现简单,可扩展性强,不需要 USART、CAN 等通讯协议的外部收发设备,现在被广泛地使用在系统内多个集成电路(IC)间的通讯。下面我们分别对 I2C 协议的物理层及协议层进行讲解。1.物理层2C 通讯设备之间的常用连接方式通讯结构如下{mtitle title="I2C总线物理拓扑图"/}它的物理层有以下几个主要特点:1.支持多设备的总线。“总线”指多个设备共用的信号线。在一个 I2C 通讯总线中,可连接多个 I2C 通讯设备,支持多个通讯主机及多个通讯从机。2.支持多设备的总线。“总线”指多个设备共用的信号线。在一个 I2C 通讯总线中,可连接多个 I2C 通讯设备,支持多个通讯主机及多个通讯从机。3.每个连接到总线的设备都有一个唯一的地址,主机利用这个地址在不同设备之间的访问。4.总线通过上拉电阻接到电源。当 I2C 设备空闲时,会输出高阻态,而当所有设备都空闲,都输出高阻态时,由上拉电阻把总线拉成高电平。多个主机同时使用总线时,为了防止数据冲突,会利用仲裁方式决定由哪个设备占用总线。5.常用的速率:标准模式传输速率为 100kbit/s ,快速模式为 400kbit/s。6.最近 I3C 出来了,性能提升大大的2.协议层 I2C的协议定义了通讯的起始和停止信号、数据有效性、响应、仲裁、时钟同步和地址广播等环节。I2C通讯过程的基本结构如下:1.I2C写格式2.I2C读格式3.I2C读写格式I2C 的几个细节如下:1.I2C 的起始和停止信号 前文中提到的起始(S)和停止(P)信号是两种特殊的状态,见图 23-5。当 SCL 线是高电平时 SDA 线从高电平向低电平切换,这个情况表示通讯的起始。当 SCL 是高电平时 SDA 线由低电平向高电平切换,表示通讯的停止。起始和停止信号一般由主机产生。2.数据有效性 I2C 使用 SDA 信号线来传输数据,使用 SCL 信号线进行数据同步。SDA 数据线在 SCL的每个时钟周期传输一位数据。传输时,SCL 为高电平的时候 SDA 表示的数据有效,即此时的 SDA 为高电平时表示数据“1”,为低电平时表示数据“0”。当 SCL 为低电平时,SDA 的数据无效,一般在这个时候 SDA 进行电平切换,为下一次表示数据做好准备。 每次数据传输都以字节为单位,每次传输的字节数不受限制。3.地址及数据方向 I2C 总线上的每个设备都有自己的独立地址,主机发起通讯时,通过 SDA 信号线发送设备地(SLAVE_ADDRESS)来查找从机。I2C 协议规定设备地址可以是 7 位或 10 位,实际中 7位的地址应用比较广泛。紧跟设备地址的一个数据位用来表示数据传输方向,它是数据方向位(R/W),第 8 位或第 11 位。数据方向位为“1”时表示主机由从机读数据,该位为“0”时表示主机向从机写数据 读数据方向时,主机会释放对 SDA 信号线的控制,由从机控制 SDA 信号线,主机接收信号,写数据方向时,SDA 由主机控制,从机接收信号。4.响应 I2C 的数据和地址传输都带响应。响应包括“应答(ACK)”和“非应答(NACK)”两种信号。作为数据接收端时,当设备(无论主从机)接收到 I2C 传输的一个字节数据或地址后,若希望对方继续发送数据,则需要向对方发送“应答(ACK)”信号,发送方会继续发送下一个数据;若接收端希望结束数据传输,则向对方发送“非应答(NACK)”信号,发送方接收到该信号后会产生一个停止信号,结束信号传输。 传输时主机产生时钟,在第 9 个时钟时,数据发送端会释放 SDA 的控制权,由数据接收端控制 SDA,若 SDA 为高电平,表示非应答信号(NACK),低电平表示应答信号(ACK)。 抄了这么多理论其实没什么用,因为 ESP32 带硬件 I2C,只要调用相关 API 即可,用起来非常简单。::(喷)SHT40温湿度传感器参数介绍SHT40温湿度测试范围参数精度相对湿度精度±1.5%RH温度精度高达±0.1°C电源电压1.08 V…3.6 V平均电流0.4µA(平均速率1Hz)工作范围0…100 %RH, -40…125 °CSHT40读写时序硬件设计及原理 本实验板使用了 ESP32 的 I2C_0,下表是我们的程序 IO 的映射。名称功能映射引脚SCL时钟IO22SDA数据IO213V3电源正极3V3GND电源负极GND软件设计代码逻辑代码编写#include <stdio.h> #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "esp_err.h" #include "esp_log.h" #include "driver/i2c.h" #define I2C_MASTER_SCL 22 // I2C专用时钟线GPIO #define I2C_MASTER_SDA 21 // I2C专用时钟线GPIO #define I2C_MASTER_NUM 0 // I2C总线号 #define I2C_MASTER_FREQ_HZ 400*1000 // I2C总线频率 uint8_t c=0xFD;//传感器操作指令 void I2C_Intal()//I2C初始化 { i2c_config_t conf =//i2c结构配置 { .mode = I2C_MODE_MASTER, //I2C运行模式 .sda_io_num = I2C_MASTER_SDA, //SDA串口 .sda_pullup_en =GPIO_PULLUP_ENABLE, //SDA使能 .scl_io_num = I2C_MASTER_SCL, //SCL串口 .scl_pullup_en = GPIO_PULLUP_ENABLE, //SCL使能 .master.clk_speed = I2C_MASTER_FREQ_HZ //I2C总线频率 }; i2c_param_config(I2C_MASTER_NUM,&conf);//配置I2C绑定 i2c_driver_install(I2C_MASTER_NUM, I2C_MODE_MASTER, 0, 0, 0);//I2C安装 printf("i2c_driver_install is ok\n"); } int I2C_ad()//寻找I2C子设备地址 { int address; for (address = 0x03; address < 0x77; address++) { i2c_cmd_handle_t cmd =i2c_cmd_link_create();//创建I2C句柄 i2c_master_start(cmd);//写启动信号到缓冲函数 i2c_master_write_byte(cmd,(address<<1) | I2C_MASTER_WRITE,I2C_MASTER_NACK);//写一个字节的命令道缓存函数 i2c_master_stop(cmd);//写停止信号到缓冲函数 esp_err_t ert = i2c_master_cmd_begin(I2C_MASTER_NUM,cmd,100);//I2C发送函数 if (ert == ESP_OK) { printf("Device found at address 0x%02X\n", address);//将寻找到的设备地址打印输出 } i2c_cmd_link_delete(cmd);//删除I2C连接函数 vTaskDelay(10); } return address; } void I2C_read()//接收传感器数据 { while (1) { //I2C地址的写入操作 i2c_cmd_handle_t cmd = i2c_cmd_link_create(); i2c_master_start(cmd); i2c_master_write_byte(cmd,(0x44 << 1) | I2C_MASTER_WRITE ,I2C_MASTER_NACK); i2c_master_write(cmd,&c,1,I2C_MASTER_NACK); i2c_master_stop(cmd); esp_err_t ert = i2c_master_cmd_begin(I2C_MASTER_NUM,cmd, 50 /portTICK_PERIOD_MS); i2c_cmd_link_delete(cmd); if (ert != ESP_OK) { ESP_LOGE("Tag:","%dI2C Write failed.....\n",ert); } vTaskDelay(50 /portTICK_PERIOD_MS); //进行I2C的读取操作 uint8_t I2C_data[6]={0,0,0,0,0,0};//用于存储数据 cmd = i2c_cmd_link_create(); i2c_master_start(cmd); i2c_master_write_byte(cmd,(0x44 <<1) | I2C_MASTER_READ ,I2C_MASTER_NACK); for (int i = 0; i < 6; i++) { i2c_master_read_byte(cmd,&I2C_data[i],I2C_MASTER_ACK);//将所读数据存储在数组 } i2c_master_stop(cmd); ert = i2c_master_cmd_begin(I2C_MASTER_NUM,cmd,50 / portTICK_PERIOD_MS); i2c_cmd_link_delete(cmd); if (ert == ESP_OK) { for (int i = 0; i < 6; i++) { printf(" %d ",I2C_data[i]); } printf("\n"); //温度、湿度的数值计算 float t_ticks = (uint16_t)I2C_data[0]*256+(uint16_t)I2C_data[1]; float rh_ticks = (uint16_t)I2C_data[3]*256+(uint16_t)I2C_data[4]; float temperature =-45+175.0*t_ticks / 65535.0; float humidity =-6+125.0*rh_ticks / 65535.0; ESP_LOGI("温度","%.2lf",temperature); ESP_LOGI("湿度","%.2lf",humidity); } vTaskDelay(400); } i2c_driver_delete(I2C_MASTER_NUM);//删除I2C功能 } void app_main() { I2C_Intal();//I2C初始化 I2C_ad();//I2C寻址 I2C_read();//接收数据消息 }{mtitle title="效果图"/}
2023年10月26日
309 阅读
0 评论
0 点赞
2023-09-29
ESP32_UART的简单使用
串口协议简介 串口通讯(Serial Communication)是一种设备间非常常用的串行通讯方式,因为它简单便捷,大部分电子设备都支持该通讯方式,电子工程师在调试设备时也经常使用该通讯方式输出调试信息,ESP32 自有一个串口用于程序下载和 log 打印,就是这个道理。 在计算机科学里,大部分复杂的问题都可以通过分层来简化。如芯片被分为内核层和片上外设;对于通讯协议,我们也以分层的方式来理解,最基本的是把它分为物理层和协议层。物理层规定通讯系统中具有机械、电子功能部分的特性,确保原始数据在物理媒体的传输。协议层主要规定通讯逻辑,统一收发双方的数据打包、解包标准。简单来说物理层规定我们用嘴巴还是用肢体来交流,协议层则规定我们用中文还是英文来交流物理层 串口通讯的物理层有很多标准及变种,我们主要讲解 RS-232 标准 ,RS-232 标准主要规定了信号的用途、通讯接口以及信号的电平标准。使用 RS-232 标准的串口设备间常见的通讯结构如下 在上面的通讯方式中,两个通讯设备的“DB9 接口”之间通过串口信号线建立起连接,串口信号线中使用“RS-232 标准”传输数据信号。由于 RS-232 电平标准的信号不能直接被控制器直接识别,所以这些信号会经过一个“电平转换芯片”转换成控制器能识别的“TTL校准”的电平信号,才能实现通讯。协议层 串口通讯的数据包由发送设备通过自身的 TXD 接口传输到接收设备的 RXD 接口。在串口通讯的协议层中,规定了数据包的内容,它由启始位、主体数据、校验位以及停止位组成,通讯双方的数据包格式要约定一致才能正常收发数据,其组成如下:1.波特率 文中主要讲解的是串口异步通讯,异步通讯中由于没有时钟信号(如前面讲解的 DB9接口中是没有时钟信号的),所以两个通讯设备之间需要约定好波特率,即每个码元的长度,以便对信号进行解码,上图中用虚线分开的每一格就是代表一个码元。常见的波特率为 4800、9600、115200 等2.通讯的起始和停止信号 串口通讯的一个数据包从起始信号开始,直到停止信号结束。数据包的起始信号由一个逻辑 0 的数据位表示,而数据包的停止信号可由 0.5、1、1.5 或 2 个逻辑 1 的数据位表示,只要双方约定一致即可。3.有效数据 在数据包的起始位之后紧接着的就是要传输的主体数据内容,也称为有效数据,有效数据的长度常被约定为 5、6、7 或 8 位长4.数据校验在有效数据之后,有一个可选的数据校验位。由于数据通信相对更容易受到外部干扰导致传输数据出现偏差,可以在传输过程加上校验位来解决这个问题。校验方法有奇校验(odd)、偶校验(even)、0 校验(space)、1 校验(mark)以及无校验(noparity)。在无校验的情况下,数据包中不包含校验位硬件设计及原理设备连接UART1功能映射 ESP32 的引脚TTL转串口引脚TX发送1RXRX接收3TX3V3供电 VCCGND接地 GND 若使用的实验板 UART 的连接方式或引脚不一样,只需根据工程修改引脚即可,程序的控制原理相同。 {mtitle title="实现效果图"/}软件设计 #include <stdio.h> #include "freertos/FreeRTOS.h"//freertos系统文件 #include "freertos/task.h"//任务创建 #include "driver/uart.h"//串口驱动 #include "driver/gpio.h"//gpio(引脚,输入输出) #include "sdkconfig.h" #define Uart_1 UART_NUM_0 //选择串口端口 #define Uart1_rate 115200 //设置串口波特率 #define Uart1_data UART_DATA_8_BITS//数据位 #define Uart1_parity UART_PARITY_DISABLE//奇偶校验 #define Uart1_stop UART_STOP_BITS_1 //停止位 #define Uart1_ctrl UART_HW_FLOWCTRL_DISABLE//流控 #define Uart1_flow 122//硬件RTS阀值 #define BUF_SIZE 1024 void uart_init() { //配置UART相关参数 uart_config_t uart1_config = { .baud_rate = Uart1_rate, .data_bits = Uart1_data, .parity = Uart1_parity, .stop_bits = Uart1_stop, .flow_ctrl = Uart1_ctrl, .rx_flow_ctrl_thresh = Uart1_flow, }; //串口参数配置 串口号、串口配置参数 ESP_ERROR_CHECK(uart_param_config(Uart_1,&uart1_config)); //安装串口驱动 串口编号、接收buff、发送buff、事件队列、分配中断的标志 ESP_ERROR_CHECK(uart_set_pin(Uart_1,1,3,UART_PIN_NO_CHANGE,UART_PIN_NO_CHANGE)); //安装串口驱动 串口编号、接收buff、发送buff、事件队列、分配中断的标志 ESP_ERROR_CHECK(uart_driver_install(Uart_1,1024 *2,1024*2,0,NULL,0)); // 申请临时内存 uint8_t *data = (uint8_t *) malloc(BUF_SIZE); while (1) { // Read data from the UART 接收到串口数据 int len = uart_read_bytes(Uart_1, data, BUF_SIZE, 20 / portTICK_PERIOD_MS); // Write data back to the UART 发送串口数据 uart_write_bytes(Uart_1, (const char *) data, len); } } void app_main(void) { xTaskCreate(uart_init, "uart_echo_task", 1024*2, NULL,10, NULL); //创建串口应声虫任务 }
2023年09月29日
133 阅读
0 评论
1 点赞
2023-09-28
ESP32_OLED128*64显示
OLED简介 OLED英文全名Organic Light-Emitting Diode,又可称为「有机发光二极体」或是「有机电雷射显示」。 OLED有着色彩鲜艳、功耗低的优点,它的显示技术具有自发光的特性,透过非常薄的有机材料涂层和玻璃基板,当有电流通过时,这些有机材料就会发光,不仅显示屏幕可视角度大,因为少了LED背光,耗电能够降低。还有一个很大的特性,在荧幕应用设计上,它可以弯曲,因此能够用来设计的范围更广,如曲面屏幕、屏幕下指纹辨识等。闪屏 因OLED的调光方式,导致可能出现闪屏的现象,闪屏指的是屏幕以低频率闪烁,虽然视觉上看不出闪烁,看久了可能会产生视觉疲劳的现象,但这部分因人而异,有些人感觉不出来。{mtitle title="OLED显示效果"/}代码实现OLED引脚ESP32引脚VCC3V3GNDGNDSCL5SDL4#include <U8g2lib.h> #include <Wire.h> #define SCL 5 #define SDA 4 U8G2_SSD1306_128X64_NONAME_F_SW_I2C u8g2(U8G2_R0, /*clock=*/SCL, /*data=*/SDA, /*reset=*/U8X8_PIN_NONE); void setup() { u8g2.begin(); u8g2.enableUTF8Print(); // enable UTF8 support for the Arduino print() function } void loop() { //u8g2.setFont(u8g2_font_unifont_t_symbols); u8g2.setFont(u8g2_font_wqy16_t_gb2312b);//中文字库 u8g2.firstPage(); do { u8g2.setCursor(0, 15); //指定显示位置 u8g2.print("Hello World!"); //使用print来显示字符串 u8g2.setCursor(0, 30); //指定显示位置 u8g2.print("你好,朋友"); //使用print来显示字符串 } while (u8g2.nextPage()); delay(1000); } {cloud title="u8g2库下载" type="lz" url="https://wwxj.lanzout.com/iksJ11a5bdab" password=""/}
2023年09月28日
143 阅读
0 评论
1 点赞
2023-09-16
ESP32_PWM 驱动LED灯
1. 学习目的及目标学习 LED 灯电路及硬件原理学习 ESP32 的 PWM(ledc)功能的配置掌握 PWM(ledc)控制LED 灯渐变2.LED 灯控制原理 要使用 ESP32 控制 LED 灯输出多种亮度等级,可以通过控制输出脉冲的占空比来实现。就是我们今天要学习的 PWM 功能,在 ESP32中就是 ledc 功能。 上图列出了周期相同而占空比分别为100%、80%、50和20%的脉冲波形,假如利用这样的脉冲控制 LED 灯,即可控制 LED 灯亮灭时间长度的比例。若提高脉冲的频率,LED 灯将会高频率进行开关切换,由于视觉暂留效应,人眼看不到 LED 灯的开关导致的闪烁现象,而是感觉到使用不同占空比的脉冲控制 LED 灯时的亮度差别。即单个控制周期内,LED 灯亮的平均时间越长,亮度就越高,反之越暗。 把脉冲信号占空比分成 256 个等级,即可用于控制 LED 灯输出 256 种亮度,使用三种这样的信号控制 RGB 灯即可得到256x256x256种颜色混合的效果。而要控制占空比,直接使用 ESP32 的 LEDC 功能即可.3.硬件设计原理实验使用ESP32开发板自带的LED灯进行实验LED标号LED引脚ESP32引脚LED_IO224.代码设计1.代码逻辑2.源码编写#include <stdio.h> #include <sdkconfig.h> #include <driver/ledc.h> #include <driver/gpio.h> #include <driver/ledc.h> #include <esp_log.h> #include <freertos/FreeRTOS.h> #include <freertos/task.h> #define LED_IO 2 #define LEDC_MAX_DUTY (8191) //最大占空比,2的13次方 #define LEDC_FADE_TIME 1000 //渐变时间 //ledc_timer_config_t ledc_timer; ledc_channel_config_t ledc_con; //声明结构体函数 void ledc_init(void) { //设置LED定时器 ledc_timer_config_t ledc_timer = { .duty_resolution = LEDC_TIMER_13_BIT, //设置PWM分辨率 .freq_hz = 5000 , //设置频率 .speed_mode = LEDC_HIGH_SPEED_MODE,//设置为高速模式 .timer_num = LEDC_TIMER_0,//选择定时器 }; //启动定时器的PWM模式 ledc_timer_config(&ledc_timer); //LED 灯结构体配置 ledc_con.channel = LEDC_CHANNEL_0;//pwm通道 ledc_con.duty = 0;//占空比 ledc_con.gpio_num = LED_IO; //选择IO口 ledc_con.speed_mode = LEDC_HIGH_SPEED_MODE; //选择高速通道 ledc_con.timer_sel = LEDC_TIMER_0; //选择定时器 ledc_channel_config(&ledc_con); //安装LED渐变 ledc_fade_func_install(0); } void app_main(void) { //选择IO口 esp_rom_gpio_pad_select_gpio(LED_IO); //设置IO口 gpio_set_direction(LED_IO,GPIO_MODE_OUTPUT); //定时器、LED灯初始化 ledc_init(); while (1) { //LED灯从渐变到100%,时间是 LEDC_FADE_TIME ledc_set_fade_with_time(ledc_con.speed_mode,ledc_con.channel,LEDC_MAX_DUTY,LEDC_FADE_TIME); //渐变开始 ledc_fade_start(ledc_con.speed_mode,ledc_con.channel,LEDC_FADE_NO_WAIT); //延时LEDC_FADE_TIME,给LEDC控制时间 vTaskDelay(LEDC_FADE_TIME / portTICK_PERIOD_MS); //LED灯渐变到0%,时间为LEDC_FADE_TIME ledc_set_fade_with_time(ledc_con.speed_mode,ledc_con.channel,0,LEDC_FADE_TIME); //启动渐变,等待时间为LEDC_FADE_NO_WAIT不等待 ledc_fade_start(ledc_con.speed_mode,ledc_con.channel,LEDC_FADE_NO_WAIT); //延时LEDC_FADE_TIME,给LEDC控制时间 vTaskDelay(LEDC_FADE_TIME / portTICK_PERIOD_MS); } }3.展示效果LED灯由暗到亮,再由亮变暗,如此循环。5.PWM(ledc)总结渐变在指示灯处比较常用。不用渐变的时候可以使用,设置占空比函数直接怼。设置占空比 ledc_set_duty();还有几个常用的 ledc 库函数,请参考 ledc.h 文件。
2023年09月16日
141 阅读
0 评论
1 点赞
2023-09-12
ESP32_定时器的简单使用
学习目的及目标掌握 LED 灯电路设计:控制方式掌握 ESP32 定时器的库函数写 LED 闪烁灯程实验原理本实验板使用esp32自带的一个引脚为2的LED灯,使用定时器对LED灯就行亮灭控制,在定时5秒后自动重启计时器。代码设计代码逻辑串口输出代码#include <stdio.h> #include <sdkconfig.h> #include <freertos/FreeRTOS.h> #include <freertos/task.h> #include <freertos/queue.h> #include <driver/gpio.h> #include <esp_log.h> #include <driver/gptimer.h> #include <esp_timer.h> #include <esp_types.h> #include "esp_private/periph_ctrl.h" #define LED_IO 2 static const char *TAG = "example"; //定时器句柄 esp_timer_handle_t fw_timer_handle = 0; void fw_timer_cb(void *arg) { //获取时间戳 int64_t tick = esp_timer_get_time(); ESP_LOGI(TAG,"timer cnt = %lld \r\n",tick); if (tick >50*1000*1000)//如果大于50秒则自动停止 { //定时器暂停、删除 esp_timer_stop(fw_timer_handle); ESP_LOGI(TAG,"timer is stop!!"); esp_timer_delete(fw_timer_handle); ESP_LOGI(TAG,"timer is delete!!"); //定时器重启 //esp_timer_restart(fw_timer_handle,50); esp_restart(); // ESP_LOGI(TAG,"the fw_timer static : %d",esp_timer_restart(fw_timer_handle,tick)); } //LED亮0.5一秒 gpio_set_level(LED_IO,0); vTaskDelay(500 /portTICK_PERIOD_MS); //LED灯灭0.5秒 gpio_set_level(LED_IO,1); vTaskDelay(500 /portTICK_PERIOD_MS); } void app_main(void) { //选择IO口 esp_rom_gpio_pad_select_gpio(LED_IO); //设置IO为输出 gpio_set_direction(LED_IO,GPIO_MODE_OUTPUT); //定时器结构体初始化 esp_timer_create_args_t fw_timer = { .callback = &fw_timer_cb, //回调函数 .arg = NULL, //参数 .name = "fw_timer" //定时器名称 }; //定时器创建,启动 esp_err_t err = esp_timer_create(&fw_timer,&fw_timer_handle); err =esp_timer_start_periodic(fw_timer_handle, 1000*1000 );//1秒回调 //判断是否创建并成功启动 if (err == ESP_OK) { ESP_LOGI(TAG,"fw_timer create and start OK!\r\n"); } else { printf("error: %d",err); } }
2023年09月12日
154 阅读
0 评论
1 点赞
2023-09-11
ESP32_开关按键控制
1.学习目标学习轻开关键检测电路及硬件原理学习 ESP32 GPIO 作为输入时候的配置掌握库函数读取 GPIO 状态掌握开关按键检测程序2.硬件设计及原理 通过检测输入按键的高低电平来判断是断开状态还是启动状态 从按键的原理图可知,这些按键在没有被按下的时候,GPIO 15引脚的输入状态为高电平(按键所在的电路不通),当按键按下时,GPIO 引脚的输入状态为低电平(按键所在的电路导通,引脚接到 GPIO4)。只要我们检测引脚的输入电平,即可判断按键是否被按下。将检测到的状态用自带的LED灯表示出来,用户按键占用 ESP32 的引脚如下按键引脚接引至引脚作用GPIO4GPIO15按键开关GPIO2无LED灯显示3.代码实现1.代码逻辑初始化LED灯初始化按键检测按键状态状态用LED显示并打印到串口重复开关按键,检测是否准确2.源码编写#include <stdio.h> #include <sdkconfig.h> #include <driver/gpio.h> #include <esp_log.h> #include <freertos/FreeRTOS.h> #include <freertos/task.h> #define Key_IO 4 #define LED_IO 2 #define Key_IO2 15 static const char *TAG = "example"; void key_read(void) { if (gpio_get_level(Key_IO2==0)) //判断按键是否为接通 { while (gpio_get_level(Key_IO2)==0)//等待松手 { //灯亮 gpio_set_level(LED_IO,1); ESP_LOGI(TAG,"The Led is turn"); } } if (gpio_get_level(Key_IO2==1)) //判断按键是否断开 { while (gpio_get_level(Key_IO2)==1)//等待松手 { //灯灭 gpio_set_level(LED_IO,0); ESP_LOGI(TAG,"The Led is off"); } } } void app_main(void) { //选择IO口 esp_rom_gpio_pad_select_gpio(Key_IO); esp_rom_gpio_pad_select_gpio(Key_IO2); esp_rom_gpio_pad_select_gpio(LED_IO); //设置输入模式 gpio_set_direction(Key_IO2,GPIO_MODE_INPUT); gpio_set_direction(Key_IO,GPIO_MODE_OUTPUT); gpio_set_direction(LED_IO,GPIO_MODE_OUTPUT); while (1) { key_read();//按键识别 } }
2023年09月11日
138 阅读
0 评论
0 点赞
2023-09-10
ESP32-驱动LED灯
学习目标掌握LED灯电路的控制方式掌握 ESP32 库函数对 IO 配置掌握 ESP32 库函数对 IO 控制的操作编写 LED 闪烁和流水灯程序硬件设计由于ESP32开发板上自带一颗引脚为2的LED灯,所以直接使用这一颗就能进行实验实现原理代码实现闪烁灯代码#include <stdio.h> #include <sdkconfig.h> #include <driver/gpio.h> #include <esp_log.h> #include <freertos/FreeRTOS.h> #include <freertos/task.h> #define LED_IO 2 static const char *TAG = "example"; void app_main(void) { //选择IO口 esp_rom_gpio_pad_select_gpio(LED_IO); //设置IO口模式 gpio_set_direction(LED_IO,GPIO_MODE_OUTPUT); while (1) { //IO拉高,灯亮 gpio_set_level(LED_IO,1); ESP_LOGI(TAG,"The LED is turn"); //延迟1秒 vTaskDelay(1000 / portTICK_PERIOD_MS); //IO拉高,灯灭 gpio_set_level(LED_IO,1); ESP_LOGI(TAG,"The LED is off"); vTaskDelay(1000 / portTICK_PERIOD_MS); } } 流水灯代码#include <stdio.h> #include <sdkconfig.h> #include <driver/gpio.h> #include <esp_log.h> #include <freertos/FreeRTOS.h> #include <freertos/task.h> #define LED_IO1 2 #define LED_IO2 18 #define LED_IO3 19 static const char *TAG = "example"; void app_main(void) { //选择IO口 esp_rom_gpio_pad_select_gpio(LED_IO1); esp_rom_gpio_pad_select_gpio(LED_IO2); esp_rom_gpio_pad_select_gpio(LED_IO3); //设置IO口模式 gpio_set_direction(LED_IO1,GPIO_MODE_OUTPUT); gpio_set_direction(LED_IO2,GPIO_MODE_OUTPUT); gpio_set_direction(LED_IO3,GPIO_MODE_OUTPUT); while (1) { //1灯亮 gpio_set_level(LED_IO1,1); gpio_set_level(LED_IO2,0); gpio_set_level(LED_IO3,0); ESP_LOGI(TAG,"The LED1 is turn"); //延迟1秒 vTaskDelay(1000 / portTICK_PERIOD_MS); //2灯亮 gpio_set_level(LED_IO1,0); gpio_set_level(LED_IO2,1); gpio_set_level(LED_IO3,0); ESP_LOGI(TAG,"The LED2 is turn"); //延迟1秒 vTaskDelay(1000 / portTICK_PERIOD_MS); //3灯亮 gpio_set_level(LED_IO1,0); gpio_set_level(LED_IO2,0); gpio_set_level(LED_IO3,1); ESP_LOGI(TAG,"The LED3 is turn"); //延迟1秒 vTaskDelay(1000 / portTICK_PERIOD_MS); } }
2023年09月10日
128 阅读
0 评论
0 点赞
1
2