【STM32】TIM定時器輸出比較

1?輸出比較

1.1?輸出比較簡介

  1. OC(Output Compare)輸出比較;IC(Input?Capture)輸入捕獲;CC(Capture/Compare)輸入捕獲和輸出比較的單元
  2. 輸出比較可以通過比較CNTCCR寄存器值(CCR捕獲/比較寄存器)的關系,來對輸出電平進行置1、置0或翻轉的操作,用于輸出一定頻率和占空比的PWM波形
  3. 每個高級定時器和通用定時器都擁有4個輸出比較通道
  4. 高級定時器的前3個通道額外擁有死區生成和互補輸出的功能

主要是用來輸出PWM波形的,PWM波形又是驅動電機的必要條件。

這個CCR是共用的,當使用輸入捕獲時,它就是捕獲寄存器;當使用輸出比較時,它就是比較寄存器。在輸出比較這里,這塊電路會比較CNT和CCR的值,CNT計數自增,CCR是我們給定的一個值,當CNT大于CCR、小于CCR、等于CCR時,輸出就會置1,置0,置1,置0,這樣就可以輸出一個電平不斷跳變的PWM波形了。

1.2?PWM簡介

PWM(Pulse Width Modulation)脈沖寬度調制

在具有慣性的系統中,可以通過對一系列脈沖的寬度進行調制,來等效地獲得所需要的模擬參量,常應用于電機控速等領域

PWM參數:

???? 頻率 = 1 / TS??????????? 占空比 = TON / TS?????????? 分辨率 = 占空比變化步距

1.3?輸出比較通道

通用定時器的輸出比較部分電路

對應的是

?最后通過TIMx_CH1輸出到GPIO引腳上。

左邊是CNT計數器和CCR1第一路的捕獲/比較寄存器;它倆比較,當CNT > CCR1?或者?CNT = CCR1時,就會給輸出模式控制器傳一個信號,然后輸出模式控制器就會改變它輸出OC1REF(reference參考信號)的高低電平;接下來可以把OC1REF映射到主模式的TRGO輸出上去;不過REF的主要去向還是走下面。

這是一個極性選擇,給這個寄存器寫0,信號就會往上走,就是信號電平不反轉;寫1的話,信號就會往下走,信號會通過一個非門取反,輸出的信號就會發生反轉。最后就是OC1引腳,這個引腳是CH1通道的引腳,在引腳定義中就可以具體知道是哪個GPIO了。

輸出模式控制器的工作:輸出比較模式,通過寄存器來配置。

模式

描述

凍結

CNT=CCR時(無效),REF保持為原狀態

匹配時置有效電平

CNT=CCR時,REF置有效電平(高電平),一次性的

匹配時置無效電平

CNT=CCR時,REF置無效電平(低電平),一次性的

匹配時電平翻轉

CNT=CCR時,REF電平翻轉

強制為無效電平

CNTCCR無效,REF強制為無效電平。在暫停期間保持高電平

強制為有效電平

CNTCCR無效,REF強制為有效電平。在暫停期間保持低電平

PWM模式1

向上計數:CNT<CCR時,REF置有效電平,CNTCCR時,REF置無效電平

向下計數:CNT>CCR時,REF置無效電平,CNTCCR時,REF置有效電平

PWM模式2

向上計數:CNT<CCR時,REF置無效電平,CNTCCR時,REF置有效電平

向下計數:CNT>CCR時,REF置有效電平,CNTCCR時,REF置無效電平

(1)凍結模式:輸出暫停;

(2)匹配時置有效電平、匹配時置無效電平、匹配時電平翻轉:有效/無效電平一般是高級定時器的說法;簡單理解有效電平是高電平,無效電平是低電平。

(3)PWM模式

PWM模式2是PWM模式1的取反。

1.4?PWM基本結構

?左上角是時基單元和控制部分,輸出PWM暫時不需要中斷。下面就是輸出比較單元了,總共有4路。輸出比較單元的最開始,是CCR捕獲/比較寄存器,CCR是我們自己設定的,CNT不斷自增運行,同時它倆還在不斷比較,后面是輸出模式控制器(PWM模式1)。

藍色線是CNT的值,黃色線是ARR的值,CNT(藍色線)從0開始自增,一直增到ARR的值,之后清零繼續自增。在這個過程中再設置一條紅線(CCR的值),之后再執行【CNT<CCR時,REF置有效電平;CNT≥CCR時,REF置無效電平】,下面綠色部分是輸出。

