CH32V307系統提供了多個類型的定時器,具體可查看手冊了解:
這次的分享,我們使用到的定時器為系統時基定時器和基本定時器TIM6。
閃爍使用的LED,為LED1,使用連接線將LED1和PA0連接即可;實際運行時,間隔1秒閃爍一次。
有的同學可能會說,使用Delay_Ms或Delay_Us做演示,也能實現LED閃爍呀!
但在Delay的時候,你的程序,需要在這個地方,等待Delay時間后,才會繼續運行。
而使用中斷,我們的程序,能夠繼續運行做其他的事情,等到定時中斷到來的時候,才處理LED的閃爍。這樣程序的處理效率將會更高。
一、系統時基定時器SysTick
現在,我們了解一下系統時基定時器SysTick。
系統時基定時器:這是內核控制器自帶的一個 64 位可選遞增或遞減的計數器,用于產生 SYSTICK 異常(異常號:15),可專用于實時操作系統,為系統提供“心跳”節律,也可當成一個標準的 64 位計數器。具有自動重加 載功能及可編程的時鐘源。
1、系統的運行頻率可以工作在72MHz,也可以工作在144MHz,通過system_ch32v30x.h/system_ch32v30x.c來修改:
// #define SYSCLK_FREQ_72MHz 72000000
(左右移動查看全部內容)
在我的實例中,設置工作在144MHz。
2、在設置SysTick的時候,通過SysTick->CMP來設置定時中斷周期:SysTick->CMP = SystemCoreClock / 1000 * 1000; //后面的1000代表1000HZ(那就是1ms進一次中斷),*1000 表示 1000ms進入一次
3、有人會遇到,中斷只進入一次,經過請教沁恒的陶工,了解到如下處理方法:
// 中斷只進入一次的問題解決方法:
// 1. 如果使用沁恒提供的工具鏈,則使用如下的聲明:
// void SysTick_Handler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
// 2. 如果使用通用的risc-v工具鏈,如我在macOS下使用賽昉提供的工具鏈,則使用如下的聲明:
void SysTick_Handler(void) __attribute__((interrupt()));
(左右移動查看全部內容)
最終,具體的代碼如下:
/*
使用VTF IRQ中斷控制LED閃爍
*/
// 中斷只進入一次的問題解決方法:
// 1. 如果使用沁恒提供的工具鏈,則使用如下的聲明:
// void SysTick_Handler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
// 2. 如果使用通用的risc-v工具鏈,如我在macOS下使用賽昉提供的工具鏈,則使用如下的聲明:
void SysTick_Handler(void) __attribute__((interrupt()));
// LED狀態
volatile uint16_t LED_Status = 0; // 中斷里使用的變量加 volatile 可當成全局變量
// 初始化 GPIO
void GPIO_INIT(void)
{
GPIO_InitTypeDef GPIO_InitStructure = {0};
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
// 初始化 SysTick 定時器
void SysTick_init(void)
{
/*配置中斷優先級*/
NVIC_InitTypeDef NVIC_InitStructure = {0};
NVIC_InitStructure.NVIC_IRQChannel = SysTicK_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;//搶占式優先級
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;//響應式優先級
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//使能
NVIC_Init(&NVIC_InitStructure);
/*配置定時器*/
SysTick->CTLR= 0;
SysTick->SR = 0;
SysTick->CNT = 0;
SysTick->CMP = SystemCoreClock / 1000 * 1000; //后面的1000代表1000HZ(那就是1ms進一次中斷),*1000 表示 1000ms進入一次
SysTick->CTLR= 0xf;
}
int main(void)
{
/* Initialize board components. */
BOARD_SystemClock_Config();
BOARD_IOMUX_Init();
BOARD_Peripheral_Init();
GPIO_INIT(); // 初始化 GPIO
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //設置中斷控制器的優先級分組為 占優先級 2位 ,優先級2位。
USART_Printf_Init(115200);
printf("SystemClk:%drn", SystemCoreClock);
printf("Interrupt SysTick Testrn");
SysTick_init();
while (1)
{
}
}
// 中斷服務處理
void SysTick_Handler(void)
{
SysTick->SR = 0;
LED_Status = !LED_Status; // 將 LED 狀態值取反
GPIO_WriteBit(GPIOA, GPIO_Pin_0, LED_Status); // 配置 PA0 (即 LED1) 狀態
printf("Toggle LED by SysTick: %drn", LED_Status);
}
(左右移動查看全部內容)
在上述代碼中,關鍵部分如下:
GPIO_INIT:初始化GPIO,使用PA0;記得預先連接LED1和PA0
SysTick_init:SysTick初始化,主要設置中斷周期
SysTick_Handler:中斷服務處理,其內部的操作需要狠準快
除了板載的LED1(前提是連好了線)會間隔1秒閃爍一次,通過串口工具,我們也可以看到輸出的調試信息:
二、基本定時器TIM6
然后,我們再來了解一下基本定時器。
基本定時器:基本定時器是一個 16 位自動裝載計數器,支持 16 位可編程預分頻器??梢晕粩的^D換(DAC)提供時鐘,觸發 DAC 的同步電路?;径〞r器之間是互相獨立的,互不共享任何資源。
CH32V307提供了兩個基本定時器TIM6和TIM7,用法是一樣的,下面的實例中,使用TIM6。
通過官方提供的實例和資料了解到,基本定時器使用的過程中,有兩個設置是最重要的:
TIM_Prescaler:定時器預分頻器設置,時鐘源經該預分頻器才是定時器時鐘。
TIM_Period:定時器周期,實際就是設定自動重載寄存器的值。
這兩個參數結合就能實現實際所需要的定時。
根據定時器時鐘的頻率,比如時鐘的頻率是144MHz,可以理解為1秒鐘MCU會自己數144M次,預分頻系數就是將頻率分割,比如分頻系數是144,則該時鐘的頻率會變成144MHZ/144=1MHz,但是在設置的時候要注意,數值應該是144-1。
為了讓 LED1間隔 1 秒閃爍一次,我們需要讓定時器 1 秒溢出,要計數 144M * 1 = 144M 個時鐘周期,而定時器只有16位,最大65535,所以這是不夠的。因此,需要用到預分頻器,設分頻系數為 14400,可以得到 10KHz 的定時器時鐘,這樣設置計數值 10000 就可以做到 1s 定時。
最終具體的代碼如下:
/*
使用基本定時器TIM6控制LED閃爍
*/
// 中斷只進入一次的問題解決方法:
// 1. 如果使用沁恒提供的工具鏈,則使用如下的聲明:
// void TIM6_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
// 2. 如果使用通用的risc-v工具鏈,如我在macOS下使用賽昉提供的工具鏈,則使用如下的聲明:
void TIM6_IRQHandler(void) __attribute__((interrupt()));
// LED狀態
volatile uint16_t LED_Status = 0; // 中斷里使用的變量加 volatile 可當成全局變量
// 初始化 GPIO
void GPIO_INIT(void)
{
GPIO_InitTypeDef GPIO_InitStructure = {0};
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
// 初始化定時器 TIM6
void TIM6_Init(u16 arr, u16 psc)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE);
TIM_TimeBaseInitStructure.TIM_Period = arr;
TIM_TimeBaseInitStructure.TIM_Prescaler = psc;
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Down;
TIM_TimeBaseInit(TIM6, &TIM_TimeBaseInitStructure);
TIM_ITConfig(TIM6, TIM_IT_Update, ENABLE);
TIM_ARRPreloadConfig(TIM6, ENABLE);
TIM_Cmd(TIM6, ENABLE);
}
// 初始化定時器中斷
void Interrupt_Init(void)
{
NVIC_InitTypeDef NVIC_InitStructure = {0};
NVIC_InitStructure.NVIC_IRQChannel = TIM6_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //搶占優先級
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; //子優先級
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
int main(void)
{
/* Initialize board components. */
BOARD_SystemClock_Config();
BOARD_IOMUX_Init();
BOARD_Peripheral_Init();
GPIO_INIT(); // 初始化 GPIO
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //設置中斷控制器的優先級分組為 占優先級 2位 ,優先級2位。
USART_Printf_Init(115200);
TIM6_Init(10000 - 1, 14400 - 1); // 初始化定時器,讓 LED 1 秒閃爍一次,我們需要讓定時器 1 秒溢出,要計數 `144M * 1 = 144M` 個時鐘周期,而定時器只有16位,這是不夠的。需要用到預分頻器,設分頻系數為 14400,可以得到 10KHz 的定時器時鐘,這樣設置計數值 10000 就可以做到 1s 定時。
Interrupt_Init(); //初始化定時器中斷
printf("SystemClk:%drn", SystemCoreClock);
printf("Interrupt TIM6 Testrn");
while (1)
{
}
}
// 中斷服務處理
void TIM6_IRQHandler(void)
{
TIM_ClearFlag(TIM6, TIM_FLAG_Update); //清除標志位
LED_Status = !LED_Status; // 將 LED 狀態值取反
GPIO_WriteBit(GPIOA, GPIO_Pin_0, LED_Status); // 配置 PE11 (即 LED1) 狀態
printf("Toggle LED by TIM6: %drn", LED_Status);
}
(左右移動查看全部內容)
在上述代碼中,關鍵部分如下:
GPIO_INIT:初始化GPIO,使用PA0;記得預先連接LED1和PA0
TIM6_init:TIM6初始化,主要設置分頻和時間周期
Interrupt_Init:終端初始化
TIM6_IRQHandler中斷服務處理,其內部的操作同樣需要狠準快
除了板載的LED1(前提是連好了線)會間隔1秒閃爍一次,通過串口工具,我們也可以看到輸出的調試信息:
更多熱點文章閱讀
原文標題:【試用報告】沁恒CH32V307評估板體驗:定時器使用基礎
文章出處:【微信公眾號:電子發燒友論壇】歡迎添加關注!文章轉載請注明出處。
-
電子技術
+關注
關注
18文章
884瀏覽量
55853 -
電子發燒友論壇
+關注
關注
4文章
197瀏覽量
1055 -
ch32
+關注
關注
0文章
73瀏覽量
628
原文標題:【試用報告】沁恒CH32V307評估板體驗:定時器使用基礎
文章出處:【微信號:gh_9b9470648b3c,微信公眾號:電子發燒友論壇】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論