STM32的定時器

定時器的介紹

介紹:STM32F103C8T6微控制器內部集成了多種類型的定時器,這些定時器在嵌入式系統中扮演著重要角色,用于計時、延時、事件觸發以及PWM波形生成、脈沖捕獲等應用。

*幾種定時器(STM32F103系列):

7個定時器
高級定時器(1)通用定時器(3)看門口(2)滴答定時器(1)

TIM1:

  • 116位帶死區控制和緊急剎車,用于電機 控制的PWM高級控制定時器。
  • 不僅具備基本的定時中斷功能,還擁有內外時鐘源選擇、輸入捕獲、輸出比較、編碼器接口以及主從觸發模式等多種功能。

TIM2TIM3TIM4

  • 316位定時器,每個定時器有多達4個用于輸入捕獲/輸出比較/PWM或脈沖計數的通道和增量編碼器輸入。
  • 這些是通用定時器,同樣具有定時功能,但在功能上與高級定時器有所區別。
  • 用定時器通常用于實現一些基本的定時任務,如LED閃爍、脈沖寬度測量等。
2 個看門狗定時器 ( 獨立的和窗口型的 )
系統時間定時器: 24 位自減型計數器

定時器的工作原理

定時器的核心:計數器

????????每個定時器都由一個16位計數器預分頻器自動重裝寄存器時基單元組成。預分頻器可以對時鐘進行分頻,計數器則對預分頻后的時鐘進行計數。當計數器的值達到設定值時,會觸發中斷,從而執行相應的定時任務。

?注意事項:設置預分頻器系數(PSC)和自動重裝值(ARR)

  • 代碼PSC寫?0,實際:分頻系數是1(不分頻);PSC寫1,分頻系數是2(2分頻);
  • 代碼ARR寫65536-1,實際是2^16 = 65536。

?三種定時器的介紹

類型編號總線功能
高級定時器(本章先不介紹)TIM1、TIM8APB2
擁有通用定時器全部功能,并額外具有重復計數器、死區生
成、互補輸出、剎車輸入(三項無刷電機的特供:foc)等功能;-------三種計數模式。
通用定時器TIM2、TIM3、TIM4、TIM5APB1
擁有基本定時器全部功能,并額外具有 內外時鐘源選擇 輸入捕獲、輸出比較 PWM 或 脈沖計數的通道 編碼器接口、主從觸發模式等功能;------三種計數模式。
基本定時器(這個芯沒有)TIM6、TIM7APB1
(時基)擁有定時中斷、主模式觸發 DAC(繞過CPU) 的功能。------只支持向上計數。
  • ?定時器都是72MHz

定時器的框圖

(參考手冊中)

  • ?基本定時器

  • ?通用定時器

  • 簡圖:

  • ?高級定時器:

  • ?通用定時器時鐘的來源

簡圖:

框圖:?

?定時器的計數模式

計數模式計數器溢出值計數器重裝值
向上計數CNT = ARRCNT = 0
向下計數CNT = 0CNT = 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=71ARR=65535
  • 下降沿捕獲、輸入通道 2 映射在 TI2 、不分頻、不濾波。

硬件清單:開發板、ST-Link、USB轉TTL

思路:

輸入捕獲回調函數中的流程圖:?

拓展:串口打印功能

  • 利用串口調試助手:

  • ?引腳接線:
USB轉TTL開發板(型號不同,引腳不同)
TXDRX1(PA10)
RXDTX1(PA9)
GNDGND
  • ?相關代碼和配置:

注意事項:

  • 代碼中的波特率要和串口助手中的波特率設置的相同,例如: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-1ARR=65536-1
  • 外部時鐘模式1、觸發選擇:下降沿觸發、不分頻、不濾波

實驗清單:開發板、ST-Link、USB轉TTL

實驗思路:

  1. 初始化時基單元;
  2. 配置輸入通道,從模式:時鐘模式1;
  3. msp函數初始化GPIO口、CLOCK、NVIC;
  4. 打開計數器;
  5. 獲取計數器的值并進行打印。
  • 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循環中,一直打印。?(給打印函數一個條件)
  • 要使能輸入和打開計數器。這個函數沒有捕獲中斷。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/80256.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/80256.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/80256.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

算法中的數學:約數

