微控制器應用——PWM輸出(一)
按下三路按鍵,MCU喚醒且三路PWM有輸出(佔空比30%),鬆開按鍵PWM無輸出,且MCU進入休眠狀態(低功耗狀態)。按鍵1按下,PWM1輸出,按鍵2按鍵3按下,PWM2/PWM3輸出
具體源程式如下所示
8位微控制器專案合作請聯絡我:18665321219
/* ========================================================================= * Project: GPIO_Setting * File: main.c * Description: Set GPIO of PORTB * 1. PORTB I/O state * - PB4 set input mode and enable pull-high resistor * - PB2 set output mode * - PB1 set input mode and enable pull-low resistor * - PB0 set open-drain output mode * * Author: JasonLee * Version: V1.1 * Date: 2018/09/07 =========================================================================
*/ #include <ny8.h> /* ========================================================================= * Project: GPIO_Setting * File: main.c * Description: Set GPIO of PORTB * 1. PORTB I/O state * - PB4 set input mode and enable pull-high resistor * - PB2 set output mode * - PB1 set input mode and enable pull-low resistor * - PB0 set open-drain output mode * * Author: JasonLee * Version: V1.1 * Date: 2018/09/07 =========================================================================*/ #include "ny8_constant.h" #include <stdint.h> #define UPDATE_REG(x) __asm__("MOVR _" #x ",F") struct pwmflg { uint8_t pwm1en : 1; uint8_t pwm2en : 1; uint8_t pwm3en : 1; }pwmflg; uint8_t sleepcent; uint8_t pwmdcycle; //計數1000為一個週期 uint8_t pwmduty1; uint8_t pwmduty2; uint8_t pwmduty3; uint8_t pwmduty1s; uint8_t pwmduty2s; uint8_t pwmduty3s;void peripinit(void) { // ;Initial GPIO // ; PORTB I/O state // ; PB0、PB1、PB2 set output mode and enable pull-high resister // ;BPHCON = (uint8_t) ~( C_PB1_PHB | C_PB0_PHB | C_PB2_PHB ); // Enable PB0、PB1、PB2 Pull-High Resistor,others disable BPLCON = (uint8_t) ~( C_PB3_PLB ); //Enable PB3 Pull-low Resistor,others disable IOSTB = (uint8_t) ((~( C_PB1_Input | C_PB2_Input | C_PB0_Input )) | C_PB3_Input | C_PB4_Input | C_PB5_Input); // Set PB0、PB1、PB2 to output mode,Set PB3、PB4、PB5 to output mode PORTB = 0x00; //初始化為0 BWUCON = C_PB5_Wakeup | C_PB4_Wakeup | C_PB3_Wakeup; //使能PB5、PB4、PB3按鍵喚醒 INTE = INTE | C_INT_PBKey; //使能按鍵喚醒中斷 //;Initial time1 // ; instrclk i_hrc 4/4M div = 1 計數8次溢位即可 // ; TMRH = 0X20 TMR1 = 0x70; //到0下溢位中斷,計數100 //20M/2/100 = 100K T1CR1 = C_TMR1_Reload | C_TMR1_En; //自動過載 T1CR2 = C_TMR1_ClkSrc_Inst | C_PS1_Dis ; //指令時鐘 INTE = INTE | C_INT_TMR1; //使能定時器中斷 INTF = 0; //清除中斷標誌 OSCCR = C_FHOSC_Sel; //喚醒後進入正常模式 } //儘量減小中斷程式碼時長 void isr_hw(void) __interrupt(0) { if(INTFbits.T1IF) { pwmdcycle++; if(pwmdcycle == 0x3) //週期10 { PORTBbits.PB2 = 0; PORTBbits.PB1 = 0; PORTBbits.PB0 = 0; pwmduty1s = pwmduty1; //按鍵按下時賦值0x3,按鍵鬆開賦值0xf(不可能執行) pwmduty2s = pwmduty2; // pwmduty3s = pwmduty3; pwmdcycle = 0; } if(pwmdcycle == pwmduty1s) //佔空比3 { PORTBbits.PB0 = 1; } if(pwmdcycle == pwmduty2s) //佔空比3 { PORTBbits.PB1 = 1; } if(pwmdcycle == pwmduty3s) //佔空比3 { PORTBbits.PB2 = 1; } INTFbits.T1IF = 0; //寫在if語句防止意外清除標誌位 } if(INTFbits.PBIF) //清除按鍵中斷標誌 { INTFbits.PBIF = 0; } } void delayms(uint8_t ms) //CLK_20M/IN_2T = 10M,MS = 100,延時61ms { uint8_t i = 0xff; while(ms--) { while(i--); } } void main(void) //main()函數週期11us { pwmflg.pwm1en = 0; pwmflg.pwm2en = 0; pwmflg.pwm3en = 0; pwmduty1s = 0; pwmduty2s = 0; pwmduty3s = 0; pwmdcycle = 0; pwmduty1 = 0xf; pwmduty2 = 0xf; pwmduty3 = 0xf; sleepcent = 0; DISI(); peripinit(); ENI(); while(1) { CLRWDT(); //PB3狀態檢測 if((PORTBbits.PB3 == 1)&&(pwmflg.pwm1en == 0)) { delayms(50); //估計在10ms左右 if(PORTBbits.PB3 == 1) { pwmduty1 = 2; //佔空比為25% pwmflg.pwm1en = 1; } else { pwmduty1 = 0xf; //佔空比為就是不執行 } } else if(PORTBbits.PB3 == 0) { pwmduty1 = 0xf; //佔空比為就是不執行 pwmflg.pwm1en = 0; } //PB4狀態檢測 if((PORTBbits.PB4 == 1)&&(pwmflg.pwm2en == 0)) { delayms(50); //估計在10ms左右 if(PORTBbits.PB4 == 1) { pwmduty2 = 2; //佔空比為25% pwmflg.pwm2en = 1; } else { pwmduty2 = 0xf; //佔空比為就是不執行 } } else if(PORTBbits.PB4 == 0) { pwmduty2 = 0xf; //佔空比為就是不執行 pwmflg.pwm2en = 0; } //PB5狀態檢測 if((PORTBbits.PB5 == 1)&&(pwmflg.pwm3en == 0)) { delayms(50); //估計在10ms左右 if(PORTBbits.PB5 == 1) { pwmduty3 = 2; //佔空比為30% pwmflg.pwm3en = 1; } else { pwmduty3 = 0xf; //佔空比為就是不執行 } } else if(PORTBbits.PB5 == 0) { pwmduty3 = 0xf; //佔空比為就是不執行 pwmflg.pwm3en = 0; } //休眠檢測 if(((PORTB & 0x38) == 0x00) && ((PORTB & 0x07) == 0x00)) //PB5、PB4、PB3輸入低(無效),PB0、PB1、PB2輸出低(無效) { sleepcent++; //累加100次 if(sleepcent == 100) { PCON = PCON & (~ C_WDT_En);//關閉看門狗定時器 SLEEP();//進入睡眠模式 DISI();//關閉中斷,喚醒後直接執行下一條指令 PCON = PCON | C_WDT_En;//開啟看門狗定時器 ENI();//開啟中斷 } //delayms(100); //估計在10ms左右 } else { sleepcent = 0; } } }