CNT<CCR時,REF置有效電平;CNT≥CCR時,REF置無效電平。并且它的占空比是受CCR值調控的;如果CCR設置高一些,輸出占空比就大一些。

1.5?參數計算

PWM頻率:? Freq = CK_PSC / (PSC + 1) / (ARR + 1)

對應著計數器的一個溢出更新周期,PWM的頻率等于計數器的更新頻率。

PWM占空比:? Duty = CCR / (ARR + 1)

PWM分辨率:? Reso = 1 / (ARR + 1)

輸出一個頻率為1KHz,占空比可以任意調控,切分辨率為1%的PWM波形

Reso = 1 / (ARR + 1) = 1% =====》ARR = 99

Duty = CCR / (ARR + 1) = CCR / 100? =====》?CCR = [0, 100]

Freq = CK_PSC / (PSC + 1) / (ARR + 1) = 1000 =====》?CK_PSC / (PSC + 1) = 100000

1.6?舵機簡介

舵機是一種根據輸入PWM信號占空比來控制輸出角度的裝置

輸入PWM信號要求:周期為20ms,高電平寬度為0.5ms~2.5ms

大概的執行邏輯:PWM信號輸入到控制板,給控制板一個指定的目標角度,然后電位器會檢測輸出軸的當前角度;如果大于目標角度,電機就會反轉;否則正轉。最終使輸出軸固定在指定角度。

1.6.1?舵機硬件電路

1.7?直流電機

直流電機是一種將電能轉換為機械能的裝置,有兩個電極,當電極正接時,電機正轉,當電極反接時,電機反轉

直流電機屬于大功率器件,GPIO口無法直接驅動,需要配合電機驅動電路來操作

TB6612是一款雙路H橋型的直流電機驅動芯片,可以驅動兩個直流電機并且控制其轉速和方向

1.7.1?硬件電路

看圖和引腳說明,很清晰。

STBY引腳是待機控制引腳。如果接GND,芯片就不工作,處于待機狀態;如果接邏輯電源VCC,芯片就正常工作。

看手冊

強置輸出模式:CNT和CCR無效,REF強制為高和低的那兩種模式

輸出比較模式:CNT=CCR時,REF凍結、置高、置低、反轉那四種模式

PWM 模式:CNT > CCR或者CNT < CCR時,REF置高或者置低的那兩種模式。

2?TIM輸出比較之PWM驅動LED呼吸燈

2.1?接線圖

注意這里:高電平點亮,低電平熄滅。即占空比越大,LED越亮;占空比越小,LED越暗。

2.2?封裝模塊

按這個流程圖進行初始化

先看輸出比較相關的函數