1.求一個整數的所有約數 對于一個整數x&#xff0c;他的其中一個約數若為i&#xff0c;那么x/i也是x的一個約數。而其中一個約數的大小一定小于等于根號x&#xff08;完全平方數則兩個約數都為根號x&#xff09;&#xff0c;所以我們只需要遍歷到根號x&#xff0c;然后計算出另…

不同OS版本中的同一yum源yum list差異排查思路

問題描述&#xff1a; qemu-guest-agent二進制rpm包的yum倉庫源和yum源倉庫配置文件path_to_yum_conf&#xff0c; 通過yum list --available -c path_to_yum_conf 查詢時&#xff0c;不同的OS版本出現了不同的結果 anolis-8無法識別 centos8可以識別 說明&#xff1a; 1 測試…

如何使用極狐GitLab 軟件包倉庫功能托管 helm chart?

極狐GitLab 是 GitLab 在中國的發行版&#xff0c;關于中文參考文檔和資料有&#xff1a; 極狐GitLab 中文文檔極狐GitLab 中文論壇極狐GitLab 官網 軟件包庫中的 Helm charts (BASIC ALL) WARNING:Helm chart 庫正在開發中&#xff0c;由于功能有限&#xff0c;尚未準備好用…

【PostgreSQL數據分析實戰:從數據清洗到可視化全流程】3.1 數據質量評估指標(完整性/一致性/準確性)

&#x1f449; 點擊關注不迷路 &#x1f449; 點擊關注不迷路 &#x1f449; 點擊關注不迷路 文章大綱 數據質量評估核心指標&#xff1a;完整性、一致性、準確性實戰解析3.1 數據質量評估指標體系3.1.1 完整性&#xff1a;數據是否存在缺失1.1.1 核心定義與業務影響1.1.2 檢測…

詳解 FFMPEG 交叉編譯 `FLAGS` 和 `INCLUDES` 的作用

FLAGS 和 INCLUDES這兩行是 Android NDK 編譯時的編譯器選項&#xff0c;用于控制代碼生成、優化、調試、安全性和頭文件搜索路徑。下面逐項詳解&#xff1a; 1. FLAGS 詳解&#xff08;編譯器選項&#xff09; FLAGS 定義了傳遞給 C/C 編譯器&#xff08;如 clang 或 gcc&…

【RK3588嵌入式圖形編程】-Cairo-Cairo圖形庫支持后端

Cairo圖形庫支持后端 文章目錄 Cairo圖形庫支持后端1、PNG圖像后端2、PDF文件后端3、SVG文件后端4、GTK窗口支持Cairo庫支持多種后端。在本文中,我們使用Cairo創建PNG圖像、PDF文件、SVG文件,并在GTK窗口上繪制。 1、PNG圖像后端 在第一個示例中,我們創建一個 PNG 圖像。 …

【常用算法:排序篇】2.快速排序的算法精要

快速排序是算法領域的"九陽神功"&#xff0c;掌握其精髓能讓你在算法修煉之路上突破瓶頸。 1. 快速排序的核心思想 快速排序&#xff08;Quicksort&#xff09;是一種基于分治思想的高效排序算法&#xff0c;核心步驟為&#xff1a; 選擇基準值&#xff08;Pivot&…

在現代Web應用中集成 PDF.js (pdfjs-dist 5.2 ESM): 通過 jsdelivr 實現動態加載與批注功能的思考

PDF 文檔在現代 Web 應用中越來越常見&#xff0c;無論是作為文檔預覽、報告展示還是在線編輯的載體。Mozilla 的 PDF.js 是一個功能強大的 JavaScript 庫&#xff0c;它使得在瀏覽器端渲染和顯示 PDF 文件成為可能&#xff0c;無需依賴原生插件。 本文將深入探討如何在你的項…

基于FPGA控制ADC0832雙通道采樣+電壓電流采樣+LCD屏幕顯示

基于FPGA控制ADC0832雙通道采樣電壓電流采樣LCD屏幕顯示 前言一、芯片手冊閱讀1.SPI通信時序 二、仿真分析三、代碼分析總結視頻演示 前言 定制 要求使用ADC0832芯片進行ADC采樣。其中電壓采樣以及電流采樣是固定電路&#xff0c;是硬件設計&#xff0c;跟軟件沒沒關系。本質上…

生產部署方案pm2配合python3腳本

