国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

手把手教你開發(fā)stm32——定時器(上)(基于hal庫)

這篇具有很好參考價值的文章主要介紹了手把手教你開發(fā)stm32——定時器(上)(基于hal庫)。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

1.stm32定時器介紹

1.1.stm32f103定時器介紹

  • 定時器可以對輸入的時鐘進行計數(shù),并在計數(shù)值達到設(shè)定值時觸發(fā)中斷。
  • 16位計數(shù)器、預(yù)分頻器、自動重裝載寄存器的時基單元。
  • 不僅具備基本的定時中斷功能,而且還包含內(nèi)外時鐘源選擇、輸入捕獲、輸出比較、編碼器接口、主從觸發(fā)模式等多種功能。
  • 根據(jù)復(fù)雜度和引用場景分為了高級定時器、通用定時器、基本定時器三種類型。
    stm32裸機開發(fā)定時器,手把手教你學(xué)stm32,stm32,單片機,嵌入式硬件
    以上是各類定時器的主要功能

1.2.定時器計數(shù)模式

stm32裸機開發(fā)定時器,手把手教你學(xué)stm32,stm32,單片機,嵌入式硬件

  1. 向上計數(shù)模式
    計數(shù)器從0計數(shù)到自動加載值(TIMx_ARR),然后重新從0開始技術(shù)并且產(chǎn)生一個計數(shù)器溢出事件。
  2. 向下計數(shù)模式
    計數(shù)器從自動裝入的值(TIMx_ARR)開始向下計數(shù)到0,然后從自動裝入的值重新開始,并產(chǎn)生一個計數(shù)器向下溢出事件。
  3. 中央對齊模式(向上/向下計數(shù))
    計數(shù)器從0開始計數(shù)到自動裝入的值-1,產(chǎn)生一個計數(shù)器溢出事件,然后向下計數(shù)到1并且產(chǎn)生一個計數(shù)器溢出四件;然后再從0開始重新計數(shù)。

1.3.定時器的時鐘

stm32裸機開發(fā)定時器,手把手教你學(xué)stm32,stm32,單片機,嵌入式硬件
上圖是stm32的系統(tǒng)結(jié)構(gòu),我們可以從上圖中看到,TIM1和TIM8是掛載到APB2總線上的,而TIM2-TIM7是掛載到APB1總線上的。
在stm32f103系列的MCU中,雖然定時器掛載的總線是不同的,但是每個定時器的時鐘頻率都是相同的。而其他系列的MCU,比如說stm32f407系列的MCU,如果掛載到不同的總線上,那么定時器的時鐘頻率可能是不同的。從下圖配置的cubemx圖中我們可以看到每個定時器上具體的時鐘。
stm32裸機開發(fā)定時器,手把手教你學(xué)stm32,stm32,單片機,嵌入式硬件
我們從上面這個圖中可以看到,掛載到APB1和APB2總線上的定時器的時鐘都是72MHZ。

2.stm32時鐘的工作方式

我們這個地方主要就是講一下定時器基本的定時計數(shù)的功能,定時器基本的定時計數(shù)功能主要是通過以下的框圖來進行的。
stm32裸機開發(fā)定時器,手把手教你學(xué)stm32,stm32,單片機,嵌入式硬件

  • 時鐘源:定時器時鐘TIMxCLK,即內(nèi)部時鐘CK_INT,經(jīng)過APB預(yù)分頻器分頻后提供,就是從APB總線上引出的時鐘來源。
  • 計數(shù)器時鐘:計數(shù)器時鐘是經(jīng)過②PSC預(yù)分頻器后產(chǎn)生的,就是由于不需要APB總線上這么高頻率的時鐘,所以在時鐘輸入以后,還需要進行預(yù)分頻以后,才能產(chǎn)生真正驅(qū)動CNT計數(shù)器的時鐘,每個定時器的時鐘的預(yù)分頻器PSC都是最高16位的,所以不能超過預(yù)分頻器的范圍。
  • 計數(shù)器CNT:計數(shù)器CNT是進行計數(shù)的單元,當(dāng)接收到CK_CNT來的時鐘信號以后,每經(jīng)過一個時鐘頻率,CNT就會進行向上計數(shù)或者向下計數(shù),當(dāng)向上計數(shù)到自動重裝載寄存器的值(ARR)或者從ARR減到0以后,就會產(chǎn)生中斷或者事件更新。計數(shù)器CNT是一個16位/32位的計數(shù)器,每個定時器都是不同的,所以我們需要根據(jù)實際的情況來進行設(shè)置。
  • 自動重裝載寄存器(ARR):這里面裝著計數(shù)器能計數(shù)的最大數(shù)值,當(dāng)計數(shù)到這個值的時候,如果使能了中斷的話,定時器就會產(chǎn)生溢出中斷。
  • 計時中斷時間:1/(TIMxCLK/(PSC+1)*(ARR+1))