// 這4個函數是用來配置輸出比較的
void TIM_OC1Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
void TIM_OC2Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
void TIM_OC3Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
void TIM_OC4Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);// 用來給輸出比較結構體賦值一個默認值的
void TIM_OCStructInit(TIM_OCInitTypeDef* TIM_OCInitStruct);// 僅高級定時器使用,在使用高級定時器輸出PWM時,需要用這個函數使能主輸出;否則PWM將不能正常輸出
void TIM_CtrlPWMOutputs(TIM_TypeDef* TIMx, FunctionalState NewState);// 用來配置強制輸出模式的。強制輸出高電平和輸出設置100%占空比一樣
void TIM_ForcedOC1Config(TIM_TypeDef* TIMx, uint16_t TIM_ForcedAction);
void TIM_ForcedOC2Config(TIM_TypeDef* TIMx, uint16_t TIM_ForcedAction);
void TIM_ForcedOC3Config(TIM_TypeDef* TIMx, uint16_t TIM_ForcedAction);
void TIM_ForcedOC4Config(TIM_TypeDef* TIMx, uint16_t TIM_ForcedAction);// 配置CCR寄存器的預裝功能,就是影子寄存器;寫入的值不會立即生效,在更新事件才會生效
void TIM_OC1PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload);
void TIM_OC2PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload);
void TIM_OC3PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload);
void TIM_OC4PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload);// 配置快速使能的
void TIM_OC1FastConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCFast);
void TIM_OC2FastConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCFast);
void TIM_OC3FastConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCFast);
void TIM_OC4FastConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCFast);// 外部事件時清除ref信號
void TIM_ClearOC1Ref(TIM_TypeDef* TIMx, uint16_t TIM_OCClear);
void TIM_ClearOC2Ref(TIM_TypeDef* TIMx, uint16_t TIM_OCClear);
void TIM_ClearOC3Ref(TIM_TypeDef* TIMx, uint16_t TIM_OCClear);
void TIM_ClearOC4Ref(TIM_TypeDef* TIMx, uint16_t TIM_OCClear);// 單獨設置輸出比較極性的
void TIM_OC1PolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity);
void TIM_OC1NPolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCNPolarity);
void TIM_OC2PolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity);
void TIM_OC2NPolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCNPolarity);
void TIM_OC3PolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity);
void TIM_OC3NPolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCNPolarity);
void TIM_OC4PolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity);// 單獨修改輸出使能參數的
void TIM_CCxCmd(TIM_TypeDef* TIMx, uint16_t TIM_Channel, uint16_t TIM_CCx);
void TIM_CCxNCmd(TIM_TypeDef* TIMx, uint16_t TIM_Channel, uint16_t TIM_CCxN);// 選擇輸出比較模式
void TIM_SelectOCxM(TIM_TypeDef* TIMx, uint16_t TIM_Channel, uint16_t TIM_OCMode);// 單獨更改RCC寄存器的值
void TIM_SetCompare1(TIM_TypeDef* TIMx, uint16_t Compare1);
void TIM_SetCompare2(TIM_TypeDef* TIMx, uint16_t Compare2);
void TIM_SetCompare3(TIM_TypeDef* TIMx, uint16_t Compare3);
void TIM_SetCompare4(TIM_TypeDef* TIMx, uint16_t Compare4);

要掌握的

// 這4個函數是用來配置輸出比較的
void TIM_OC1Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
void TIM_OC2Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
void TIM_OC3Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
void TIM_OC4Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);// 單獨更改RCC寄存器的值
void TIM_SetCompare1(TIM_TypeDef* TIMx, uint16_t Compare1);
void TIM_SetCompare2(TIM_TypeDef* TIMx, uint16_t Compare2);
void TIM_SetCompare3(TIM_TypeDef* TIMx, uint16_t Compare3);
void TIM_SetCompare4(TIM_TypeDef* TIMx, uint16_t Compare4);

看這個圖

有TIM2_CH1_ETR在PA0這一行,說明TIM2的ETR引腳和通道1的引腳都是借用了PA0引腳,換句話,TIM2的引腳復用到了PA0引腳上,所以如果要使用TIM2的OC1也就是CH1t通道,輸出PWM那它就只能在PA0的引腳輸出,不能任意接。同樣,TIM2的CH2對應PA1。。。。。。

還可以修改

計算:頻率1kHz,占空比50% ,分辨率為1%。

PWM分辨率:?? ?Reso = 1 / (ARR + 1) = 1% ? ? ??? ??? ??? ??? ??? ??? ????????????==> ARR= 100 - 1

PWM占空比:?? ?Duty = CCR / (ARR + 1) = 50% ? ?? ??? ??? ??? ??? ??? ?????????==> CCR = 50

PWM頻率:?? ?Freq = CK_PSC(72M) / (PSC + 1) / (ARR + 1) = 1K ??? ?==> PSC = 720 - 1

// 2配置時基單元(預分頻器、自動重裝器、計數模式等)// ...TIM_TimeBaseInitStructure.TIM_Period = 100 - 1;				// ARR自動重裝器的值 兩個合起來計數0.1秒TIM_TimeBaseInitStructure.TIM_Prescaler = 720 - 1;			// PSC預分頻器的值,720分頻,得到100k計數TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);// 3配置輸出比較單元(CCR的值、輸出比較模式、極性選擇、輸出使能)TIM_OCInitTypeDef TIM_OCInitStructure;TIM_OCStructInit(&TIM_OCInitStructure);               					 // 先初始化,后面再按需修改// ...TIM_OCInitStructure.TIM_Pulse = 0;            							 // CCR的值w為50,先設置為0,后面變化// 這個函數的選擇按照GPIO口需求來,PA0口對應的是第一個輸出比較通道TIM_OC1Init(TIM2, &TIM_OCInitStructure);

PWM.c

