定時器基礎知識
定時器就是用來定時的機器,是存在于STM32單片機中的一個外設。STM32總共有8個定時器,分別是2個高級定時器(TIM1、TIM8),4個通用定時器(TIM2、TIM3、TIM4、TIM5)和2個基本定時器(TIM6、TIM7),如下圖所示:
STM32F10X系列總共最多有八個定時器
三種STM32定時器的區別:
向上是指1234逐個遞增計數,向下是指逐個遞減計數,向上/向下是指中央對齊模式(基本定時器只能向上,上圖寫錯了)?,捕獲指的是輸入捕獲,比較指的是輸出比較
基本定時器
1. 時鐘源 2. 控制器 3. 時基單元
時鐘源
時鐘源來自RCC的TIMx_CLK(屬于內部的CK_INIT)
外設掛載在總線下的APB1對應的是時鐘2~時鐘7(所以我們的基本定時器TIM6 TIM7在APB1下的)
根據時鐘樹
因為AHB 72M,(AHB默認分頻是2)所以APB1是 36M,(APB1默認分頻是2)所以根據(如果APB1預分頻系數=1則頻率不變,否則頻率x2.)可知定時器的頻率 = 72M
時基(定時器的心臟)
????????定時器最重要的就是時基部分:包括預分頻器、計數器、自動重裝載寄存器 ?
????????預分頻器:1-16位預分頻器PSC對內部時鐘CK_PSC進行分頻之后,得到計數器時鐘CK_INT=CK_PSC/(PSC+1)
????????CNT在計數器時鐘的驅動下開始計數,計數一次的時間為1/CK_INT
? ? ? ??計數器、重裝在寄存器:定時器使能(CEN置1)后,計數器CNT在CK_CNT驅動 下計數,當CNT值與ARR的設定值相等時就自動生成事件并CNT自動清零,然后 自動重新開始計數,如此重復以上過程。
影子寄存器
1.PSC和ARR都有影子寄存器,功能框圖上有個影子
2.影子寄存器的存在起到一個緩沖的作用,用戶值->寄存器->影子寄存器->起作用, 如果不使用影子寄存器則用戶值在寫到寄存器之后則里面起作用,ARR影子, TIMx_CR1:APRE位控制。
?定時時間的計算
定時器時間=(PSC+1)*(ARR+1)/72M
因為我們的計數器是從0開始計數的,所以要加1
基本定時器的功能
1.計數器16bit,只能向上計數,只有TIM6和TIM7
2.沒有外部的GPIO,是內部資源,只能用來定時
3.時鐘來自PCKL1,為72M,可實現1~65536分頻
通用定時器
STM32 的通用定時器功能:
位于低速的APB1總線上(APB1)
16 位/32 位(僅 TIM2 和 TIM5)向上、向下、向上/向下自動裝載計數器 (TIMx_CNT),注意:TIM9~TIM14 只支持向上(遞增)計數方式
16 位可編程(可以實時修改)預分頻器(TIMx_PSC),計數器時鐘頻率的分頻系數為 1~ 65535 之間的任意數值
4 個獨立通道(TIMx_CH1~4,TIM9~TIM14 最多 2 個通道),這些通道可以用來作為:
????????????????輸入捕獲
????????????????輸出比較
????????????????PWM 生成(邊緣或中間對齊模式) ,注意:TIM9~TIM14 不支持中間對齊模式
????????????????單脈沖模式輸出
可使用外部信號(TIMx_ETR)控制定時器和定時器互連(可以用 1 個定時器控制另外 一個定時器)的同步電路。
????????如下事件發生時產生中斷/DMA(TIM9~TIM14 不支持 DMA):
????????????????更新:計數器向上溢出/向下溢出,計數器初始化(通過軟件或者內部/外部觸發)
????????????????觸發事件(計數器啟動、停止、初始化或者由內部/外部觸發計數)
????????????????輸入捕獲
????????????????輸出比較
????????????????支持針對定位的增量(正交)編碼器和霍爾傳感器電路(TIM9~TIM14 不支持)
????????????????觸發輸入作為外部時鐘或者按周期的電流管理(TIM9~TIM14 不支持)?
STM32的通用定時器可以被用于:測量輸入信號的脈沖長度(輸入捕獲)或者產生輸出波形(輸出比較和PWM)等
使用定時器分頻器和RCC時鐘控制分頻器,脈沖長度和波型周期可以在幾個微妙到幾個毫秒間調整,STM32的每個通用定時器都是完全獨立的,沒有互相共享的任何資源????????
計數器模式 ?
????????向上計數模式:計數器從0計數到自動加載值(TIMx_ARR),然后重新從0開始計數并且 產生一個計數器溢出事件
????????向下計數模式:計數器從自動裝入的值(TIMx_ARR)開始向下計數到0,然后從自動裝 入的值重新開始,并產生一個計數器向下溢出事件
????????中央對齊模式(向上/向下計數):計數器從0開始計數到自動裝入的值-1,產生一個 計數器溢出事件,然后向下計數到1并且產生一個計數器溢出事件;然后再從0開始重新計數
通用定時器框圖
框圖可以分為四個大部分,分別是:
時鐘產生部分
時基單元部分
輸入捕獲部分
輸出捕獲部分
時鐘產生部分?
內部時鐘(CKINT)
外部時鐘模式:外部觸發輸入(ETR)
內部觸發輸入(TRX):使用一個定時器作為另一個定時器的預分頻器,如可以配置一個定時器Timer1而作為另一個定時器Iimer2的預分頻器。
外部時鐘模式:外部輸入腳(TIx)
時機單元
時基單元就是定時器框圖的第二部分,它包括三個寄存器,分別是:計教器寄存器(TIMXCND、預分頻器寄存器(TIMXPSC)和自動裝載寄存器(TIMX ARR)。對這三個寄存器的介紹如下:
計數器寄存器(TIMx_CNT)
????????向上計數、向下計數或者中心對齊計數;
預分頻器寄存器(TIMx_PSC)
???????可將時鐘頻率按1到65535之間的任意值進行分頻,可在運行時改變其設置值;
自動裝載寄存器(TIMX ARR)
????????如果TIMx_CR1寄存器中的ARPE位為0,ARR寄存器的內容將直接寫入影子寄存器;如果ARPE為1,ARR寄存器的那日同將在每次的更新時間UEV發生時,傳送到影子寄存器;
輸入捕獲通道
1.IC1、2和IC3、4可以分別通過軟件設置將其映射到T11、TI2和TI3、TI4;
2.4個16位捕捉比較寄存器可以編程用于存放檢測到對應的每一次輸入捕捉時計數器的值,
3.當產生一次捕捉,相應的CCxIF標志位被置1;同時如果中斷或DMA請求使能,則產生中斷或DMA請求。
4.如果當CCxIF標志位已經為1,當又產生一個捕捉,則捕捉溢出標志位CCxOF將被置1。
輸出比較通道
PWM模式運行產生:
????????定時器2、3和4可以產生獨立的信號:頻率和占空比可以進行如下設定一個自動重載寄存器用于設定PWM的周期;每個PWM通道有一個
捕捉比較寄存器用于設定占空時間。
兩種可設置PWM模式:
????????邊沿對齊模式
????????中心對齊模式
常用庫函數
定時器參數初始化函數(第一個參數定時器幾,第二個參數結構體指針)
?void TIM_TimeBaseInit(TIM_TypeDef* TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct);
結構體內部成員
typedef struct
{uint16_t TIM_ClockDivision; ? ? //外部輸入時鐘分頻因子,基本定時器沒有uint16_t TIM_CounterMode; ? ? ? //計數模式,基本定時器只能向上計數uint16_t TIM_Period; ? ? ? ? ? //自動重裝載值 //注意重裝載值和分頻因子的數配置不能超過65535uint16_t TIM_Prescaler; ? ?//分頻因子 ? ? ?uint8_t TIM_RepetitionCounter; //重復計數值,基本定時器沒有,高級定時器專用} TIM_TimeBaseInitTypeDef; ?
65535
?定時器控制LED燈軟件流程設計
初始化系統
? ? ? ? 初始化定時器和LED的IO時鐘、初始化LED的引腳IO
? ? ? ? 使能定時器時鐘、初始化定時器、開啟中斷配置、使能定時器、
編寫定時器中斷函數
定時器時間= (ARR+1)*(PSC+1)/TCLK(72M=72 000 000)
假如定時1秒 1= 72 00*10000/72M
#include "stm32f10x.h"
#include "tim.h"void Base_Tim_Init()
{NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);TIM_TimeBaseInitTypeDef TIM_TimeIinitStruct;NVIC_InitTypeDef NVIC_InitStruct;RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);TIM_TimeIinitStruct.TIM_ClockDivision = TIM_CKD_DIV1;TIM_TimeIinitStruct.TIM_CounterMode = TIM_CounterMode_Up;TIM_TimeIinitStruct.TIM_Period = 7200 - 1;TIM_TimeIinitStruct.TIM_Prescaler = 10000 - 1;TIM_TimeIinitStruct.TIM_RepetitionCounter = 0;TIM_TimeBaseInit(TIM2,&TIM_TimeIinitStruct);TIM_ITConfig(TIM2,TIM_IT_Update, ENABLE);TIM_Cmd(TIM2, ENABLE);NVIC_InitStruct.NVIC_IRQChannel = TIM2_IRQn;NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;NVIC_Init(&NVIC_InitStruct);}
TIM_ITConfig(TIM2,TIM_IT_Update, ENABLE);
第二個參數
輸入捕獲輸出比較所用到的通道
如果我們只是想產生定時器的更新源中斷用第一個參數
#include "stm32f10x.h"
#include "main.h"
#include "led.h"
#include "bear.h"
#include "key.h"
#include "relay.h"
#include "shake.h"
#include "usart.h"
#include "stdio.h"
#include "tim.h"void delay(uint16_t time) {uint16_t i = 0;while (time--) {i = 12000;while (i--);}
}int main()
{Led_Init();Base_Tim_Init();while (1){ }
}void TIM2_IRQHandler(void)
{if(TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET){GPIO_ResetBits(GPIOA, GPIO_Pin_1);delay(1000);GPIO_SetBits(GPIOA, GPIO_Pin_1);delay(1000);}TIM_ClearITPendingBit(TIM2, TIM_IT_Update);}
定時器中斷應用?
超聲波模塊
? ? ? ? ? ? ? ? ? ? ? ? ?
?1.工作原理
首先單片機給Trig引腳,給至少10us(10微秒)的高電平信號。
模塊自動發送8個40KHz的方波,自動檢測是否有信號返回。
有信號返回,通過Echo引腳輸出高電平,高電平持續時間就是超聲波從發射到返回的時間
HC-SR04超聲波測距模塊提供2cm-400cm的測距功能,精度達3mm。
2.硬件接線
四根杜邦線,VCC連接單片機3.3-5V(推薦5V供電),GND接到板子的GND,Trig為外部觸發信號輸入,輸入一個10us的高電平即可觸發模塊測距,Echo(接收引腳)即為 回響信號輸出,測距結束時此管引腳輸出一個低電平,電平寬度反映超聲波往返時間之和。
3.控制超聲波測距步驟
初始化定時器時鐘和定時器中斷
初始化超聲波時鐘和超聲波引腳模式
編寫定時器中斷函數測距
先發送10us的高電平信號,發送了之后我的定時器就開始捕獲Echo的高電平的時間,什么時候低電平就什么時候關閉定時器,就開始算比如說我們產生了多少次定時器的中斷,比如是一次定時器中斷是1秒,多少個定時器中斷就是多少個秒,通過一系列公式就能知道距離是多少
1.?發送 10μs 的高電平信號(觸發信號)
目的:啟動一次測距操作。
這里的 “發送高電平” 通常是通過單片機的 IO 口輸出一個持續?10 微秒(μs)?的高電平脈沖(如 HC-SR04 模塊需要這樣的觸發信號)。為什么是 10μs?
這是目標設備(如超聲波傳感器)的協議規定,用于告知傳感器 “開始發射信號”(例如超聲波傳感器會在接收到 10μs 高電平后,發射一束超聲波)。2.?定時器開始捕獲 Echo 信號的高電平時間
Echo 信號是什么?
Echo 是 “回波信號”,即目標設備接收到反射回來的信號后,輸出的電信號。例如:
發送端發射超聲波后,Echo 信號保持低電平;
當超聲波遇到障礙物反射回來被接收端檢測到,Echo 信號變為高電平;
直到信號接收完畢,Echo 信號重新變為低電平。
定時器的作用:
從觸發信號發送完成的時刻起,定時器開始記錄 Echo 信號?高電平的持續時間(即從 “收到回波” 到 “回波結束” 的時間)。3.?檢測到低電平時關閉定時器
何時關閉定時器?
當 Echo 信號從高電平跳轉為低電平時(即回波接收完畢),立即停止定時器計數。本質:
定時器記錄的是?“回波信號高電平的持續時間 T”,這個時間 T 等于信號從發射到接收的?往返時間(即信號從發射端→障礙物→接收端的總時間)。4.?通過定時器中斷次數計算時間 T
定時器中斷機制:
定時器通常配置為按固定周期產生中斷(例如每 1μs、1ms 產生一次中斷),每次中斷時計數器加 1。
假設定時器中斷周期為?1μs(即每 1 微秒產生一次中斷),中斷次數為 N 次,則總時間?T = N × 1μs。
(原句中 “一次中斷是 1 秒” 是簡化舉例,實際應用中中斷周期遠小于 1 秒,通常為微秒或毫秒級,否則精度不足。)
如何計算中斷次數?
定時器啟動后,每當 Echo 為高電平時,中斷計數器持續累加,直到 Echo 變低時停止計數,此時計數器的值即為高電平期間的中斷次數。5.?通過公式計算距離
核心公式(以超聲波測距為例):
距離 = (信號速度 × 時間 T) / 2
除以 2 的原因:信號往返一次(發射→障礙物→接收),實際距離是單程距離。
信號速度:超聲波在空氣中約為 340m/s(即 0.034cm/μs),光速約為 3×10?m/s(用于激光測距)。
舉例計算:
若 T = 1000μs(1 毫秒),則距離 = (0.034cm/μs × 1000μs) / 2 = 17cm。
?超聲波代碼框架
只有收到回響信號的時候,我們的trigr,在信號發出的時候我的echo引腳輸入給我們的單片機,然后如果我們的單片機之前是低電平,檢測高電平的瞬間才開始打開定時器(怎么打開和關閉定時器呢)之前配置定時器的時候結構體配置和中斷的配置TIM_Cmd(TIM2, DISABLE);函數,先關閉
當收到信號的時候再打開,怎么計算高電平時間?首先要先判斷echo引腳什么時候變成高電平
用GPIO_ReadInputDataBit函數然后這里再打開定時器這時就開始我們的中斷函數,中斷函數去計數定時器進入的次數,因為我們用定時器的開啟的時候用定時器的中斷計算進入定時器的時間,注意? 這里定時器的配置TIM_Initstruct.TIM_Period = 1000 -1;? TIM_Initstruct.TIM_Prescaler = 72 -1;
所以定時器的定時周期的1毫秒,計數器每計1次代表1微秒?,中斷1次是1毫秒,因為我們對應的時間是高電平的時間等于中斷次數加上不足一個中斷的次數(不足一個中斷的次數是說不到1毫秒但有多少個微秒呢)打開定時器,就會跳到定時器中斷函數void TIM2_IRQHandler()讓mscount++;這里需要定義一個新變量,然后關閉定時器,計算總電平時間,定義一個變量uint16_t t=0;定義一個函數專門用來封裝總的高電平時間int Get_Echon_Time()(這里返回值是int)然后將總時間換算成距離以種種方式將t換算距離然后返回值length
?
#include "stm32f10x.h"
#include "tim.h"uint16_t mscount = 0;//定義一個變量專門用來記錄中斷的次數void delay_us(uint32_t us)
{us*= 8;while(us--);//延時微秒函數}
void delay_ms(uint32_t ms)
{while(ms--){delay_us(1000);} //延時毫秒函數}void Base_Tim_Init()
{TIM_TimeBaseInitTypeDef TIM_Initstruct;NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);NVIC_InitTypeDef NVIC_TIM_Initstruct;RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);TIM_Initstruct.TIM_ClockDivision =TIM_CKD_DIV1;TIM_Initstruct.TIM_CounterMode = TIM_CounterMode_Up;TIM_Initstruct.TIM_Period = 1000 -1;TIM_Initstruct.TIM_Prescaler = 72 -1;TIM_Initstruct.TIM_RepetitionCounter = 0;TIM_TimeBaseInit(TIM2, &TIM_Initstruct);TIM_ITConfig(TIM2,TIM_IT_Update, ENABLE);TIM_Cmd(TIM2, DISABLE);NVIC_TIM_Initstruct.NVIC_IRQChannel = TIM2_IRQn;NVIC_TIM_Initstruct.NVIC_IRQChannelCmd = ENABLE;NVIC_TIM_Initstruct.NVIC_IRQChannelPreemptionPriority = 0;NVIC_TIM_Initstruct.NVIC_IRQChannelSubPriority = 0;NVIC_Init(&NVIC_TIM_Initstruct);}
void HC04_Iint()
{GPIO_InitTypeDef GPIO_Initstruction;RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE);//Tring B11GPIO_Initstruction.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_Initstruction.GPIO_Pin = GPIO_Pin_11;GPIO_Initstruction.GPIO_Speed = GPIO_Speed_10MHz;GPIO_Init(GPIOB, &GPIO_Initstruction);//Echo B10GPIO_Initstruction.GPIO_Mode = GPIO_Mode_IN_FLOATING;GPIO_Initstruction.GPIO_Pin = GPIO_Pin_10;GPIO_Init(GPIOB, &GPIO_Initstruction);}void Open_Tim()
{TIM_SetCounter(TIM2, 0);mscount = 0;TIM_Cmd(TIM2, ENABLE);}
void Close_Tim()
{TIM_Cmd(TIM2, DISABLE);}
//獲取定時器中斷的次數
void TIM2_IRQHandler()
{if(TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET){mscount++;TIM_ClearITPendingBit(TIM2, TIM_IT_Update);}}//獲取總的高電平時間
int Get_Echon_Time()
{uint16_t t = 0;t = mscount * 1000;t = t +TIM_GetCounter(TIM2);delay_ms(50);TIM_SetCounter(TIM2, 0);return t;}float Get_Length()
{float sum = 0;uint16_t t=0;float length = 0;int i = 0;while(i != 5){//1.hc04開始工作 Tring引腳輸出高電平20usGPIO_SetBits(GPIOB, GPIO_Pin_11)delay_us(20);//延時20微秒GPIO_ResetBits(GPIOB, GPIO_Pin_11);//然后關閉//2.定時器計算高電平時間while(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_10) == 0);//當GPIO 10引腳高電平時 會卡在這Open_Tim();//打開定時器while(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_10) == 1);//當高電平跳成低電平時Close_Tim();//關閉定時器t = Get_Echon_Time();//3.將時間換算成距離length = ((float)t/58.0);sum = sum+length;}length = sum/5.0;return length;}
int main()
{float length = 0;my_usart_init();Ch04_Init();Led_Init();Base_Tim_Init();while (1){length = Get_Length();printf("%f\r\n",length);}
}
?通用定時輸出PWM
第一步內部時鐘的選擇,第二步是預分頻器,計數器,去配置輸出 捕獲和比較
定時器3的通道2?
以TIM3為例,STM32的通用定時器氛圍TIM2,TIM3,TIM4,TIM5,每個定時器都有獨立的四個通道可以用來作為: 輸入捕獲,輸出比較,PWM輸出,單脈沖模式輸出等。
STM32的定時器除了TIM6和TIM7(基本定時器)之外,其他的定時器都可以產生PWM波輸出,高級定時器TIM1,TIM8可以同時產生7路PWM輸出,而通用定時器可以同時產生4路PWM輸出,這樣STM32可以最多同時輸出30路PWM輸出。
?PWM的工作原理
以向上計數為例,講述PWM原理:
①在PWM輸出模式下除了CNT(計數器當前值),ARR(自動重裝載值),CCRx(捕獲/比較寄存器值)。
②當CNT小于CCRx時,TIMx_CHx通道輸出低電平
③當CNT等于或大于CCRx時,TIMx_CHx通道輸出高電平
假設ARR設置是100CRRX是80,在0加到80過程中都屬于低電平,在80加到100都屬于高電平,這就是一個周期,所以占空比為百分之二十,
????????? 所謂脈寬調制信號(PWM波),就是一個TIMx_ARR自動重裝載寄存器確定頻率=周期的導數(由它決定PWM周期),TIM_CCRx寄存器確定占空比信號。
占空比=高電平占低電平的時間
?PWM的內部運作機制
CCR1:設置捕獲比較寄存器,設置比較值。??????
CCMR1寄存區:設置PWM模式1 或者PWM模式2。
CCER:? P位:輸出/捕獲?? :設置極性: 0 高電平有效,1 低電平有效
???????????? E位:輸出/捕獲?? : 使能端口
PWM的模式?
模式一??? 邊沿對齊模式
向上計數時: 當TIMx_CNT<TIMx_CCRx時通道1為有效電平,否則為無效電平;(計數值小于有效值是有效電平)
向下計數時:?? 一旦TIMx_CNT>TIMx_CCRx,CCR1通道1為無效電平,否則為有效電平。(計數值大于比較值為無效電平)
但是這里的有效電平是高電平還是低電平有極性( 0 高電平有效,1 低電平有效)去選擇
模式二??? 中央對齊模式
向上計數時: 當TIMx_CNT<TIMx_CCRx時通道1為無效電平,否則為無效電平;
向下計數時:?? 一旦TIMx_CNT>TIMx_CCRx,CCR1通道1為有效電平,否則為無效電平。
和模式一相反
?但是這里的有效電平是高電平還是低電平有極性( 0 高電平有效,1 低電平有效)去選擇
?自動加載的預加載寄存器
?
簡單的說:
APER =1 ,ARR立即生效
APER =0,ARR下個周期生效
void TIM_ARRPreloadConfig(TIM_TypeDef* TIMx, FunctionalState NewState);
?定時器輸出PWM 結構體
typedef struct
{uint16_t TIM_OCMode; //配置PWM模式1還是模式2uint16_t TIM_OutputState; //配置輸出使能/ OR失能uint16_t TIM_OutputNState; uint16_t TIM_Pulse; //配置比較值,CCRxuint16_t TIM_OCPolarity; //比較輸出極性uint16_t TIM_OCNPolarity; uint16_t TIM_OCIdleState; uint16_t TIM_OCNIdleState;
} TIM_OCInitTypeDef;
定時器輸出PWM 庫函數
void TIM_OCxInit //結構體初始化
(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
void TIM_SetCompare1 //設置比較值函數
(TIM_TypeDef* TIMx, uint16_t Compare1);
void TIM_OC1PreloadConfig //使能輸入比較預裝載
(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload);
void TIM_Cmd //開啟定時器(TIM_TypeDef* TIMx, FunctionalState NewState)
void TIM_ARRPreloadConfig //使能自動重裝載的預裝載寄存器允許位
(TIM_TypeDef* TIMx, FunctionalState NewState);
void TIM_OC1PolarityConfig //配置修改極性
(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity);
定時器輸出PWM 庫函數
TIM3 PWM輸出? 驅動SG90電機??? 配置過程:
1.GPIO結構體
2.配置通用定時器結構體
3.配置定時去輸出PWM結構體
4.打開時鐘? ---> GPIO時鐘,TIM定時器時鐘,部分重映射時鐘
5.配置PWM比較值
void motor_config(void)
{GPIO_InitTypeDef GPIO_MotorInitStruct;TIM_TimeBaseInitTypeDef TIM_MotorInit;TIM_OCInitTypeDef TIMPWM_MotorInit;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO,ENABLE);RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE);//部分重映射配置GPIO_MotorInitStruct.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_MotorInitStruct.GPIO_Pin = GPIO_Pin_5;GPIO_MotorInitStruct.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB, &GPIO_MotorInitStruct);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);TIM_MotorInit.TIM_ClockDivision = TIM_CKD_DIV1; //設置時鐘分割TIM_MotorInit.TIM_CounterMode = TIM_CounterMode_Up;//TIM向上計數模式TIM_MotorInit.TIM_Period = 200-1;//設置下一個更新事件裝入活動的自動重裝載值TIM_MotorInit.TIM_Prescaler = 7200 -1; //分頻周期TIM_TimeBaseInit(TIM3, &TIM_MotorInit);TIMPWM_MotorInit.TIM_OCMode = TIM_OCMode_PWM1;//選擇定時器模式1TIMPWM_MotorInit.TIM_OutputState = TIM_OutputState_Enable;//比較輸出使能TIMPWM_MotorInit.TIM_OCNPolarity = TIM_OCPolarity_Low;//選擇有效輸出極性TIM_OC2Init(TIM3, &TIMPWM_MotorInit);//因為選擇的是定時器3的通道2 所以選OC2TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);TIM_Cmd(TIM3, ENABLE);}
int main()
{uint16_t pwmval = 155;motor_config();while(1){for(pwmval = 195;pwmval >= 175;pwmval-=5){TIM_SetCompare2(TIM2, pwmval);delay(500);}}}
垃圾桶項目?
int main()
{int pwmval =195;float Length =0;Ch04_Init(); my_usart_init();motor_config();while(1){pwmval =155;Length= Get_Length();printf("%.3f\r\n",Length);if(Length<5){for(pwmval=195;pwmval>=155;pwmval-=15){TIM_SetCompare2(TIM3, pwmval);delay(500); }}else if(Length>5){TIM_SetCompare2(TIM3, pwmval-20);}}}