3.定時器中斷具體實現(xiàn)

我們需要實現(xiàn)的目標(biāo)是利用基本定時器實現(xiàn)定時1s中斷,并在中斷處理函數(shù)中控制LED燈的亮滅。

3.1.cubemx的具體配置

首先配置TIM2的相關(guān)參數(shù)
stm32裸機開發(fā)定時器,手把手教你學(xué)stm32,stm32,單片機,嵌入式硬件
其次配置TIM2的相關(guān)中斷
stm32裸機開發(fā)定時器,手把手教你學(xué)stm32,stm32,單片機,嵌入式硬件

3.2.具體代碼的實現(xiàn)

stm32裸機開發(fā)定時器,手把手教你學(xué)stm32,stm32,單片機,嵌入式硬件
我們設(shè)置了定時器中斷,同樣需要在這個中斷C文件中去尋找相關(guān)的TIM2的中斷,我們找到這個函數(shù)以后追進去。
stm32裸機開發(fā)定時器,手把手教你學(xué)stm32,stm32,單片機,嵌入式硬件
我們找到定時器更新事件,不出意外需要重寫回調(diào)函數(shù)。
stm32裸機開發(fā)定時器,手把手教你學(xué)stm32,stm32,單片機,嵌入式硬件
進行回調(diào)函數(shù)的重寫,寫的規(guī)則是if(htim->Instance == TIM2) {HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_1);},這樣就可以在每一秒鐘,使得PA1口的LED燈進行亮滅的操作。
其中htim->Instance 是指htim是一個結(jié)構(gòu)體指針,然后指向他的成員變量intance(這個是寄存器基地址),如果這個寄存器的基地址等于TIM2的基地址,則證明這兩者相同,也就是說是TIM2產(chǎn)生的事件更新中斷,然后再進行下一步的操作。

寫到這個地方以后,我們還需要進行定時器中斷時基單元的開啟,這樣,定時器才能開始計數(shù)。
stm32裸機開發(fā)定時器,手把手教你學(xué)stm32,stm32,單片機,嵌入式硬件
我們在main函數(shù)中開啟TIM2的時基單元,這樣就能實現(xiàn)最終的效果了。

4.通用定時器功能分析