#include "stm32f10x.h"                  // Device header// PWM初始化函數
void PWM_Init(void)
{// 1RCC開啟時鐘RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);TIM_InternalClockConfig(TIM2);// 2配置時基單元(預分頻器、自動重裝器、計數模式等)TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;		// 時鐘分頻,影響不大TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;	// 計數模式,向上計數TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;			// 重復計數器的值// 關鍵參數TIM_TimeBaseInitStructure.TIM_Period = 100 - 1;				// ARR自動重裝器的值 兩個合起來計數0.1秒TIM_TimeBaseInitStructure.TIM_Prescaler = 720 - 1;			// PSC預分頻器的值,720分頻,得到100k計數TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);// 3配置輸出比較單元(CCR的值、輸出比較模式、極性選擇、輸出使能)TIM_OCInitTypeDef TIM_OCInitStructure;TIM_OCStructInit(&TIM_OCInitStructure);               					 // 先初始化,后面再按需修改TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;     					 // 輸出比較模式,PWM模式1TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;                // 輸出比較極性,高級性,極性不反轉,有效電平是高電平TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;            // 輸出狀態輸出使能TIM_OCInitStructure.TIM_Pulse = 0;            							 // CCR的值w為50,先設置為0,后面變化// 這個函數的選擇按照GPIO口需求來,PA0口對應的是第一個輸出比較通道TIM_OC1Init(TIM2, &TIM_OCInitStructure);// 頻率1kHz,占空比50% ,分辨率為1%。 CCR = 50 ,/**PWM分辨率:	Reso = 1 / (ARR + 1) = 1%      						==> ARR= 100 - 1PWM占空比:	Duty = CCR / (ARR + 1) = 50%   						==> CCR = 50PWM頻率:	Freq = CK_PSC(72M) / (PSC + 1) / (ARR + 1) = 1K  	==> PSC = 720 - 1*/// 4配置GPIO(初始化為復用推挽輸出,參考引腳定義表)RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;				// 復用推挽輸出。定時器控制引腳,輸出控制權轉移給片上外設GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);// 5運行控制,啟動計數器TIM_Cmd(TIM2, ENABLE);
}// 更改通道1的CCR值
void PWM_SetCompare1(uint16_t Compare)
{TIM_SetCompare1(TIM2, Compare);
}

2.3?主函數

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "PWM.h"uint8_t i;int main()
{OLED_Init();					// 初始化OLEDPWM_Init();						// PWM初始化OLED_ShowString(1, 1, "Hello");while (1){// 點亮for (i = 0; i <= 100; i++){PWM_SetCompare1(i);Delay_ms(10);}// 熄滅for (i = 0; i <= 100; i++) {PWM_SetCompare1(100 - i);Delay_ms(10);}}
}

現象:接在PA0號口的燈如呼吸一般亮滅

復用到PA15

PWM.c

#include "stm32f10x.h"                  // Device header// PWM初始化函數
void PWM_Init(void)
{// 1RCC開啟時鐘RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);TIM_InternalClockConfig(TIM2);RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);      // 重映射使用AFIOGPIO_PinRemapConfig(GPIO_PartialRemap1_TIM2, ENABLE);     // 部分重映射PA15GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);  // 解除調試端口// 2配置時基單元(預分頻器、自動重裝器、計數模式等)TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;		// 時鐘分頻,影響不大TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;	// 計數模式,向上計數TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;			// 重復計數器的值// 關鍵參數TIM_TimeBaseInitStructure.TIM_Period = 100 - 1;				// ARR自動重裝器的值 兩個合起來計數0.1秒TIM_TimeBaseInitStructure.TIM_Prescaler = 720 - 1;			// PSC預分頻器的值,720分頻,得到100k計數TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);// 3配置輸出比較單元(CCR的值、輸出比較模式、極性選擇、輸出使能)TIM_OCInitTypeDef TIM_OCInitStructure;TIM_OCStructInit(&TIM_OCInitStructure);               					 // 先初始化,后面再按需修改TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;     					 // 輸出比較模式,PWM模式1TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;                // 輸出比較極性,高級性,極性不反轉,有效電平是高電平TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;            // 輸出狀態輸出使能TIM_OCInitStructure.TIM_Pulse = 0;            							 // CCR的值w為50,先設置為0,后面變化// 這個函數的選擇按照GPIO口需求來,PA0口對應的是第一個輸出比較通道TIM_OC1Init(TIM2, &TIM_OCInitStructure);// 頻率1kHz,占空比50% ,分辨率為1%。 CCR = 50 ,/**PWM分辨率:	Reso = 1 / (ARR + 1) = 1%      						==> ARR= 100 - 1PWM占空比:	Duty = CCR / (ARR + 1) = 50%   						==> CCR = 50PWM頻率:	Freq = CK_PSC(72M) / (PSC + 1) / (ARR + 1) = 1K  	==> PSC = 720 - 1*/// 4配置GPIO(初始化為復用推挽輸出,參考引腳定義表)RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;				// 復用推挽輸出。定時器控制引腳,輸出控制權轉移給片上外設
//	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);// 5運行控制,啟動計數器TIM_Cmd(TIM2, ENABLE);
}// 更改通道1的CCR值
void PWM_SetCompare1(uint16_t Compare)
{TIM_SetCompare1(TIM2, Compare);
}

