天天看點

STM32 PWM實作呼吸燈

STM32 PWM控制呼吸燈程式(脈沖寬度調制)

PWM工作原理

STM32 PWM實作呼吸燈

ARR:自動預裝載寄存器

CNT:自動裝載計數器

CRR:比較器

圖解:在一個周期t2内,随着計數器(CNT)值的不斷增加,取任一時刻t1,CNT的值與CCR的值進行比較,如果CNT>CCR,則選擇t1-t2時間段為有效電平(具體根據選擇的PWM模式來确定)

通過不斷改變比較器裡的值來與定時計數器的值作比較來實作脈沖寬度的調制,具體結合PWM的模式選擇向上溢出還是向下溢出

幾個關鍵詞解釋:

更新:當計數器裡面的值溢出(上溢或下溢)之後(如果設中斷的話會觸發标志位置一進中斷),計數器會重置重新計數`

占空比:對于呼吸燈而言,即在一個周期内,高電平持續的時間(此處為有效電平,如果高電平有效)

代碼部分及詳解

注意:配置led燈,包括時鐘開關,複用功能等等,關于定時器的配置網上都有成片的代碼,我用的STM32 F103ZET6,将PF6用作呼吸燈,用的是TIM2定時器,主要是在PF6上沒有預設的TIM2的通道,隻能引入一個引腳PA0并輸入可調制的脈沖寬度,然後将一根杜邦線将PF6引腳和PA0引腳相連就OK了,當時在這糾結了好久,思維定勢,總是對PF6進行操作

最後main函數的兩個while循環功能就是不斷地改變比較器裡面的值(這個方法也是在網上找的,隻要達到這個功能就行),延時函數不可忽略,最好用庫函數我是自己寫的,如果沒有延時函數的話效果看不見或者是不明顯,還有注意不需要點燈代碼Setbits()

注:代碼僅僅針對PWM,定時器方面沒做解釋,是以很簡單,很容易幫助了解脈沖寬度調制

void delay(int v)
{
	for( i = 1000;i>0;i--)
		for( j = 1000;j > 1000;j--);
}
void LED_Config(void)
{
        GPIO_InitTypeDef GPIO_InitStructure;
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOF | RCC_APB2Periph_GPIOA,ENABLE);

        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(GPIOA, &GPIO_InitStructure);
	
//		  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;
//        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
//        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
//        GPIO_Init(GPIOA, &GPIO_InitStructure);
}

void Timer_Init(void)
{
        TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
        TIM_OCInitTypeDef TIM_OCInitStructure;
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE); //打開定時器時鐘
        
        //定時器2 設定 360分頻 1KHz 向上計數
        TIM_DeInit(TIM2);
        TIM_TimeBaseStructure.TIM_Period =199;//
        TIM_TimeBaseStructure.TIM_Prescaler =359; //360分頻 即為200KHz,16位的值,最大65536
        TIM_TimeBaseStructure.TIM_ClockDivision =0x00; //時鐘分頻系數,不分頻
        TIM_TimeBaseStructure.TIM_CounterMode =TIM_CounterMode_Up;
        TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); //初始化定時器

        TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //主定時器TIM2為PWM1模式
        TIM_OCInitStructure.TIM_OutputState =TIM_OutputState_Enable;//使能輸出比較狀态
        TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
        //ch1 配置項
        TIM_OCInitStructure.TIM_Pulse = 5;
        TIM_OC1Init(TIM2, & TIM_OCInitStructure); //ch1占空比75%
        TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Enable); //使能的預裝載寄存器

        TIM_ClearFlag(TIM2, TIM_IT_CC1);
        TIM_Cmd(TIM2,ENABLE); //使能定時器2
}
int main()
{
	u16 i;
	LED_Config();
	Timer_Init();
	while (1) 
	{
		i = 0; //i置為0
		
		while (i <= 300) 
		{
			delay(1000);
			//delay_ms(10);
			TIM_SetCompare1(TIM2, i);
			i++;
		}
		
		i = 300; //i置為300
		
		while (i > 0) 
		{
			//delay_ms(10);
			delay(1000);
			TIM_SetCompare1(TIM2, i);
			i--;
		}
	}

}