脈沖信號用于設備控制是比較常見的,但在一些情況下,我們希望精準的控制脈沖的數量以實現對運動的精確控制,實現的方式也有多種多樣。定時器是單片機內部最基礎且常用的外設,有著非常豐富的功能,如輸入功能(測量輸入信號的脈沖寬度、頻率,PWM 輸入等),輸出功能(PWM 輸出、死區時間可編程的互補輸出、 單脈沖模式輸出等) ,容易想到使用定時器輸出PWM來實現此類操作。
MM32F5270系列集成有豐富的外設模塊,其中定時器部分包括 2 個 16 位高級定時器, 2 個 16 位通用定時器、 2 個 32 位通用定時器, 2 個 16 位基礎定時器和1 個低功耗定時器。以TIM1為例,該模塊主要由輸入單元、輸出單元、時基單元、捕獲/比較模塊、剎車單元等結構組成,功能框圖如下:
這里以MM32F5270定時器應用為例,介紹幾種常用的精準輸出脈沖數量的方法:
1?中斷計數方式
定時器配置為PWM輸出模式,在PWM中斷程序中計數,判斷PWM輸出次數達到設定值時,停止PWM輸出。
中斷計數的方式實現起來簡單,但也存在明顯的缺點。當PWM頻率較高時,頻繁的中斷將影響程序運行的效率,占用大量的MCU資源,這在大多數情況下是不可接受的。以下幾種方式較為優化。
2?定時器單脈沖重復計數
定時器單脈沖輸出是定時器比較輸出中的一種模式,在定時器比較輸出模式的基礎上進行配置。單脈沖模式(OPM)下,計數器響應一個激勵,產生一個脈寬可調的脈沖。配置 TIMx_CR1 寄存器的OPM=1,選擇單脈沖模式。
單脈沖模式可以使定時器輸出1個脈沖,而重復計數器可以用來調整更新事件產生的頻率。
邊沿對齊模式下,向上計數時,重復計數器在計數器每次上溢時遞減;向下計數時,重復計數器在計數器每次下溢時遞減。中央對齊模式下,重復計數器在計數器上溢和下溢時皆遞減。通過配置 TIMx_RCR 寄存器的 REP 來調整更新事件產生的頻率,重復計數器在 REP+1 個計數周期后產生更新事件。
配置TIM1輸出PWM,使能單脈沖模式,配置REP(重復計數器的值)為9,即TIM1在輸出10個脈沖后發生更新事件,相關代碼如下:
voidTIM1_Monopulse_Init(u16arr,u16psc) { TIM_TimeBaseInitTypeDefTIM_TimeBaseStruct; TIM_OCInitTypeDefTIM_OCInitStruct; TIM_ICInitTypeDefTIM_ICInitStruct; RCC_APB2PeriphClockCmd(RCC_APB2ENR_TIM1,ENABLE); TIM_DeInit(TIM1); TIM_TimeBaseStructInit(&TIM_TimeBaseStruct); TIM_TimeBaseStruct.TIM_Period=arr; TIM_TimeBaseStruct.TIM_Prescaler=psc; TIM_TimeBaseStruct.TIM_ClockDivision=TIM_CKD_DIV1; TIM_TimeBaseStruct.TIM_RepetitionCounter=9; TIM_TimeBaseStruct.TIM_CounterMode=TIM_CounterMode_Up; TIM_TimeBaseInit(TIM1,&TIM_TimeBaseStruct); TIM_OCStructInit(&TIM_OCInitStruct); TIM_OCInitStruct.TIM_OCMode=TIM_OCMode_PWM2; TIM_OCInitStruct.TIM_OutputState=TIM_OutputState_Enable; TIM_OCInitStruct.TIM_Pulse=arr/2; TIM_OCInitStruct.TIM_OCPolarity=TIM_OCPolarity_High; TIM_OCInitStruct.TIM_OCIdleState=TIM_OCIdleState_Reset; TIM_OC1Init(TIM1,&TIM_OCInitStruct); TIM_OC1PreloadConfig(TIM1,TIM_OCPreload_Enable); TIM_ARRPreloadConfig(TIM1,ENABLE); TIM_SelectOnePulseMode(TIM1,TIM_OPMode_Single); TIM_SetCounter(TIM1,0); TIM_CtrlPWMOutputs(TIM1,ENABLE); TIM_Cmd(TIM1,ENABLE); }
邏輯分析儀接PA8(程序中配置PA8作為TIM1_CH1),觀測輸出波形如下:
由于REP只有8位,所以它最大是255,當然也可以進行一些判斷后再次賦值,目前只有高級定時器具有重復計數功能。
3?DMA方式
使用DMA功能更新PWM的輸出,DMA傳輸將數據從一個地址空間復制到另一個地址空間,提供在外設和存儲器之間或者存儲器和存儲器之間的高速數據傳輸。它允許不同速度的硬件裝置來溝通,而不需要依賴于MPU的大量中斷負載。該方式占用很少的MCU資源,實現脈沖發送的精確控制。
通過設置DMA傳輸數據的數量,可以控制發送的脈沖數。通過設置不同的裝載值和順序,可以使用不同頻率和脈寬。
TIMx_DCR 和 TIMx_DMAR 寄存器跟 DMA 模式相關。DMA 控制器的目標是唯一的,必須指向TIMx_DMAR 寄存器。開啟 DMA 使能后,在給定的 TIMx 事件發生時, TIMx 會給 DMA 發送請求。對TIMx_DMAR 寄存器的每次寫操作都被重定向到一個 TIMx 寄存器。
TIMx_DMAR 連續模式 DMA 地址寄存器:
TIMx_DCR DMA 控制寄存器:
程序中配置TIM1的更新周期為10ms。
TIM1_PWM_Init(10000-1,SystemCoreClock/1000000-1);
定義一個數組,元素的數量表示可以控制發送的脈沖數,元素的值表示脈寬。
staticu16data[10]={1000,2000,3000,4000,5000,6000,7000,8000,9000,0};
配置TIM1輸出PWM,相關代碼同上,使能COM的DMA請求,配置DMA初始化,使能DMA傳輸完成中斷,TIM1_CH1對應DMA1_Channel2。
voidTIM1_DMA_Init(void) { DMA_InitTypeDefDMA_InitStruct; DMA_Channel_TypeDef*channel; channel=DMA1_Channel2; RCC_DMA_ClockCmd(DMA1,ENABLE); DMA_DeInit(channel); DMA_StructInit(&DMA_InitStruct); //Transferregisteraddress DMA_InitStruct.DMA_PeripheralBaseAddr=(u32)&(TIM1->CCR1); //Transfermemoryaddress DMA_InitStruct.DMA_MemoryBaseAddr=(u32)data; //Transferdirection,frommemorytoregister DMA_InitStruct.DMA_DIR=DMA_DIR_PeripheralDST; DMA_InitStruct.DMA_BufferSize=10; DMA_InitStruct.DMA_PeripheralInc=DMA_PeripheralInc_Disable; //Transfercompletedmemoryaddressincrement DMA_InitStruct.DMA_MemoryInc=DMA_MemoryInc_Enable; DMA_InitStruct.DMA_PeripheralDataSize=DMA_PeripheralDataSize_HalfWord; DMA_InitStruct.DMA_MemoryDataSize=DMA_MemoryDataSize_HalfWord; DMA_InitStruct.DMA_Mode=DMA_Mode_Normal;//DMA_Mode_Circular; DMA_InitStruct.DMA_Priority=DMA_Priority_High; DMA_InitStruct.DMA_M2M=DMA_M2M_Disable; DMA_InitStruct.DMA_Auto_reload=DMA_Auto_Reload_Disable; DMA_Init(channel,&DMA_InitStruct); DMA_ITConfig(channel,DMA_IT_TC,ENABLE); DMA_Cmd(DMA1_Channel2,ENABLE); }
DMA中斷服務子程序:
voidDMA1_Channel2_IRQHandler(void) { if(DMA_GetITStatus(DMA1_IT_TC2)){ DMA_ClearITPendingBit(DMA1_IT_TC2); TIM_Cmd(TIM1,DISABLE); } }
邏輯分析儀接PA8(程序中配置PA8作為TIM1_CH1),觀測輸出波形如下:
輸出9個脈沖,脈寬分別為10%、20%、30%......90%。
DMA方式算是一個很確定的方式,不會丟失脈沖。當需要發送較多數量的脈沖時,則可以使用DMA傳輸完成中斷中切換DMA傳輸的數據起始地址及發送數量。
4?主從模式
定時器同步功能可以配置多個定時器在內部相連。
利用定時器的主從模式,即一個是主定時器,一個是從定時器,由主定時器輸出脈沖信號,主定時器產生的更新觸發傳遞給從定時器進行計數,溢出時觸發從定時器的中斷服務函數。通過主從定時器進行設定,不占用主程序時鐘,且能精準控制。
主從關系要遵循參考手冊中所提供的配置,TIMx之間的互聯:
參考TIMx_CR2和TIMx_SMCR寄存器配置主從模式。
TIMx_CR2 控制寄存器 2:
TIMx_SMCR 從模式控制寄存器:
配置TIM1為主模式,輸出PWM:
voidTIM1_Master_Init(u16arr,u16psc) { TIM_TimeBaseInitTypeDefTIM_TimeBaseStruct; TIM_OCInitTypeDefTIM_OCInitStruct; RCC_APB2PeriphClockCmd(RCC_APB2ENR_TIM1,ENABLE); TIM_TimeBaseStructInit(&TIM_TimeBaseStruct); TIM_TimeBaseStruct.TIM_Period=arr; TIM_TimeBaseStruct.TIM_Prescaler=psc; TIM_TimeBaseStruct.TIM_ClockDivision=TIM_CKD_DIV1; TIM_TimeBaseStruct.TIM_RepetitionCounter=0; TIM_TimeBaseStruct.TIM_CounterMode=TIM_CounterMode_Up; TIM_TimeBaseInit(TIM1,&TIM_TimeBaseStruct); TIM_OCStructInit(&TIM_OCInitStruct); TIM_OCInitStruct.TIM_OCMode=TIM_OCMode_PWM2; TIM_OCInitStruct.TIM_OutputState=TIM_OutputState_Enable; TIM_OCInitStruct.TIM_Pulse=499; TIM_OCInitStruct.TIM_OCPolarity=TIM_OCPolarity_High; TIM_OC1Init(TIM1,&TIM_OCInitStruct); TIM_OC1PreloadConfig(TIM1,TIM_OCPreload_Enable); TIM_ARRPreloadConfig(TIM1,ENABLE); TIM_SelectMasterSlaveMode(TIM1,TIM_MasterSlaveMode_Enable); TIM_SelectOutputTrigger(TIM1,TIM_TRIGSource_Update); TIM_SetCounter(TIM1,0); TIM_CtrlPWMOutputs(TIM1,ENABLE); TIM_Cmd(TIM1,ENABLE); }
配置TIM3為從模式,選擇ITR0觸發(對應內部觸發源TIM1),使能更新中斷:
voidTIM3_Slave_Init(u16arr,u16psc) { TIM_TimeBaseInitTypeDefTIM_TimeBaseStruct; RCC_APB1PeriphClockCmd(RCC_APB1ENR_TIM3,ENABLE); TIM_TimeBaseStructInit(&TIM_TimeBaseStruct); TIM_TimeBaseStruct.TIM_Period=arr; TIM_TimeBaseStruct.TIM_Prescaler=psc; TIM_TimeBaseStruct.TIM_ClockDivision=TIM_CKD_DIV1; TIM_TimeBaseStruct.TIM_RepetitionCounter=0; TIM_TimeBaseStruct.TIM_CounterMode=TIM_CounterMode_Up; TIM_TimeBaseInit(TIM3,&TIM_TimeBaseStruct); TIM_ARRPreloadConfig(TIM3,DISABLE); TIM_SelectInputTrigger(TIM3,TIM_TS_ITR0); TIM_SelectSlaveMode(TIM3,TIM_SlaveMode_External1); TIM_SelectMasterSlaveMode(TIM3,TIM_MasterSlaveMode_Enable); TIM_ClearFlag(TIM3,TIM_FLAG_Update); TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE); TIM_SetCounter(TIM3,0); TIM_Cmd(TIM3,ENABLE); }
TIM3控制脈沖數量,此處設置為10:
TIM3_Slave_Init(10,0);
TIM3中斷服務子程序:
voidTIM3_IRQHandler(void) { if(TIM_GetITStatus(TIM3,TIM_IT_Update)!=RESET){ TIM_ClearITPendingBit(TIM3,TIM_IT_Update); TIM_CtrlPWMOutputs(TIM1,DISABLE); TIM_Cmd(TIM1,DISABLE); TIM_Cmd(TIM3,DISABLE); TIM_ITConfig(TIM3,TIM_IT_Update,DISABLE); } }
邏輯分析儀接PA8(程序中配置PA8作為TIM1_CH1),觀測輸出波形如下:
TIM1輸出10個脈沖后停止。
以上簡要列舉了幾種控制脈沖數量輸出的方式,以MM32F5270為例演示其實現的可行性。在實際應用中,幾種方法各有優缺點,具體的方式還需要根據資源和需求進行綜合考慮。
審核編輯:湯梓紅
-
PWM
+關注
關注
114文章
5198瀏覽量
214890 -
定時器
+關注
關注
23文章
3255瀏覽量
115381 -
Tim
+關注
關注
0文章
81瀏覽量
17956 -
脈沖信號
+關注
關注
6文章
400瀏覽量
37078
原文標題:靈動微課堂 (第239講)|MM32F5270 TIM 精準脈沖數量輸出
文章出處:【微信號:MindMotion-MMCU,微信公眾號:靈動MM32MCU】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論