3 TIM輸出比較之PWM驅動舵機

3.1?接線圖

注意顏色

3.2?模塊封裝

輸入PWM信號要求:周期為20ms,高電平寬度為0.5ms~2.5ms

	// 輸入PWM信號要求:周期為20ms(50Hz),高電平寬度為0.5ms~2.5ms,占空比[2.5%, 12.5%]/**PWM分辨率:	Reso = 1 / (ARR + 1)PWM占空比:	Duty = CCR / (ARR + 1)PWM頻率:	Freq = CK_PSC(72M) / (PSC + 1) / (ARR + 1)PSC = 72 - 1ARR = 20000 - 1CCR的范圍是[500, 2500]*/

現在使用的是PA1的通道2

PWM.c

#include "stm32f10x.h"                  // Device header// PWM初始化函數
void PWM_Init(void)
{// 1RCC開啟時鐘RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);TIM_InternalClockConfig(TIM2);// 2配置時基單元(預分頻器、自動重裝器、計數模式等)TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;		// 時鐘分頻,影響不大TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;	// 計數模式,向上計數TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;			// 重復計數器的值// 關鍵參數TIM_TimeBaseInitStructure.TIM_Period = 20000 - 1;				// ARR自動重裝器的值 兩個合起來計數0.1秒TIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1;				// PSC預分頻器的值,72分頻,得到100k計數TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);// 3配置輸出比較單元(CCR的值、輸出比較模式、極性選擇、輸出使能)TIM_OCInitTypeDef TIM_OCInitStructure;TIM_OCStructInit(&TIM_OCInitStructure);               					 // 先初始化,后面再按需修改TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;     					 // 輸出比較模式,PWM模式1TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;                // 輸出比較極性,高級性,極性不反轉,有效電平是高電平TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;            // 輸出狀態輸出使能TIM_OCInitStructure.TIM_Pulse = 0;            							 // CCR的值w為50,先設置為0,后面變化// 這個函數的選擇按照GPIO口需求來,PA1口對應的是第二個輸出比較通道TIM_OC2Init(TIM2, &TIM_OCInitStructure);// 輸入PWM信號要求:周期為20ms(50Hz),高電平寬度為0.5ms~2.5ms,占空比[2.5%, 12.5%]/**PWM分辨率:	Reso = 1 / (ARR + 1)PWM占空比:	Duty = CCR / (ARR + 1)PWM頻率:	Freq = CK_PSC(72M) / (PSC + 1) / (ARR + 1)PSC = 72 - 1ARR = 20000 - 1CCR的范圍是[500, 2500]*/// 4配置GPIO(初始化為復用推挽輸出,參考引腳定義表)RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;				// 復用推挽輸出。定時器控制引腳,輸出控制權轉移給片上外設GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);// 5運行控制,啟動計數器TIM_Cmd(TIM2, ENABLE);
}// 更改通道2的CCR值
void PWM_SetCompare2(uint16_t Compare)
{TIM_SetCompare2(TIM2, Compare);
}

Servo.c

#include "stm32f10x.h"                  // Device header
#include "PWM.h"// 舵機模塊
void Servo_Init(void)
{PWM_Init();   // 初始化PWM模塊
}// 設置舵機角度。即改CCR的值
void Servo_SetAngle(float angle)
{// 0°   500// 180  2500PWM_SetCompare2(angle / 180 * 2000 + 500);
}