通用定時器除了最基本的定時功能以外,還有輸入捕獲和輸出比較的功能,具體的功能我們可以通過下面的結(jié)構(gòu)框圖來進行了解。
stm32裸機開發(fā)定時器,手把手教你學(xué)stm32,stm32,單片機,嵌入式硬件
我們一塊一塊來分析

  1. 第1塊是整個定時器的時鐘源,用來進行時鐘源的選擇,時鐘源有以下幾個選擇:

    • 內(nèi)部時鐘(CK_INT):內(nèi)部時鐘源就是通過stm32的內(nèi)部時鐘來進行時鐘的輸入的,通過內(nèi)部時鐘總來作為定時器的時鐘來源
    • 外部時鐘模式1:外部輸入引腳Tlx(x=1,2,3,4),采用定時器的外部通道引腳的輸入信號(TI1,TI2)作為定時器的時鐘源。TI1(TI2)通過濾波和邊緣檢測,得到信號TI1FP2(TI2FP2)作為計數(shù)器的觸發(fā)信號。值得注意的是,只有TI1FP2和TI2FP2可以作為時鐘源,也就是說想要使用外部時鐘模式1,時鐘信號只能通過通道1或者通道2輸入。
    • 外部時鐘模式2:外部觸發(fā)輸入ETR,采用定時器的ETR引腳作為外部時鐘信號源,通過邊沿檢測和濾波來作為定時器的時鐘源。
    • 外部觸發(fā)輸入(ITRx):使用一個定時器作為另一定時器的預(yù)分頻器,將主定時器的TRGO信號作為從定時器的ITRx輸入作為時鐘源。
      一般而言,我們都是使用內(nèi)部時鐘作為定時器的時鐘來源
  2. 第2塊是通用定時器的控制器,主要包括觸發(fā)控制器、從模式控制器以及編碼器接口。觸發(fā)控制器用來針對片內(nèi)外設(shè)輸出觸發(fā)信號,比如為其他定時器提供時鐘和觸發(fā)DAC/ADC轉(zhuǎn)換。編碼器接口專門針對編碼器計數(shù)來使用;從模式控制器可以控制計數(shù)器復(fù)位、啟動、遞增/遞減、計數(shù)等功能??刂破髌鋵嵳f白了就是時鐘系統(tǒng)的配置單元,一個外設(shè)中需要使能相應(yīng)的功能那么就需要進行控制器的配置,比如說我們需要配置定時器的中斷、定時器主從級聯(lián)、定時器發(fā)送信號等功能就需要進行控制器的配置,由控制器來控制整個定時器的功能。

  3. 第3塊是時基單元,定時器產(chǎn)生的定時計數(shù)就是從這個地方產(chǎn)生的。通用定時器的時基單元主要由預(yù)分頻器PSC、計數(shù)器CNT、自動沖轉(zhuǎn)載寄存器ARR組成的。時鐘單元我們在第二章stm32時鐘工作方式講過,這個地方就不再贅述。

  4. 第4塊是輸入捕獲的部分,輸入捕獲部分我們主要就是用來捕獲外部輸入信號的頻率或者脈寬,我們肯定是需要去將外部的信號去連接我們的定時器通道。

    • 當(dāng)一個信號輸入進來以后,首先我們需要對輸入進來的信號進行一個濾波,因為輸入進來的信號可能不是很穩(wěn)定的信號,所以我們首先需要進行濾波的操作;然后我們還需要進行一個邊沿的檢測,當(dāng)我們需要去檢測一個外部信號的脈寬或者頻率的時候,我們首先要想的就是如何去檢測這個信號,我們肯定是要用邊沿來檢測這樣一個信號,如果要去檢測脈寬,那么就需要測量一個信號的上升沿/下降沿和下降沿/上升沿,如果需要去檢測一個信號的頻率,那么我們就需要去檢測一個信號的兩次邊沿,這樣就能測量出來這個信號的頻率,這就是我們需要使用一個輸入濾波和邊沿檢測器的原因了。
    • 采集到信號以后,我們需要進行預(yù)分頻器的設(shè)置,我們可以去設(shè)置這個預(yù)分頻器,也可以不去設(shè)置這個預(yù)分頻器的值,如果設(shè)置這個預(yù)分頻器,比如說我們將預(yù)分頻器的值設(shè)置為2,那么這個意思就是,我們在采集信號頻率的時候,并不是采集到兩次上升沿或者兩次下降沿就去報告我們采集到這個信號的頻率,我們需要去采集四次上升沿和下降沿再去匯報這個信號的頻率,這樣做的目的就是我們可以進行信號的一次采集濾波,更好地去測試信號的頻率。
  5. 第5塊是捕獲/比較寄存器,輸入捕獲和輸出比較的時候都需要用到這個寄存器,在我們使用輸入捕獲的功能的時候,我們可以用這個寄存器來存放我們輸入捕獲到的值,這就是我們在輸入捕獲過程中需要使用這個寄存器的方法;而輸出比較的時候,我們需要通過這個寄存器來設(shè)置CCR的值,通過這個CCR的值和ARR的值的比較,我們就可以輸出一個PWM的波形,這樣就可以用作電機PWM調(diào)速或者產(chǎn)生呼吸燈的效果,具體的輸出比較功能我們放在第6塊來講解。

  6. 輸出比較的功能就是用來產(chǎn)生PWM波形,下面這個圖就是顯示PWM的原理。
    我們可以看到在0-t1的過程中,CCR的值小于ARR的值,這樣就可以產(chǎn)生一個低電平;在t1-t2的過程中,ARR的值大于CCR,這樣就可以產(chǎn)生一個高電平;我們知道,PWM的全稱是脈沖寬度調(diào)制,當(dāng)高低電平在一個周期中有不同的時候,這樣就可以產(chǎn)生不同的電壓。比如說我們知道高電平是3.3V,當(dāng)?shù)碗娖綍r間在一個周期里面占40%,那么高電平時間占60%的時間,那么這樣在一個周期里面的平均電平就是1.98V,這樣就是PWM的原理,通過輸出比較的功能,我們就可以看到這樣就可以產(chǎn)生一個PWM的信號用來驅(qū)動電機或者產(chǎn)生呼吸燈的效果。
    stm32裸機開發(fā)定時器,手把手教你學(xué)stm32,stm32,單片機,嵌入式硬件

5.高級定時器功能分析

stm32裸機開發(fā)定時器,手把手教你學(xué)stm32,stm32,單片機,嵌入式硬件
高級定時器和通用定時器的主要區(qū)別就是在第3塊和第5塊的地方
第3塊主要的區(qū)別就是,高級定時器比通用定時器多了一個重復(fù)次數(shù)計數(shù)器,重復(fù)次數(shù)計數(shù)器的作用就是,當(dāng)CNT計數(shù)器產(chǎn)生溢出的時候,并不會直接產(chǎn)生中斷,而是會將溢出傳遞到重復(fù)次數(shù)計數(shù)器,重復(fù)次數(shù)計數(shù)器也會存一個數(shù)值,每次CNT計數(shù)器產(chǎn)生溢出以后,重復(fù)次數(shù)計數(shù)器數(shù)值就會減一,當(dāng)重復(fù)次數(shù)計數(shù)器減到0以后,才會產(chǎn)生溢出。
第5塊主要區(qū)別就是高級定時器增加了可編程的死區(qū)互補輸出功能,主要應(yīng)用在工業(yè)電機控制方面。但是目前來講,我沒有用到過這個功能,因此我也就不在這里班門弄斧了。

