采用定時(shí)器2的通道2,使PA1輸出頻率1K,占空比40的PWM波形,用PA8隨意延時(shí)取反led燈,指示程序運(yùn)行
上午花了半天時(shí)間熟悉了stm32的PWM模塊。中午利用午飯時(shí)間把PWM功能調(diào)試成功。當(dāng)然,很簡(jiǎn)單的東西,也許很多前輩估計(jì)都不屑一顧的東西。
今天最大的感嘆就是網(wǎng)絡(luò)資源實(shí)在是個(gè)巨大的寶庫,真的很慶幸,在這個(gè)復(fù)雜的社會(huì)環(huán)境里,在一個(gè)到處充斥著私心、私利的時(shí)代,各個(gè)網(wǎng)站,各個(gè)論壇上的眾多網(wǎng)友都時(shí)刻保持著開源的氛圍。學(xué)習(xí)一定要和他人交流,而網(wǎng)絡(luò)提供了這么一個(gè)極好的平臺(tái)。
廢話少說,言歸正傳。
實(shí)現(xiàn)功能:采用定時(shí)器2的通道2,使PA1輸出頻率1K,占空比40的PWM波形,用PA8隨意延時(shí)取反led燈,指示程序運(yùn)行。
首先熟悉一下定時(shí)器的PWM相關(guān)部分。看圖最明白
其實(shí)PWM就是定時(shí)器的一個(gè)比較功能而已。
CNT里的值不斷++,一旦加到與CCRX寄存器值相等,那么就產(chǎn)生相應(yīng)的動(dòng)作。這點(diǎn)和AVR單片機(jī)很類似。既然這樣,我們要產(chǎn)生需要的PWM信號(hào),就需要設(shè)定PWM的頻率和PWM的占空比。
首先說頻率的確定。由于通用定時(shí)器的時(shí)鐘來源是PCLK1,而我又喜歡用固件庫的默認(rèn)設(shè)置,那么定時(shí)器的時(shí)鐘頻率就這樣來確定了,如下:
AHB(72MHz)→APB1分頻器(默認(rèn)2)→APB1時(shí)鐘信號(hào)(36MHz)→倍頻器(*2倍)→通用定時(shí)器時(shí)鐘信號(hào)(72MHz)。
這里為什么是這樣,在RCC模塊學(xué)習(xí)記錄里有詳細(xì)記載,不多說。
因此圖中的CK_PSC就是72MHz了。
下面的資料也是網(wǎng)上一搜一大把,我就羅列了:
STM32的PWM輸出有兩種模式,模式1(PWM1)和模式2(PWM2),由TIMx_CCMRx寄存器中的OCxM位確定的(“110”為模式1,“111”為模式2)。模式1和模式2的區(qū)別如下:
110:PWM模式1-在向上計(jì)數(shù)時(shí),一旦TIMx_CNT=TIMx_CCR1時(shí)通道1為無效電平(OC1REF=0),否則為有效電平(OC1REF=1)。
111:PWM模式2-在向上計(jì)數(shù)時(shí),一旦TIMx_CNT=TIMx_CCR1時(shí)通道1為有效電平,否則為無效電平。
由此看來,模式1和模式2正好互補(bǔ),互為相反,所以在運(yùn)用起來差別也并不太大。我用的是模式一,因此后面的設(shè)定都是按照模式一來設(shè)定的。
PWM的周期是就是由定時(shí)器的自動(dòng)重裝值和CNT計(jì)數(shù)頻率決定的。而CNT的計(jì)數(shù)時(shí)鐘是CK_PSC經(jīng)分頻器PSC得到,因此CNT的時(shí)鐘就是CK_PSC/分頻系數(shù)。這個(gè)分頻系數(shù)在TIM_TimeBaseStructure.TIM_Prescaler確定。成都網(wǎng)站設(shè)計(jì)我設(shè)置的值是72,因此CNT的計(jì)數(shù)頻率也就是CK_CNT的頻率為1MHz。
下一步就是確定定時(shí)器自動(dòng)重裝值。因?yàn)镃NT每自加到ARR寄存器的值時(shí)就會(huì)自動(dòng)清零,當(dāng)然前提是設(shè)定為為向上計(jì)數(shù)模式,而就是根據(jù)這個(gè)溢出事件來改變PWM的周期。所以PWM信號(hào)的頻率由ARR的值來確定。我設(shè)置的值是1000-1,即TIM_TimeBaseStructure.TIM_Period = 1000-1;因此PWM的周期是1MHz/1000=1KHz。
接下來就要確定PWM的占空比了。因?yàn)镃NT在自加到ARR值的過程中會(huì)不斷和CRRX的值相比較,一旦二者相等就產(chǎn)生匹配事件,但要注意CNT不會(huì)理會(huì)這件事,它會(huì)繼續(xù)++直到等于ARR。而CRRX的值我設(shè)定為400-1,那么占空比就隨之確定為40%。
好了,下面就是庫函數(shù)的配置了。
TIMER輸出PWM實(shí)現(xiàn)步驟
1.設(shè)置RCC時(shí)鐘;
2.設(shè)置GPIO;
3.設(shè)置TIMx定時(shí)器的相關(guān)寄存器;
4.設(shè)置TIMx定時(shí)器的PWM相關(guān)寄存器。
首先是main函數(shù)和全局變量申明,很簡(jiǎn)單,不作說明
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TimOCInitStructure;
int main(void)
{
rcc_cfg();
gpio_cfg();
tim2_cfg();
pwm_cfg();
//
while (1)
{
GPIO_WriteBit(GPIOA, GPIO_Pin_8, Bit_SET);
delay();
GPIO_WriteBit(GPIOA, GPIO_Pin_8, Bit_RESET);
delay();
}
}
下面是IO口的配置:
void gpio_cfg()
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
此處要注意的是PWM輸出口要配置為復(fù)用推挽輸出,原因我也不知道,反正照搬就是了。
下面是TIM配置函數(shù),注釋很清楚了,不作說明:
void tim2_cfg()
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
TIM_DeInit(TIM2);
TIM_InternalClockConfig(TIM2);
//預(yù)分頻系數(shù)為72,這樣計(jì)數(shù)器時(shí)鐘為72MHz/72 = 1MHz
TIM_TimeBaseStructure.TIM_Prescaler = 72;
//設(shè)置時(shí)鐘分割
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
//設(shè)置計(jì)數(shù)器模式為向上計(jì)數(shù)模式
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
//設(shè)置計(jì)數(shù)溢出大小,每計(jì)1000個(gè)數(shù)就產(chǎn)生一個(gè)更新事件
TIM_TimeBaseStructure.TIM_Period = 1000-1;
//將配置應(yīng)用到TIM2中
TIM_TimeBaseInit(TIM2,&TIM_TimeBaseStructure);
//禁止ARR預(yù)裝載緩沖器
TIM_ARRPreloadConfig(TIM2, DISABLE);
TIM_Cmd(TIM2, ENABLE);//使能TIMx外設(shè)
}
接下來是關(guān)鍵的PWM的配置函數(shù):
void pwm_cfg()
{
//設(shè)置缺省值
TIM_OCStructInit(&TimOCInitStructure);
//PWM模式1輸出
TimOCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
//設(shè)置占空比,占空比=(CCRx/ARR)*100%或(TIM_Pulse/TIM_Period)*100%
TimOCInitStructure.TIM_Pulse = 400-1;
//TIM輸出比較極性高
TimOCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
//使能輸出狀態(tài)
TimOCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
//TIM2的CH2輸出
TIM_OC2Init(TIM2, &TimOCInitStructure);
//設(shè)置TIM2的PWM輸出為使能
TIM_CtrlPWMOutputs(TIM2,ENABLE);
}
stm32固件庫的輸出比較單元結(jié)構(gòu)體與定時(shí)器的時(shí)基單元是分開定義的,而PWM模式只是輸出比較結(jié)構(gòu)體成員TimOCInitStructure.TIM_OCMode的一個(gè)取值,當(dāng)把此結(jié)構(gòu)體填充完后,還要映射到某個(gè)定時(shí)器,用TIM_OCXInit函數(shù)實(shí)現(xiàn),我用了一個(gè)X,說明不止一個(gè)這樣的函數(shù),事實(shí)上,stm32的通用定時(shí)器都有四個(gè)通道,每個(gè)通道對(duì)應(yīng)一個(gè)初始化函數(shù),這里真夠糾結(jié)的!最后還要使能該定時(shí)器的PWM輸出功能,TIM_CtrlPWMOutputs(TIM2,ENABLE)函數(shù)要注意,是outputs而不是output,說明TIM2不止一個(gè)通道嘛!夠復(fù)雜,夠繁瑣的!
下面是輸出比較單元的結(jié)構(gòu)體原型:
typedef struct
{
uint16_t TIM_OCMode;
uint16_t TIM_OutputState;
uint16_t TIM_OutputNState;
uint16_t TIM_Pulse;
uint16_t TIM_OCPolarity;
uint16_t TIM_OCNPolarity;
uint16_t TIM_OCIdleState;
uint16_t TIM_OCNIdleState;
} TIM_OCInitTypeDef;
其中沒有加色的成員是高級(jí)定時(shí)器才有的,通用定時(shí)器就不用管了。
這里還有個(gè)TimOCInitStructure.TIM_OCPolarity成員需要注意,它有什么作用呢?在網(wǎng)上查的資料,如下圖:
前面說到pwm有pwm1和pwm2兩種模式,這兩種模式只能控制到OCXREF為止,TIM_OCPolarity 能控制OC1是直接等于OCXREF,還是取反極性!OC1才是最終的PWM信號(hào)。
這里有個(gè)小插曲,我用示波器去測(cè)量PWM信號(hào),發(fā)現(xiàn)信號(hào)居然是雙極性的,然后改變TIM_OCPolarity ,再測(cè),還是雙極性,只是倒了個(gè)跟頭。還真以為stm32單片機(jī)能輸出兩極性的PWM,后面把示波器改為直流檔(之前用的是交流檔),波形才從零電位一下縱向移上去。以后要注意!
-
STM32
+關(guān)注
關(guān)注
2270文章
10895瀏覽量
355731
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論