CH32V307系統(tǒng)提供了多個(gè)類型的定時(shí)器,具體可查看手冊(cè)了解:

這次的分享,我們使用到的定時(shí)器為系統(tǒng)時(shí)基定時(shí)器和基本定時(shí)器TIM6。
閃爍使用的LED,為L(zhǎng)ED1,使用連接線將LED1和PA0連接即可;實(shí)際運(yùn)行時(shí),間隔1秒閃爍一次。

有的同學(xué)可能會(huì)說(shuō),使用Delay_Ms或Delay_Us做演示,也能實(shí)現(xiàn)LED閃爍呀!
但在Delay的時(shí)候,你的程序,需要在這個(gè)地方,等待Delay時(shí)間后,才會(huì)繼續(xù)運(yùn)行。
而使用中斷,我們的程序,能夠繼續(xù)運(yùn)行做其他的事情,等到定時(shí)中斷到來(lái)的時(shí)候,才處理LED的閃爍。這樣程序的處理效率將會(huì)更高。
一、系統(tǒng)時(shí)基定時(shí)器SysTick
現(xiàn)在,我們了解一下系統(tǒng)時(shí)基定時(shí)器SysTick。
系統(tǒng)時(shí)基定時(shí)器:這是內(nèi)核控制器自帶的一個(gè) 64 位可選遞增或遞減的計(jì)數(shù)器,用于產(chǎn)生 SYSTICK 異常(異常號(hào):15),可專用于實(shí)時(shí)操作系統(tǒng),為系統(tǒng)提供“心跳”節(jié)律,也可當(dāng)成一個(gè)標(biāo)準(zhǔn)的 64 位計(jì)數(shù)器。具有自動(dòng)重加 載功能及可編程的時(shí)鐘源。
通過(guò)查看提供的實(shí)例和資料,了解到如下的關(guān)鍵信息:
1、系統(tǒng)的運(yùn)行頻率可以工作在72MHz,也可以工作在144MHz,通過(guò)system_ch32v30x.h/system_ch32v30x.c來(lái)修改:
// #define SYSCLK_FREQ_72MHz 72000000
(左右移動(dòng)查看全部?jī)?nèi)容)
在我的實(shí)例中,設(shè)置工作在144MHz。
2、在設(shè)置SysTick的時(shí)候,通過(guò)SysTick->CMP來(lái)設(shè)置定時(shí)中斷周期:SysTick->CMP = SystemCoreClock / 1000 * 1000; //后面的1000代表1000HZ(那就是1ms進(jìn)一次中斷),*1000 表示 1000ms進(jìn)入一次
3、有人會(huì)遇到,中斷只進(jìn)入一次,經(jīng)過(guò)請(qǐng)教沁恒的陶工,了解到如下處理方法:
// 中斷只進(jìn)入一次的問(wèn)題解決方法:
// 1. 如果使用沁恒提供的工具鏈,則使用如下的聲明:
// void SysTick_Handler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
// 2. 如果使用通用的risc-v工具鏈,如我在macOS下使用賽昉提供的工具鏈,則使用如下的聲明:
void SysTick_Handler(void) __attribute__((interrupt()));(左右移動(dòng)查看全部?jī)?nèi)容)
最終,具體的代碼如下:
/*
使用VTF IRQ中斷控制LED閃爍
*/
// 中斷只進(jìn)入一次的問(wèn)題解決方法:
// 1. 如果使用沁恒提供的工具鏈,則使用如下的聲明:
// void SysTick_Handler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
// 2. 如果使用通用的risc-v工具鏈,如我在macOS下使用賽昉提供的工具鏈,則使用如下的聲明:
void SysTick_Handler(void) __attribute__((interrupt()));
// LED狀態(tài)
volatile uint16_t LED_Status = 0; // 中斷里使用的變量加 volatile 可當(dāng)成全局變量
// 初始化 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 定時(shí)器
void SysTick_init(void)
{
/*配置中斷優(yōu)先級(jí)*/
NVIC_InitTypeDef NVIC_InitStructure = {0};
NVIC_InitStructure.NVIC_IRQChannel = SysTicK_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;//搶占式優(yōu)先級(jí)
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;//響應(yīng)式優(yōu)先級(jí)
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//使能
NVIC_Init(&NVIC_InitStructure);
/*配置定時(shí)器*/
SysTick->CTLR= 0;
SysTick->SR = 0;
SysTick->CNT = 0;
SysTick->CMP = SystemCoreClock / 1000 * 1000; //后面的1000代表1000HZ(那就是1ms進(jìn)一次中斷),*1000 表示 1000ms進(jìn)入一次
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); //設(shè)置中斷控制器的優(yōu)先級(jí)分組為 占優(yōu)先級(jí) 2位 ,優(yōu)先級(jí)2位。
USART_Printf_Init(115200);
printf("SystemClk:%drn", SystemCoreClock);
printf("Interrupt SysTick Testrn");
SysTick_init();
while (1)
{
}
}
// 中斷服務(wù)處理
void SysTick_Handler(void)
{
SysTick->SR = 0;
LED_Status = !LED_Status; // 將 LED 狀態(tài)值取反
GPIO_WriteBit(GPIOA, GPIO_Pin_0, LED_Status); // 配置 PA0 (即 LED1) 狀態(tài)
printf("Toggle LED by SysTick: %drn", LED_Status);
}(左右移動(dòng)查看全部?jī)?nèi)容)
在上述代碼中,關(guān)鍵部分如下:
GPIO_INIT:初始化GPIO,使用PA0;記得預(yù)先連接LED1和PA0
SysTick_init:SysTick初始化,主要設(shè)置中斷周期
SysTick_Handler:中斷服務(wù)處理,其內(nèi)部的操作需要狠準(zhǔn)快
除了板載的LED1(前提是連好了線)會(huì)間隔1秒閃爍一次,通過(guò)串口工具,我們也可以看到輸出的調(diào)試信息:

二、基本定時(shí)器TIM6
然后,我們?cè)賮?lái)了解一下基本定時(shí)器。
基本定時(shí)器:基本定時(shí)器是一個(gè) 16 位自動(dòng)裝載計(jì)數(shù)器,支持 16 位可編程預(yù)分頻器。可以位數(shù)模轉(zhuǎn)換(DAC)提供時(shí)鐘,觸發(fā) DAC 的同步電路?;径〞r(shí)器之間是互相獨(dú)立的,互不共享任何資源。
CH32V307提供了兩個(gè)基本定時(shí)器TIM6和TIM7,用法是一樣的,下面的實(shí)例中,使用TIM6。
通過(guò)官方提供的實(shí)例和資料了解到,基本定時(shí)器使用的過(guò)程中,有兩個(gè)設(shè)置是最重要的:
TIM_Prescaler:定時(shí)器預(yù)分頻器設(shè)置,時(shí)鐘源經(jīng)該預(yù)分頻器才是定時(shí)器時(shí)鐘。
TIM_Period:定時(shí)器周期,實(shí)際就是設(shè)定自動(dòng)重載寄存器的值。
這兩個(gè)參數(shù)結(jié)合就能實(shí)現(xiàn)實(shí)際所需要的定時(shí)。
根據(jù)定時(shí)器時(shí)鐘的頻率,比如時(shí)鐘的頻率是144MHz,可以理解為1秒鐘MCU會(huì)自己數(shù)144M次,預(yù)分頻系數(shù)就是將頻率分割,比如分頻系數(shù)是144,則該時(shí)鐘的頻率會(huì)變成144MHZ/144=1MHz,但是在設(shè)置的時(shí)候要注意,數(shù)值應(yīng)該是144-1。
為了讓 LED1間隔 1 秒閃爍一次,我們需要讓定時(shí)器 1 秒溢出,要計(jì)數(shù) 144M * 1 = 144M 個(gè)時(shí)鐘周期,而定時(shí)器只有16位,最大65535,所以這是不夠的。因此,需要用到預(yù)分頻器,設(shè)分頻系數(shù)為 14400,可以得到 10KHz 的定時(shí)器時(shí)鐘,這樣設(shè)置計(jì)數(shù)值 10000 就可以做到 1s 定時(shí)。
最終具體的代碼如下:
/*
使用基本定時(shí)器TIM6控制LED閃爍
*/
// 中斷只進(jìn)入一次的問(wèn)題解決方法:
// 1. 如果使用沁恒提供的工具鏈,則使用如下的聲明:
// void TIM6_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
// 2. 如果使用通用的risc-v工具鏈,如我在macOS下使用賽昉提供的工具鏈,則使用如下的聲明:
void TIM6_IRQHandler(void) __attribute__((interrupt()));
// LED狀態(tài)
volatile uint16_t LED_Status = 0; // 中斷里使用的變量加 volatile 可當(dāng)成全局變量
// 初始化 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);
}
// 初始化定時(shí)器 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);
}
// 初始化定時(shí)器中斷
void Interrupt_Init(void)
{
NVIC_InitTypeDef NVIC_InitStructure = {0};
NVIC_InitStructure.NVIC_IRQChannel = TIM6_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //搶占優(yōu)先級(jí)
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; //子優(yōu)先級(jí)
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); //設(shè)置中斷控制器的優(yōu)先級(jí)分組為 占優(yōu)先級(jí) 2位 ,優(yōu)先級(jí)2位。
USART_Printf_Init(115200);
TIM6_Init(10000 - 1, 14400 - 1); // 初始化定時(shí)器,讓 LED 1 秒閃爍一次,我們需要讓定時(shí)器 1 秒溢出,要計(jì)數(shù) `144M * 1 = 144M` 個(gè)時(shí)鐘周期,而定時(shí)器只有16位,這是不夠的。需要用到預(yù)分頻器,設(shè)分頻系數(shù)為 14400,可以得到 10KHz 的定時(shí)器時(shí)鐘,這樣設(shè)置計(jì)數(shù)值 10000 就可以做到 1s 定時(shí)。
Interrupt_Init(); //初始化定時(shí)器中斷
printf("SystemClk:%drn", SystemCoreClock);
printf("Interrupt TIM6 Testrn");
while (1)
{
}
}
// 中斷服務(wù)處理
void TIM6_IRQHandler(void)
{
TIM_ClearFlag(TIM6, TIM_FLAG_Update); //清除標(biāo)志位
LED_Status = !LED_Status; // 將 LED 狀態(tài)值取反
GPIO_WriteBit(GPIOA, GPIO_Pin_0, LED_Status); // 配置 PE11 (即 LED1) 狀態(tài)
printf("Toggle LED by TIM6: %drn", LED_Status);
}(左右移動(dòng)查看全部?jī)?nèi)容)
在上述代碼中,關(guān)鍵部分如下:
GPIO_INIT:初始化GPIO,使用PA0;記得預(yù)先連接LED1和PA0
TIM6_init:TIM6初始化,主要設(shè)置分頻和時(shí)間周期
Interrupt_Init:終端初始化
TIM6_IRQHandler中斷服務(wù)處理,其內(nèi)部的操作同樣需要狠準(zhǔn)快
除了板載的LED1(前提是連好了線)會(huì)間隔1秒閃爍一次,通過(guò)串口工具,我們也可以看到輸出的調(diào)試信息:



更多熱點(diǎn)文章閱讀
龍芯架構(gòu)首款面向嵌入式應(yīng)用的開(kāi)發(fā)板,2K500開(kāi)發(fā)應(yīng)用實(shí)例
ARM架構(gòu)國(guó)產(chǎn)MCU移植!國(guó)民技術(shù)N32系列開(kāi)源移植樣例合集
RK3568!四核64位ARMv8.2A架構(gòu),匯聚編譯源碼及實(shí)戰(zhàn)樣例
OpenHarmony開(kāi)源鴻蒙大賽作品集:基于RK2206開(kāi)發(fā)板20+成熟應(yīng)用案例!
24Bit ADC高精度低功耗MCU 醫(yī)療級(jí)別設(shè)備參考設(shè)計(jì)(附上高精確算法+電路原理圖)
原文標(biāo)題:【試用報(bào)告】沁恒CH32V307評(píng)估板體驗(yàn):定時(shí)器使用基礎(chǔ)
文章出處:【微信公眾號(hào):電子發(fā)燒友論壇】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
-
電子技術(shù)
+關(guān)注
關(guān)注
19文章
934瀏覽量
60108 -
電子發(fā)燒友論壇
+關(guān)注
關(guān)注
5文章
198瀏覽量
1680 -
ch32
+關(guān)注
關(guān)注
0文章
74瀏覽量
1273
原文標(biāo)題:【試用報(bào)告】沁恒CH32V307評(píng)估板體驗(yàn):定時(shí)器使用基礎(chǔ)
文章出處:【微信號(hào):gh_9b9470648b3c,微信公眾號(hào):電子發(fā)燒友論壇】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
國(guó)產(chǎn)100M以太網(wǎng)PHY:沁恒CH182H2性能測(cè)試應(yīng)用看這篇就夠了
沁恒CH9347助力新國(guó)標(biāo)充電寶全平臺(tái)無(wú)感連接
智能電表方案MCU單片機(jī)CH32V307系列
RT-Thread Studio CH32V307工程,程序運(yùn)行異常怎么解決?
【作品合集】沁恒微電子CH585開(kāi)發(fā)板測(cè)評(píng)
沁恒CH554評(píng)估板資料包
【沁恒CH585開(kāi)發(fā)板免費(fèi)試用體驗(yàn)】定時(shí)器操作
【沁恒CH585開(kāi)發(fā)板免費(fèi)試用體驗(yàn)】1、開(kāi)箱評(píng)測(cè)
【沁恒CH585開(kāi)發(fā)板免費(fèi)試用體驗(yàn)】+品讀老朋友的新產(chǎn)品
【沁恒CH585開(kāi)發(fā)板免費(fèi)試用體驗(yàn)】+開(kāi)箱點(diǎn)燈篇
【沁恒CH585開(kāi)發(fā)板免費(fèi)試用體驗(yàn)】+開(kāi)箱及開(kāi)發(fā)環(huán)境準(zhǔn)備
沁恒微電子:從互連互通應(yīng)用推動(dòng)RISC-V落地發(fā)展
CH32V303/305/307/317工業(yè)級(jí)通用微控制器數(shù)據(jù)手冊(cè)
使用RTT studio建立CH32V317的項(xiàng)目,無(wú)法使用以太網(wǎng)功能怎么辦?
沁恒微藍(lán)牙轉(zhuǎn)接芯片系列解析:CH9140/CH9141/CH9142/CH9143
【試用報(bào)告】沁恒CH32V307評(píng)估板體驗(yàn):定時(shí)器使用基礎(chǔ)
評(píng)論