6.輸入捕獲實驗

我們上面介紹過,定時器有一個非常好用的功能就是輸入捕獲,很多的示波器的原理就是利用時鐘的輸入捕獲的功能,本章節(jié)就來具體講一個輸入捕獲的實驗。
實驗?zāi)繕?biāo):利用定時器4的輸入捕獲功能測量按鍵按下后低電平持續(xù)的時間,并用LED燈亮的時間來顯示捕獲的時間。

6.1.理論知識

輸入捕獲功能框圖如下圖所示
stm32裸機開發(fā)定時器,手把手教你學(xué)stm32,stm32,單片機,嵌入式硬件
我們可以從每個定時器的通道中來進行輸入捕獲,具體的結(jié)構(gòu)分析我們在上面的理論知識中已經(jīng)講過了,這里就不再贅述了。

6.2.cubemx配置

stm32裸機開發(fā)定時器,手把手教你學(xué)stm32,stm32,單片機,嵌入式硬件
stm32裸機開發(fā)定時器,手把手教你學(xué)stm32,stm32,單片機,嵌入式硬件
其他配置都和原來的配置相同,將調(diào)試端口、時鐘配置、文件名配置完成后就可以生成對應(yīng)的文件了。

6.3.具體代碼實現(xiàn)

實驗?zāi)繕?biāo):利用定時器4的輸入捕獲功能測量按下按鍵后低電平持續(xù)的時間,并通過PA3口LED燈亮的時間來顯示。

  1. 首先輸入捕獲模式,可以用來測量頻率或者電平保持的時間,如下圖所示:
    stm32裸機開發(fā)定時器,手把手教你學(xué)stm32,stm32,單片機,嵌入式硬件
    我們?nèi)绻枰东@低電平的時間,就需要從value2處觸發(fā)一次捕獲中斷,然后再從value3處觸發(fā)一次捕獲中斷,通過這兩次捕獲中斷的差值就可以來計算出低電平持續(xù)的時間了。但是我們一開始設(shè)置的是下降沿捕獲,而第二次捕獲需要進行上升沿的捕獲,所以中間就會涉及到一次邊沿捕獲方式的轉(zhuǎn)變。
  2. 然后我們需要考慮捕獲的時間,由于我們低電平持續(xù)的時間可能會大于定時器ARR的值,導(dǎo)致中途溢出,如下圖所示:
    stm32裸機開發(fā)定時器,手把手教你學(xué)stm32,stm32,單片機,嵌入式硬件
    所以我們還需要考慮每次中途溢出的時間,我們可以用一個標(biāo)志位來記錄每次按鍵按下以后,低電平持續(xù)時間中,定時器中斷溢出了幾次,這樣我就可以使用標(biāo)志位*ARR的值來計算溢出的時間,然后通過最后捕獲的時間減去初始時間就能得到最后精確的值了。

以下是我的代碼的具體實現(xiàn)方式:

  1. 我們首先找到TIM4的中斷函數(shù)
    stm32裸機開發(fā)定時器,手把手教你學(xué)stm32,stm32,單片機,嵌入式硬件
  2. 追進去以后需要找到兩個回調(diào)函數(shù),第一個就是定時器中斷溢出的回調(diào)函數(shù),第二個就是輸入捕獲的回調(diào)函數(shù),我們找到這兩個回調(diào)函數(shù)以后,需要對這兩個回調(diào)函數(shù)進行重寫,來實現(xiàn)我們的功能。

stm32裸機開發(fā)定時器,手把手教你學(xué)stm32,stm32,單片機,嵌入式硬件
stm32裸機開發(fā)定時器,手把手教你學(xué)stm32,stm32,單片機,嵌入式硬件
3. 兩個回調(diào)函數(shù)的重寫
我的兩個回調(diào)函數(shù)是在time.c中重寫并實現(xiàn)具體的功能的,我的回調(diào)函數(shù)都有寫注釋,然后具體可以看我寫的注釋。

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	if(htim->Instance==TIM4)
	{
		HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_3);  //當(dāng)按鍵按下以后,每過1s鐘,PA3上的LED燈就翻轉(zhuǎn)一次
		tim_value+=10000;  //按鍵按下后,當(dāng)?shù)竭_溢出以后,tim_value的值就加上ARR設(shè)置的值,ARR設(shè)置的值為10000
	}
}


