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
發布評論請先 登錄
相關推薦
評論