定时器控制LED灯

定时器控制LED灯闪烁,按钮改变闪烁频率

一. 实验目的

  1. 为了更好的了解嵌入式中的功能,以较简单的方式提升自己对嵌入式的爱好,所以在这里开展了定时器控制LED灯的实验,本章可以基本了解ESP32的GPIO和软件定时器
  2. 硬件说明:本例程会用到一个软件定时器、一个按钮和一个LED灯

二. ESP32 GPIO介绍

1.GPIO的简介
  • ESP32具有34个物理管脚,每个管脚都可用作一个通用IO或者连接外部信号。通过 IO MUX、RTC IO MUX 和 GPIO 交换矩阵,可配置外设模块的输入信号来源于任何的 IO 管脚,并且外设模块的输出信号也可连接到任意 IO 管脚。
2. GPIO的主要特性
  • 输出状态可选推挽、上拉和下拉。
  • 输入状态可选择悬空、上拉或下拉、模拟。
  • 可设置中断条件,可以选择上升沿触发、下降沿触发、高电平触发、低电平触发.

三. ESP32定时器的介绍

1. 定时器的介绍

ESP32 内置 4 个 64-bit 通用定时器。每个定时器包含一个 16-bit 预分频器和一个 64-bit 可自动重新加载向上/向下计数器。
ESP32 的定时器分为 2 组,每组 2 个。TIMGn_Tx 的 n 代表组别,x 代表定时器编号。具有16-bit预分频、64-bit时基计数、警报产生、MWDT(主系统看门狗)、中断等多种功能

2. 定时器特性
  • 可配置向上/向下时基计数器
  • 暂停和恢复时基计数器
  • 电平触发中断和边沿触发中断
  • 软件控制的即时重新加载

四. 实验原理及程序结构

1. GPIO

基本原理就是利用ESP32的软件定时器特性,在周期性回调函数中控制LED灯的状态不断翻转,达到闪烁的效果。我们先来看GPIO的初始化

1.1. LED灯和按钮的初始化:
gpio_config_t led;
    led.pin_bit_mask = 1 << LED_R;
    led.mode = GPIO_MODE_OUTPUT;
    led.pull_up_en = GPIO_PULLUP_DISABLE;
    led.pull_down_en = GPIO_PULLDOWN_DISABLE;
    led.intr_type = GPIO_INTR_DISABLE;
    gpio_config(&led);
    
    gpio_config_t btn;
    btn.pin_bit_mask = 1 << BUTTON_PIN;
    btn.mode = GPIO_MODE_INPUT;
    btn.pull_up_en = GPIO_PULLUP_ENABLE;
    btn.pull_down_en = GPIO_PULLDOWN_DISABLE;
    btn.intr_type = GPIO_INTR_DISABLE;
    gpio_config(&btn);

LED灯和按钮的初始化比较简单,选择好引脚,将LED灯设为输出模式,按钮设为输入模式即可。

1. 2 LED控制
static void periodic_timer_callback(void* arg)
{
    static bool state = true;
    gpio_set_level (LED_R,state);
    state = !state;
    int64_t time_since_boot = esp_timer_get_time();
    printf("回调成功!\n");
}

每次调用定时器中的一次回调函数,LED灯的状态翻转一次,只要设置好定时器中的时间就可以改变LED灯的闪烁频率

2. 软件定时器
2.1 使用最简单的软件定时器
void app_main(void)
{
	//创建了一个新的事件,便于按钮控制定时器的时间
    xTaskCreate(myTask, "myTask", 1024, NULL, 1, NULL);
    //创建一个周期性定时器
    const esp_timer_create_args_t periodic_timer_args = {
        .callback = &periodic_timer_callback, //周期定时回调
        //定时器名称
        .name = "periodic"};
    esp_timer_handle_t periodic_timer;
    /* 计时器已经创建,但还没有运行 */
    ESP_ERROR_CHECK(esp_timer_create(&periodic_timer_args, &periodic_timer));
    //创建定时器句柄,设置定时器周期为2秒,启动定时器
    ESP_ERROR_CHECK(esp_timer_start_periodic(periodic_timer, 2*000*000));
}

这里设置的定时器为两秒,每调用一次,LED灯的状态就翻转一次,实现闪烁到这里,定时器控制LED灯已经完成了,但按钮控制还没有完成。

2.2 按钮控制定时器

在这里只要控制了定时器的时间就改变了LED灯的闪烁频率,接下来就看按钮如何控制定时器的:

void Led_Init(esp_timer_handle_t handle)
{
int level = 0;
    uint32_t period = 1000;
    while (1)
    {
    	//确定按钮是否按下,消抖
        if (gpio_get_level(BUTTON_PIN) == 0)
        {
        	//再次确定按钮是否按下,防止一次按下多次触发
            vTaskDelay(pdMS_TO_TICKS(10));
            if (gpio_get_level(BUTTON_PIN) == 0)
            {
                period -= 35;
                timer_set(handle, period);
            }
        }
        //防止看门狗报错
        vTaskDelay(pdMS_TO_TICKS(10));
    }
}

在这里调用了定时器中的句柄,重新设置了定时器的时间,并在按钮程序中让定时器的时间逐渐减少,进而达到LED灯闪烁越来越快的效果,实现按钮控制LED灯的闪烁频率。

五. 源码

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "esp_timer.h"
#include "esp_log.h"
#include "esp_sleep.h"
#include "sdkconfig.h"

// gpio头文件
#include "driver/gpio.h"
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
// gpio文件结束

// gpio宏定义
#define LED_R 2
#define BUTTON_PIN 14
// gpio宏定义结束
void myTask(void *pvParam)
{
    while (1)
    {
        printf("five by five\n");
        vTaskDelay(60000 / portTICK_PERIOD_MS);
    }
}
//----------------------------------------------------------------------------------------------------------------------------------------
// gpio开始配置
static void timer_set(esp_timer_handle_t handle, uint32_t nms)
{
    /* 启动正在运行的定时器,需要先停止 */
    ESP_ERROR_CHECK(esp_timer_stop(handle));
    //将时间从微秒化成毫秒
    ESP_ERROR_CHECK(esp_timer_start_periodic(handle, nms * 1000));
}
//----------------------------------------------------------------------------------------------------------------------------------------
void Led_Init(esp_timer_handle_t handle)
{
    gpio_config_t led;
    led.pin_bit_mask = 1 << LED_R;
    led.mode = GPIO_MODE_OUTPUT;
    led.pull_up_en = GPIO_PULLUP_DISABLE;
    led.pull_down_en = GPIO_PULLDOWN_DISABLE;
    led.intr_type = GPIO_INTR_DISABLE;
    gpio_config(&led);

    gpio_config_t btn;
    btn.pin_bit_mask = 1 << BUTTON_PIN;
    btn.mode = GPIO_MODE_INPUT;
    btn.pull_up_en = GPIO_PULLUP_ENABLE;
    btn.pull_down_en = GPIO_PULLDOWN_DISABLE;
    btn.intr_type = GPIO_INTR_DISABLE;
    gpio_config(&btn);

    int level = 0;
    uint32_t period = 1000;
    while (1)
    {
        if (gpio_get_level(BUTTON_PIN) == 0)
        {
            vTaskDelay(pdMS_TO_TICKS(10));
            if (gpio_get_level(BUTTON_PIN) == 0)
            {
                // level = !level;
                // gpio_set_level(LED_R, level);
                period -= 35;
                timer_set(handle, period);
            }
        }
        vTaskDelay(pdMS_TO_TICKS(10));
    }
}
//----------------------------------------------------------------------------------------------------------------------------------------
static void periodic_timer_callback(void *arg);

static const char *TAG = "example";
//打印信息配置
//----------------------------------------------------------------------------------------------------------------------------------------
void app_main(void)
{
    xTaskCreate(myTask, "myTask", 1024, NULL, 1, NULL);
    //创建一个周期性定时器
    const esp_timer_create_args_t periodic_timer_args = {
        .callback = &periodic_timer_callback, //周期定时回调
        //定时器名称
        .name = "periodic"};
    esp_timer_handle_t periodic_timer;
    /* 计时器已经创建,但还没有运行 */
    ESP_ERROR_CHECK(esp_timer_create(&periodic_timer_args, &periodic_timer));
    //创建定时器句柄,设置定时器周期为2秒,启动定时器
    ESP_ERROR_CHECK(esp_timer_start_periodic(periodic_timer, 4 * 000 * 000));
    Led_Init(periodic_timer);
}
//----------------------------------------------------------------------------------------------------------------------------------------
static void periodic_timer_callback(void *arg)
{
    static bool state = true;
    gpio_set_level(LED_R, state);
    state = !state;
    int64_t time_since_boot = esp_timer_get_time();
    printf("回调成功!\n");
}

六. 总结

1 实验需求:

在这里插入图片描述
不难看出这个实验的需求只有三个:LED灯、按钮和定时器,配置它们是最基础的地方,其他的只要逻辑思维不出错便没有太多的难点。

2. 实践操作
2.1 定时器控制LED
Created with Raphaël 2.3.0 启动定时器 开始回调 调用LED即翻转 LED灯开始闪烁 yes
2.2 按钮控制LED
Created with Raphaël 2.3.0 按下按钮 定时器时间递减 改变LED频率 LED越闪越快直到停止 yes
  • 4
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值