void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)  //輸入捕獲中斷的回調(diào)函數(shù)
{
	if(htim->Instance==TIM4)  //檢查是否為TIM4觸發(fā)的中斷
	{
		if(toggle_flag==0) //檢查標(biāo)志位
		{
			HAL_Delay(20); //消抖
			if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_6)==GPIO_PIN_RESET)
			{
				toggle_flag=1;  //進入中斷后首先翻轉(zhuǎn)標(biāo)志位
				HAL_GPIO_WritePin(GPIOA,GPIO_PIN_2,GPIO_PIN_SET); //PA2的LED燈亮200ms,顯示進入輸入捕獲函數(shù)
				HAL_Delay(200);
				HAL_GPIO_WritePin(GPIOA,GPIO_PIN_2,GPIO_PIN_RESET);
				HAL_TIM_Base_Start_IT(htim); //開啟溢出中斷,開始進行計時
				
				__HAL_TIM_DISABLE(htim);  //關(guān)閉TIM4
				
				__HAL_TIM_SET_COUNTER(htim,0); //設(shè)置時鐘計數(shù)值為0
				TIM_RESET_CAPTUREPOLARITY(htim,TIM_CHANNEL_1);  //清除TIM4通道1的原始設(shè)置
				TIM_SET_CAPTUREPOLARITY(htim,TIM_CHANNEL_1,TIM_INPUTCHANNELPOLARITY_RISING);//將觸發(fā)輸入捕獲中斷源設(shè)置為上升沿捕獲
				
				__HAL_TIM_ENABLE(htim);//使能TIM4
			} 
		}
		else if(toggle_flag==1)//檢查標(biāo)志位
		{
			HAL_Delay(20);//消抖
			if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_6)==GPIO_PIN_SET)//檢查是否為上升沿
			{
				toggle_flag=0; 
				HAL_TIM_Base_Stop_IT(htim);//關(guān)閉溢出中斷
				HAL_GPIO_WritePin(GPIOA,GPIO_PIN_2,GPIO_PIN_SET);//若是上升沿觸發(fā)輸入捕獲中斷,LED燈亮200ms
				HAL_Delay(200);
				HAL_GPIO_WritePin(GPIOA,GPIO_PIN_2,GPIO_PIN_RESET);
				
				tim_value=(tim_value+HAL_TIM_ReadCapturedValue(&htim4,TIM_CHANNEL_1 ))/10+20;//計算捕獲的總時間
				
				HAL_GPIO_WritePin(GPIOA,GPIO_PIN_2,GPIO_PIN_SET); //計算出總時間后,使得PA2口的LED燈亮的時間和總時間相同,以顯示輸入捕獲效果
				HAL_Delay(tim_value);
				HAL_GPIO_WritePin(GPIOA,GPIO_PIN_2,GPIO_PIN_RESET);
				
				__HAL_TIM_DISABLE(htim);
				
				TIM_RESET_CAPTUREPOLARITY(htim,TIM_CHANNEL_1);
				TIM_SET_CAPTUREPOLARITY(htim,TIM_CHANNEL_1,TIM_INPUTCHANNELPOLARITY_FALLING);
				
				__HAL_TIM_ENABLE(htim);
			}
		}
	}
}
  1. 其他工作
    我們用到了定時器的相關(guān)內(nèi)容,就需要使能這些內(nèi)容。
  • 首先我們需要開啟定時器的輸入捕獲功能。
    stm32裸機開發(fā)定時器,手把手教你學(xué)stm32,stm32,單片機,嵌入式硬件
  • 當(dāng)然我們還需要開啟定時器溢出中斷的功能,但是這部分功能我在重寫輸入捕獲的回調(diào)函數(shù)的時候才進行操作,具體可以看我上面的代碼
    stm32裸機開發(fā)定時器,手把手教你學(xué)stm32,stm32,單片機,嵌入式硬件
  • 定義相關(guān)變量
    我們在重寫定時器溢出回調(diào)函數(shù)和定時器輸入捕獲回調(diào)函數(shù)的時候用到了一些變量,我們需要在time.c中定義這些變量
    stm32裸機開發(fā)定時器,手把手教你學(xué)stm32,stm32,單片機,嵌入式硬件

下面是我的time.c和main.c中的具體代碼
main.c

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2023 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "tim.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */

/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */
	
	
  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_TIM4_Init();
  /* USER CODE BEGIN 2 */
	
	HAL_TIM_IC_Start_IT(&htim4,TIM_CHANNEL_1);
//	extern uint32_t tim_value;
//	extern uint8_t send_flag;
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
//	  if(send_flag==1)
//	  {
//		  tim_value/=1000;
//		  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_SET);
//		  HAL_Delay(tim_value);
//		  tim_value=0;
//	  }
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    Error_Handler();
  }
}