前言 使用python3來處理redis 消息隊列&#xff0c;記錄下生產部署方案 「生產部署方案」&#xff1a; 多進程&#xff08;動態擴容&#xff09;無限自愈日志自動壓縮系統級守護可多隊列多worker 終極穩健版&#xff1a;PM2 Logrotate 自動擴容 守護鏈 適合&#xff1a…

Python全流程開發實戰:基于IMAP協議安全下載個人Gmail郵箱內所有PDF附件

文章目錄 一、需求分析與安全前置&#xff1a;為什么需要專用工具&#xff1f;1.1 痛點場景1.2 技術方案選擇 二、準備工作&#xff1a;Gmail賬號安全配置與環境搭建2.1 開啟兩步驗證&#xff08;必做&#xff01;&#xff09;2.2 創建應用專用密碼&#xff08;替代普通密碼&am…

巧用python之--模仿PLC(PLC模擬器)

工作中用到了VM(VisionMaster4.3)有時候需要和PLC打交道,但是PLC畢竟是別人的,不方便修改別人的程序,這時候需要一個靈活的PLC模擬器是多么好呀! 先說背景: PLC型號 匯川Easy521: Modbus TCP 192.168.1.10:502 在匯川Easy521中Modbus保持寄存器D寄存器 ,在modbus協議中 0-4區…

docker構建鏡像并上傳dockerhub

docker構建鏡像并上傳dockerhub 前提條件&#xff1a;需要連接梯子 將梯子配置到虛擬機中&#xff08;確保主機能夠連接 hub.docker.com&#xff09; 使用ipconfig 查詢主機的 ip4地址虛擬機的連接模式改成橋接模式&#xff08;復制主機的地址網絡&#xff09;將ip4配置到虛擬…

python實現的音樂播放器

python實現的音樂播放器 音樂播放器,原來寫過一個簡陋的例子,可見 https://blog.csdn.net/cnds123/article/details/137874107 那個不能拖動播放進度條上的滑塊到新的位置播放。下面介紹的可以拖動播放進度條上的滑塊到新的位置播放。 簡單實用的音樂播放器 這個簡單實用的…

[網安工具] 端口信息收集工具 —— 御劍高速 TCP 全端口掃描工具 · 使用手冊

&#x1f31f;想了解其它網安工具&#xff1f;看看這個&#xff1a;[網安工具] 網絡安全工具管理 —— 工具倉庫 管理手冊 https://github.com/NepoloHebo/Yujian-high-speed-TCP-full-port-scannerhttps://github.com/NepoloHebo/Yujian-high-speed-TCP-full-port-scanner 0…

數字孿生賦能智慧城市:從概念到落地的深度實踐

在城市規模與復雜度持續攀升的當下&#xff0c;傳統管理模式已難以滿足現代城市精細化治理需求。數字孿生技術憑借構建虛擬城市鏡像、實現實時數據交互與智能決策的特性&#xff0c;成為智慧城市建設的核心引擎。本文將通過多個典型案例&#xff0c;深度解析數字孿生技術如何重…

DeFi開發系統軟件開發:技術架構與生態重構

DeFi開發系統軟件開發&#xff1a;技術架構與生態重構 ——2025年去中心化金融開發的范式革新與實踐指南 一、技術架構演進&#xff1a;從單一鏈到多鏈混合引擎 現代DeFi系統開發已從單一公鏈架構轉向“跨鏈互操作混合模式”&#xff0c;結合中心化效率與去中心化安全雙重優勢…

相同IP和端口的服務器ssh連接時出現異常

起因 把服務器上的一個虛擬機搞壞了&#xff0c;所以刪除重新創建了一個&#xff0c;端口號和IP與之前的虛擬機相同。 ssh usernameIP -p port 時報錯 WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY! Someone…

驗證es啟動成功

1. 查看命令行輸出信息 在啟動 Elasticsearch 時&#xff0c;命令行窗口會輸出一系列日志信息。若啟動成功&#xff0c;日志里通常會有類似下面的信息&#xff1a; plaintext [2025-05-06T13:20:00,000][INFO ][o.e.n.Node ] [node_name] started其中 [node_na…

CentOS網絡之network和NetworkManager深度解析

文章目錄 CentOS網絡之network和NetworkManager深度解析1. CentOS網絡服務發展歷史1.1 傳統network階段&#xff08;CentOS 5-6&#xff09;1.2 過渡期&#xff08;CentOS 7&#xff09;1.3 新時代&#xff08;CentOS 8&#xff09; 2. network和NetworkManager的核心區別3. ne…