精品国产人成在线_亚洲高清无码在线观看_国产在线视频国产永久2021_国产AV综合第一页一个的一区免费影院黑人_最近中文字幕MV高清在线视频

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

探究用雙定時器控制單片機輸出固定的數量的PWM脈沖!

Q4MP_gh_c472c21 ? 來源:21ic論壇 ? 作者: 吶咯密密 ? 2021-04-29 11:51 ? 次閱讀

最近在逛論壇,看到幾個帖子都在咨詢如何控制單片機輸出固定的數量的PWM脈沖,用于控制電機的轉停,剛好前兩天本人也需要該功能做測試,我是輸出PWM給伺服電機驅動器,驅動器以位置模式工作,收到脈沖就控制電機轉動,如果需要精確控制電機轉過的角度,就需要給驅動器輸入固定數量的脈沖。于是我便用STM32F031的雙定時器實現了該功能,下文便詳細描述。

我在進行代碼編譯之前也在網絡上搜索過相應的方法,總結起來一共五個方法:

1、單脈沖法,需要一個脈沖中斷一次,中斷次數多,影響效率

2、一個定時器輸出PWM,另一定時器使用輸入捕獲進行中斷計數,與方法1一樣,同樣需要頻繁的中斷

3、用主從定時器門控方式,比較繁瑣

4、用一個定時器(從)作為另一個定時器(主)的外部時鐘觸發源

5、高級定時器T1、T8的重復計數方式,RCR計數中斷,看手冊好像這種方式最簡單,能滿足一部分人要求,缺點是寄存器只有8位,最多實現255個脈沖計數輸出。

我在最初時使用了第2和方法,該方法對于我來說你叫簡單,后來在寫這篇文章時選擇了第4個方法,總結起來還是4比較靠譜,但是這里的第2方法也描述一下,便于大家選擇。

方法2:

因為條件限制,干脆說為了省事,我在原來用于其他功能的板子上進行測試,因為只開放了PB3和PB4,所以這里只好用TIM2和TIM3進行測試。

TIM2用于產生PWM脈沖輸出,在輸出給驅動器的同時將該脈沖也接到PB4,也就是TIM3的輸入口,這樣TIM3也能接收到TIM2發出的脈沖,TIM3只需要配置為輸入捕獲,并開啟中斷,便可以在每次脈沖到來進入中斷,在TIM3的中斷中去計數,達到需要的脈沖數便關閉TIM2便可。

首先依舊是初始化端口

先貼一下time.h文件:

* 定義防止遞歸包含 ----------------------------------------------------------*/#ifndef _TIMER_H#define _TIMER_H /* 包含的頭文件 --------------------------------------------------------------*/#include "stm32f0xx.h" /* 宏定義 --------------------------------------------------------------------*/#define TIM6_COUNTER_CLOCK 1000000 //計數時鐘(1M次/秒) //預分頻值#define TIM6_PRESCALER_VALUE (SystemCoreClock/TIM6_COUNTER_CLOCK - 1)#define TIM6_PERIOD_TIMING (10 - 1) //定時周期(相對于計數時鐘:1周期 = 1計數時鐘) #define TIM2_COUNTER_CLOCK 24000000 //計數時鐘(24M次/秒) //預分頻值#define TIM2_PRESCALER_VALUE (SystemCoreClock/TIM2_COUNTER_CLOCK - 1) /* 函數申明 ------------------------------------------------------------------*/void Systick_Init(void);void Delay_ms(__IO uint32_t nTime);void TimingDelay_Decrement(void);void Delay(uint32_t
temp);voiddelay_us(uint32_t nus);void delay_init();

void TIMER_Initializes(void); void TIMDelay_N10us(uint16_t Times);void TIMDelay_Nms(uint16_t Times);void TIMDelay_Ns(uint16_t Times); void TIMER_PWM_GPIO_Configuration(void);void TIM2_CH2_PWM(uint32_t Freq, uint16_t Dutycycle);void TIMER_IC_Configuration(void); #endif /* _TIMER_H */

因為我的時鐘初始化是單獨定義的,所以這里未進行時鐘的初始化,在參考的我的代碼時需注意:

void TIMER_PWM_GPIO_Configuration(void){ GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; //TIM2引腳 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; //復用模式 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //高速輸出 GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推完輸出 GPIO_InitStructure.

GPIO_PuPd = GPIO_PuPd_UP; //上拉 GPIO_Init(GPIOB, &GPIO_InitStructure); GPIO_PinAFConfig(GPIOB, GPIO_PinSource3, GPIO_AF_2); //復用配置 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4; //TIM3引腳 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; //復用模式 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

//高速輸出 GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推完輸出 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; //無上下拉(浮空) GPIO_Init(GPIOB, &GPIO_InitStructure); GPIO_PinAFConfig(GPIOB, GPIO_PinSource4, GPIO_AF_1); }

配置定時器2,TIM2作為PWM的脈沖輸出:

/************************************************函數名稱 :TIM2_CH2_PWM功 能 :定時器2通道2輸出PWM參 數 :Freq -------- 頻率 Dutycycle --- 占空比返 回 值 :無作 者 :吶咯密密*************************************************/void TIM2_CH2_PWM(uint32_t Freq, uint16_t Dutycycle){ TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; uint16_t tim2_period; uint16_t tim2_pulse; tim2_period = (uint16_t)(TIM2_COUNTER_CLOCK/Freq - 1); //計算出計數周期(決定輸出的頻率) tim2_pulse = (tim2_period + 1)*Dutycycle / 100; //計算出脈寬值(決定PWM占空比) /* TIM2時基單元配置 */ TIM_TimeBaseStructure.TIM_Prescaler = TIM2_PRESCALER_VALUE; //預分頻值 TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;

//向上計數模式 TIM_TimeBaseStructure.TIM_Period = tim2_period; //定時周期(自動從裝載寄存器ARR的值) TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //時鐘分頻因子 TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); /* TIM2通道2:PWM1模式配置 */ TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //輸出PWM1模式 TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;

//使能輸出 TIM_OCInitStructure.TIM_Pulse = tim2_pulse; //脈寬值 TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //輸出極性 TIM_OC2Init(TIM2, &TIM_OCInitStructure); TIM_OC2PreloadConfig(TIM2, TIM_OCPreload_Enable); TIM_ARRPreloadConfig(TIM2, ENABLE); TIM_Cmd(TIM2, ENABLE); //初始化PWM。}

配置定時器3,作為捕獲輸入:

void TIMER_IC_Configuration(void){ TIM_ICInitTypeDef TIM_ICInitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_TimeBaseStructure.TIM_Prescaler = 1 - 1; //1分頻(與捕獲分頻相同) TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上計數模式 TIM_TimeBaseStructure.TIM_Period = 0xFFFFFFFF; //定時周期(自動從裝載寄存器ARR的值) TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //時鐘分頻因子 TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);

TIM_ICInitStructure.TIM_Channel = TIM_Channel_1; //通道1 TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Falling; //捕獲極性 TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //捕獲選擇 TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //捕獲分頻 TIM_ICInitStructure.TIM_ICFilter = 0; //捕獲濾波 TIM_ICInit(TIM3, &TIM_ICInitStructure); TIM3->SR = (uint16_t)~TIM_IT_CC1; //清除中斷標志 TIM_Cmd(TIM3, ENABLE); //使能TIM3 TIM_ITConfig(TIM3, TIM_IT_CC1, ENABLE); //使能中斷}

關于定時器的通道要根據手冊定義來確定,我的只適配我的硬件

這里需要著重說一下預分頻TIM_Prescaler的值和捕獲分頻TIM_ICPrescaler的值要對應,在上面的代碼中這兩個值均為1,效果就是每來一個脈沖就會進一次中斷。我們只需在中斷里進行計數,想要幾個脈沖就進中斷幾次,達到需要的脈沖數就關閉TIM2。如下所示:

配置中斷:

NVIC_InitTypeDef NVIC_InitStructure; NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; //IRQ通道:定時器2 NVIC_InitStructure.NVIC_IRQChannelPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure);

void TIM3_IRQHandler(void){ if(TIM_GetITStatus(TIM3, TIM_IT_CC1) != RESET) { TIM_ClearITPendingBit(TIM3,TIM_IT_CC1);//先清空中斷標志位,以備下次使用。 capture++; if(capture==16) { /*每16個脈沖轉動電機一次*/ TIM_OC2PreloadConfig(TIM2, TIM_OCPreload_Disable); TIM_ARRPreloadConfig(TIM2, DISABLE); TIM_Cmd(TIM2, DISABLE);

TIM_Cmd(TIM3, DISABLE); //失能TIM2 TIM_ITConfig(TIM3, TIM_IT_CC1, DISABLE); //失能中斷 capture=0; delay_us(5000); TIM_Cmd(TIM3, ENABLE); //失能TIM2 TIM_ITConfig(TIM3, TIM_IT_CC1, ENABLE); //失能中斷 TIM_OC2PreloadConfig(TIM2, TIM_OCPreload_Enable); TIM_ARRPreloadConfig(TIM2, ENABLE); TIM_Cmd(TIM2, ENABLE); } }}/*

在TIM3的中斷函數中,我們定義一個變量capture,每次進入中斷該值會加一,進入16次中斷,也就是有16個脈沖輸入就會滿足條件進入if()函數,關閉TIM2和TIM3,延時5000us后再打開這兩個定時器,如此循環。可從示波器看現象:

9c4a1b6c-a86f-11eb-9728-12bb97331649.png

9c89712c-a86f-11eb-9728-12bb97331649.png

現在我們已經完成了對TIM2的輸出固定個數脈沖的試驗,但是這種方式每個脈沖都進一次中斷太麻煩,于是可以修改預分頻TIM_Prescaler的值為8-1,和捕獲分頻TIM_ICPrescaler的值為TIM_ICPSC_DIV8,便可8個脈沖進一次中斷。

9cc82336-a86f-11eb-9728-12bb97331649.png

此時也將中斷函數里的判斷條件改為1,進一次中斷便會關閉定時器,我們接上示波器看看現象:

9cd37128-a86f-11eb-9728-12bb97331649.png

通過示波器我們可以看到,雖然只進了一次中斷,但是我們卻輸出8個脈沖,以此可減少進入中斷的次數。至此,通過TIM3的輸入捕獲控制PWM脈沖數的試驗就完成了。 方法4: 方法4是利用主從定時器進行脈寬調制,不占用主時鐘,在代碼時間要求苛刻和多電機控制時非常實用,可以精準控制。 GPIO的初始化和上文保持不變,僅改變TIM的配置: TIM2設置為主模式

/***********************TIM2初始化函數*****************************參數:****************************************************//******u32 Cycle用于設定計數頻率(計算公式:Cycle=1Mhz/目標頻率)******返回值:**************************************************//******無*****************************************************/void TIM2_config(uint32_t Cycle){ TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; TIM_TimeBaseStructure.TIM_Period = Cycle-1; //使用Cycle來控制頻率(f=48/(47+1)/Cycle) 當Cycle為100時脈沖頻率為10KHZ TIM_TimeBaseStructure.TIM_Prescaler =47; //設置用來作為TIMx時鐘頻率除數的預分頻值 TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //設置時鐘分割:TDTS= Tck_tim TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上計數模式 TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;

//重復計數,一定要=0!!! TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //選擇定時器模式:TIM脈沖寬度調制模式1 TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比較輸出使能 TIM_OCInitStructure.TIM_Pulse = Cycle/2-1; //設置待裝入捕獲寄存器的脈沖值(占空比:默認50%,這可也可以調節如果需要的話將它作為一個參數傳入即可) TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //輸出極性 TIM_OC2Init(TIM2, &TIM_OCInitStructure); //使能通道2 TIM_SelectMasterSlaveMode(TIM2, TIM_MasterSlaveMode_Enable);

//設置為主從模式 TIM_SelectOutputTrigger(TIM2, TIM_TRGOSource_Update); //選擇定時器2的觸發方式(使用更新事件作為觸發輸出) TIM_OC2PreloadConfig(TIM2, TIM_OCPreload_Enable); //使能通道2預裝載寄存器 TIM_ARRPreloadConfig(TIM2, ENABLE); //使能TIM2在ARR上的預裝載寄存器 } TIM3設置為從模式:

/***********************TIM3初始化函數*************************//****參數:****************************************************//******u32 PulseNum用于設定脈沖數量****************************//****返回值:*************************************************//******無*****************************************************/ void TIM3_config(uint32_t PulseNum){ TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); TIM_TimeBaseStructure.TIM_Period = PulseNum-1; //設置自動重裝載周期值 TIM_TimeBaseStructure.

TIM_Prescaler =0; TIM_TimeBaseStructure.TIM_ClockDivision = 0; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); TIM_SelectInputTrigger(TIM3, TIM_TS_ITR1); TIM_SelectSlaveMode(TIM3,TIM_SlaveMode_External1 );// 等同 TIM3->SMCR|=0x07 //設置從模式寄存器 TIM_ITConfig(TIM3,TIM_IT_Update,DISABLE); } 這里的TIM_SelectInputTrigger(TIM3, TIM_TS_ITR1);是設置為內部觸發,參數由手冊進行獲取:

9d1d078e-a86f-11eb-9728-12bb97331649.png

/************************脈沖輸出函數**************************//****參數:****************************************************//******u32 Cycle用于設定計數頻率(計算公式:Cycle=1Mhz/目標頻率)//******u32 PulseNum用于設定輸出脈沖的數量(單位:個)************//****返回值:**************************************************//******無*****************************************************/void Pulse_output(uint32_t Cycle,uint32_t PulseNum){ TIM3_config(PulseNum); //設置脈沖數量 TIM_Cmd(TIM3, ENABLE); //使能TIM3(從定時器) TIM_ClearITPendingBit(TIM3,TIM_IT_Update); //清除中斷標志位 TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE); //使能更新中斷 TIM2_config(Cycle); //使能定時器2(主定時器) TIM_Cmd(TIM2, ENABLE); //使能定時器2// TIM_CtrlPWMOutputs(TIM2, ENABLE); //高級定時器一定要加上,主輸出使能}

void TIM3_IRQHandler(void){ if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) //TIM_IT_Update { TIM_ClearITPendingBit(TIM3, TIM_IT_Update); // 清除中斷標志位 TIM_CtrlPWMOutputs(TIM2, DISABLE); //主輸出使能 TIM_Cmd(TIM2, DISABLE); //關閉定時器 TIM_Cmd(TIM3, DISABLE); //關閉定時器 TIM_ITConfig(TIM3, TIM_IT_Update, DISABLE); //關閉TIM2更新中斷 }} 當TIM的CNT寄存器的值到達設定的Update值會觸發更新中斷,此時設定的脈沖數已輸出完畢,關閉TIM2和TIM3. 主函數:

9d29a7aa-a86f-11eb-9728-12bb97331649.png

9d3f18c4-a86f-11eb-9728-12bb97331649.png

該代碼本人均已調通,原理部分過于繁雜,這里以本人能力可能無法解釋的清除,諸位可參考手冊或網絡獲取相關講解。

編輯:jq

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 單片機
    +關注

    關注

    6032

    文章

    44516

    瀏覽量

    632985
  • 脈沖
    +關注

    關注

    20

    文章

    884

    瀏覽量

    95538
  • 定時器
    +關注

    關注

    23

    文章

    3237

    瀏覽量

    114467
  • Tim
    Tim
    +關注

    關注

    0

    文章

    81

    瀏覽量

    17875

原文標題:深度:用雙定時器控制單片機輸出固定的數量的PWM脈沖!

文章出處:【微信號:gh_c472c2199c88,微信公眾號:嵌入式微處理器】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    瑞薩單片機PWM輸出

    如何通過e2-studio配置GPT定時器輸出指定數量PWM后停止輸出
    發表于 09-19 10:01

    簡述單片機定時器的工作原理

    單片機定時器的工作原理是一個復雜而精細的過程,它涉及到單片機內部的多個組件和機制。
    的頭像 發表于 08-19 18:20 ?1119次閱讀

    定時器的工作方式介紹

    或實現周期性事件的硬件模塊。它可以用于實現各種定時任務,如定時中斷、PWM脈沖寬度調制)輸出、頻率測量等。
    的頭像 發表于 07-12 10:29 ?729次閱讀

    基于51單片機的路燈【固定時間,紅外,DS1302,LCD1602】(仿真)

    基于51單片機的路燈【固定時間,紅外,DS1302,LCD1602】(仿真)
    的頭像 發表于 04-10 00:44 ?492次閱讀
    基于51<b class='flag-5'>單片機</b>的路燈【<b class='flag-5'>固定時</b>間,紅外,DS1302,LCD1602】(仿真)

    STM32同一定時器PWM輸出定時,會影響我的PWM輸出嗎?

    求助各位大佬 ,我定時器2通道1輸出PWM 定時器設置為TIM2_PERIODE (1000-1) TIM2_PRESCALER 36,現
    發表于 03-26 07:23

    使用定時器控制pwm發送脈沖,如何能夠同時控制頻率,脈沖個數?

    大神門,使用定時器控制pwm發送脈沖,如何能夠同時控制頻率,脈沖個數。因為需要精準
    發表于 03-14 07:02

    使用555定時器的可調定時器電路

    定時器 IC 555 是最通用和最常用的 IC 之一,因為它的應用范圍更廣,如 PWM放大器、延遲定時器、開關電路、占空比選擇、時鐘脈沖發生器
    的頭像 發表于 02-25 15:16 ?2011次閱讀
    使用555<b class='flag-5'>定時器</b>的可調<b class='flag-5'>雙</b><b class='flag-5'>定時器</b>電路

    8031單片機定時器和計數是怎么工作的

    8031單片機定時器和計數是通過內部的時鐘源來工作的。具體來說,定時器/計數T0和T1的輸入端都接到了機器周期信號上,因此它們的計數初
    發表于 02-02 17:13 ?1134次閱讀

    TCPWM來生成PWM脈沖,如何設置PWM發送脈沖數量?比如固定發10個脈沖

    目前我TCPWM來生成PWM脈沖,通過延時可以控制發送脈沖的個數,如下: Cy_TCPWM_TriggerStart(TCPWM0,
    發表于 02-02 08:16

    單片機外部中斷和定時器中斷的區別和用法

    單片機外部中斷和定時器中斷在觸發來源、應用場景以及功能特點上存在明顯差異** **。
    的頭像 發表于 01-28 17:35 ?2876次閱讀

    單片機定時器的用法

    本章以CW32通定時器為例介紹單片機定時器的用法。
    的頭像 發表于 01-04 10:37 ?1345次閱讀
    <b class='flag-5'>單片機</b><b class='flag-5'>定時器</b>的用法

    【有那么點詳細的CW32學習筆記】通用定時器——輸出比較

    本章以CW32通定時器為例介紹單片機定時器的用法。 定時器單片機中一個非常傳統且重要的外設,
    的頭像 發表于 12-28 11:24 ?1276次閱讀
    【有那么點詳細的CW32學習筆記】通用<b class='flag-5'>定時器</b>——<b class='flag-5'>輸出</b>比較

    單片機輸出比較是小思考

    一、工具1、硬件:GD32F30x系列單片機2、編譯環境:KEIL二、需求分析如下圖所示,現要求控制單片機同時輸出3路方波,并且每個方波的高低電平持續的時長是可調整的,因為對時長有著嚴格的要求,這就
    的頭像 發表于 12-27 08:00 ?481次閱讀
    <b class='flag-5'>單片機</b>的<b class='flag-5'>輸出</b>比較是小思考

    51單片機定時器定時1秒程序流水燈結果分析

    51單片機是一種廣泛應用的嵌入式微控制器,具有高性能、低功耗、易擴展等優勢。在實際應用中,定時器常用于定時操作,如控制程序運行時間、生成精確
    的頭像 發表于 12-26 14:57 ?6639次閱讀

    基于STM32CUBEMX驅動低壓步進電機驅動STSPIN220(3)----定時器中斷產生指定數量脈沖

    在步進電機控制過程中,為了實現精確的位置和速度控制,經常需要輸出指定數量脈沖。這就需要使用定時器
    的頭像 發表于 12-01 15:26 ?1157次閱讀
    基于STM32CUBEMX驅動低壓步進<b class='flag-5'>器</b>電機驅動<b class='flag-5'>器</b>STSPIN220(3)----<b class='flag-5'>定時器</b>中斷產生指定<b class='flag-5'>數量</b><b class='flag-5'>脈沖</b>