/* USER CODE BEGIN 4 */



/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  while (1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

time.c

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file    tim.c
  * @brief   This file provides code for the configuration
  *          of the TIM instances.
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2023 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "tim.h"

/* USER CODE BEGIN 0 */
uint32_t tim_value=0;
uint8_t toggle_flag=0;
//uint8_t send_flag=0;
/* USER CODE END 0 */

TIM_HandleTypeDef htim4;

/* TIM4 init function */
void MX_TIM4_Init(void)
{

  /* USER CODE BEGIN TIM4_Init 0 */

  /* USER CODE END TIM4_Init 0 */

  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};
  TIM_IC_InitTypeDef sConfigIC = {0};

  /* USER CODE BEGIN TIM4_Init 1 */

  /* USER CODE END TIM4_Init 1 */
  htim4.Instance = TIM4;
  htim4.Init.Prescaler = 7200;
  htim4.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim4.Init.Period = 10000;
  htim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim4.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
  if (HAL_TIM_Base_Init(&htim4) != HAL_OK)
  {
    Error_Handler();
  }
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim4, &sClockSourceConfig) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_TIM_IC_Init(&htim4) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim4, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_FALLING;
  sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI;
  sConfigIC.ICPrescaler = TIM_ICPSC_DIV1;
  sConfigIC.ICFilter = 0;
  if (HAL_TIM_IC_ConfigChannel(&htim4, &sConfigIC, TIM_CHANNEL_1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN TIM4_Init 2 */

  /* USER CODE END TIM4_Init 2 */

}

void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* tim_baseHandle)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(tim_baseHandle->Instance==TIM4)
  {
  /* USER CODE BEGIN TIM4_MspInit 0 */

  /* USER CODE END TIM4_MspInit 0 */
    /* TIM4 clock enable */
    __HAL_RCC_TIM4_CLK_ENABLE();

    __HAL_RCC_GPIOB_CLK_ENABLE();
    /**TIM4 GPIO Configuration
    PB6     ------> TIM4_CH1
    */
    GPIO_InitStruct.Pin = GPIO_PIN_6;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

    /* TIM4 interrupt Init */
    HAL_NVIC_SetPriority(TIM4_IRQn, 1, 1);
    HAL_NVIC_EnableIRQ(TIM4_IRQn);
  /* USER CODE BEGIN TIM4_MspInit 1 */

  /* USER CODE END TIM4_MspInit 1 */
  }
}

void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef* tim_baseHandle)
{

  if(tim_baseHandle->Instance==TIM4)
  {
  /* USER CODE BEGIN TIM4_MspDeInit 0 */

  /* USER CODE END TIM4_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_TIM4_CLK_DISABLE();

    /**TIM4 GPIO Configuration
    PB6     ------> TIM4_CH1
    */
    HAL_GPIO_DeInit(GPIOB, GPIO_PIN_6);

    /* TIM4 interrupt Deinit */
    HAL_NVIC_DisableIRQ(TIM4_IRQn);
  /* USER CODE BEGIN TIM4_MspDeInit 1 */

  /* USER CODE END TIM4_MspDeInit 1 */
  }
}

/* USER CODE BEGIN 1 */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	if(htim->Instance==TIM4)
	{
		HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_3);  //當(dāng)按鍵按下以后,每過1s鐘,PA3上的LED燈就翻轉(zhuǎn)一次
		tim_value+=10000;  //按鍵按下后,當(dāng)?shù)竭_溢出以后,tim_value的值就加上ARR設(shè)置的值,ARR設(shè)置的值為10000
	}
}


