CM3計算板RTC鬧鐘喚醒系統

1、前言

一個週期性控制系統的核心爲CM3計算板,在電池供電情況下要求儘可能提高使用時長。由於系統空閒時長較多,因此在考慮低功耗的情況下將系統關機以進一步降低功耗。需要注意的是,系統關機後需要在指定時間喚醒,繼續執行相關任務,這涉及到如何喚醒系統。

系統關機很容易用代碼實現功能,一旦關機系統的服務都掛掉,如何保留開機任務?需要藉助系統外圍設計。

可以進一步抽象該需求,如何定時開機。目前我的設計比較暴力,其一,開機方式通過重置CM3計算板的Reset (RUN)引腳加以實現;其二,定時方式通過外部RTC時鐘芯片進行設置,且RTC時鐘芯片可以設置鬧鐘,產生硬件中斷等電平觸發跳變。

2、硬件

根據前面的描述,硬件連接示意圖如下所示。詳細電路連接不在此處羅列,以下介紹設計的要求。

  • CM3:提供一組I2C接口用於設置外部RTC
  • RTC:電池供電的實時時鐘芯片,用I2C進行通信,具有鬧鐘功能,能產生鬧鐘中斷
  • MCU:識別RTC鬧鐘中斷信號,輸出CM3系統復位信號。

具體地,選用的RTC爲DS3231,該RTC的芯片資料可以在這裏查看,邏輯框圖大概就是這麼回事。

本例的MCU作用很單一,檢測RTC中斷,並復位CM3。所以可以用很簡單的單片機,比如51單片機都可以,我這裏用的是SOP8封裝的STC15W104單片機,STC單片機,你懂得。單片機採用中斷還是電平檢測都可以,這是由於DS3231產生鬧鐘中斷後,INT管腳在沒有被清除鬧鐘之前一直保持低電平,這很重要。

當然,如果不想對MCU單片機編程,也可以用其他邊沿觸發電路來代替MCU,比如採用JK觸發器實現下降沿的捕獲,再配合其他的硬件電路產生一個CM3復位電平即可。CM3的復位管腳Run爲電平復位,拉低然後保持一點時間,再鬆開即可完成復位重啓。如下圖。

其他需要說明的,在採用MCU方式輸出CM3復位信號的方案下,通常不要用MCU管腳直接連接CM3的復位系統,做一次信號隔離和驅動以保證兩個系統的耦合性,例如,可以採用以下三極管驅動的方式。SYS_RST爲MCU輸出的信號,注意,此處需要MCU拉電流,因此配置MCU的相關管腳爲強輸出,即推輓輸出以保證足夠的驅動能力。

3、軟件

3.1 DS3231驅動軟件

DS3231採用標準I2C接口,Linux環境下在Github找到了現成的驅動rtcctl[點擊鏈接]。使用起來非常方便,簡單介紹使用方法。

(1) 下載

github地址: https://github.com/bablokb/pi-wake-on-rtc

(2)  安裝

cd pi-wake-on-rtc //進入下載的文件夾內
sudo tools/install //執行安裝腳本

(3)  使用

命令爲rtcctl,詳細的命令參數如下所示:

Available commands (date and time are synonyms):
     help                                - dump list of available commands
     init                                - initialize RTC
     show  [date|time|alarm1|alarm2|sys]
                                         - display given type or all
     dump  [control|status|alarm1|alarm1]
                                         - display registers (hex/binary format)
     set   date|time|alarm1|alarm2|sys   - set date/time, alarm1, alarm2 times
                                           Format: dd.mm.YYYY [HH:MM[:SS]] or
                                                   mm/dd.YYYY [HH:MM[:SS]]
                                           (does not turn alarm on!)
     on    alarm1|alarm2                 - turn alarm1/alarm2 on
     off   alarm1|alarm2                 - turn alarm1/alarm2 off
     clear alarm1|alarm2                 - clear alarm1/alarm2-flag

****注意1,該腳本使用的I2C默認掛接到I2C1,需要在系統中提前打開I2C接口,用i2cdetect 識別一下是否存在ID爲68的設備。

****注意2,該腳本部分爲window環境下編輯,如果執行命令報錯,且提示存在"\r\n"錯誤,需要將該格式全部換成linux下的文件,可以參考這篇博文

rtcctl命令使用起來很簡單,如下:

/* rtcctl 初始化 */
rtcctl init
/* rtcctl 查看系統時間 */
rtcctl show sys
/* rtcctl 查看鬧鐘1信息 */
rtcctl show alarm1
/* rtcctl 啓用鬧鐘1 */
rtcctl on alarm1
/* rtcctl 清除鬧鐘1 */
rtcctl clear alarm1
/* rtcctl 設置鬧鐘1時間 2019/06/01 15:30:00 鬧鐘產生中斷*/
rtcctl set 06/01/2019 15:30:00

3.2 MCU軟件

MCU主要檢測RTC鬧鐘中斷,RTC鬧鐘產生中斷後如果不清除則一直保持低電平狀態。簡單寫的一個邊沿識別程序如下:

void main()
{
    uint16_t Alarm1_tick = 0;
    uint8_t isSYSRstWorked = 0;
    uint8_t Alarm_reg0 = 0;
    uint8_t Alarm_reg1 = 0;
    
    /*! I/O configure */
    P3M1 = 0x00;
    P3M0 = 0x0C;
    
    SYS_RST_Out = 0;//init pin state
    
    while(1){
 
        delay_ms(1);//systick

        /*!  handle RTC wake up alarm1  */
        if(isSYSRstWorked == 0){
            Alarm_reg1 = Alarm_reg0;
            Alarm_reg0 = RTC_Alarm1_In;
            /*! check RTC alarm1 fall-edge */
            if((!Alarm_reg0) && Alarm_reg1 == 1){
                isSYSRstWorked = 1;
            }
        }
        else{
            Alarm1_tick++;
            /* ___________|-----|_____________ */
            if(Alarm1_tick < 2000) SYS_RST_Out = 1;
            else{
                Alarm1_tick = 0;
                SYS_RST_Out = 0;
                isSYSRstWorked = 0;
            }
        }
    }
}

可見,只要MCU識別到一個下降沿,就會產生一個CM3復位脈衝,脈衝寬度爲2s,經過測試,可以實現CM3復位重啓,達到定時開機的要求了。

3.3 CM3執行邏輯

RTC和MCU的外設配置完成後,需要在CM3編寫執行邏輯。首先CM3開機後執行清除RTC鬧鐘(# rtcctl clear alarm1),或者直接對RTC進行初始化(# rtcctl init),其次執行正常監控管理任務,最後在關機之前設置下一次需要喚醒的RTC鬧鐘時間,推薦採用絕對時間方式,即計算重啓時間到1970年1月1日(epoch·time)過了多少秒,再將重啓時間的秒數轉換爲rtcctl命令的時間戳 mm/dd/yyyy HH:MM:SS,即可。

4、最後

總的來說,這個方案容易想到,實現起來也不復雜,簡單的外設即可搞定。多謝github作者的rtcctl源碼,學習了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章