- 1 中断矩阵
- 2 代码实现
- 2.1 GPIO 信号作为中断源
首先总结一下前面以及学习的内容:配置好开发环境后实现了基本的信号输入输出。 之前学习过中断相关知识就可以跳过前言部分了,如果初学的话,首先了解一下中断的概念。 之前的demo运行起来都是 初始化 -> while(1)循环 的工作模式。 现在有一个简单的场景:我们在while(1)循环中完成这些事:
1 看文档 -> 2 写代码 -> 3 调试代码 ┐
↑ │
└──────────────────────────────┘
以上是学习的过程, 现在增加一个触发状态"学累了"可以触发"玩手机"这个事件。 如果还是以前的循环处理过程,则实现的结果是每次在完成"看文档"、“写代码”、“调试代码”后,才可以判断是否学累了。 而实际情况是我们在做这三件事情的过程中可能就会达到“学累了”状态,而触发“玩手机”事件,玩了一会手机之后,继续进行学习任务。这就是中断的作用,在处理一个任务时,通过中断让cpu先处理中断事件,处理完后继续做之前的任务。
1 中断矩阵ESP32 中断矩阵将任一外部中断源单独分配到每个 CPU 的任一外部中断上。
中断矩阵:
- 输入:71个外部中断
- 输出:两个 CPU 分别生成 26 个外部中断
- 屏蔽 CPU 的 NMI 类型中断
- 查询外部中断源当前的中断状态
关于外部中断源,没必要都去学习,我们只要知道一些常用的外设都可以产生中断就行,比如gpio、串口、spi、定时器等。
2 代码实现 2.1 GPIO 信号作为中断源参考examples\peripherals\gpio\generic_gpio中的示例工程。 esp32系列(3):GPIO学习(以简单GPIO输入输出、ADC、DAC为例)通过 esp_err_t gpio_config(const gpio_config_t *pGPIOConfig)
函数配置GPIO的基本输入输出,同样的 gpio_config_t 结构体的 gpio_int_type_t类型 intr_type
字段可以设置中断类型。
- GPIO_INTR_DISABLE : 禁用GPIO中断
- GPIO_INTR_POSEDGE : 上升沿触发
- GPIO_INTR_NEGEDGE : 下降沿触发
- GPIO_INTR_ANYEDGE : 任意沿触发
- GPIO_INTR_LOW_LEVEL : 低电平触发
- GPIO_INTR_HIGH_LEVEL : 高电平触发
配置完成后,调用 esp_err_t gpio_install_isr_service(int intr_alloc_flags)
函数设置 GPIO ISR(中断服务程序,interrupt service routine) 处理服务。
调用 esp_err_t gpio_isr_handler_add(gpio_num_t gpio_num, gpio_isr_t isr_handler, void *args);
为相应的GPIO引脚添加ISR handler。
在ISR handler指向的函数中,示例程序新建了一个 queue ,这涉及到freeRTOS的知识,不懂。但我试了如果不适用 queue 直接将相关的处理放在中断处理程序中,在运行时程序会崩溃。具体的原理有待学习。使用 queue 大概的流程就是
- xQueueCreate( uxQueueLength, uxItemSize ) 创建一个queue实例。
- xTaskCreate 函数创建一个新任务,并将其添加到准备运行的任务列表中。
- 在中断处理程序中调用 xQueueSendFromISR 函数,功能:在 queue 中发布一个 item ,在中断服务程序中使用这个函数是安全的。
- 在xTaskCreate创建的任务中 调用 xQueueReceive 函数从 queue 中接收 item 。并在收到 item 后完成相应的处理。
代码实现:
#include
#include
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "driver/gpio.h"
/**
* Brief:
* 基本的GPIO中断输入学习
*
* GPIO status:
* GPIO4: input,interrupt from rising edge.
*
* Test:
*
*
*/
#define GPIO_4 4
#define ESP_INTR_FLAG_DEFAULT 0 //中断标志位
static xQueueHandle gpio_evt_queue = NULL;
void gpio_task1(void)
{
for (int i = 5; i > 0; i--)
{
printf("task1: %d\n", i);
vTaskDelay(500 / portTICK_RATE_MS);
}
return;
}
void gpio_task2(void)
{
for (int i = 5; i > 0; i--)
{
printf("task2: %d\n", i);
vTaskDelay(500 / portTICK_RATE_MS);
}
return;
}
void 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)
{
for( ;; )
{
// Task code goes here.
uint32_t io_num;
if(xQueueReceive(gpio_evt_queue, &io_num, portMAX_DELAY)) {
printf("GPIO[%d] intr, val: %d\n", io_num, gpio_get_level(io_num));
}
}
}
void app_main(void)
{
// GPIO1
gpio_config_t io_conf = {}; //新建配置GPIO pad的gpio_config功能参数的结构体
io_conf.pin_bit_mask = (1ULL
关注
打赏
最近更新
- 深拷贝和浅拷贝的区别(重点)
- 【Vue】走进Vue框架世界
- 【云服务器】项目部署—搭建网站—vue电商后台管理系统
- 【React介绍】 一文带你深入React
- 【React】React组件实例的三大属性之state,props,refs(你学废了吗)
- 【脚手架VueCLI】从零开始,创建一个VUE项目
- 【React】深入理解React组件生命周期----图文详解(含代码)
- 【React】DOM的Diffing算法是什么?以及DOM中key的作用----经典面试题
- 【React】1_使用React脚手架创建项目步骤--------详解(含项目结构说明)
- 【React】2_如何使用react脚手架写一个简单的页面?