1.Task_key_timer
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#include "esp_timer.h"
#define E(name) static void name(void *params)
#define KEY1_GPIO GPIO_NUM_0
#define KEY2_GPIO GPIO_NUM_1
#define KEY3_GPIO GPIO_NUM_2
#define KEY4_GPIO GPIO_NUM_3
static TaskHandle_t t1;
static esp_timer_handle_t key_timer;
// 入口函数
E(task1_entry)
{
while (1)
{
uint32_t notify_value = 0;
// 等待通知到达(阻塞)
BaseType_t res = xTaskNotifyWait(
0x03, // 接收通知之前要清空的位(0x00表示不清空) // 0xFFFFFFFF, // 清空所有位
0x00, // 退出的时候清空哪些位
¬ify_value, // 获取直达任务通知的值
pdMS_TO_TICKS(1000) // 等待时长
);
if (res == pdTRUE)
{
printf("获得任务通知: %X\n", notify_value);
// 清空标志位
// ulTaskNotifyValueClear(
// t1, // 操作哪个任务的标志位
// 0x00 // 清空哪些位
// );
}
else
{
printf("我没收到通知\n");
}
vTaskDelay(pdMS_TO_TICKS(2000));//延时两秒
}
vTaskDelete(NULL);
}
/** 定时器消抖
* 1. 初始化定时器
* 2. 安装中断服务函数
* 在中断服务函数中打开定时器
* 3. 定时器回调函数判断按键
*/
/**
* @brief 定时器回调函数
* 这是个任务回调函数,不是中断回调
* 所以要使用 xTaskNotify 而不是 xTaskNotifyFromISR
*/
static void key_timer_cb(void *args)
{
// 查看是否还是为低电平,如果持续为低电平,说明确实被按下了
// 如果不为低电平,说明是没有被按下
if (gpio_get_level(KEY1_GPIO) == 0)
{
// 被按下了
xTaskNotify(
t1, // 接收通知的任务句柄
1, // 通知值
eSetBits // 通知方式
);
}
}
/**
* @brief 按键中断定时器初始化
*/
static void key_timer_init()
{
// 1. 设置定时器参数表
esp_timer_create_args_t timer_args = {
.callback = key_timer_cb, // 回调函数
.name = "key_timer", // 定时器名称
};
// 创建定时器
esp_timer_create(
&timer_args, // 参数表
&key_timer // 句柄
);
}
static void key_dd_isr_handler(void *arg)
{
// 启动定时器,20ms 查询是否为低电平
// 1s = 1000 ms
// 1ms = 1000 us
esp_timer_start_once(key_timer, 20000); // 20 ms 后启动,消除抖动
// esp_timer_start_periodic(key_timer,20000); // 每间隔 20ms 启动一次
}
/**
* @brief 中断服务函数原型
*/
static void key_isr_handler(void *arg)
{
uint32_t value = *((uint32_t *)arg);
// 触发中断
xTaskNotifyFromISR(
t1, // 接收通知的任务句柄
value, // 通知值
eSetBits, // 通知方式
NULL // 是否优做切换
);
}
uint32_t key1_value = 1;
uint32_t key2_value = 2;
uint32_t key3_value = 3;
void app_main(void)
{
key_timer_init();
// 创建任务
xTaskCreate(
task1_entry, // 任务入口函数
"Task1", // 任务名称
4 * 1024, // 栈空间大小 字数非字节数 在大多数系统中,一个字的大小是 4 字节,16384 字节或 16KB。
NULL, // 参数指针
1, // 优先级
&t1 // 句柄
);
// 初始化按键中断
// 1. 初始化 gpio
gpio_config_t key_cfg = {
.pin_bit_mask = (1ULL << KEY1_GPIO) |
(1ULL << KEY2_GPIO) |
(1ULL << KEY3_GPIO) , // 按键的 GPIO 掩码
.mode = GPIO_MODE_INPUT, // 设置为输入模式
.pull_up_en = GPIO_PULLUP_ENABLE, // 因为 GPIO 0 接地导通,下降沿触发,所以上拉使能
.intr_type = GPIO_INTR_NEGEDGE // 下降沿触发
};
gpio_config(&key_cfg);
// 2. 设置中断类型
// 写不写无所谓,在 gpio_config_t 中的 intr_type 已经设置了
// gpio_set_intr_type(
// KEY1_GPIO, // 要设置的 GPIO
// GPIO_INTR_NEGEDGE // 中断触发方式
// );
// 3. 启用中断服务
gpio_install_isr_service(0); // 启用中断服务
// 4. 安装中断服务函数
gpio_isr_handler_add(
KEY1_GPIO, // 要安装的 gpio 编号
key_dd_isr_handler, // 函数地址(名称)
NULL // 参数
);
gpio_isr_handler_add(KEY2_GPIO, key_isr_handler, &key2_value);
gpio_isr_handler_add(KEY3_GPIO, key_isr_handler, &key3_value);
}