3.3?主函數

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "Key.h"
#include "OLED.h"
#include "Servo.h"uint8_t keyNum;
float angle;int main()
{OLED_Init();       						// 初始化OLED_ShowString(1, 1, "angle:");   		// 顯示字符串Servo_Init();KEY_Init();while (1){keyNum = KEY_GetNum();				// 讀按鍵if (keyNum == 1){angle += 30;if (angle > 180){angle = 0;}}Servo_SetAngle(angle);				// 設置舵機角度(設置CCR的值)OLED_ShowNum(1, 7, angle, 3);}
}

現象:按按鍵,舵機從0°開始,每次轉動30°,當大于180°時,回到0°

輸入PWM信號要求:周期為20ms,高電平寬度為0.5ms~2.5ms

通過修改CCR的值,改變占空比,進而輸出不同占空比的PWM波形。

4?TIM輸出比較之PWM驅動直流電機

4.1?接線圖

4.2?模塊封裝

電機接到了通道3上

PWM.c

#include "stm32f10x.h"                  // Device header// PWM初始化函數
void PWM_Init(void)
{// 1RCC開啟時鐘RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);TIM_InternalClockConfig(TIM2);// 2配置時基單元(預分頻器、自動重裝器、計數模式等)TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;		// 時鐘分頻,影響不大TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;	// 計數模式,向上計數TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;			// 重復計數器的值// 關鍵參數TIM_TimeBaseInitStructure.TIM_Period = 100 - 1;				// ARR自動重裝器的值 兩個合起來計數0.1秒TIM_TimeBaseInitStructure.TIM_Prescaler = 36 - 1;			// PSC預分頻器的值,36分頻TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);// 3配置輸出比較單元(CCR的值、輸出比較模式、極性選擇、輸出使能)TIM_OCInitTypeDef TIM_OCInitStructure;TIM_OCStructInit(&TIM_OCInitStructure);               					 // 先初始化,后面再按需修改TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;     					 // 輸出比較模式,PWM模式1TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;                // 輸出比較極性,高級性,極性不反轉,有效電平是高電平TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;            // 輸出狀態輸出使能TIM_OCInitStructure.TIM_Pulse = 0;            							 // CCR的值w為50,先設置為0,后面變化// 這個函數的選擇按照GPIO口需求來,PA2口對應的是第一個輸出比較通道TIM_OC3Init(TIM2, &TIM_OCInitStructure);// 頻率1kHz,占空比50% ,分辨率為1%。 CCR = 50 ,/**PWM分辨率:	Reso = 1 / (ARR + 1) = 1%      						==> ARR= 100 - 1PWM占空比:	Duty = CCR / (ARR + 1) = 50%   						==> CCR = 50PWM頻率:	Freq = CK_PSC(72M) / (PSC + 1) / (ARR + 1) = 1K  	==> PSC = 720 - 1*/// 4配置GPIO(初始化為復用推挽輸出,參考引腳定義表)RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;				// 復用推挽輸出。定時器控制引腳,輸出控制權轉移給片上外設GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);// 5運行控制,啟動計數器TIM_Cmd(TIM2, ENABLE);
}// 更改通道1的CCR值
void PWM_SetCompare3(uint16_t Compare)
{TIM_SetCompare3(TIM2, Compare);
}

Motor.c

