第二部分,定時器的輸出比較功能
OC(Output Compare)輸出比較
輸出比較可以通過比較CNT與CCR寄存器值的關系,來對輸出電平進行置1、置0或翻轉的操作,用于輸出一定頻率和占空比的PWM波形
每個高級定時器和通用定時器都擁有4個輸出比較通道
高級定時器的前3個通道額外擁有死區生成和互補輸出的功能
IC:輸入捕獲、CC:表示輸入捕獲和輸出比較的單元、CCR:捕獲比較寄存器
CCR是輸入捕獲和輸出捕獲比較共用的,會根據輸出和輸入比較的情況,轉換對于寄存器功能;在輸出比較中,電路會比較CNT和CCR的值,CNT自增,當CNT大于CCR、等于CCR和小于CCR時,會輸出對于的置0或1,從而輸出一個電平不斷跳變的PWN波形;共用一個CNT計數器
PWM(Pulse Width Modulation)脈沖寬度調制
最常見的用途是產生PWM波形,用于驅動電機等設備
在具有慣性的系統中,可以通過對一系列脈沖的寬度進行調制,來等效地獲得所需要的模擬參量,常應用于電機控速等領域,是數字信號
PWM參數:
???? 頻率 = 1 / TS??????????? 占空比 = TON / TS?????????? 分辨率 = 占空比變化步距
Ts圖下:代表一個高低電平變換周期的時間
Ton:高電平的時間、Toff? 同理
?
頻率越快,等效模擬的信號就越平穩,性能的開銷就大
在今天的實驗中我們實現的LED呼吸燈中,正常來說數字信號只有0和1,所以只會實現亮和滅的情況,但是通過PWM波形用數字信號來輸出一段模擬信號就可以實現呼吸燈:讓LED燈不斷點亮、熄滅、點亮、熄滅,當點亮和熄滅的頻率足夠大時,LED就不會閃爍了,而是呈現出一個中等亮度,這時進行調控點亮和熄滅的時間比例,就能呈現出不同亮度;(唯快不破)
輸出比較通道(通用)
整體電路所在的方位? ? ? ?
CCR與CNT比較,輸出數字信號(0和1),輸出控制器會改變它輸出OC1PRE的高低電平;REF信號可以進入主模式控制器,這樣可以將REF映射到TRGO輸出上去;主要是走下一路,達到極性選擇,通過極性選擇到輸出使能電路,選擇要不要輸出,輸出至OC1引腳(引腳對應表)
極性選擇 :給這個寄存器寫0,信號就會往上走,信號電平不翻轉;寫1,信號會往下走,信號會通過一個非門取反,此時輸出的信號就是輸入信號高低電平反轉的信號
REF信號:實際就是指這里信號的高低電平——參考信號
輸出比較的8種模式
輸出控制器里的執行邏輯,靈活地控制REF的輸出;通過一個寄存器來進行配置
作用:
凍結:在輸出PWM波形時,想要進行停止,就可以設置此,此時就暫停了輸出,并且高低電平也維持在暫停時的樣子
匹配時置無效電平&匹配時置有效電平:一般是高級定時器的說法,與關斷、剎車燈功能一起的,有效電平就是高電平,無效電平則反之,一次性的,不適合輸出連續變化的波形。
匹配時電平翻轉:可以輸出一個頻率可調,占空比始終50%的PWM波形:比如當CCR設置為0時,CNT每次更新清0時,就會產生一次CNT=CCR的事件,從而導致輸出電平翻轉一次,每更新兩次,輸出為一個周期,同時高低電平時間始終相等,占空比始終為50%;則關系是輸出頻率=更新頻率/2
強制為無效電平&強制為有效電平:與凍結差不多
PWM模式1& PWM模式2:用于輸出頻率和占空比都可調的PWM波形,主要使用
PWM的基本結構:
紅色代表:CCR
藍色代表:CNT
黃色代表:ARR
下面的圖表示輸出的PWM波形:
藍色從0開始自增,直到與黃色相同時,出現中斷,更新清0繼續自增;
紅色設置為30,因為輸出控制器設置的模式是,當CNT<CCR時,為高電平;所以根據藍色與黃色不斷的更新,CCR會輸出不同的REF信號,同時不僅可以調整紅色設置的值,并且占空比也受CCR的調控。
參數計算
- PWM頻率:??? Freq = CK_PSC / (PSC + 1) / (ARR + 1)
- PWM占空比:?????? Duty = CCR / (ARR + 1)
- PWM分辨率:?????? Reso = 1 / (ARR + 1)
CK_PSC:輸入定時器的總頻率;PSC=預分頻器的分頻數
占空比變化越細,越好
輸出比較通道(高級定時器)
與通用定時器的區別:
當外部設備是一個大功率開關管(Mos管),兩邊開關分別連接著OC1和OC1N,假設是高電平導通,電平斷開;兩個開關中間對應輸出;如果上管導通,下管斷開,則是高電平,反之;但是如果兩邊都導通,則會短路或者兩邊都斷開,則是高阻態;這就是推挽電路;如果有兩個這樣的電路相連接,則是H橋電路,可控制直流電路正反轉了;如果有三個這樣的電路,就可以用于驅動三相無刷電機;
回歸內部,如果在上管關斷的瞬間,下管立刻就打開,那可能會上管還沒完全關斷,下管已經導通,出現兩邊同時導通的現象,從而功率損耗,所以避免這個問題就設置了死區發生器電路,會在關閉的時候延遲一段時間,再導通;
外部設備:
舵機簡介
- 舵機是一種根據輸入PWM信號占空比來控制輸出角度的裝置
- 輸入PWM信號要求:周期為20ms(50Hz),高電平寬度為0.5ms~2.5ms
?
邏輯:PWM信號輸入到控制板,給控制板一個指定的目標角度,然后這個電位器檢測輸出軸的當前角度,如果大于目標角度,電機會反轉,反之,最終使輸出軸固定在指定角度。
輸出軸角度:時間是指此輸入信號的電平變化到下一個電平變化的時間
這里是PWM當作一個通信協議
硬件電路:
引腳定義圖
直流電機及驅動簡介
- 直流電機是一種將電能轉換為機械能的裝置,有兩個電極,當電極正接時,電機正轉,當電極反接時,電機反轉
- 直流電機屬于大功率器件,GPIO口無法直接驅動,需要配合電機驅動電路來操作
- TB6612是一款雙路H橋型的直流電機驅動芯片,可以驅動兩個直流電機并且控制其轉速和方向
硬件電路:
?
接線圖
6-3 PWM驅動LED呼吸燈
這里我們LED正極接入A0引腳,負極在GND的方法,這樣是高電平點亮,正極性驅動;占空比越高越亮;
- RCC開啟時鐘,把TIM外設和GPIO外設的時鐘打開
- 配置時基單元,包括時鐘源選擇
- 配置輸出比較單元:包括CCR的值、輸出比較模式、極性選擇、輸出使能等由結構體統一配置
- 配置GPIO,把PWM對于的GPIO口,初始化為復用推挽輸出的配置
- 運行控制
相關庫函數:
//配置輸出比較模塊,一個函數配置一個單元,一共有四個單元,不同的通道對不同的GPIO口,對應關系:
得知:TIM2的ETR引腳和CH1通道1的引腳復用在PA0引腳上,所以我們要輸出TIM2的OC1通道輸出PWM,那就只能在PA0的引腳上輸出;如果想跳出這個映射,則需要看這重定義功能表里是否對應接口映射,再通過配置AFIO來完成。
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);//用來輸出比較結構體賦一個默認值
//小功能和運行參數
//配置強制輸出模式,就是設置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);
//用來單獨設置輸出比較的極性,帶N的就是高級定時器里互補通道的配置
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);
//用來單獨更改CCR寄存器值的函數,更改占空比
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);
//僅高級定時器使用,在使用高級定時器輸出PWM時,需要調用這個函數使能輸出
void TIM_CtrlPWMOutputs(TIM_TypeDef* TIMx, FunctionalState NewState);
示波器:1KHz,CCR為50,此時占空比為50%
1KHz,CCR為10,占空比減少至10%,燈變暗
1KHz,CCR為90,占空比增加至90%,燈變亮
main.c
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "PWM.h"
uint8_t i;
int main(void){OLED_Init();PWM_Init();while(1){for(i=0;i<=100;i++){PWM_set(i);Delay_ms(50);}for(i=0;i<=100;i++){PWM_set(100-i);Delay_ms(50);}}
}PWM.c
#include "stm32f10x.h" // Device header
void PWM_Init(void){RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE); //開啟APB1的時鐘函數,TIM2在APB1總線中//選擇時基單元TIM_InternalClockConfig(TIM2);//系統默認是內部時鐘,不寫也可以//配置時基單元TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1; //給輸入的濾波器一個采樣頻率TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;//計數方式TIM_TimeBaseInitStructure.TIM_Period=100-1;//ARR自動重裝器的值TIM_TimeBaseInitStructure.TIM_Prescaler=720-1;//PSC預分配器的值TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0;//重復計數器的值,我們用的通用寄存器,所以直接寫0就好了TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);TIM_ClearFlag(TIM2,TIM_IT_Update);//初始化輸出比較單元:頻率1kHz,占空比為50%的PWM波形//TIM_OCInitStructure函數有一部分是高級定時器里的,要么就把全部成員拉出來配置,要么就用TIM_OCStructInit先賦一個初始值0TIM_OCInitTypeDef TIM_OCInitStructure;TIM_OCStructInit(&TIM_OCInitStructure);TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;//8種輸出比較模式TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High;//輸出比較極性TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;//輸出使能//因此通過觀察得知,我們需要完成的呼吸燈的變化效果就與CCR的值息息相關,TIM_SetCompare1單獨更改CCR值的函數就有用了TIM_OCInitStructure.TIM_Pulse=0;//就是CCR的值TIM_OC1Init(TIM2, &TIM_OCInitStructure);//現在把TIM2上的OC1通道上就可以輸出PWM波形,這個波形是需要借助GPIO口才能輸出,郵引腳定義表得知我們鎖定在PA0引腳上/*開啟時鐘*/RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //開啟GPIOA的時鐘/*GPIO初始化*/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); //啟動定時器TIM_Cmd(TIM2, ENABLE);
}
void PWM_set(uint16_t compare){TIM_SetCompare1(TIM2,compare);
}
重定義映射:
開啟AFIO時鐘
使用引腳重映射配置GPIO_PinRemapConfig
與TIM2的映射關系一共4個,我們要把PA0映射到PA5,就使用2或則和4的關系
APIO的函數參數
注意PA15上電后默認復用調試端口JTDI,需要把它的默認給取消了才能正常使用
繼續使用GPIO_PinRemapConfig,參數
三個參數:就是來解除復用的:
GPIO_Remap_SWJ_NoJTRST? :解除JTRST引腳的復用
GPIO_Remap_SWJ_JTAGDisable? :解除JTAG調試端口的復用
GPIO_Remap_SWJ_Disable? :把SWD和JTAG的調試端口全部解除,此參數需要考慮使用,因為如果使用了,那STLInk就沒有輸出端口了,需要額外去配置
PWM.c
#include "stm32f10x.h" // Device header
void PWM_Init(void){RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE); //開啟APB1的時鐘函數,TIM2在APB1總線中//用引腳重映射,所以需要考慮使用AFIORCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);GPIO_PinRemapConfig(GPIO_FullRemap_TIM2,ENABLE);//PA0到PA15//注意PA15也有自己的默認,需要把它的默認給取消了才能正常使用GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);//選擇時基單元TIM_InternalClockConfig(TIM2);//系統默認是內部時鐘,不寫也可以//配置時基單元TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1; //給輸入的濾波器一個采樣頻率TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;//計數方式TIM_TimeBaseInitStructure.TIM_Period=100-1;//ARR自動重裝器的值TIM_TimeBaseInitStructure.TIM_Prescaler=720-1;//PSC預分配器的值TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0;//重復計數器的值,我們用的通用寄存器,所以直接寫0就好了TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);TIM_ClearFlag(TIM2,TIM_IT_Update);//初始化輸出比較單元:頻率1kHz,占空比為50%的PWM波形//TIM_OCInitStructure函數有一部分是高級定時器里的,要么就把全部成員拉出來配置,要么就用TIM_OCStructInit先賦一個初始值0TIM_OCInitTypeDef TIM_OCInitStructure;TIM_OCStructInit(&TIM_OCInitStructure);TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;//8種輸出比較模式TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High;//輸出比較極性TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;//輸出使能//因此通過觀察得知,我們需要完成的呼吸燈的變化效果就與CCR的值息息相關,TIM_SetCompare1單獨更改CCR值的函數就有用了TIM_OCInitStructure.TIM_Pulse=0;//就是CCR的值TIM_OC1Init(TIM2, &TIM_OCInitStructure);//現在把TIM2上的OC1通道上就可以輸出PWM波形,這個波形是需要借助GPIO口才能輸出,郵引腳定義表得知我們鎖定在PA0引腳上/*開啟時鐘*/RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //開啟GPIOA的時鐘/*GPIO初始化*/GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//復用推挽輸出,因為普通的推挽輸出,引腳的控制權是來自于輸出數據寄存器的,那我們這時想讓的是定時器來控制引腳,則需要使用復用推挽輸出GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;//重映射GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure); //啟動定時器TIM_Cmd(TIM2, ENABLE);
}
void PWM_set(uint16_t compare){TIM_SetCompare1(TIM2,compare);
}
6-4 PWM驅動舵機
CCR為500,對應轉0°
修改參數:
CCR為2500,對應180°;
修改參數:
CCR為1500,對應90°;
main.c
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "Servo.h"
#include "key.h"
#include "PWM.h"uint8_t Keynum=0;//按鍵鍵碼
float Angle;//角度變量
int main(void){OLED_Init();PWM_Init();
// //PWM_set(500);//此時時間為0.5ms,處于不動的狀態//PWM_set(2500);//此時時間為2.5ms,轉180°
// PWM_set(1500);//此時時間為1.5ms,轉90°Key_Init();Servo_Init();OLED_ShowString(1,1,"Angle:");while(1){Keynum=Key_GetNum();if(Keynum==1){Angle+=30;if(Angle>180){Angle=0;}}Servo_Setangle(Angle);OLED_ShowNum(1,7,Angle,3);}
}
Servo.c
#include "stm32f10x.h" // Device header
#include "PWM.h"
//給舵機一個模塊,用來實現目標功能void Servo_Init(void){PWM_Init();
}void Servo_Setangle(float Angle){PWM_set(Angle/180*2000+500);
}
PWM.c
#include "stm32f10x.h" // Device header
void PWM_Init(void){RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE); //開啟APB1的時鐘函數,TIM2在APB1總線中/*開啟時鐘*/RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //開啟GPIOA的時鐘,設置舵機PWM的接口/*GPIO初始化*/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); //選擇時基單元TIM_InternalClockConfig(TIM2);//系統默認是內部時鐘,不寫也可以//配置時基單元TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1; //給輸入的濾波器一個采樣頻率TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;//計數方式TIM_TimeBaseInitStructure.TIM_Period=20000-1;//ARR自動重裝器的值TIM_TimeBaseInitStructure.TIM_Prescaler=72-1;//PSC預分配器的值TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0;//重復計數器的值,我們用的通用寄存器,所以直接寫0就好了TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);TIM_ClearFlag(TIM2,TIM_IT_Update);//初始化輸出比較單元:舵機要求的周期是20ms,則頻率為1/20ms=50Hz,要求高電平時間是0.5-2.5ms//PWM頻率: Freq = CK_PSC / (PSC + 1) / (ARR + 1)//PWM占空比: Duty = CCR / (ARR + 1)//PWM分辨率: Reso = 1 / (ARR + 1)//TIM_OCInitStructure函數有一部分是高級定時器里的,要么就把全部成員拉出來配置,要么就用TIM_OCStructInit先賦一個初始值0TIM_OCInitTypeDef TIM_OCInitStructure;TIM_OCStructInit(&TIM_OCInitStructure);TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;//8種輸出比較模式TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High;//輸出比較極性TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;//輸出使能//因此通過觀察得知,我們需要完成的呼吸燈的變化效果就與CCR的值息息相關,TIM_SetCompare1單獨更改CCR值的函數就有用了TIM_OCInitStructure.TIM_Pulse=0;//就是CCR的值TIM_OC2Init(TIM2, &TIM_OCInitStructure); //通道修改為2,同一個定時器不同的特性:因為不同的通道相位,產生PWM都是一樣的,但是CCR是可以單獨設置的//啟動定時器TIM_Cmd(TIM2, ENABLE);
}
void PWM_set(uint16_t compare){TIM_SetCompare2(TIM2,compare); //修改通道2的CCR
}
6-5 PWM驅動直流電機
main.c
#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(void){OLED_Init();Key_Init();Motor_Init();//Motor_Speed(50);//正轉
// Motor_Speed(-50);//反轉OLED_ShowString(1,1,"Speed:");while(1){Keynum=Key_GetNum();if(Keynum==1){Speed +=20;if(Speed>100){Speed=-100;}}Motor_Speed(Speed);OLED_ShowSignedNum(1,7,Speed,3);}
}Motor.c
#include "stm32f10x.h" // Device header
#include "PWM.h"
void Motor_Init(void){PWM_Init();//需要額外去控制電機的方向控制的兩個腳/*開啟時鐘*/RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //開啟GPIOA的時鐘/*GPIO初始化*/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); //將PA1和PA2引腳初始化為推挽輸出//默認就是低電平,所以不需要對輸出電平進行設置就可以亮燈}void Motor_Speed(int8_t Speed){if(Speed>=0){//設置方向一個為高,一個為低GPIO_SetBits(GPIOA,GPIO_Pin_4);GPIO_ResetBits(GPIOA,GPIO_Pin_5);PWM_set(Speed);}else{GPIO_ResetBits(GPIOA,GPIO_Pin_4);GPIO_SetBits(GPIOA,GPIO_Pin_5);PWM_set(-Speed);}
}