void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)  //輸入捕獲中斷的回調(diào)函數(shù)
{
	if(htim->Instance==TIM4)  //檢查是否為TIM4觸發(fā)的中斷
	{
		if(toggle_flag==0) //檢查標(biāo)志位
		{
			HAL_Delay(20); //消抖
			if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_6)==GPIO_PIN_RESET)
			{
				toggle_flag=1;  //進入中斷后首先翻轉(zhuǎn)標(biāo)志位
				HAL_GPIO_WritePin(GPIOA,GPIO_PIN_2,GPIO_PIN_SET); //PA2的LED燈亮200ms,顯示進入輸入捕獲函數(shù)
				HAL_Delay(200);
				HAL_GPIO_WritePin(GPIOA,GPIO_PIN_2,GPIO_PIN_RESET);
				HAL_TIM_Base_Start_IT(htim); //開啟溢出中斷,開始進行計時
				
				__HAL_TIM_DISABLE(htim);  //關(guān)閉TIM4
				
				__HAL_TIM_SET_COUNTER(htim,0); //設(shè)置時鐘計數(shù)值為0
				TIM_RESET_CAPTUREPOLARITY(htim,TIM_CHANNEL_1);  //清除TIM4通道1的原始設(shè)置
				TIM_SET_CAPTUREPOLARITY(htim,TIM_CHANNEL_1,TIM_INPUTCHANNELPOLARITY_RISING);//將觸發(fā)輸入捕獲中斷源設(shè)置為上升沿捕獲
				
				__HAL_TIM_ENABLE(htim);//使能TIM4
			} 
		}
		else if(toggle_flag==1)//檢查標(biāo)志位
		{
			HAL_Delay(20);//消抖
			if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_6)==GPIO_PIN_SET)//檢查是否為上升沿
			{
				toggle_flag=0; 
				HAL_TIM_Base_Stop_IT(htim);//關(guān)閉溢出中斷
				HAL_GPIO_WritePin(GPIOA,GPIO_PIN_2,GPIO_PIN_SET);//若是上升沿觸發(fā)輸入捕獲中斷,LED燈亮200ms
				HAL_Delay(200);
				HAL_GPIO_WritePin(GPIOA,GPIO_PIN_2,GPIO_PIN_RESET);
				
				tim_value=(tim_value+HAL_TIM_ReadCapturedValue(&htim4,TIM_CHANNEL_1 ))/10+20;//計算捕獲的總時間
				
				HAL_GPIO_WritePin(GPIOA,GPIO_PIN_2,GPIO_PIN_SET); //計算出總時間后,使得PA2口的LED燈亮的時間和總時間相同,以顯示輸入捕獲效果
				HAL_Delay(tim_value);
				HAL_GPIO_WritePin(GPIOA,GPIO_PIN_2,GPIO_PIN_RESET);
				
				__HAL_TIM_DISABLE(htim);
				
				TIM_RESET_CAPTUREPOLARITY(htim,TIM_CHANNEL_1);
				TIM_SET_CAPTUREPOLARITY(htim,TIM_CHANNEL_1,TIM_INPUTCHANNELPOLARITY_FALLING);
				
				__HAL_TIM_ENABLE(htim);
			}
		}
	}
}


/* USER CODE END 1 */

以上就是定時器(上)的相關(guān)內(nèi)容,我們了解了定時器的相關(guān)結(jié)構(gòu)、定時器的工作原理、定時器中斷實驗和輸入捕獲實驗,歡迎各位大佬進行批評指正!文章來源地址http://www.zghlxwxcb.cn/news/detail-775430.html

