环境
系统:Ubuntu 16.04
软件:ESP-IDF
硬件平台:安信可开发板(使用自制开发板或者其他开发板子都可以)
1、前期准备
这里笔者还是使用安信可开发板上的资源(因为懒得画板子)
按键的引脚的确定
led引脚的确定
2、创建工程
#1、初始化ESP-IDF环境
get_idf
#2、创建工程 idf.py create-project 工程名
idf.py create-project led
#3、配置工程芯片为esp32c3
cd led
idf.py set-target esp32c3
#4、使用menuconfig配置工程
#进入配置界面,配置相关信息,配置完成后保存,退出
#配置详情如下:
#Component config → ESP32C3-Specific → Minimum Supported ESP32-C3 Revision
#选择REV0
idf.py menuconfig
3、代码编写
这里笔者参考了官方历程写的一个例子
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "driver/gpio.h"
#define GPIO_OUTPUT_IO_0 18
#define GPIO_INPUT_IO_0 9
#define ESP_INTR_FLAG_DEFAULT 0
static xQueueHandle gpio_evt_queue = NULL;
static void gpio_task(void *arg);
static void IRAM_ATTR gpio_isr_handler(void *arg);
void app_main(void)
{
gpio_config_t io_config;
io_config.intr_type = GPIO_INTR_DISABLE;
io_config.pin_bit_mask = 1ULL << GPIO_OUTPUT_IO_0;
io_config.mode = GPIO_MODE_OUTPUT;
io_config.pull_down_en = 0;
io_config.pull_up_en = 0;
gpio_config(&io_config);
io_config.intr_type = GPIO_INTR_NEGEDGE;
io_config.pin_bit_mask = 1ULL << GPIO_INPUT_IO_0;
io_config.mode = GPIO_MODE_INPUT;
io_config.pull_down_en = 1;
gpio_config(&io_config);
gpio_evt_queue = xQueueCreate(10,sizeof(uint32_t));
xTaskCreate(gpio_task,"gpio_task",2048,NULL,10,NULL);
gpio_install_isr_service(ESP_INTR_FLAG_DEFAULT);
gpio_isr_handler_add(GPIO_INPUT_IO_0,gpio_isr_handler,NULL);
printf("Minimum free heap size: %d bytes\n", esp_get_minimum_free_heap_size());
int cnt = 0;
while (1)
{
printf("cnt: %d\n", cnt++);
vTaskDelay(1000 / portTICK_RATE_MS);
}
}
char cntt = 0;
static void IRAM_ATTR gpio_isr_handler(void *arg)
{
cntt++;
char led_state = cntt %2;
gpio_set_level(GPIO_OUTPUT_IO_0,led_state);
xQueueSendFromISR(gpio_evt_queue,&led_state,NULL);
}
static void gpio_task(void *arg)
{
char led_state;
while (1)
{
if(xQueueReceive(gpio_evt_queue,&led_state,portMAX_DELAY)){
printf("led state :%d\n",led_state);
}
}
}
代码解析
上面的代码工作流程:
1、初始化相关引脚
2、初始化消息队列,用于存放led的状态
3、创建任务,用于打印led的状态
4、安装中断处理服务
5、设置引脚中断时,中断处理函数
相关函数以及结构体解析:
gpio_config_t结构体:
typedef struct {
uint64_t pin_bit_mask; //GPIO的引脚
gpio_mode_t mode; //GPIO模式 其参数见gpio_mode_t
gpio_pullup_t pull_up_en; //上拉使能
gpio_pulldown_t pull_down_en; //下拉使能
gpio_int_type_t intr_type; //GPIO中断类型 参数见gpio_int_type_t
} gpio_config_t;
typedef enum {
GPIO_MODE_DISABLE = GPIO_MODE_DEF_DISABLE, /*!< GPIO mode : disable input and output */
GPIO_MODE_INPUT = GPIO_MODE_DEF_INPUT, /*!< GPIO mode : input only */
GPIO_MODE_OUTPUT = GPIO_MODE_DEF_OUTPUT, /*!< GPIO mode : output only mode */
GPIO_MODE_OUTPUT_OD = ((GPIO_MODE_DEF_OUTPUT) | (GPIO_MODE_DEF_OD)), /*!< GPIO mode : output only with open-drain mode */
GPIO_MODE_INPUT_OUTPUT_OD = ((GPIO_MODE_DEF_INPUT) | (GPIO_MODE_DEF_OUTPUT) | (GPIO_MODE_DEF_OD)), /*!< GPIO mode : output and input with open-drain mode*/
GPIO_MODE_INPUT_OUTPUT = ((GPIO_MODE_DEF_INPUT) | (GPIO_MODE_DEF_OUTPUT)), /*!< GPIO mode : output and input mode */
} gpio_mode_t;
typedef enum {
GPIO_INTR_DISABLE = 0, /*!< Disable GPIO interrupt (不使能中断) */
GPIO_INTR_POSEDGE = 1, /*!< GPIO interrupt type : rising edge (上升沿)*/
GPIO_INTR_NEGEDGE = 2, /*!< GPIO interrupt type : falling edge(下降沿)*/
GPIO_INTR_ANYEDGE = 3, /*!< GPIO interrupt type : both rising and falling edge (上升沿和下降沿)*/
GPIO_INTR_LOW_LEVEL = 4, /*!< GPIO interrupt type : input low level trigger(低电平) */
GPIO_INTR_HIGH_LEVEL = 5, /*!< GPIO interrupt type : input high level trigger(高电平) */
GPIO_INTR_MAX,
} gpio_int_type_t;
esp_err_t gpio_config(const gpio_config_t * pGPIOConfig ):
该函数用于初始化引脚配置
xQueueHandle xQueueCreate( unsigned portBASE_TYPE uxQueueLength, unsigned portBASE_TYPE uxItemSize )
该函数用于新建一个队列
参数:
uxQueueLength | 队列最大长度 |
---|---|
uxItemSize | 数据体的数据大小,注意:队列中每个数据体的大小必须要保存一致 |
portBASE_TYPE xQueueReceive( xQueueHandle xQueue, void *pvBuffer, portTickType xTicksToWait )
该函数用于读取队列的里面的数值
参数
pvBuffer | 数据指针用于指向出队的数据地址 |
---|---|
xTicksToWait | 任务中断并等待队列中可用空间的最大时间。若设置为0且队列为空时,调用立刻返回。因为阻塞时间是以系统心跳周期为单位的,所以绝对时间取决于系统心跳频率,如果要设置具体时间可以用(时间/portTICK_RATE_MS)公式来获取具体时间。又若设置为( portMAX_DELAY) 将导致任务无限期中断也就是阻塞 |
portBASE_TYPE xQueueSendFromISR(xQueueHandle pxQueue,const void *pvItemToQueue,portBASE_TYPE *pxHigherPriorityTaskWoken);
该函数用于往队列的里面插入数值
参数
pxQueue | 队列句柄,其值为xQueueCreate放回值,类型为:xQueueHandle |
---|---|
pvItemToQueue | 要存入队列的数据的指针,数据类型要和xQueueCreate初始化的数据类型一样 |
pxHigherPriorityTaskWoken | 如果数据入队使任务解锁,并且解锁的任务的优先级高于当前运行任务的优先级xQueueSendFromISR将设置 *pxHigherPriorityTaskWoken到 pdTRUE 。如果xQueueSendFromISR()设置这个值到 pdTRUE,那么在中断退出的时候将会进行任务切换。 |
esp_err_t gpio_install_isr_service( int intr_alloc_flags )
该函数用于安装驱动程序的GPIO ISR处理程序服务,该服务允许每针GPIO中断处理程序
参数
intr_alloc_flags | 用于分配中断的标志 |
---|
esp_err_t gpio_isr_handler_add(gpio_num_t gpio_num,gpio_isr_t isr_handler,void * args )
该函数用于为相应的GPIO引脚添加中断处理函数
参数
gpio_num | GPIO引脚号 |
---|---|
isr_handler | 中断处理函数名 |
args | 往中断函数传递的参数 |
esp_err_t gpio_set_level(gpio_num_t gpio_num, uint32_t level)
该函数用于设置GPIO输出的电平
参数
gpio_num | GPIO引脚号 |
---|---|
level | 高低电平,1:高电平,0:低电平 |
4、编译,烧录
//编译
idf.py build
//烧录
idf.py -p /dev/ttyUSB0 flash monitor
附录
环境初始化脚本 init_env.sh
#!/bin/bash
#给usb设备设置权限
echo "sudo chmod 777 /dev/#具体的usb设备名"
$echo sudo chmod 777 /dev/#具体的usb设备名
echo "get_idf"
$echo get_idf
编译运行脚本run.sh
#!/bin/bash
#编译
echo "idf.py build"
$echo idf.py build
#烧录
echo "idf.py -p /dev/ttyUSB0 flash monitor"
$echo idf.py -p /dev/ttyUSB0 flash monitor