#include "stm32f10x.h"                  // Device header
#include "PWM.h"// 電機初始化
void Motor_Init(void)
{// 還有兩個角需要初始化(控制電機方向)RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);// 配置端口GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;			// 推挽輸出GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);// 初始化PWMPWM_Init();
}// 設置速度函數
void Motor_Speed(int8_t speed)
{// 正轉if (speed >= 0){// 設置方向GPIO_SetBits(GPIOA, GPIO_Pin_4);GPIO_ResetBits(GPIOA, GPIO_Pin_5);// 速度,RCC的值,即調節占空比PWM_SetCompare3(speed);}else{// 設置方向GPIO_ResetBits(GPIOA, GPIO_Pin_4);GPIO_SetBits(GPIOA, GPIO_Pin_5);// 速度,RCC的值,即調節占空比PWM_SetCompare3(-speed);}}

4.3?主函數

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "Motor.h"
#include "Key.h"uint8_t keyNum;
int8_t speed;int main()
{OLED_Init();					// 初始化OLEDOLED_ShowString(1, 1, "Speed:");Motor_Init();KEY_Init();while (1){keyNum = KEY_GetNum();if (keyNum == 1){speed += 20;if (speed >= 100){speed = -100;}}Motor_Speed(speed);OLED_ShowSignedNum(1, 7, speed, 3);}
}

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

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

相關文章

JavaWeb-HTTP協議

1. 什么是HTTP協議 HTTP超文本傳輸協(Hyper Text transfer protocol)&#xff0c;是一種用于用于分布式、協作式和超媒體信息系統的應用層協議。它于1990年提出&#xff0c;經過十幾年的使用與發展&#xff0c;得到不斷地完善和擴展。HTTP 是為 Web 瀏覽器與 Web 服務器之間的…

AI自動生成代碼工具

AI自動生成代碼工具是一種利用人工智能技術來輔助或自動化軟件開發過程中的編碼任務的工具。這些工具使用機器學習和自然語言處理等技術&#xff0c;根據開發者的需求生成相應的源代碼。以下是一些常見的AI自動生成代碼工具&#xff0c;希望對大家有所幫助。北京木奇移動技術有…

Redisson的基本使用

Redisson官網描述&#xff1a;Redisson 是一個在 Redis 的基礎上實現的 Java 駐內存數據網格客戶端&#xff08;In-Memory Data Grid&#xff09;。它不僅提供了一系列的 redis 常用數據結構命令服務&#xff0c;還提供了許多分布式服務&#xff0c;例如分布式鎖、分布式對象、…

HCIP —— BGP 基礎 (上)

BGP --- 邊界網關協議 &#xff08;路徑矢量協議&#xff09; IGP --- 內部網關協議 --- OSPF RIP ISIS EGP --- 外部網關協議 --- EGP BGP AS --- 自治系統 由單一的組織或者機構獨立維護的網絡設備以及網絡資源的集合。 因 網絡范圍太大 需 自治 。 為區分不同的AS&#…

vim常見操作

vim常見操作 文章目錄 vim常見操作1. 回退/前進2. 搜索3. 刪除4. 定位到50行5. 顯示行號6. 復制粘貼7. 剪貼8. 替換9. vim打開文件的時候出現 1. 回退/前進 1.esc進入命令模式 2.ctrlr 前進 u 回退2. 搜索 1&#xff09; esc進入命令模式 2&#xff09; /text  查找text&am…

Docker load 命令

docker load &#xff1a;導入使用docker save命令導出的鏡像。 語法 docker load [OPTIONS]OPTIONS 說明&#xff1a; --input , -i &#xff1a;指定導入的文件&#xff0c;代替STDIN。 --quiet , -q &#xff1a;精簡輸出信息。 實例&#xff1a; 導入鏡像&#xff1a…

【STM32】TIM定時器輸入捕獲

1 輸入捕獲 1.1 輸入捕獲簡介 IC&#xff08;Input Capture&#xff09;輸入捕獲 輸入捕獲模式下&#xff0c;當通道輸入引腳出現指定電平跳變時&#xff08;上升沿/下降沿&#xff09;&#xff0c;當前CNT的值將被鎖存到CCR中&#xff08;把CNT的值讀出來&#xff0c;寫入到…

ubuntu16.04安裝ROS+Gazebo

ubuntu16.04安裝ROS參考文章 ros安裝&#xff08;一鍵最簡安裝&#xff0c;吹爆魚香ROS&#xff0c;請叫我魚吹&#xff09; ROS篇——Ubuntu快速一鍵安裝ROS或ROS2&#xff08;通用&#xff09; ubuntu安裝ROS melodic(最新、超詳細圖文教程) 配置ubuntu以及安裝ros2必要環…

類風濕性關節炎口腔黏膜破裂引發抗瓜氨酸細菌和人蛋白抗體反應

今天給同學們分享一篇實驗文章“Oral mucosal breaks trigger anti-citrullinated bacterial and human protein antibody responses in rheumatoid arthritis”&#xff0c;這篇文章發表在Sci Transl Med期刊上&#xff0c;影響因子為17.1。 結果解讀&#xff1a; 口腔黏膜破…

Redis主從復制的配置和實現原理

Redis的持久化功能在一定程度上保證了數據的安全性&#xff0c;即便是服務器宕機的情況下&#xff0c;也可以保證數據的丟失非常少。通常&#xff0c;為了避免服務的單點故障&#xff0c;會把數據復制到多個副本放在不同的服務器上&#xff0c;且這些擁有數據副本的服務器可以用…

如何快速構建知識服務平臺,打造個人或企業私域流量

隨著互聯網的快速發展&#xff0c;傳統的知識付費平臺已經不能滿足用戶的需求。而SaaS知識付費小程序平臺則是一種新型的知識付費方式&#xff0c;具有靈活、便捷、高效等特點&#xff0c;為用戶提供了更加優質的付費知識服務。本文將介紹如何搭建自己的SaaS知識付費小程序平臺…

如何掌握構建 LMS 網站的藝術

目錄 什么是學習管理系統 (LMS) 在線課程和 LMS 網站的好處 為什么 WordPress 對于 LMS 網站很重要 統一學習中心 多功能性和可擴展性 提高教育參與度 簡化管理和監控 節省時間和費用 技能評估和績效監督 持續學習和技能提升 使用 WordPress 插件構建成功的 LMS 課程 專注于您的…

sparkc程序idea調試提示內存不足

報錯如下&#xff1a; Exception in thread "main" java.lang.IllegalArgumentException: System memory 259522560 must be at least 471859200. Please increase heap size using the --driver-memory option or spark.driver.memory in Spark configuration. 測…

自動駕駛:傳感器初始標定

手眼標定 機器人手眼標定AxxB&#xff08;eye to hand和eye in hand&#xff09;及平面九點法標定 Ax xB問題求解&#xff0c;旋轉和平移分步求解法 手眼標定AXXB求解方法&#xff08;文獻總結&#xff09; 基于靶的方法 相機標定 (1) ApriTag (2) 棋盤格&#xff1a;cv::f…

富時中國A50指數暴跌

近年來&#xff0c;中國股市的波動一直備受關注&#xff0c;而富時中國A50指數更是其中一項備受矚目的指標之一。然而&#xff0c;近期卻出現了一場引人矚目的暴跌&#xff0c;引發了廣泛的關注和討論。 富時中國A50指數簡介 富時中國A50指數&#xff0c;作為富時羅素指數系列…

【C/PTA】結構體專項練習

本文結合PTA專項練習帶領讀者掌握結構體&#xff0c;刷題為主注釋為輔&#xff0c;在代碼中理解思路&#xff0c;其它不做過多敘述。 目錄 6-1 選隊長6-2 按等級統計學生成績6-3 學生成績比高低6-4 綜合成績6-5 利用“選擇排序算法“對結構體數組進行排序6-6 結構體的最值6-7 復…

香港商標注冊申請所需資料及辦理流程

作為東方明珠&#xff0c;自由港香港是世界上較自由的貿易通商口岸&#xff0c;再加上本身良好的基礎設施和健全的法律制度&#xff0c;這給企業家提供了得天獨厚的營商環境。在香港注冊商標&#xff0c;可以迅速提高企業的知名度&#xff0c;提升企業不斷成長的競爭力&#xf…

全新UI彩虹外鏈網盤系統源碼V5.5/支持批量封禁+優化加載速度+用戶系統與分塊上傳

源碼簡介&#xff1a; 全新UI彩虹外鏈網盤系統源碼V5.5&#xff0c;它可以支持批量封禁優化加載速度。新增用戶系統與分塊上傳。 彩虹外鏈網盤&#xff0c;作為一款PHP網盤與外鏈分享程序&#xff0c;具備廣泛的文件格式支持能力。它不僅能夠實現各種格式文件的上傳&#xff…

CLASS60 DM藍牙5.2雙模熱插拔PCB

鍵盤使用說明索引&#xff08;均為出廠默認值&#xff09; 軟件支持&#xff08;驅動的詳細使用幫助&#xff09;一些常見問題解答&#xff08;FAQ&#xff09;首次使用步驟藍牙配對規則&#xff08;重要&#xff09;藍牙和USB切換鍵盤默認層默認觸發層0的FN鍵配置的功能默認功…

使用word中的VBA 批量設置Word中所有圖片大小

在VBA編輯器中&#xff0c;你可以創建、編輯和運行VBA宏代碼&#xff0c;以實現自動化任務和自定義Word 功能。如果你是VBA編程初學者&#xff0c;可以在VBA編輯器中查看Word VBA宏代碼示例&#xff0c;以便更好地了解如何使用VBA編寫代碼。 要打開VBA編輯器&#xff0c;你可以…