AiPi-Eyes-S1是安信可开源团队专门为Ai-M61-32S设计的一款开发板,支持WiFi6、BLE5.3。所搭载的Ai-M61-32S 模组具有丰富的外设接口,具体包括 DVP、MJPEG、Dispaly、AudioCodec、USB2.0、SDU、以太网 (EMAC)、SD/MMC(SDH)、SPI、UART、I2C、I2S、PWM、GPDAC、GPADC、ACOMP 和 GPIO 等。
AiPi-Eyes-S1集成了SPI屏幕接口,DVP摄像头接口,外置ES8388音频编解码芯片以及预留TF卡座,并且引出USB接口,可接入USB摄像头。
从零开始学习小安派:
1、零基础开发小安派-Eyes-S1【入门篇】——初识小安派-Eyes-S1
2、零基础开发小安派-Eyes-S1【入门篇】——安装VMware与Ubuntu
3、入门篇:零基础开发小安派-Eyes-S1——新建工程并烧录调试
4、零基础开发小安派-Eyes-S1入门篇——Win下SSH连接Linux
5、零基础开发小安派-Eyes-S1【入门篇】——Samba共享文件夹
6、零基础开发小安派-Eyes-S1【入门篇】——工程文件架构
7、零基础开发小安派-Eyes-S1【外设篇】——GPIO 输入输出
8、零基础开发小安派-Eyes-S1【外设篇】——GPIO中断编程
9、零基础开发小安派-Eyes-S1【外设篇】——PWM
10、零基础开发小安派-Eyes-S1【外设篇】——UART
11、零基础开发小安派-Eyes-S1【外设篇】——I2C
12、零基础开发小安派-Eyes-S1【外设篇】——ADC
13、零基础开发小安派-Eyes-S1【外设篇】——I2S
TIMER 也就是定时器,可以根据时钟源来分配计时的时间周期,实现准确的计时,一般软件的定时会出现误差,一些特殊情况需要精准的定时,那就需要使用到硬件定时器,如定时 5 分钟执行某些特殊任务。定时器可以搭配中断来使用,利用好时间间隔而满足个人的需求。
一、了解小安派-Eyes-S1 的 TIMER
芯片内置了两个 32-Bit 定时器,这两个定时器在 LHAL 库里对应 timer0 和 timer1。
这两组 TIMER 有以下特征:
• 多种时钟来源,最高可支持 80M 时钟
• 8-bit 时钟分频器,分频系数为 1-256
• 两个 32-bit 定时器:channel 0 和 channel 1
• 定时器包含三组报警值设定,可设定报警值溢出时报警
• 支持 Free Run 模式和 Pre_load 模式
• 一个 16-bit 看门狗定时器
• 支持写入密码保护,防止误设定造成系统异常
• 支持中断或复位两种看门狗溢出方式
• 支持测量外部 GPIO 的脉冲宽度
定时器的时钟来源有以下五种选择:
• BCLK--总线时钟
• 32K--32K 时钟
• 1K--1K 时钟(32K 的分频)
• XTAL--外部晶振
• GPIO--外部 GPIO
#define TIMER_CLKSRC_BCLK 0
#define TIMER_CLKSRC_32K 1
#define TIMER_CLKSRC_1K 2
#define TIMER_CLKSRC_XTAL 3
#define TIMER_CLKSRC_GPIO 4
#define TIMER_CLKSRC_NO 5
计数模式有以下两种:
定时器计数模式分为两种: freerun(向上计数模式)、preload(重装载模式)。
#define TIMER_COUNTER_MODE_PROLOAD 0
#define TIMER_COUNTER_MODE_UP 1
定时器一共三个 compare id, 用于设置不同的定时时间,可以当三个定时器使用。
#define TIMER_COMP_ID_0 0
#define TIMER_COMP_ID_1 1
#define TIMER_COMP_ID_2 2
二、结构体与函数接口
struct bflb_timer_config_s
说明:Timer 初始化配置结构体
struct bflb_timer_config_s {
uint8_t counter_mode;
uint8_t clock_source;
uint8_t clock_div;
uint8_t trigger_comp_id;
uint32_t comp0_val;
uint32_t comp1_val;
uint32_t comp2_val;
uint32_t preload_val;
};
bflb_timer_init
说明: 初始化 timer。使用之前需要开启 timer ip 时钟。
void bflb_timer_init(struct bflb_device_s *dev, const struct bflb_timer_config_s *config);
bflb_timer_deinit
说明: 反初始化 timer。
void bflb_timer_deinit(struct bflb_device_s *dev);
bflb_timer_start
说明: 启动 timer 。
void bflb_timer_start(struct bflb_device_s *dev);
bflb_timer_stop
说明: 停止 timer。
void bflb_timer_stop(struct bflb_device_s *dev);
bflb_timer_set_compvalue
说明: 设置 timer comp id 比较值。
void bflb_timer_set_compvalue(struct bflb_device_s *dev, uint8_t cmp_no, uint32_t val);
bflb_timer_get_compvalue
说明: 获取 comp id 比较值。
uint32_t bflb_timer_get_compvalue(struct bflb_device_s *dev, uint8_t cmp_no);
bflb_timer_get_countervalue
说明: 获取 timer 计数值。
uint32_t bflb_timer_get_countervalue(struct bflb_device_s *dev);
bflb_timer_compint_mask
说明: timer comp 中断屏蔽开关。
void bflb_timer_compint_mask(struct bflb_device_s *dev, uint8_t cmp_no, bool mask);
bflb_timer_get_compint_status
说明: 获取 timer comp id 中断匹配标志。
bool bflb_timer_get_compint_status(struct bflb_device_s *dev, uint8_t cmp_no);
bflb_timer_compint_clear
说明: 清除 timer comp id 中断标志
void bflb_timer_compint_clear(struct bflb_device_s *dev, uint8_t cmp_no);
三、定时器的两种计数方式以及中断触发
定时器时钟源的选择以及分频
以选择 TIMER_CLKSRC_XTAL 这个外部晶振的时钟源来举例,频率为 40MHz,而分频系数,也就是结构体中的 clock_div,这里系数可选 0~255,选择 39,时钟计数=时钟频率/(分频系数 +1)。也就是 40Mhz/(39+1),也就是 1Mhz,而周期与频率互为倒数,也就是 1us 一个计数。这样分频的话就是一微秒计数 +1。
计数模式
TIMER 有两种计数模式,分别是 freerun(向上计数模式)、preload(重装载模式)。
FreeRun 模式下,计数器的初始值为 0,定时器开始后,累加计数,当达到计数最大值后,然后从 0 再次开始计数。而最大值的数量估计是 comp0 的数据类型最大值,也就是 32 位数据。
相比之下,PreLoad 模式就好用多了,计数器的初始值是 PreLoad 寄存器的值,然后向上累加计数,当满足 PreLoad 条件时,计数器的值被置为 PreLoad 寄存器的值,然后计数器再次开始向上累加计数。
中断
结构体有 trigger_comp_id 选择几个比较 ID,如果选择三个 ID 的情况下,在定时器的计数器计数过程中,一旦计数器的值与三个比较器中的某比较值一致,该比较器的比较标志就会置位,并可以产生相应的比较中断。在所有的 ID 中断调节都达到后,会回到 PreLoad 的值,也就是 preload_val 重新开始计时。有如下一个示例的时序图,若预加载寄存器的值为 10,比较器 0 的值为 13,比较器 1 的值为 16,比较器 2 的值为 19。
在 FreeRun 模式下,定时器工作时序与 PreLoad 基本相同,只是计数器会从 0 开始累计到最大值,期间产生的比较标志和比较中断的机制与 FreeRun 模式相同。
简单示例:定时器分频每一秒进入一次中断,在中断修改全局变量,在主函数中打印
Main
#include "bflb_mtimer.h"
#include "bflb_timer.h"
#include "board.h"
struct bflb_device_s *timer0;
volatile static uint16_t MyTime_s = 0; //定义一个全局变量,在中断中修改,这里注意要用volatile关键字防止变量被优化
void timer0_isr(int irq, void *arg)
{
bool status = bflb_timer_get_compint_status(timer0, TIMER_COMP_ID_0);
if (status) {
bflb_timer_compint_clear(timer0, TIMER_COMP_ID_0);
if (MyTime_s==60)
{
MyTime_s = 0;
}
MyTime_s++;
printf("time is %drn",MyTime_s);
}
}
//中断服务函数,每进入一次变量自增1,到达60也就是1分钟置为0
int main(void)
{
board_init();
printf("Timer basic testn");
/* timer clk = XCLK/(div + 1 )*/
struct bflb_timer_config_s cfg0;
cfg0.counter_mode = TIMER_COUNTER_MODE_PROLOAD; /* 选择重装载模式 */
cfg0.clock_source = TIMER_CLKSRC_XTAL;//选择外部时钟晶振,40MHz
cfg0.clock_div = 39; /* for bl616/bl808/bl606p is 39, for bl702 is 31 */
cfg0.trigger_comp_id = TIMER_COMP_ID_0;//选择比较ID的个数,这里选择一个ID,也就是只会到达下面的ID1
cfg0.comp0_val = 1000000; /* 比较值ID1,当计数达到1000000时,根据前面的分频一微秒一个计数,也就是总共1秒 */
cfg0.comp1_val = 2500000; /* 比较值ID2,需要大于ID1,由于前面只设置了一个ID,所以这里不会触发 */
cfg0.comp2_val = 3500000; /* 比较值ID2,需要大于ID2,由于前面只设置了一个ID,所以这里不会触发 */
cfg0.preload_val = 0; /* 重装载值,开始的值,以及比较完所有ID个数后重启的值 */
timer0 = bflb_device_get_by_name("timer0");
/* Timer init with default configuration */
bflb_timer_init(timer0, &cfg0);
bflb_irq_attach(timer0->irq_num, timer0_isr, NULL);
bflb_irq_enable(timer0->irq_num);
/* Enable timer */
bflb_timer_start(timer0);//开启定时器
printf("case success.rn");
while (1) {
switch (MyTime_s)
{
case 10:
printf("10 seconds have passedrn");
break;
case 20:
printf("20 seconds have passedrn");
break;
case 30:
printf("30 seconds have passedrn");
break;
case 40:
printf("40 seconds have passedrn");
break;
case 50:
printf("50 seconds have passedrn");
break;
case 60:
printf("One minute has already passedrn");
break;
default:
break;
}
//对全局变量进行判断,通过switch语句分别打印
bflb_mtimer_delay_ms(900);
//这个延迟是为了防止在主函数中重复判断导致疯狂打印
}
}
效果
审核编辑 黄宇
-
开源
+关注
关注
3文章
3309浏览量
42471 -
Timer
+关注
关注
1文章
64浏览量
12784
发布评论请先 登录
相关推荐
评论