由 爱笑 贡献,Ai-Thinker 进行整理
【Ai-WB2入门篇】定时器使用
通用定时器,用于定时,当时间到达我们所设置的定时时间会产生定时中断,可以用来完成定时任务。本文将详细介绍如何使用BL602的定时器功能。 一:Ai-WB2定时器介绍 Ai-WB2内置2组32-bit 计数器,每个计数器可独立控制配置其参数与时钟频率。定时器的功能框图如下:

Ai-WB2的定时器有如下特性:
📜 点击展开完整代码
**·** 多种时钟来源,最高可支持160M时钟
**·** 8-bit 时钟分频器,分频系数为1-256
**·** 两组32-bit定时器
**·** 每个定时器包含三组报警值设定,可独立设定每组报警值溢出时报警
**·** 支持Free Run模式和Pre load模式
**·** 16-bit 看门狗定时器
**·** 支持写入密码保护,防止误设定造成系统异常
**·** 支持中断或复位两种看门狗溢出方式每个定时器时钟来源都有四种选择,来源如下:
📜 点击展开完整代码
**·** Fclk-系统主时钟
**·** 32K-32K时钟
**·** 1K-1K时钟(32K的分频)
**·** Xtal-外部晶振每个计数器有各自的8-bit分频器,可通过APB将选择到的时钟进行1-256的分频,具体来说设定为0时表示不分频,设定为1时进行2分频以此类推,最大分频系数为256,计数器将以分频后的时钟作为计数周期单位,每经过一个计数周期进行上数一的动作。 通用定时器工作原理 每个通用定时器都包含三组比较器一个计数器以及一个预加载寄存器,当设定好时钟源,启动定时器后,计数器开始向上累加计数当计数器的值与比较器相等的时候,比较标志置位同时可以产生比较中断。 计数器的初始值取决于定时的模式,在FreeRun模式下,计数器的初始值是0,然后累加计数,当达到计数最大值后,然后从0再次开始 计数。在PreLoad模式下,计数器的初始值是PreLoad寄存器的值,然后向上累加计数,当满足PreLoad条件时,计数器的值被置为PreLoad寄存器的值,然后计数器再次开始向上累加计数,在定时器的计数器计数过程中,一旦计数器的值与三个比较器中的某比较值一致,该比较器的比较标志就会置位,并可以产生相应的比较中断。 若预加载寄存器的值为10,比较器0的值为13,比较器1的值为16,比较器2的值为19,则定时器在PreLoad的模式下工作时序如下图:

在FreeRun模式下,定时器工作时序与PreLoad基本相同,只是计数器会从0开始累计到最大值,期间产生的比较标志和比较中断的机制与FreeRun模式相同。 警报设置 每一组计数器有三个比较值提供软件设定,并可设定每一组比较值是否触发报警中断, 当计数器与比较值吻合且设定会报警时,计数器会通过中断通知处理器。软件可以通过APB读取目前是否发生报警和是哪个比较值触发报警中断, 当清理报警中断时亦会同步清理报警状态。 二:定时器驱动API介绍 定时器的HOSAL层的高级驱动API在文件 components/platform/hosal/include/hosal timer.h中定义。常用的API函数如下: · int hosal_timer_init(hosal_timer_dev_t *tim):初始化定时器,参数说明如下: · tim:定时器设备。其定义如下:
📜 点击展开完整代码
typedef struct {
int8_t port; /**< 定时器端口 */
hosal_timer_config_t config; /**< 定时器配置 */
void *priv; /**< 用户自定义数据 */
} hosal_timer_dev_t;hosal_timer_confit_t定时器配置定义如下:
📜 点击展开完整代码
typedef struct {
uint32_t period; /**< 定时器周期以纳秒为单位 */
uint8_t reload_mode; /**< 是否自动重载 */
hosal_timer_cb_t cb; /**< 超时中断回调函数 */
void *arg; /**< 回调函数参数 */
} hosal_timer_config_t;hosal_timer_cb_t为定时器回调函数,其定义如下:
- typedef void (*hosal_timer_cb_t)(void *arg);
📜 点击展开完整代码
**·** 返回值:成功时返回0;否则返回非零值
**·** int hosal_timer _start(hosal_timer_dev_t *tim):启动定时器。参数说明如下:
**·** tim:定时器设备对象
**·** 返回值:成功时返回0;否则返回非零值
**·** void hosal_timer_stop(hosal_timer_dev_t *tim):停止定时器。参数说明如下:
**·** tim:定时器设备对象
**·** 返回值:成功时返回0;否则返回非零值
**·** int hosal_timer_finalize(hosal_timer_dev_t *tim):定时器销毁。当不再使用定时器需要调用此函数。参数说明如下:
**·** tim:定时器设备对象
**·** 返回值:成功时返回0:否则返回非零值
**三:定时器使用实例**BL602的通用定时器分为单次计时和持续计时两种模式,
- #define TIMER_RELOAD_PERIODIC 1 /**< 定时器自动重载 */
- #define TIMER_RELOAD_ONCE 2 /**< 定时器自动重载一次,需要手动重载 */
下面将演示如何使用这两种模式
📜 点击展开完整代码
单次计时
#include <stdio.h>
#include <string.h>
#include <FreeRTOS.h>
#include <task.h>
#include <stdio.h>
#include <stdbool.h>
#include <bl_gpio.h>
#include <hosal_gpio.h>
#include <hosal_timer.h>
#include <blog.h>
#define TAG "uart_demo"
#define LED_RED 14
#define LED_GREEN 17
#define LED_BLUE 3
static hosal_timer_dev_t timer;
void timer_callback(void *arg)
{
static int i = 0;
if (i % 3 == 0) {
bl_gpio_output_set(LED_RED,1);
bl_gpio_output_set(LED_GREEN,0);
bl_gpio_output_set(LED_BLUE,0);
} else if(i % 3 == 1) {
bl_gpio_output_set(LED_RED,0);
bl_gpio_output_set(LED_GREEN,1);
bl_gpio_output_set(LED_BLUE,0);
}else{
bl_gpio_output_set(LED_RED,0);
bl_gpio_output_set(LED_GREEN,0);
bl_gpio_output_set(LED_BLUE,1);
}
i++;
}
void timer_demo_init(void)
{
timer.port = 0;
timer.config.period = 2000 * 1000; /* 2000ms */
timer.config.reload_mode = TIMER_RELOAD_ONCE;
timer.config.cb =timer_callback;
timer.config.arg = NULL;
bl_gpio_enable_output(LED_RED, 1, 0);
bl_gpio_enable_output(LED_GREEN, 1, 0);
bl_gpio_enable_output(LED_BLUE, 1, 0);
// 初始化定时器
hosal_timer_init(&timer);
// 启动定时器
hosal_timer_start(&timer);
}
void main(void) {
timer_demo_init();
printf("timer demo start\r\n");
}
持续计时
#include <stdio.h>
#include <string.h>
#include <FreeRTOS.h>
#include <task.h>
#include <stdio.h>
#include <stdbool.h>
#include <bl_gpio.h>
#include <hosal_gpio.h>
#include <hosal_timer.h>
#include <blog.h>
#define TAG "uart_demo"
#define LED_RED 14
#define LED_GREEN 17
#define LED_BLUE 3
static hosal_timer_dev_t timer;
void timer_callback(void *arg)
{
static int i = 0;
if (i % 3 == 0) {
bl_gpio_output_set(LED_RED,1);
bl_gpio_output_set(LED_GREEN,0);
bl_gpio_output_set(LED_BLUE,0);
} else if(i % 3 == 1) {
bl_gpio_output_set(LED_RED,0);
bl_gpio_output_set(LED_GREEN,1);
bl_gpio_output_set(LED_BLUE,0);
}else{
bl_gpio_output_set(LED_RED,0);
bl_gpio_output_set(LED_GREEN,0);
bl_gpio_output_set(LED_BLUE,1);
}
i++;
}
void timer_demo_init(void)
{
timer.port = 0;
timer.config.period = 200 * 1000; /* 200ms */
timer.config.reload_mode = TIMER_RELOAD_PERIODIC;
timer.config.cb =timer_callback;
timer.config.arg = NULL;
bl_gpio_enable_output(LED_RED, 1, 0);
bl_gpio_enable_output(LED_GREEN, 1, 0);
bl_gpio_enable_output(LED_BLUE, 1, 0);
hosal_timer_init(&timer);
hosal_timer_start(&timer);
}
void main(void) {
timer_demo_init();
printf("timer demo start\r\n");
}