到了這里,關(guān)于手把手教你開發(fā)stm32——定時器(上)(基于hal庫)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

  • 手把手教你編寫跑馬燈——STM32

    手把手教你編寫跑馬燈——STM32

    新建一個文件夾 ,打開KeiL,projiece-----new vision projection ?給文件命名(隨便?。??根據(jù)自己開發(fā)板的信號選擇對應(yīng)的型號 ?在剛才創(chuàng)建的文件夾里面 新建一個main.c文件 ?雙擊source group 1,點擊main.c,點擊add ?添加頭文件 led.c main.c led就可以全亮然后全滅一直循環(huán)

    2024年02月08日
    瀏覽(102)
  • 手把手教你寫stm32f103智能風(fēng)扇

    手把手教你寫stm32f103智能風(fēng)扇

    本系統(tǒng)可以分為兩個模式來進行運行,分別為手動模式和自動模式,同時,在上電進入系統(tǒng)后,還會有一個模式選擇的界面產(chǎn)生。 模式選擇:在此界面中,可以通過按鍵K1來控制模式選擇,兩個模式分別為手動模式和自動模式;通過按鍵K2可以進入模式。 手動模式:在手動模

    2023年04月17日
    瀏覽(93)
  • 動手實踐丨手把手教你用STM32做一個智能魚缸

    動手實踐丨手把手教你用STM32做一個智能魚缸

    摘要: 本文基于STM32單片機設(shè)計了一款基于物聯(lián)網(wǎng)的智能魚缸。 本文分享自華為云社區(qū)《基于STM32+華為云IOT設(shè)計的物聯(lián)網(wǎng)魚缸【玩轉(zhuǎn)華為云】》,作者: DS小龍哥 。 為了緩解學(xué)習(xí)、生活、工作帶來的壓力,提升生活品質(zhì),許多人喜歡在家中、辦公室等場所養(yǎng)魚。為節(jié)省魚友

    2024年01月16日
    瀏覽(29)
  • FPGA之手把手教你寫串口協(xié)議解析(STM32與FPGA數(shù)據(jù)互傳)

    最近趁熱打鐵做了一個關(guān)于STM32與FPGA通信并且控制高速DA模塊產(chǎn)生不同頻率信號的正弦波、方波、三角波和鋸齒波的項目,從中收獲到了很多東西,也踩了一些雷和坑,將分為幾篇文章將整個過程分享出來。 這一次準(zhǔn)備分享的是對串口數(shù)據(jù)的解析和賦值。解析的數(shù)據(jù)由STM32發(fā)

    2024年02月06日
    瀏覽(28)
  • 手把手教你,通過HAL庫實現(xiàn)STM32的超聲波測距--以SR-04為例

    手把手教你,通過HAL庫實現(xiàn)STM32的超聲波測距--以SR-04為例

    目錄 0、SR-04基本原理 1、準(zhǔn)備工作 2、連線 ?3、STM32CUBEMX設(shè)置 3.1新建工程 3.2芯片通用設(shè)置 3.3定時器捕獲設(shè)置 ?3.4其他設(shè)置 3.5生成工程 ?4、程序完善 4.1完善打印輸出函數(shù) ?4.2完善tim.c 4.3完善gpio.c? 4.4完善main函數(shù)? ?5、總結(jié) 聲波遇到障礙物會反射,而聲波的速度已知,所以

    2024年02月14日
    瀏覽(24)
  • 手把手教你使用USB的CDC+MSC復(fù)合設(shè)備(基于stm32f407)

    手把手教你使用USB的CDC+MSC復(fù)合設(shè)備(基于stm32f407)

    ??最近對usb有點興趣,感覺挺好玩的,于是買了本圈圈大神的經(jīng)典著作-圈圈教你玩USB,里面使用51單片機+usb芯片對usb的基本知識潺潺道來,做了十個左右的常用案例實驗,很有趣,建議大家看看。 ??趁熱打鐵,拿身邊的開發(fā)板來練練手,探索一下復(fù)合設(shè)備的好玩方便的

    2024年02月13日
    瀏覽(99)
  • 基于STM32F103RCT6之手把手教你寫智能家居項目(2)

    基于STM32F103RCT6之手把手教你寫智能家居項目(2)

    ??????? 上一節(jié)我們簡述了智能家居項目,實現(xiàn)了點燈的相關(guān)代碼編寫,還有WIFI模塊的固件燒錄。 連接什么平臺: ??????? 我們想要遠程控制家具的開關(guān)和獲取家中的狀態(tài),少不了一個可以傳輸數(shù)據(jù)的云平臺。我認為易監(jiān)控是一個簡單好用的云平臺。 怎么連接平臺:

    2024年02月20日
    瀏覽(909)
  • STM32系列——手把手教你將SYN6288語音播報模塊的標(biāo)準(zhǔn)庫程序轉(zhuǎn)為hal庫使用

    STM32系列——手把手教你將SYN6288語音播報模塊的標(biāo)準(zhǔn)庫程序轉(zhuǎn)為hal庫使用

    目錄 前言 1. 原理 2. Cubmx配置 3. keil5編寫代碼 3.1 main.c 3.2 syn6288.c 3.3 syn6288.h 本教程基于 stm32f103c8t6 最小系統(tǒng)板, hal庫 開發(fā)。 操作簡單,講解直接清楚,旨在讓大家少走彎路。 SYN6288就是用到一個串口資源即可,用STM32開發(fā)起來不難。 配置串口3為異步通信模式?,注意波特率

    2024年02月07日
    瀏覽(139)
  • STM32系列——手把手教你藍牙模塊HC05、HC06的使用,重在“用起來”(HAL庫)

    STM32系列——手把手教你藍牙模塊HC05、HC06的使用,重在“用起來”(HAL庫)

    不論是HC05還是HC06,我們用到的都是藍牙模塊的透傳功能,只需要用到4個引腳:RXD、TXD、VCC(5V)、GND。 1、HC-05有6個引腳,但是我們只用到4個。 2、HC-05正面有一個按鍵。與HC-06的區(qū)別是, 它上電之前必須要按住此按鍵再插入電腦中,才能夠進入AT模式 。HC-06沒有按鍵,直接

    2024年02月05日
    瀏覽(100)
  • FPGA之手把手教你做多路信號發(fā)生器(STM32與FPGA數(shù)據(jù)互傳控制波形生成)

    FPGA之手把手教你做多路信號發(fā)生器(STM32與FPGA數(shù)據(jù)互傳控制波形生成)

    最近趁熱打鐵做了一個關(guān)于STM32與FPGA通信并且控制高速DA模塊產(chǎn)生不同頻率信號的正弦波、方波、三角波和鋸齒波的項目,從中收獲到了很多東西,也踩了一些雷和坑,將分為幾篇文章將整個過程分享出來。 這一次準(zhǔn)備分享的是將串口解析的出來的波形頻率數(shù)據(jù)以及波形類型

    2024年02月15日
    瀏覽(100)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包