1)實驗平臺:正點原子APM32E103最小系統(tǒng)板
2)平臺購買地址:https://detail.tmall.com/item.htm?id=609294757420
3)全套實驗源碼+手冊+視頻下載地址: http://www.openedv.com/docs/boards/xiaoxitongban
第二十一章 高級定時器輸出指定個數(shù)PWM實驗
本章將介紹使用APM32E103高級定時器輸出指定個數(shù)的PWM。通過本章的學(xué)習(xí),讀者將學(xué)習(xí)到高級定時器重復(fù)計數(shù)器的使用。
本章分為如下幾個小節(jié):
21.1 硬件設(shè)計
21.2 程序設(shè)計
21.3 下載驗證
21.1 硬件設(shè)計
21.1.1 例程功能
- 按下KEY0按鍵,控制定時器8通過PC6引腳以2Hz的頻率輸出5個PWM脈沖
21.1.2 硬件資源 - 按鍵
KEY0 - PE4 - 定時器8
通道1 - PC6
21.1.3 原理圖
本章實驗使用的定時器8為APM32E103的片上資源,因此沒有對應(yīng)的連接原理圖。
21.2 程序設(shè)計
21.2.1 Geehy標(biāo)準(zhǔn)庫的TMR驅(qū)動
本章實驗將使用KEY0按鍵控制TMR8通過通道1(PC6引腳)輸出指定個數(shù)的PWM。對于高級定時器自動重裝載值、預(yù)分頻計數(shù)器數(shù)值等基本參數(shù)的配置,與基本定時器和通用定時器的配置基本一致;對于高級定時器輸出PWM,則于通用定時器輸出PWM的配置基本一致,不過于通用定時器不同的是,高級定時器使能輸出PWM需要將“剎車和死區(qū)寄存器(TMRx_BDT)”的MOEN位置1。要做到輸出指定個數(shù)的PWM,需要使用到高級定時器的重復(fù)計數(shù)寄存器,重復(fù)計數(shù)寄存器可以配置高級定時器產(chǎn)生多少次上溢或下溢(一次上溢或下溢對應(yīng)一個PWM)后才產(chǎn)生一次更新事件,其具體的配置步驟如下:
①:配置TMR8的自動重裝載值和預(yù)分頻器數(shù)值等參數(shù)
②:配置輸出比較通道1
③:使能TMR8的更新中斷
④:使能TMR8中斷,并配置其相關(guān)的中斷優(yōu)先級
⑤:使能TMR8
⑥:使能輸出比較通道1輸出
⑦:使能TMR8的PWM輸出
⑧:配置TMR8的重復(fù)計數(shù)寄存器
在Geehy標(biāo)準(zhǔn)庫中對應(yīng)的驅(qū)動函數(shù)如下:
①:配置TMR
請見第16.2.1小節(jié)中配置TMR的相關(guān)內(nèi)容。
②:配置輸出比較通道
請見第18.2.1小節(jié)中配置輸出比較通道的相關(guān)內(nèi)容。
③:使能TMR指定中斷
請見第16.2.1小節(jié)中使能TMR指定中斷的相關(guān)內(nèi)容。
④:配置TMR中斷
請見第12.2.3小節(jié)中配置中斷的相關(guān)內(nèi)容。
⑤:使能TMR
請見第16.2.1小節(jié)中使能TMR的相關(guān)內(nèi)容。
⑥:使能捕獲比較通道
請見第18.2.1小節(jié)中使能捕獲比較通道的相關(guān)內(nèi)容。
⑦:使能高級定時器PWM輸出
該函數(shù)用于使能高級定時器輸出PWM,其函數(shù)原型如下所示:
void TMR_EnablePWMOutputs(TMR_T* tmr);
該函數(shù)的形參描述,如下表所示:
形參 描述
tmr 指向高級TMR外設(shè)結(jié)構(gòu)體的指針
例如:TMR1、TMR8(在apm32e10x.h文件中有定義)
表21.2.1.1 函數(shù)TMR_EnablePWMOutputs()形參描述
該函數(shù)的返回值描述,如下表所示:
返回值 描述
無 無
表21.2.1.2 函數(shù)TMR_EnablePWMOutputs()返回值描述
該函數(shù)的使用示例,如下所示:
#include "apm32e10x.h"
#include "apm32e10x_tmr.h"
void example_fun(void)
{
/* 使能TMR8使出PWM */
TMR_EnablePWMOutputs(TMR8);
}
⑧:配置重復(fù)計數(shù)寄存器
高級定時器的重復(fù)計數(shù)寄存器可以在配置TMR寄存器參數(shù)時,通過函數(shù)TMR_ConfigTimeBase()進(jìn)行配置,也可以通過寫寄存器的方式直接修改高級定時器重復(fù)計數(shù)寄存器的數(shù)值,示例如下所示:
#include "apm32e10x.h"
void example_fun(void)
{
/* 配置TMR8的重復(fù)計數(shù)寄存器為5 */
TMR8->REPCNT = 5;
}
21.2.2 高級定時器驅(qū)動
本章實驗的高級定時器驅(qū)動主要負(fù)責(zé)向應(yīng)用層提供高級定時器的初始化和輸出指定個數(shù)PWM的函數(shù),并實現(xiàn)高級定時器的中斷回調(diào)函數(shù)。本章實驗中,高級定時器驅(qū)動的驅(qū)動代碼包括atmr.c和atmr.h兩個文件。
高級定時器驅(qū)動中,對TMR、GPIO的相關(guān)宏定義,如下所示:
/* 高級定時器PWM輸出引腳定義 */
#define ATMRX_TMRX_NPWM_CHY_GPIO_PORT GPIOC
#define ATMRX_TMRX_NPWM_CHY_GPIO_PIN GPIO_PIN_6
#define ATMRX_TMRX_NPWM_CHY_GPIO_CLK_ENABLE() do{ RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_GPIOC); }while(0)
/* 高級定時器定義 */
#define ATMRX_TMRX_NPWM TMR8
#define ATMRX_TMRX_NPWM_IRQn TMR8_UP_IRQn
#define ATMRX_TMRX_NPWM_IRQHandler TMR8_UP_IRQHandler
#define ATMRX_TMRX_NPWM_CHY TMR_CHANNEL_1
#define ATMRX_TMRX_NPWM_CHY_CLK_ENABLE() do{ RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_TMR8); }while(0)
高級定時器驅(qū)動中TMR8的初始化函數(shù),如下所示:
/**
* @brief 初始化高級定時器PWM輸出模式
* @note
* 高級定時器的時鐘來自APB2, 而PCLK2 = 120Mhz, 我們設(shè)置PPRE2不分頻, 因此
* 高級定時器時鐘 = 120Mhz
* 定時器溢出時間計算方法: Tout = ((arr + 1) * (psc + 1)) / Ft us.
* Ft=定時器工作頻率,單位:Mhz
*
* @param arr: 自動重裝值
* @param psc: 時鐘預(yù)分頻數(shù)
* @retval 無
*/
void atmr_tmrx_npwm_chy_init(uint16_t arr, uint16_t psc)
{
GPIO_Config_T gpio_init_struct;
TMR_BaseConfig_T tmr_init_struct;
TMR_OCConfig_T tmr_oc_init_struct;
/* 使能時鐘 */
ATMRX_TMRX_NPWM_CHY_GPIO_CLK_ENABLE(); /* 高級定時器通道I/O口時鐘使能 */
ATMRX_TMRX_NPWM_CHY_CLK_ENABLE(); /* 高級定時器時鐘使能 */
/* 配置PWM輸出引腳 */
gpio_init_struct.pin = ATMRX_TMRX_NPWM_CHY_GPIO_PIN; /* 通道y的GPIO口 */
gpio_init_struct.mode = GPIO_MODE_AF_PP; /* 推挽復(fù)用輸出 */
gpio_init_struct.speed = GPIO_SPEED_50MHz; /* 高速 */
GPIO_Config(ATMRX_TMRX_NPWM_CHY_GPIO_PORT, &gpio_init_struct);/* 初始化GPIO*/
/* 配置高級定時器 */
tmr_init_struct.countMode = TMR_COUNTER_MODE_UP; /* 遞增計數(shù)模式 */
tmr_init_struct.clockDivision = TMR_CLOCK_DIV_1; /* 時鐘分頻系數(shù) */
tmr_init_struct.period = arr; /* 自動重裝載值 */
tmr_init_struct.division = psc; /* 定時器分頻 */
tmr_init_struct.repetitionCounter = 0; /* 重復(fù)計數(shù)器初始值 */
TMR_ConfigTimeBase(ATMRX_TMRX_NPWM, &tmr_init_struct); /* 初始化PWM */
/* 配置指定個PWM輸出 */
tmr_oc_init_struct.mode = TMR_OC_MODE_PWM1; /* 模式選擇PWM1 */
tmr_oc_init_struct.outputState = TMR_OC_STATE_ENABLE; /* 使能輸出比較狀態(tài) */
tmr_oc_init_struct.outputNState = TMR_OC_NSTATE_ENABLE;/* 使能輸出比較N狀態(tài) */
tmr_oc_init_struct.polarity = TMR_OC_POLARITY_HIGH; /* 輸出比較極性為高 */
tmr_oc_init_struct.nPolarity = TMR_OC_NPOLARITY_HIGH; /* 輸出比較N極性為高 */
/* 當(dāng)MOE=0,重置高級定時器輸出比較空閑狀態(tài) */
tmr_oc_init_struct.idleState = TMR_OC_IDLE_STATE_RESET;
/* 當(dāng)MOE=0,重置高級定時器輸出比較空閑狀態(tài) */
tmr_oc_init_struct.nIdleState = TMR_OC_NIDLE_STATE_RESET;
/* 設(shè)置比較值,此值用來確定占空比 */
tmr_oc_init_struct.pulse = arr / 2;
/* 配置高級定時器通道與重裝載 */
TMR_ConfigOC1(ATMRX_TMRX_NPWM, &tmr_oc_init_struct); /* 配置高級定時器通道 */
/* 使能高級定時器在CCMx上的預(yù)裝 */
TMR_ConfigOC1Preload(ATMRX_TMRX_NPWM, TMR_OC_PRELOAD_ENABLE);
TMR_EnableAUTOReload(ATMRX_TMRX_NPWM); /* 配置重裝載寄存器 */
/* 開啟高級定時器相對應(yīng)的通道以及相中斷 */
NVIC_EnableIRQRequest(ATMRX_TMRX_NPWM_IRQn, 1, 0); /* 開啟高級定時器中斷 */
TMR_EnablePWMOutputs(ATMRX_TMRX_NPWM); /* 開啟高級定時器PWM輸出 */
TMR_EnableInterrupt(ATMRX_TMRX_NPWM, TMR_INT_UPDATE); /* 允許更新中斷 */
/* 開啟對應(yīng)PWM通道 */
TMR_EnableCCxChannel(ATMRX_TMRX_NPWM, ATMRX_TMRX_NPWM_CHY);
}
從上面的代碼中可以看出,本章實驗中對高級定時器的初始化于前面章節(jié)中使用通用定時器輸出PWM中對通用定時器的初始化配置是比較類似的,最大不同還是在高級定時器中斷服務(wù)函數(shù)中對高級定時器特有的重復(fù)計數(shù)寄存器的相關(guān)處理中。
高級定時器驅(qū)動中,開啟高級定時器輸出指定個數(shù)PWM的函數(shù),如下所示:
/**
* @brief 高級定時器設(shè)置PWM個數(shù)
* @param rcr: PWM的個數(shù), 1~2^32次方個
* @retval 無
*/
void atmr_tmrx_npwm_chy_set(uint32_t npwm)
{
if (npwm == 0)
{
return;
}
g_npwm_remain = npwm; /* 保存脈沖個數(shù) */
TMR_GenerateEvent(ATMRX_TMRX_NPWM, TMR_EVENT_UPDATE); /* 產(chǎn)生一次更新事件,在中斷里面處理脈沖輸出 */
TMR_Enable(ATMRX_TMRX_NPWM); /* 使能高級定時器 */
}
該函數(shù)記錄下了需要產(chǎn)生的PWM個數(shù),因為會在TMR8的更新中斷中處理輸出PWM,因此手動產(chǎn)生了一次更新事件,由于初始化函數(shù)中開啟了TMR8的更新中斷,因此隨后會進(jìn)入TMR的中斷服務(wù)函數(shù)中。
高級定時器驅(qū)動中,TMR8的中斷回調(diào)函數(shù),如下所示:
/**
* @brief 高級定時器NPWM中斷服務(wù)函數(shù)
* @param 無
* @retval 無
*/
void ATMRX_TMRX_NPWM_IRQHandler(void)
{
uint16_t npwm = 0;
/* 檢查通用定時器更新中斷是否發(fā)生 */
if (TMR_ReadIntFlag(ATMRX_TMRX_NPWM, TMR_INT_UPDATE) != RESET)
{
/* 清除定時器溢出中斷標(biāo)志位 */
TMR_ClearIntFlag(ATMRX_TMRX_NPWM, TMR_INT_UPDATE);
if (g_npwm_remain > 256) /* 還有大于256個脈沖需要發(fā)送 */
{
g_npwm_remain = g_npwm_remain - 256;
npwm = 256;
}
else if (g_npwm_remain % 256) /* 還有位數(shù)(不到256)個脈沖要發(fā)送 */
{
npwm = g_npwm_remain % 256;
g_npwm_remain = 0; /* 沒有脈沖了 */
}
if (npwm) /* 有脈沖要發(fā)送 */
{
/* 設(shè)置重復(fù)計數(shù)寄存器值為npwm-1, 即npwm個脈沖 */
ATMRX_TMRX_NPWM->REPCNT = npwm - 1;
/* 產(chǎn)生一次更新事件,在中斷里面處理脈沖輸出 */
TMR_GenerateEvent(ATMRX_TMRX_NPWM, TMR_EVENT_UPDATE);
TMR_Enable(ATMRX_TMRX_NPWM); /* 使能高級定時器 */
}
else
{
TMR_Disable(ATMRX_TMRX_NPWM); /* 關(guān)閉高級定時器 */
}
}
}
因為高級定時器的重復(fù)計數(shù)寄存器只有低八位有效,因此需要在需要產(chǎn)生大于255個PWM的情況下做特殊處理,隨后將需要產(chǎn)生的PWM個數(shù)值減1寫入TMR8的重復(fù)計數(shù)寄存器,并且由于寫入重復(fù)計數(shù)寄存器的新值只有在下一次更新事件發(fā)生時才生效,因此需要手動產(chǎn)生一次更新事件,最后使能TMR8,這么一來,TMR8就會持續(xù)地輸出PWM直到重復(fù)計數(shù)寄存器的數(shù)值為0后,產(chǎn)生一次更新中斷,若此時已經(jīng)輸出完了指定個數(shù)的PWM,那么就會使用函數(shù)TMR_Disable()關(guān)閉高級定時器。
21.2.3 實驗應(yīng)用代碼
本實驗的應(yīng)用代碼,如下所示:文章來源:http://www.zghlxwxcb.cn/news/detail-834493.html
int main(void)
{
uint8_t t = 0;
uint8_t key = 0;
NVIC_ConfigPriorityGroup(NVIC_PRIORITY_GROUP_4); /* 設(shè)置中斷優(yōu)先級分組為組4 */
sys_apm32_clock_init(15); /* 配置系統(tǒng)時鐘 */
delay_init(120); /* 初始化延時功能 */
usart_init(115200); /* 初始化串口 */
led_init(); /* 初始化LED */
atmr_tmrx_npwm_chy_init(5000 - 1, 12000 - 1); /* 初始化PWM輸出模式 */
atmr_tmrx_npwm_chy_set(5); /* 高級定時器輸出PWM個數(shù) */
while (1)
{
key = key_scan(0);
if (key == KEY0_PRES) /* KEY0按下 */
{
/* 輸出5個PWM波(控制TMR8_CH1, 即PC6輸出5個脈沖) */
atmr_tmrx_npwm_chy_set(5);
}
t++;
delay_ms(10);
if (t > 50)
{
t = 0;
/* 控制LED0閃爍, 提示程序運行狀態(tài) */
LED0_TOGGLE();
}
}
}
從上面的代碼中可以看到,TMR8的自動重裝載值配置為(5000-1),TMR8的預(yù)分頻器數(shù)值配置為(12000-1),并且TMR8的時鐘頻率為120MHz,因此TMR8的計數(shù)頻率為10KHz,且TMR8每計數(shù)5000次溢出一次,因此溢出頻率為2Hz,也就是輸出PWM的頻率為2Hz。
初始化完TMR8后,就重復(fù)地掃描按鍵,若KEY0按鍵被按下,則輸出5個PWM。
21.3 下載驗證
在完成編譯和燒錄操作后,按下KEY0按鍵,此時可以通過示波器或外接LED的方式觀察PC6引腳輸出了5個頻率為2Hz,占空比為50%的PWM。文章來源地址http://www.zghlxwxcb.cn/news/detail-834493.html
到了這里,關(guān)于【正點原子STM32連載】第二十一章 高級定時器輸出指定個數(shù)PWM實驗 摘自【正點原子】APM32E103最小系統(tǒng)板使用指南的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!