定時器的介紹
介紹:STM32F103C8T6微控制器內部集成了多種類型的定時器,這些定時器在嵌入式系統中扮演著重要角色,用于計時、延時、事件觸發以及PWM波形生成、脈沖捕獲等應用。
*幾種定時器(STM32F103系列):
高級定時器(1) | 通用定時器(3) | 看門口(2) | 滴答定時器(1) |
TIM1:
| TIM2、TIM3和TIM4:
| 2 個看門狗定時器 ( 獨立的和窗口型的 ) | 系統時間定時器: 24 位自減型計數器 |
定時器的工作原理
定時器的核心:計數器
????????每個定時器都由一個16位計數器、預分頻器和自動重裝寄存器的時基單元組成。預分頻器可以對時鐘進行分頻,計數器則對預分頻后的時鐘進行計數。當計數器的值達到設定值時,會觸發中斷,從而執行相應的定時任務。
?注意事項:設置預分頻器系數(PSC)和自動重裝值(ARR)
- 代碼PSC寫?0,實際:分頻系數是1(不分頻);PSC寫1,分頻系數是2(2分頻);
- 代碼ARR寫65536-1,實際是2^16 = 65536。
?三種定時器的介紹
類型 | 編號 | 總線 | 功能 |
高級定時器(本章先不介紹) | TIM1、TIM8 | APB2 | 擁有通用定時器全部功能,并額外具有重復計數器、死區生 成、互補輸出、剎車輸入(三項無刷電機的特供:foc)等功能;-------三種計數模式。 |
通用定時器 | TIM2、TIM3、TIM4、TIM5 | APB1 | 擁有基本定時器全部功能,并額外具有 內外時鐘源選擇 、 輸入捕獲、輸出比較 、 PWM 或 脈沖計數的通道 、 編碼器接口、主從觸發模式等功能;------三種計數模式。 |
基本定時器(這個芯沒有) | TIM6、TIM7 | APB1 | (時基)擁有定時中斷、主模式觸發 DAC(繞過CPU) 的功能。------只支持向上計數。 |
- ?定時器都是72MHz
定時器的框圖
(參考手冊中)
- ?基本定時器
- ?通用定時器
- 簡圖:
- ?高級定時器:
- ?通用定時器時鐘的來源
簡圖:
框圖:?
?定時器的計數模式
計數模式 | 計數器溢出值 | 計數器重裝值 |
向上計數 | CNT = ARR | CNT = 0 |
向下計數 | CNT = 0 | CNT = ARR |
中心對齊計數 | CNT = ARR - 1 CNT = 1 | CNT = ARR CNT = 0 |
定時器溢出時間?
?說明:
Tout:定時器溢出時間;Ft:定時器的時鐘源頻率;
ARR:自動重裝載寄存器的值;PSC:預分頻器寄存器的值。
舉例:要定時500ms,PSC、ARR、Ft的值是多少??
答:PSC = 7199,ARR = 4999,Ft = 72M。
(當頻率大時,記一個數的時間短,ARR的值會變大;當頻率小時,記一個數的時間短,ARR的值小)。
定時器寄存器
時基單元寄存器
- 預分頻寄存器( TIMx_PSC)-16位
- 自動重裝載寄存器( TIMx_ARR)-16位
- DMA/中斷使能寄存器 (TIMx_DIER)
?第 0 位, 該位是更新中斷允許位, 當定時器的更新中斷,該位要設置為 1,來允許由于更新事件所產生的中斷。?
- ?狀態寄存器( TIMx_SR)
該寄存器用來標記當前與定時器相關的各種事件/中斷是否發生。?
?輸入捕獲/輸出比較寄存器
- 捕獲/比較寄存器( TIMx_CCR1~4)
????????該寄存器用來存儲捕獲發生時, TIMx_CNT的值,我們從 TIMx_CCR1 就可以讀出通道 1 捕獲發生時刻的 TIMx_CNT 值,通過兩次捕獲(一次上升沿捕獲,一次下降沿捕獲)的差值,就可以計算出高電平脈沖的寬度。?
捕獲/比較模式寄存器( TIMx_CCMRx)
- TIMx_CCMR1(模式寄存器1):控制通道1和通道2
TIMx_CCMR1 是針對 2 個通道的配置,低八位[7:0]用于捕獲 / 比較通道 1 的控制,而高八位[15:8]則用于捕獲 / 比較通道 2 的控制。?
- ?TIMx_CCMR2(模式寄存器2):控制通道3和通道4
四個通道的模式寄存器一樣,重點介紹 TIMx_CMMR1 的[7:0]位:
輸入捕獲
輸出比較?
捕獲/比較使能寄存器( TIMx_CCER)
- ?TIMx_CCER(捕獲/比較使能寄存器)
?定時器中斷實驗配置步驟
定時器中斷的函數?
中斷服務公共函數?
更新中斷的回調函數
其他中斷回調函數
設置PSC值的函數:?
設置/讀取 ARR值的函數 :
小實驗:定時器中斷點燈?
實驗目的:使用定時器TIM2進行中斷點燈,500msLED燈翻轉一次。
硬件清單:上官二號、ST-Link。
- timer.c文件代碼
#include "timer.h"
#include "led.h"TIM_HandleTypeDef time_hander = {0}; //定義一個全局結構體變量,結構體成員附一個默認值0。//時基單元初始化函數和中斷公共回調函數中使用。
//定時器的時基單元初始化函數
void timer_base_init(uint16_t psc ,uint16_t arr){time_hander.Instance = TIM2;time_hander.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; //設置的是影子寄存器,是否自動重裝載。time_hander.Init.CounterMode = TIM_COUNTERMODE_UP;time_hander.Init.Prescaler = psc;time_hander.Init.Period = arr;HAL_TIM_Base_Init(&time_hander);HAL_TIM_Base_Start_IT(&time_hander); //打開時鐘和使能中斷}
//msp函數:初始化MCU相關的硬件,例如:GPIO,NVIC,CLOCK
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim){ //這個函數在HAL_TIM_Base_Init()中調用if(htim->Instance == TIM2){ //先判斷這個是不是TIM2定時器占用。__HAL_RCC_TIM2_CLK_ENABLE();HAL_NVIC_SetPriority(TIM2_IRQn,2,2);HAL_NVIC_EnableIRQ(TIM2_IRQn);}
}
//中斷服務函數
void TIM2_IRQHandler(void){//中斷公共處理的函數HAL_TIM_IRQHandler(&time_hander);
}
//更新中斷回調函數
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){ //據餅if(htim->Instance == TIM2){ //判斷這個回調函數是否被其他定時器占用。led1_toggle();}
}
- time.h文件代碼:
#ifndef __TIMER_H__
#define __TIMER_H__#include "stm32f1xx.h"void timer_base_init(uint16_t psc ,uint16_t arr);#endif
- main.c文件代碼?
#include "sys.h"
#include "led.h"
#include "delay.h"
#include "timer.h"int main(void)
{HAL_Init(); /* 初始化HAL庫 */stm32_clock_init(RCC_PLL_MUL9); /* 設置時鐘, 72Mhz */led_init(); /* LED初始化 */timer_base_init(7200-1,5000-1); //500ms產生一次中斷while(1){ }
}
?輸出比較
?簡介
輸出比較可以通過比較定時計數器的值 CNT 與設定的比較值 CCR,可以控制輸出引腳的電平狀態(置高或置低),從而實現生成一定頻率和占空比的 PWM 波形。
簡圖:?
框圖(參考手冊) :
PWM模式:?
PWM介紹?
定義:PWM波形(Pulse Width Modulation,脈沖寬度調制波形)是一種占空比可變的脈沖波形。這種調制方式通過改變脈沖的寬度來控制電路中的信號強度和頻率。具體來說,PWM波形中的高電平持續時間和低電平持續時間可以根據需要進行調整,從而實現對模擬信號電平的數字編碼。
應用:PWM波形在各種領域都有廣泛的應用,包括電源管理、電機控制、LED亮度調節等。此外,生成PWM波形的方法有多種,例如使用波形發生器、單片機或可編程邏輯器件等。
相關參數:?
頻率:1/Ts(定時器計數溢出的時間);
占空比:Ton / Ts(高電平占整個周期的比例,單位%);
分辨率:占空比變化步距。例:占空比50%,51%;分辨率:1%。分辨率越低對硬件的要求越高。
PWM相關的函數
宏函數:?修改CRR寄存器的值
輸出比較的引腳?
- ?TIM1_CHx(x:1、2、3、4)
- TIM2_CHx(x:1、2、3、4)?
- TIM3_CHx(x:1、2、3、4)?
- TIM4_CHx(x:1、2、3、4)?
定時器輸出PWM波配置步驟?
根據上面簡圖配置:?
小實驗:呼吸燈實驗
實驗目的:使用?定時器4?通道3(看引腳定義表:PB8引腳)生成 PWM 波控制 LED1?,實現呼吸燈效果。
- 頻率:2kHz。根據定時器溢出時間計算:PSC=71,ARR=499。
硬件清單:開發板、ST-Link。
- ?pwm.c文件代碼
#include "pwm.h"TIM_HandleTypeDef pwm_handle = {0};
void pwm_init(uint16_t psc,uint16_t arr){pwm_handle.Instance = TIM4;pwm_handle.Init.CounterMode = TIM_COUNTERMODE_UP;pwm_handle.Init.Period = arr;pwm_handle.Init.Prescaler = psc;pwm_handle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;HAL_TIM_PWM_Init(&pwm_handle);//pwm模式和crr寄存器設置TIM_OC_InitTypeDef tim_oc_initstruct = {0};tim_oc_initstruct.OCMode = TIM_OCMODE_PWM1; //pwm的模式tim_oc_initstruct.OCPolarity = TIM_OCPOLARITY_LOW; //高電平有效還是低電平;led燈是低電平點亮,故低電平有效tim_oc_initstruct.Pulse = arr/2; //占空比CCR的值,這里隨便填,后面crr修改函數HAL_TIM_PWM_ConfigChannel(&pwm_handle,&tim_oc_initstruct,TIM_CHANNEL_3);//使能輸出,啟動計時器HAL_TIM_PWM_Start(&pwm_handle,TIM_CHANNEL_3);
}
//初始化msp函數
void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim){if(htim ->Instance == TIM4){ //判斷這個函數是否被定時器4占用__HAL_RCC_TIM4_CLK_ENABLE(); //打開定時器4的時鐘__HAL_RCC_GPIOB_CLK_ENABLE(); //打開GPIO口的時鐘GPIO_InitTypeDef gpio_initstruct;gpio_initstruct.Mode = GPIO_MODE_AF_PP; //復用推挽輸出,看GPIO口定義表gpio_initstruct.Pin = GPIO_PIN_8;gpio_initstruct.Pull = GPIO_PULLUP;gpio_initstruct.Speed = GPIO_SPEED_FREQ_HIGH;HAL_GPIO_Init(GPIOB,&gpio_initstruct);}
}
//修改crr的值的函數
void pwm_cmpare_set(uint16_t value){__HAL_TIM_SET_COMPARE(&pwm_handle,TIM_CHANNEL_3,value);
}
- pwm.h文件代碼
#ifndef __PWM_H__
#define __PWM_H__
#include "stm32f1xx.h"void pwm_init(uint16_t psc,uint16_t arr);
void pwm_cmpare_set(uint16_t value);#endif
main.c文件代碼
#include "sys.h"
#include "led.h"
#include "delay.h"
#include "pwm.h"int main(void)
{HAL_Init(); /* 初始化HAL庫 */stm32_clock_init(RCC_PLL_MUL9); /* 設置時鐘, 72Mhz */led_init(); /* LED初始化 */pwm_init(72-1,500-1);//在while函數中不停的修改CRR的值,來實現占空比不斷改變while(1){ for(uint16_t i = 0;i<300;i++){pwm_cmpare_set(i);delay_ms(5);}for(uint16_t i = 0;i<300;i++){pwm_cmpare_set(300-i);delay_ms(5);}}
}
寫這個代碼遇到的問題:
- 調用函數時要注意:DeInit函數和init函數。
- 根據引腳定義表,輸出比較口對應哪一個GPIO口。
- 關于外設GPIO口的配置:(參考手冊110)
?輸入捕獲
簡介?
????????輸入捕獲模式可以用來?測量脈沖寬度 或者 測量頻率。STM32 的定時器,除了 TIM6 和 TIM7,其他定時器都有輸入捕獲功能。 STM32 的輸入捕獲,簡單的說就是通過檢測 TIMx_CHx 上的邊沿信號,在邊沿信號發生跳變(比如上升沿/下降沿)的時候,將當前定時器的值(TIMx_CNT)存放到對應的通道的捕獲/比較寄存器(TIMx_CCRx)里面,完成一次捕獲。同時還可以配置捕獲時是否觸發中斷/DMA 等。
框圖:(參考手冊253)?
輸入捕獲引腳
- 和上面輸出比較的引腳相同,參考上面輸出比較引腳
輸入捕獲相關函數?
在輸入捕獲的時基單元里的定時器的使能更新中斷的函數:?
捕獲回調函數:?
讀取輸入捕獲中CCR的值:
清除/設置 捕獲的通道極性:
?關閉定時器:
設置計數器的值?:
獲取計數器的值:
定時器輸入捕獲實驗步驟配置?
?小實驗:測量按鍵按下的時長(測量脈沖寬度)
實驗目的:使用定時器 2 通道 2 (PA1)來捕獲 按鍵 2 (PA1)按下時間,并通過串口打印。
- 計一個數的時間:1us,PSC=71,ARR=65535
- 下降沿捕獲、輸入通道 2 映射在 TI2 上、不分頻、不濾波。
硬件清單:開發板、ST-Link、USB轉TTL
思路:
輸入捕獲回調函數中的流程圖:?
拓展:串口打印功能
- 利用串口調試助手:
- ?引腳接線:
USB轉TTL | 開發板(型號不同,引腳不同) |
TXD | RX1(PA10) |
RXD | TX1(PA9) |
GND | GND |
- ?相關代碼和配置:
注意事項:
- 代碼中的波特率要和串口助手中的波特率設置的相同,例如:9600 或 115200;
- 上述代碼中設置錯了!!!?
實驗1:捕獲一次下降沿
- ic.c代碼文件
#include "ic.h"
#include "stdio.h"TIM_HandleTypeDef ic_handle = {0};
//初始化時基單元
void ic_init(uint16_t psc,uint16_t arr){ic_handle.Instance = TIM2;ic_handle.Init.Period = arr;ic_handle.Init.Prescaler = psc;ic_handle.Init.CounterMode = TIM_COUNTERMODE_UP;HAL_TIM_IC_Init(&ic_handle);//輸入通道的配置TIM_IC_InitTypeDef ic_initstruct = {0};ic_initstruct.ICFilter = 0; //濾波ic_initstruct.ICPolarity = TIM_ICPOLARITY_FALLING; //輸入極性的判斷ic_initstruct.ICPrescaler = TIM_ICPSC_DIV1; //分頻系數:這里不分頻ic_initstruct.ICSelection = TIM_ICSELECTION_DIRECTTI; //輸入通道選擇,還有TRC輸入口HAL_TIM_IC_ConfigChannel(&ic_handle,&ic_initstruct,TIM_CHANNEL_2);//打開計數器,是能更新中斷,輸入捕獲中斷__HAL_TIM_ENABLE_IT(&ic_handle,TIM_IT_UPDATE);HAL_TIM_IC_Start_IT(&ic_handle,TIM_CHANNEL_2);
}//初始化msp函數
void HAL_TIM_IC_MspInit(TIM_HandleTypeDef *htim){if(htim->Instance == TIM2){//打開時鐘__HAL_RCC_TIM2_CLK_ENABLE();__HAL_RCC_GPIOA_CLK_ENABLE();//初始化GPIO口GPIO_InitTypeDef gpio_initstruct;gpio_initstruct.Mode = GPIO_MODE_INPUT;gpio_initstruct.Pin = GPIO_PIN_1;gpio_initstruct.Pull = GPIO_PULLUP;gpio_initstruct.Speed = GPIO_SPEED_FREQ_HIGH;HAL_GPIO_Init(GPIOA,&gpio_initstruct);//初始化NVICHAL_NVIC_SetPriority(TIM2_IRQn,2,2);HAL_NVIC_EnableIRQ(TIM2_IRQn);}
}//中斷服務函數
void TIM2_IRQHandler(void){HAL_TIM_IRQHandler(&ic_handle);
}
//捕獲中斷的回調函數
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim){ printf("下降沿觸發\n");
}
- ic.h文件代碼
#ifndef __IC_H__
#define __IC_H__
#include "stm32f1xx.h"void ic_init(uint16_t psc,uint16_t arr);#endif
- main.c文件代碼
#include "sys.h"
#include "led.h"
#include "delay.h"
#include "uart1.h"
#include "ic.h"int main(void)
{HAL_Init(); /* 初始化HAL庫 */stm32_clock_init(RCC_PLL_MUL9); /* 設置時鐘, 72Mhz */led_init(); /* LED初始化 */uart1_init(115200); //初始化串口。設置波特率115200printf("hello,world!!!\n"); //打印到串口助手ic_init(72-1,65536-1); //設置中斷溢出時長while(1){ led1_on();led2_off();delay_ms(500);led1_off();led2_on();delay_ms(500);}
}
實驗2:捕獲一次完整的按鍵,并打印出按鍵按下的時長
- ic.h文件代碼
- 根據上面流程圖,寫捕獲中斷的回調函數?
#include "ic.h"
#include "stdio.h"
#include "string.h"struct {uint8_t falling_flag;uint8_t success_flag;uint16_t timeout_cnt;
}capture_status = {0};uint16_t time_cnt = 0;TIM_HandleTypeDef ic_handle = {0};
//初始化時基單元
void ic_init(uint16_t psc,uint16_t arr){ic_handle.Instance = TIM2;ic_handle.Init.Period = arr;ic_handle.Init.Prescaler = psc;ic_handle.Init.CounterMode = TIM_COUNTERMODE_UP;HAL_TIM_IC_Init(&ic_handle);//輸入通道的配置TIM_IC_InitTypeDef ic_initstruct = {0};ic_initstruct.ICFilter = 0; //濾波ic_initstruct.ICPolarity = TIM_ICPOLARITY_FALLING; //輸入極性的判斷ic_initstruct.ICPrescaler = TIM_ICPSC_DIV1; //分頻系數:這里不分頻ic_initstruct.ICSelection = TIM_ICSELECTION_DIRECTTI; //輸入通道選擇,還有TRC輸入口HAL_TIM_IC_ConfigChannel(&ic_handle,&ic_initstruct,TIM_CHANNEL_2);//打開計數器,是能更新中斷,輸入捕獲中斷__HAL_TIM_ENABLE_IT(&ic_handle,TIM_IT_UPDATE); //使能更新中斷HAL_TIM_IC_Start_IT(&ic_handle,TIM_CHANNEL_2); //打開計時器,并使能捕獲中斷
}//初始化msp函數
void HAL_TIM_IC_MspInit(TIM_HandleTypeDef *htim){if(htim->Instance == TIM2){//打開時鐘__HAL_RCC_TIM2_CLK_ENABLE();__HAL_RCC_GPIOA_CLK_ENABLE();//初始化GPIO口GPIO_InitTypeDef gpio_initstruct;gpio_initstruct.Mode = GPIO_MODE_INPUT;gpio_initstruct.Pin = GPIO_PIN_1;gpio_initstruct.Pull = GPIO_PULLUP;gpio_initstruct.Speed = GPIO_SPEED_FREQ_HIGH;HAL_GPIO_Init(GPIOA,&gpio_initstruct);//初始化NVICHAL_NVIC_SetPriority(TIM2_IRQn,2,2);HAL_NVIC_EnableIRQ(TIM2_IRQn);}
}//中斷服務函數
void TIM2_IRQHandler(void){HAL_TIM_IRQHandler(&ic_handle);
}
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim){
// printf("下降沿觸發\n");if(capture_status.success_flag == 0){if(capture_status.falling_flag == 1){printf("上升沿捕獲\n");capture_status.success_flag =1;time_cnt = HAL_TIM_ReadCapturedValue(&ic_handle,TIM_CHANNEL_2);//獲取計數器的值TIM_RESET_CAPTUREPOLARITY(&ic_handle,TIM_CHANNEL_2); //清除捕獲通道TIM_SET_CAPTUREPOLARITY(&ic_handle,TIM_CHANNEL_2,TIM_ICPOLARITY_FALLING); //設置為下降沿捕獲}else{printf("下降沿捕獲\n");capture_status.falling_flag = 1;capture_status.timeout_cnt = 0;__HAL_TIM_DISABLE(&ic_handle);__HAL_TIM_SetCounter(&ic_handle,0); //計數器的值清零TIM_RESET_CAPTUREPOLARITY(&ic_handle,TIM_CHANNEL_2); //清除通道設置TIM_SET_CAPTUREPOLARITY(&ic_handle,TIM_CHANNEL_2,TIM_ICPOLARITY_RISING); //設置為上升沿捕獲__HAL_TIM_ENABLE(&ic_handle);}}
}
//定時器定時中斷的回調函數
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){if(htim ->Instance == TIM2){//判斷是否完成按鍵if(capture_status.falling_flag == 1) //判斷是否捕獲到下降沿capture_status.timeout_cnt ++; }
}//定義一個函數,打印按鍵按下的時間
void pressed_time_get(void){if(capture_status.success_flag == 1){printf("按下時間:%lf s \n",((double)capture_status.timeout_cnt*65536+time_cnt)/1000000);memset(&capture_status,0,sizeof(capture_status));}}
- ?ic.h文件代碼
#ifndef __IC_H__
#define __IC_H__
#include "stm32f1xx.h"void ic_init(uint16_t psc,uint16_t arr);
void pressed_time_get(void);
#endif
- main.c文件代碼
#include "sys.h"
#include "led.h"
#include "delay.h"
#include "uart1.h"
#include "ic.h"int main(void)
{HAL_Init(); /* 初始化HAL庫 */stm32_clock_init(RCC_PLL_MUL9); /* 設置時鐘, 72Mhz */led_init(); /* LED初始化 */uart1_init(115200);printf("hello,world!!!\n");ic_init(72-1,65536-1);while(1){ pressed_time_get();}
}
要解決的問題:
- 結構體中聲明多個標志位。
- 用到的函數。
- 為什么要寫到while函數中。?
?脈沖計數
簡介
脈沖計數相關的函數
初始化函數?
打開捕獲定時器?
定時器從模式的配置:通道、濾波、邊沿捕獲、映射?
?獲取CNT的值
?脈沖計數實驗步驟配置
?根據上面的框圖:
小實驗:脈沖計數實驗?(測量頻率)
實驗目的:將定時器 2 通道 2 輸入(PA1)的低電平脈沖(按下按鍵2 PA1)作為定時器 2 的時鐘,并通過串口打印脈沖數。
- PSC=1-1,ARR=65536-1
- 外部時鐘模式1、觸發選擇:下降沿觸發、不分頻、不濾波
實驗清單:開發板、ST-Link、USB轉TTL
實驗思路:
- 初始化時基單元;
- 配置輸入通道,從模式:時鐘模式1;
- msp函數初始化GPIO口、CLOCK、NVIC;
- 打開計數器;
- 獲取計數器的值并進行打印。
- counter.c文件代碼
#include "counter.h"
#include "stdio.h"TIM_HandleTypeDef counter_handle = {0};void counter_init(uint16_t psc,uint16_t arr){//初始化時基單元counter_handle.Instance = TIM2;counter_handle.Init.Prescaler = psc;counter_handle.Init.Period = arr;counter_handle.Init.CounterMode = TIM_COUNTERMODE_UP;counter_handle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;HAL_TIM_IC_Init(&counter_handle);//配置輸入通道(從模式)TIM_SlaveConfigTypeDef counter_initstruct;counter_initstruct.TriggerFilter = 0; //濾波器counter_initstruct.TriggerPolarity = TIM_TRIGGERPOLARITY_FALLING; //極性的選擇:上升沿或下降沿counter_initstruct.SlaveMode = TIM_SLAVEMODE_EXTERNAL1; //從模式的選擇counter_initstruct.InputTrigger = TIM_TS_TI2FP2; //輸入的通道。counter_initstruct.TriggerPrescaler = TIM_TRIGGERPRESCALER_DIV1; //分頻:這里用不到HAL_TIM_SlaveConfigSynchro(&counter_handle,&counter_initstruct);//使能中斷和打開時鐘HAL_TIM_IC_Start(&counter_handle,TIM_CHANNEL_2);
}//msp配置mcu外設
void HAL_TIM_IC_MspInit(TIM_HandleTypeDef *htim){ //這是個公用的函數,用的時候要進行判斷是否被占用if(htim->Instance == TIM2){//打開時鐘__HAL_RCC_TIM2_CLK_ENABLE();__HAL_RCC_GPIOA_CLK_ENABLE();//初始化GPIO口GPIO_InitTypeDef gpio_initstruct;gpio_initstruct.Pin = GPIO_PIN_1;gpio_initstruct.Mode = GPIO_MODE_INPUT;gpio_initstruct.Pull = GPIO_NOPULL;gpio_initstruct.Speed = GPIO_SPEED_FREQ_HIGH;HAL_GPIO_Init(GPIOA,&gpio_initstruct);}
}//獲取計數器的值
uint16_t Ncounter_num = 0;
uint16_t Ocounter_num = 0;
void counter_get(void){Ncounter_num = __HAL_TIM_GetCounter(&counter_handle);
//避免在while循環中一直打印計數器的值,設置打印的條件:計數器的值是否發生變化。if(Ncounter_num != Ocounter_num){printf("計數器的值:%d\n",Ncounter_num);Ocounter_num = Ncounter_num;}
}
- counter.h文件代碼
#ifndef __COUNTER_H__
#define __COUNTER_H__#include "stm32f1xx.h"
void counter_init(uint16_t psc,uint16_t arr);
void counter_get(void);
#endif
- ?main.c文件代碼
#include "sys.h"
#include "led.h"
#include "delay.h"
#include "uart1.h"
#include "counter.h"int main(void)
{HAL_Init(); /* 初始化HAL庫 */stm32_clock_init(RCC_PLL_MUL9); /* 設置時鐘, 72Mhz */led_init(); /* LED初始化 */uart1_init(115200);printf("hello,world!!!\n");counter_init(1-1,65536-1);while(1){ counter_get();}
}
- 結果:
遇到的問題和注意事項:
- main.c文件中的波特率要和串口助手的波特率相同。
- 在counter.c文件中聲明函數獲取計數器的值時,要進行條件編譯,不然會在主函數while循環中,一直打印。?(給打印函數一個條件)
- 要使能輸入和打開計數器。這個函數沒有捕獲中斷。