【PC电脑windows-学习样例generic_gpio-拓展GPIO-ESP32的GPIO程序-基础样例学习(2)】
- 1、概述
- 2、实验环境
- 3、 问题说明
- 1:问题说明:使用官方样例,增加IO,编译会重新改回去。
- 2:解决方式:使用命令界面进行控制,然后重新编译。
- 4、自我总结
- 5、本次实验说明
- (1)实验1:更改官方样例
- (2)实验2:按照网上样例,直接定义
- 6-1、实验过程1
- (1)复制目标目录
- (2)增加代码
- (3)菜单设置
- (4)下载验证
- 6-2、实验过程2
- (1)代码编写
- (2)解决报错
- (2)验证结果
- 7、代码连接
- 8、相关细节
- (1)编译环境配置
- (2)样例代码目录
- (3)IO定义
- (4)报错:无法下载1
- (5)报错:无法下载2
- 9、总结
1、概述
最为新手,想要快速入门相关设备,比如ESP32,可能最好的方式就是直接手动去敲一遍代码,之前已经敲了一遍基础代码了,但当我想扩展GPIO时,却发现了一些问题,总是也对GPIO相问题进行了总结。
2、实验环境
硬件信息:开发板 ESP32-S3-DevKitM-1(EPS32-S3-wroom-1模块)
其它硬件:杜邦线,两个usb-type-c连接线,逻辑分析仪。
3、 问题说明
1:问题说明:使用官方样例,增加IO,编译会重新改回去。
如下图所示,自己调试,在增加IO的时候,发现,一旦编译,被定义的IO,回重新定回去。
2:解决方式:使用命令界面进行控制,然后重新编译。
之前不知道这回事,觉得只要改代码就可以了,后来发现需要再菜单里配置下。
idf.py menuconfig
4、自我总结
(1)练习代码是你更快入门
练习代码比实际看代码要快些,这属于个人见解了,练习敲写代码过程汇总,就是帮助你熟悉相关代码结构,当你从一个固有套路结构代码中,切换到另一套方式时,可能直接手敲,更能让你理解。
(2)IO相关测试,手动更改
自己练习的代码,手动敲完,可能会报错,可能会有逻辑错误,在改的过程中,其实也是熟悉。
(3)IO相关调用方式
目前看到网上有关GPIO相关方式,关于写法至少有两种:
- 一种就是想官网样例的方式,加完代码后,还需要再菜单里设置下。
- 另外就是不用菜单,直接定义然后直接使用。
5、本次实验说明
(1)实验1:更改官方样例
本次实验使用样例,依旧是generic_gpio,直接复制一份在桌面,直接改写,我们的目的时再增加两个IO,发现核心板上的,P15,P16,P17,P18,这四个引脚时连在一起的,所以准备换到这几个GPIO进行输出调试。
(2)实验2:按照网上样例,直接定义
具体参考链接如下:https://blog.csdn.net/qq_36347513/article/details/115691435
本次参考以上写法,再次实现。
6-1、实验过程1
(1)复制目标目录
我这里之前实验复制过,所以可以直接使用。
使用VScode直接打开。
(2)增加代码
主要是在三个文件中,增加代码,即
main.c中
/* GPIO Example
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <inttypes.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "driver/gpio.h"
#include "driver/uart.h"
/**
* Brief:
* This test code shows how to configure gpio and how to use gpio interrupt.
*
* GPIO status:
* GPIO18: output (ESP32C2/ESP32H2 uses GPIO8 as the second output pin)
* GPIO19: output (ESP32C2/ESP32H2 uses GPIO9 as the second output pin)
* GPIO4: input, pulled up, interrupt from rising edge and falling edge
* GPIO5: input, pulled up, interrupt from rising edge.
*
* Note. These are the default GPIO pins to be used in the example. You can
* change IO pins in menuconfig.
*
* Test:
* Connect GPIO18(8) with GPIO4
* Connect GPIO19(9) with GPIO5
* Generate pulses on GPIO18(8)/19(9), that triggers interrupt on GPIO4/5
*
*/
//P15 16 17 18
#define GPIO_OUTPUT_IO_0 CONFIG_GPIO_OUTPUT_0
#define GPIO_OUTPUT_IO_1 CONFIG_GPIO_OUTPUT_1
#define GPIO_OUTPUT_IO_2 CONFIG_GPIO_OUTPUT_2
#define GPIO_OUTPUT_IO_3 CONFIG_GPIO_OUTPUT_3
#define GPIO_OUTPUT_PIN_SEL ((1ULL<<GPIO_OUTPUT_IO_0) | (1ULL<<GPIO_OUTPUT_IO_1) | (1ULL<<GPIO_OUTPUT_IO_2) | (1ULL<<GPIO_OUTPUT_IO_3) )
#define GPIO_INPUT_IO_0 CONFIG_GPIO_INPUT_0
#define GPIO_INPUT_IO_1 CONFIG_GPIO_INPUT_1
#define GPIO_INPUT_PIN_SEL ((1ULL<<GPIO_INPUT_IO_0) | (1ULL<<GPIO_INPUT_IO_1))
#define ESP_INTR_FLAG_DEFAULT 0
#define UART_PORT UART_NUM_0 //选择串口端口
static QueueHandle_t gpio_evt_queue = NULL;
static void IRAM_ATTR gpio_isr_handler(void* arg)
{
uint32_t gpio_num = (uint32_t) arg;
xQueueSendFromISR(gpio_evt_queue, &gpio_num, NULL);
}
static void gpio_task_example(void* arg)
{
uint32_t io_num;
for(;;) {
if(xQueueReceive(gpio_evt_queue, &io_num, portMAX_DELAY)) {
// printf("GPIO[%"PRIu32"] intr, val: %d\n", io_num, gpio_get_level(io_num));
}
}
}
void uart_task(void *pvParameters){
uint8_t data;
while(1){
// printf("this is my——test,helloworld!",data);
// sleep(1);
//从串口读取输入数据
if(uart_read_bytes(UART_PORT,&data,1,pdMS_TO_TICKS(10))>0){
//打印读到的字符
printf("Received:%c\n",data);
}
}
}
void app_main(void)
{
//zero-initialize the config structure.
gpio_config_t io_conf = {};
//disable interrupt
io_conf.intr_type = GPIO_INTR_DISABLE;
//set as output mode
io_conf.mode = GPIO_MODE_OUTPUT;
//bit mask of the pins that you want to set,e.g.GPIO15/16/17/18
io_conf.pin_bit_mask = GPIO_OUTPUT_PIN_SEL;
//disable pull-down mode
io_conf.pull_down_en = 0;
//disable pull-up mode
io_conf.pull_up_en = 0;
//configure GPIO with the given settings
gpio_config(&io_conf);
//interrupt of rising edge
io_conf.intr_type = GPIO_INTR_POSEDGE;
//bit mask of the pins, use GPIO4/5 here
io_conf.pin_bit_mask = GPIO_INPUT_PIN_SEL;
//set as input mode
io_conf.mode = GPIO_MODE_INPUT;
//enable pull-up mode
io_conf.pull_up_en = 1;
gpio_config(&io_conf);
//change gpio interrupt type for one pin
gpio_set_intr_type(GPIO_INPUT_IO_0, GPIO_INTR_ANYEDGE);
//create a queue to handle gpio event from isr
gpio_evt_queue = xQueueCreate(10, sizeof(uint32_t));
//start gpio task
xTaskCreate(gpio_task_example, "gpio_task_example", 2048, NULL, 10, NULL);
//install gpio isr service
gpio_install_isr_service(ESP_INTR_FLAG_DEFAULT);
//hook isr handler for specific gpio pin
gpio_isr_handler_add(GPIO_INPUT_IO_0, gpio_isr_handler, (void*) GPIO_INPUT_IO_0);
//hook isr handler for specific gpio pin
gpio_isr_handler_add(GPIO_INPUT_IO_1, gpio_isr_handler, (void*) GPIO_INPUT_IO_1);
//remove isr handler for gpio number.
gpio_isr_handler_remove(GPIO_INPUT_IO_0);
//hook isr handler for specific gpio pin again
gpio_isr_handler_add(GPIO_INPUT_IO_0, gpio_isr_handler, (void*) GPIO_INPUT_IO_0);
printf("Minimum free heap size: %"PRIu32" bytes\n", esp_get_minimum_free_heap_size());
//串口部分
//配置串口参数
uart_config_t uart_config={
.baud_rate = 9600, /*!< UART baud rate*/
.data_bits = UART_DATA_8_BITS, /*!< UART byte size*/
.parity = UART_PARITY_DISABLE, /*!< UART parity mode*/
.stop_bits = UART_STOP_BITS_1, /*!< UART stop bits*/
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE /*!< UART HW flow control mode (cts/rts)*/
};
uart_param_config(UART_PORT,&uart_config);
uart_set_pin(UART_PORT,UART_PIN_NO_CHANGE,UART_PIN_NO_CHANGE,UART_PIN_NO_CHANGE,UART_PIN_NO_CHANGE);
uart_driver_install(UART_PORT,1024,0,0,NULL,0);
//创建串口任务
xTaskCreate(uart_task,"uart_task",2048,NULL,10,NULL);
int cnt = 0;
while(1) {
printf("cnt: %d\n", cnt++);
vTaskDelay(1000 / portTICK_PERIOD_MS);
gpio_set_level(GPIO_OUTPUT_IO_0, 1);
gpio_set_level(GPIO_OUTPUT_IO_1, 1);
gpio_set_level(GPIO_OUTPUT_IO_2, 1);
gpio_set_level(GPIO_OUTPUT_IO_3, 1);
vTaskDelay(1000 / portTICK_PERIOD_MS);
gpio_set_level(GPIO_OUTPUT_IO_0, 0);
gpio_set_level(GPIO_OUTPUT_IO_1, 0);
gpio_set_level(GPIO_OUTPUT_IO_2, 0);
gpio_set_level(GPIO_OUTPUT_IO_3, 0);
}
}
在文件Kconfig.projbuild中增加内容:
menu "Example Configuration"
orsource "$IDF_PATH/examples/common_components/env_caps/$IDF_TARGET/Kconfig.env_caps"
config GPIO_OUTPUT_0
int "GPIO output pin 0"
range ENV_GPIO_RANGE_MIN ENV_GPIO_OUT_RANGE_MAX
default 15 if IDF_TARGET_ESP32 || IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32S3
default 5 if IDF_TARGET_ESP32C2 || IDF_TARGET_ESP32H2
help
GPIO pin number to be used as GPIO_OUTPUT_IO_0.
config GPIO_OUTPUT_1
int "GPIO output pin 1"
range ENV_GPIO_RANGE_MIN ENV_GPIO_OUT_RANGE_MAX
default 16 if IDF_TARGET_ESP32 || IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32S3
default 6 if IDF_TARGET_ESP32C2 || IDF_TARGET_ESP32H2
help
GPIO pin number to be used as GPIO_OUTPUT_IO_1.
config GPIO_OUTPUT_2
int "GPIO output pin 2"
range ENV_GPIO_RANGE_MIN ENV_GPIO_OUT_RANGE_MAX
default 17 if IDF_TARGET_ESP32 || IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32S3
default 7 if IDF_TARGET_ESP32C2 || IDF_TARGET_ESP32H2
help
GPIO pin number to be used as GPIO_OUTPUT_IO_2.
config GPIO_OUTPUT_3
int "GPIO output pin 3"
range ENV_GPIO_RANGE_MIN ENV_GPIO_OUT_RANGE_MAX
default 18 if IDF_TARGET_ESP32 || IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32S3
default 8 if IDF_TARGET_ESP32C2 || IDF_TARGET_ESP32H2
help
GPIO pin number to be used as GPIO_OUTPUT_IO_3.
config GPIO_INPUT_0
int "GPIO input pin 0"
range ENV_GPIO_RANGE_MIN ENV_GPIO_IN_RANGE_MAX
default 4
help
GPIO pin number to be used as GPIO_INPUT_IO_0.
config GPIO_INPUT_1
int "GPIO input pin 1"
range ENV_GPIO_RANGE_MIN ENV_GPIO_IN_RANGE_MAX
default 5
help
GPIO pin number to be used as GPIO_INPUT_IO_1.
endmenu
在文件sdkconfig中增加内容。
注意,如果此时直接编译,那么一定会重新变成18和19GPIO的,需要在菜单里设置。
(3)菜单设置
使用命令进入菜单。
idf.py menuconfig
(1)进入目录,并敲写命令
(2)菜单如下
(3)引脚改写如下
(4)退出来进行保存
(4)下载验证
之后就是重新编译和烧写下载了。
下载成功后验证
6-2、实验过程2
按照网上相关进行实验。我们选择4个引脚P35,P36,P37,P38,这一组是并排连着的。
主要参考如下部分:
我们用一个空工程,然后加入如下代码。
(1)代码编写
这里只需要写这一个文件就可以了。
#include <stdio.h>
#include <stdbool.h>
#include <unistd.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#define GPIO_OUTPUT_IO_0 35
#define GPIO_OUTPUT_IO_1 36
#define GPIO_OUTPUT_IO_2 37
#define GPIO_OUTPUT_IO_3 38
#define GPIO_OUTPUT_PIN_SEL ((1ULL<<GPIO_OUTPUT_IO_0) |(1ULL<<GPIO_OUTPUT_IO_1) | (1ULL<<GPIO_OUTPUT_IO_2) | (1ULL<<GPIO_OUTPUT_IO_3)) // 配置GPIO_OUT位寄存器
void gpio_init(void)
{
gpio_config_t io_conf; // 定义一个gpio_config类型的结构体,下面的都算对其进行的配置
io_conf.intr_type = GPIO_INTR_DISABLE; // 禁止中断
io_conf.mode = GPIO_MODE_OUTPUT; // 选择输出模式
io_conf.pin_bit_mask = GPIO_OUTPUT_PIN_SEL; // 配置GPIO_OUT寄存器
io_conf.pull_down_en = 0; // 禁止下拉
io_conf.pull_up_en = 0; // 禁止上拉
gpio_config(&io_conf); // 最后配置使能
}
// gpio_set_level(GPIO_OUTPUT_IO_0, 0); // 把这个GPIO输出低电平
// gpio_set_level(GPIO_OUTPUT_IO_0, 1); // 把这个GPIO输出高电平
void app_main(void)
{
gpio_init();
// // gpio_pad_select_gpio(GPIO_NUM_9);
// // gpio_pad_select_gpio(GPIO_NUM_10);
// // gpio_pad_select_gpio(GPIO_NUM_11);
// // gpio_pad_select_gpio(GPIO_NUM_12);
// //gpio_init();
// /* Set the GPIO as a push/pull output */
// // gpio_set_direction(GPIO_NUM_9, GPIO_MODE_OUTPUT);
// // // gpio_set_direction(GPIO_NUM_36, GPIO_MODE_OUTPUT);
// // // gpio_set_direction(GPIO_NUM_37, GPIO_MODE_OUTPUT);
// // // gpio_set_direction(GPIO_NUM_38, GPIO_MODE_OUTPUT);
while(1)
{
/* Blink off (output low) */
// printf("Turning off the LED\n");
// gpio_set_level(GPIO_NUM_22, 0);
vTaskDelay(1000 / portTICK_PERIOD_MS);
// gpio_set_level(GPIO_NUM_9, 0); // 把这个GPIO输出低电平
// gpio_set_level(GPIO_NUM_36, 0); // 把这个GPIO输出低电平
// gpio_set_level(GPIO_NUM_37, 0); // 把这个GPIO输出低电平
// gpio_set_level(GPIO_NUM_38, 0); // 把这个GPIO输出低电平
gpio_set_level(GPIO_OUTPUT_IO_0, 1); // 把这个GPIO输出高电平
gpio_set_level(GPIO_OUTPUT_IO_1, 1); // 把这个GPIO输出高电平
gpio_set_level(GPIO_OUTPUT_IO_2, 1); // 把这个GPIO输出高电平
gpio_set_level(GPIO_OUTPUT_IO_3, 1); // 把这个GPIO输出高电平
/* Blink on (output high) */
// printf("Turning on the LED\n");
// gpio_set_level(GPIO_NUM_22, 1);
vTaskDelay(1000 / portTICK_PERIOD_MS);
// gpio_set_level(GPIO_NUM_9, 1); // 把这个GPIO输出高电平
// // gpio_set_level(GPIO_NUM_36, 1); // 把这个GPIO输出高电平
// // gpio_set_level(GPIO_NUM_37, 1); // 把这个GPIO输出高电平
// // gpio_set_level(GPIO_NUM_38, 1); // 把这个GPIO输出高电平
gpio_set_level(GPIO_OUTPUT_IO_0, 0); // 把这个GPIO输出低电平
gpio_set_level(GPIO_OUTPUT_IO_1, 0); // 把这个GPIO输出低电平
gpio_set_level(GPIO_OUTPUT_IO_2, 0); // 把这个GPIO输出低电平
gpio_set_level(GPIO_OUTPUT_IO_3, 0); // 把这个GPIO输出低电平
}
}
(2)解决报错
(1)代码过旧,更新为绿色部分
(2)中英文符合错误
解决报错
如下有些中英文切换符合的错误,改好了后,可以了。
(2)验证结果
7、代码连接
(1)参照官方:https://download.csdn.net/download/qq_22146161/88650620
(2)参照网上:https://download.csdn.net/download/qq_22146161/88650618
8、相关细节
(1)编译环境配置
相关配置情况自己的其他文章:【ESP32-PC电脑windows-环境搭建-记录-hello-world-运行基础样例学习】
(2)样例代码目录
如果是默认安装,找如下目录
C:\Espressif\frameworks\esp-idf-v5.0.2\examples\peripherals\gpio
(3)IO定义
自己打代码的时候,比较疑惑,没有看到GPIO18相关的信息,怎么就是GPIO19,GPIO4,等等,后来看到配置文件。
(4)报错:无法下载1
如下图,比较常见下载错误了,直接先按boot然后rst,之后撒开rst,最后再放开boot,就可以在下载了。
(5)报错:无法下载2
如果上边方式还是不行,那么就有另一种可能了,在自己实际调试时候,我其实开了两个工具,一个是VScode,l另一个就是如下界面。
那么就会有抢占端口问题。所以下面界面无法下载。
解决方式:需要关闭一个,这里我关闭了vscode
9、总结
一步一步