2017年8月24日 星期四

手持裝置之MCU及周邊裝置省電的設計

在有MCU的手持裝置當中,省電的設計是很重要的一個環節,如何讓整個電池的使用壽命更久變得很重要,由於電池通常都是數十mAH至數百mAH,如何讓消耗電流減低考量的是設計者對程式與硬體的掌握能力,本文將介紹一些基本的概念!

(1)MCU系統頻率別太高,也別太低 : 系統頻率太高,優點是程式執行的速度快,很快就可以完成所設計的工作,但MCU本身一定是耗電的;系統頻率低,缺點是執行速度慢,所設計的工作要執行很久才能完成,也會比較省電!可是為何頻率別太高也別太低?頻率快耗電,頻率慢省電不是很合理嗎?可是必須考量一件事,我們可以適時地將MCU近入Sleep mode並關閉耗電的周邊電源,系統頻率快代表很快完成工作進入睡眠,系統頻率慢代表很慢才能完成工作再能進入睡眠,因此這筆需考量在一秒內工作多久睡眠多久加上周邊關閉多久才能決定的,簡單的方式就是量測平均號電流就可以了!


(2)如何進入睡眠?如何喚醒?
如何進入睡眠模式是個很簡單完成的工作,以Microchip PIC16為例,只要下一個sleep();這樣的巨集指令就可以進入睡眠模式了!
如何喚醒就有很多種方式了,可以是外部中斷喚醒看門狗計時器WDT溢位喚醒、跟系統頻率非同步的Timer1中斷喚醒等等...

外部中斷喚醒 : 將MCU的外部中斷Pin設為輸入,並選擇pull high or pull down,選擇Rising or Falling edge的中斷觸發方式,並清除外部中斷旗標並開啟外部中斷所需相關設定如INTE(INT中斷開關)、GIE(總中斷開關),然後程式中需有中斷服務程式來處理中斷事件,即可進入睡眠等待中斷發生!
中斷服務程式 :  
void interrupt ISR(void)
{
    if(INTE && INTF)
   {
        INTF = 0;
   }
}

外部中斷Initialize :
void Initialize_INT(void)
{
    TRISB0 = 1;                 // Interrupt pin
    OPTION_REGbits.INTEDG = 1;  // Rising edge
    INTCONbits.INTF = 0;
    INTCONbits.INTE = 1;
}

看門計時器WDT溢位喚醒 : Enable WDT,並設定看門狗計時器溢位的時間間隔(Interval),假設為100ms,在睡眠之前先執行CLRWDT();已清除WDT計時器的時間,然後下NOP();及sleep();指令進入睡眠,等100ms時間溢位了就自動會喚醒了!

系統頻率非同步的Timer1中斷喚醒  :  由於PIC16的Timer1可以外接32.768kHz振盪器,並可設定與系統clock非同步,也就是說當進入睡眠時timer1可以繼續計數,等timer溢位之後,就可以發生中斷來喚醒MCU了!



Initialize Timer 1程式 : 
void Initialize_TMR1(void)
{
        TMR1H = (65536 - 82) >> 8;
        TMR1L = (65536 - 82) & 0xff;         // 10ms interval
    
        T1CON = 0b10101100;                
        // LP OSC enable(32.768kHz), Do not synchronize asynchronous    clock input
        TMR1ON = 1;                  
        TMR1IF = 0;
        TMR1IE = 1;
}

中斷服務程式 : 
void interrupt ISR(void)
{
    if(TMR1IE && TMR1IF) // 10ms interval
    {

        TMR1IF = 0; // Clear the flag

        TMR1H = (65536 - 82) >> 8; // Update timer1 high byte

        TMR1L = (65536 - 82) & 0xff;    // Update timer1 low byte
        if(++timertick == 10) //
        {
            timertick = 0;
            FLAGbits.Timer100ms = 1;
        }

    }
}

主程式範例
void main(void)
{
    Initialize_CPU();
    Initialize_TMR1();
    Initialize_INT();
    Initialize_LCD();
    Initialize_ADC();
    PEIE = 1;
    GIE = 1;

    SWDTEN = 1;
 
    while(1)
    { 
if(FLAGbits.Timer100ms)
{
            FLAGbits.Timer100ms = 0;
            ScanBtnEvent();
            MeasureVBAT();
            MainStateMachine();
}
CLRWDT();
NOP();
SLEEP();
NOP();
    } 
    return;
}

(3)睡眠前須先將供電的周邊耗電的裝置必須關閉,並將IO port設定到不耗電的狀態!


二維陣列指標的表示方法