//——————————软串口

    1. #include "public.h"
    2. //引脚定义(外部需设定端口方向及上拉状态)
    3. #define pSTX RC2
    4. #define pSRX RC1
    5. //引脚初始化
    6. #define SRX_Init() {TRISC1=1; WPUC1=1;} //输入, 上拉
    7. #define STX_Init() {TRISC2=0; RC2=1;} //输出, 高电平
    8. //---------------------------------------- 声明为外部变量
    9. extern uint8_t SRXREG; //接收寄存器
    10. extern bit _srxdone; //接受寄存器有数据标志
    11. extern uint8_t STXREG; //发送数据寄存器
    12. extern bit _stxdone; //发送寄存器为空标志
    13. //软串口物理层初始化
    14. void suart_phyinit();
    15. //软串口物理层驱动, 仅中断调用(根据需要调整速率-调用时间)
    16. void suart_phydriver();
    1. //软件模拟串口收发通信协议
    2. uint8_t rCNTrec; //接收进入计数
    3. uint8_t rSEQreceive;//接收bit步骤
    4. uint8_t rCNTreceive;//接收bit计数
    5. uint8_t SRXPREG; //接收前端寄存器(数据首先保存在此处, 接收完成一个直接后再赋值到SRXREG)
    6. uint8_t SRXREG; //接收寄存器
    7. bit _srxdone; //接受寄存器有数据标志
    8. //发送部分
    9. uint8_t sCntisr; //发送进入计数
    10. uint8_t sSEQsend; //发送bit步骤
    11. uint8_t sCntSend; //发送bit计数
    12. uint8_t STXREG; //发送数据寄存器
    13. bit _stxdone; //发送寄存器为空标志
    14. //软串口物理层初始化
    15. void suart_phyinit()
    16. {
    17. //发送
    18. sCntisr = 0;
    19. sSEQsend = 0;
    20. sCntSend = 0;
    21. STXREG = 0;
    22. _stxdone = 1; //为1表示发送寄存器为空
    23. //接收
    24. rCNTrec = 0;
    25. rSEQreceive = 0;
    26. rCNTreceive = 0;
    27. SRXPREG = 0;
    28. SRXREG = 0;
    29. _srxdone = 0; //为0表示接收寄存器无数据
    30. }
    31. //软串口物理层驱动, 中断调用(根据需要调整速率)
    32. void suart_phydriver()
    33. {
    34. ///////////////////////串口发送物理层驱动///////////////////////////////
    35. //3个计数周期进入一次
    36. if(++sCntisr >= 3)
    37. {
    38. sCntisr = 0;
    39. //发送寄存器为空, 不进行下一步
    40. if(!_srxdone)
    41. {
    42. switch(sSEQsend)
    43. {
    44. // 起始位0:1bit
    45. case 0:
    46. pSTX = 0;
    47. sSEQsend = 1;
    48. sCntSend = 0;
    49. break;
    50. // 数据位SEND
    51. case 1:
    52. //低位先发送
    53. if(STXREG & 0x01) { pSTX = 1; }
    54. else { pSTX = 0; }
    55. STXREG >>= 1;
    56. if((++sCntSend) >= 8)
    57. {
    58. sCntSend = 0;
    59. sSEQsend = 2;
    60. }
    61. break;
    62. // 停止位(1bit)
    63. case 2:
    64. pSTX = 1;
    65. sSEQsend = 0;
    66. _srxdone = 1;
    67. break;
    68. default:
    69. pSTX = 1; //拉高电平
    70. sSEQsend = 0; //发送状态回归初始
    71. _srxdone = 1; //
    72. break;
    73. }
    74. }
    75. }
    76. //////////////////////串口接收物理层驱动///////////////////////////////
    77. switch(rSEQreceive)
    78. {
    79. // 起始位bit0
    80. case 0:
    81. if(pSRX == 0) // 收到起始位bit0
    82. {
    83. rSEQreceive = 1;
    84. rCNTrec = 0;
    85. SRXPREG = 0;
    86. }
    87. break;
    88. // 8bits_bit1数据
    89. case 1:
    90. if(++rCNTrec == 4) // 第一次进来时为4个周期,提升容错率
    91. { // 其它时机进来为3个周期,保持同步性
    92. rCNTrec = 1;
    93. if(pSRX == 1)
    94. {
    95. SRXPREG |= 0x80;
    96. }
    97. SRXPREG >>= 1;
    98. rCNTreceive++;
    99. if(rCNTreceive >= 8)
    100. {
    101. rCNTreceive = 0;
    102. rCNTrec = 0;
    103. rSEQreceive = 2;
    104. }
    105. }
    106. break;
    107. //结束
    108. case 2:
    109. _srxdone = 1;
    110. SRXREG = SRXPREG; //前端寄存器数据拷贝到后端寄存器
    111. SRXPREG = 0;
    112. rSEQreceive = 0;
    113. break;
    114. }
    115. }

    ——————————-主板

    ////////////////////////////connect main board///////////////////////////////
    /*
    灯板->主板
        1.控制命令
        2.滤芯寿命
        3.滤芯1寿命百分比
        4.滤芯2寿命百分比
    
    主板->灯板
        1.设备状态(高压开关、废水阀、进水阀、增压泵)
        2.工作状态
        3.wifi
        4.故障
    */
    #define         MB_SENDLEN  8
    #define         MB_RECVLEN  8
    
    typedef struct{
    ////////////////////// 发送 ///////////////////////////////////
        uint8_t     SendBuf[MB_SENDLEN];
        uint8_t     SendCnt;        //等待发送数据长度
    
    ////////////////////// 接收 ///////////////////////////////////
        uint8_t     RecvBuf[MD_RECVLEN];
        uint8_t     RecvCnt;        //接收数据长度
    }main_board_t;
    
    
    main_board_t    g_mBoard;
    T_BYTE          mBoardF;
    //#define     bRecvFrameDone  mBoardF.bit.b0  //接收完成一帧标志
    
    void mainboard_Init()
    {  
        //端口初始化
        SRX_Init();
        STX_Init();
    
        suart_phyinit();
    }
    
    
    //主板通讯
    void main_board_isr()
    {
    //------------------- 发送
        if(_stxdone)
        {
            if(g_mBoard.SendCnt > 1)
            {
                g_mBoard.SendCnt--;
                STXREG = g_mBoard.SendBuf[MB_SENDLEN - g_mBoard.SendCnt];
                _stxdone = 0;
            }
        }
    
    
    //------------------- 接收
        if(_srxdone)
        {
            if(g_mBoard.RecvCnt < MB_RECVLEN)
            {
                g_mBoard.RecvBuf[g_mBoard.RecvCnt] = SRXREG;
                _srxdone = 0;
    
                g_mBoard.RecvCnt++;
            }
        }
    }
    
    static uint8_t getCheckSum(uint8_t *ptr, uint8_t len)
    {
        uint8_t chk = 0;
    
        while(len)
        {
            chk += *ptr;
            ptr++;
            len--;
        }
    
        return chk;
    }
    
    
    void main_board_Process()
    {
        uint8_t x;
    
        //等待上电系统稳定
        if(!bpowerOn)
            return;
    
    //------------------------------------- 接收处理
        if(g_mBoard.RecvCnt >= MB_RECVLEN)
        {
    
            if(g_mBoard.RecvBuf[MB_RECVLEN-1] == getCheckSum(g_mBoard.RecvBuf,(MB_RECVLEN-1)))
            {
                //校验正确, 表示通讯过程数据传输正确
    
                //判断起始码是否正确, 正确开始解码数据
                if(g_mBoard.RecvBuf[0] == 0xa5)
                {
                    mDeviceStF.byte = g_mBoard.RecvBuf[1];
                    mWorkMode       = g_mBoard.RecvBuf[2];
                    mWifiSt         = g_mBoard.RecvBuf[3];
                    mError          = g_mBoard.RecvBuf[4];
                }
            }
            else
            {
                //否则传输错误, 故障计数
            }
    
            g_mBoard.RecvCnt = 0;
        }
    
    //------------------------------------- 发送数据处理
        if(g_mBoard.SendCnt == 0)
        {
            for(x=0; x<MB_SENDLEN; x++)
            {
                g_mBoard.SendBuf[x] = 0;
            }
    
            g_mBoard.SendBuf[0] = 0xa5;
    
            g_mBoard.SendBuf[1] = dCtrlCmd.byte;
            g_mBoard.SendBuf[2] = dFilterF.byte;
            g_mBoard.SendBuf[3] = gFilter.PP_work.wPercent;
            g_mBoard.SendBuf[4] = gFilter.RO_work.wPercent;
    
            g_mBoard.SendBuf[MB_SENDLEN-1] = getCheckSum(g_mBoard.SendBuf, MB_SENDLEN-1);
    
            g_mBoard.SendCnt = MB_SENDLEN;
        }
    }
    
    /*
    引脚描述
        01. SEG3/AN3/TK3/RA3                    --    
        02. T0CKI/SEG4/AN4/TK4/RA4                --    BUZ
        03. SEG8/AN8/TK8/RB0                    --    LED1
        04.    INT/SEG9/AN9/TK9/RB1                --    LED2
        05.    SEG10/AN10/TK10/RB2                    --    LED3
        06.    CCP1/RX1/DT1/AN11/TK11/RB3            --    LED4
        07.    T1G/CCP2/TX1/CK1/AN12/TK12/RB4        --    LED5
        08.    T1CKI/AN13/TK13/RB5                    --    LED6
        09.    GND
        10.    VDD
        11.    RD2/TK15/AN15                        --    K1
        12.    RD1/TK24/AN24/TX0/CK0/SCL/ICSPDAT    --    
        13.    RD0/TK25/AN25/RX0/DT0/SDA/ICSPCLK    --
        14.    RC3/TK20/AN20/COM3
        15.    RC2/TK21/AN21/COM2                    --    DA  //TX
        16.    RC1/TK22/AN22/COM1                    --    CK  //RX
        17.    RC0/TK23/AN23/COM0
        18.    RA0/TK0/AN0/SEG0
        19.    RA1/TK1/AN1/SEG1
        20.    RA1/TK1/AN1/SEG1
    */
    
    extern      volatile T_BYTE      mainRunF;
    #define     b250usFlgg  mainRunF.bit.b0
    #define     b1msFlgg    mainRunF.bit.b1
    #define     b4msFlag    mainRunF.bit.b2
    
    //------------------------------------------------------ 接收主板信息的解码数据
    //byte1
    extern      T_BYTE      mDeviceStF;  //主板检测设备状态
    #define     bSwitch_High    mDeviceStF.bit.b0   //高压开关, 接通(启动)低电平, 断开(停止)高电平
    #define     bValve_Waste    mDeviceStF.bit.b1   //废水阀
    #define     bValve_Inlet    mDeviceStF.bit.b2   //进水阀
    #define     bPump_Booster   mDeviceStF.bit.b3   //增压泵
    //byte2
    extern      uint8_t     mWorkMode;      //工作状态,0-待机,1-制水,2-冲洗
    //byte3
    extern      uint8_t     mWifiSt;        //wifi状态
    //byte4
    extern      uint8_t     mError;         //故障
    //byte5, byte6 预留
    
    //------------------------------------------------------ 发送主板数据
    //byte1
    extern      T_BYTE      dCtrlCmd;
    #define     bWashing    dCtrlCmd.bit.b0     //冲洗
    #define     bEntrReset  dCtrlCmd.bit.b1     //进入复位操作
    #define     bSelcFilter dCtrlCmd.bit.b2     //选择滤芯
    #define     bReset      dCtrlCmd.bit.b3     //复位滤芯
    #define     bFastCheck  dCtrlCmd.bit.b4     //进入快检模式
    //byte2
    extern      T_BYTE      dFilterF;
    #define     bPPLifeDone dFilterF.bit.b0     //PP滤芯寿命到达
    #define     bROLifeDone dFilterF.bit.b1     //RO滤芯寿命到达
    #define     bFilterFast dFilterF.bit.b2     //滤芯快检没送
    #define     bFilterSets dFilterF.bit.b3     //滤芯寿命设置中
    //byte3
    //gFilter.PP_work.wPercent                  //PP滤芯寿命百分比
    //byte4
    //gFilter.RO_work.wPercent                  //RO滤芯寿命百分比
    //byte5, byte6预留
    
    
    #include <cms.h>
    
    /*******************************************************
                        系统操作
    ********************************************************/
    #define     EGI()       (GIE=1)
    #define     DGI()       (GIE=0)
    #define     clrwdt()    asm("CLRWDT")
    #define     nop()       asm("NOP")
    
    /*******************************************************
                        类型定义
    ********************************************************/
    // 基本类型定义
    #if 1
    typedef   signed            char int8_t;
    typedef   signed short      int int16_t;
    typedef   signed            long  int32_t;
    
    typedef unsigned            char uint8_t;
    typedef unsigned short      int  uint16_t;
    typedef unsigned              long uint32_t;
    
    typedef int32_t  s32;
    typedef int16_t  s16;
    typedef int8_t   s8;
    
    typedef uint32_t  u32;
    typedef uint16_t  u16;
    typedef uint8_t   u8;
    
    typedef uint8_t     uchar;
    #endif
    
    //可取位类型
    typedef union{
        uint8_t byte;
        struct bit{
            uint8_t b0:1; 
            uint8_t b1:1; 
            uint8_t b2:1; 
            uint8_t b3:1;
            uint8_t b4:1; 
            uint8_t b5:1; 
            uint8_t b6:1;
            uint8_t b7:1;
        }bit;
    }T_BYTE;
    //字长类型
    typedef union{
        uint16_t word;
        uint8_t byte[2];
    }uWORD;
    
    /*******************************************************
                        宏定义
    ********************************************************/
    #define TRUE                1
    #define FALSE               0
    #define ON                  1
    #define OFF                 0
    
    /*******************************************************
                        位定义
    ********************************************************/
    #define    Set(x,y)    ((x) |= (1 << (y)))                //位置1
    #define    Clr(x,y)    ((x) &= ~ (1 << (y)))            //位清0
    
    #define    b0(x,y)        (((x) & (1 << (y))) == 0)        //位0判断 if(b0(x,y)) 判断是否为0
    #define    b1(x,y)        ((x) & (1 << (y)))                //位1判断 if(b1(x,y)) 判断是否为1
    
    /*******************************************************
                        高低字节定义
    ********************************************************/
    #define HBYTE( v1 )          ( (uint8_t)((v1) >> 8) )
    #define LBYTE( v1 )          ( (uint8_t)((v1) & 0xFF) )
    
    
    /*******************************************************/
    

    tkey

    /////////////////////////////////////触摸按键//////////////////////////////////////
    
    //variable
    TKEY_T      gtkey;
    
    /**********************************************************
    函数名称: tkeyProc()
    函数功能: 按键处理
    入口参数: 无
    出口参数: 按键事件-event 
    备    注: 4MS
    **********************************************************/
    uint8_t tkeyProc()
    {
        //filter
        if(gtkey.Map != READ_TKEY())
        {
            if((++gtkey.Debounce) >= DEBOUNCE_TICK)
            {            
                gtkey.Map   = READ_TKEY();
                gtkey.Debounce = 0;
            }
        }
        else
        {
            gtkey.Debounce = 0;
        }
    
        //tick count
        if(gtkey.State > 0)  gtkey.Tick++;
    
        //tkey state machine
        switch(gtkey.State)
        {
            case 0:
                //初始->按下, 超时->完全释放(重置)
                if(gtkey.Map != NO_TKEY)
                {                    
                    gtkey.Tick  = 0;
                    gtkey.State = 1;
                }
                else
                {
                    gtkey.Tick  = 0;
                    gtkey.Event = NO_EVE;
                }
            break;
            case 1:
                //按下->松手(释放), 按下->长按
                if(gtkey.Map == NO_TKEY)
                {
                    gtkey.Tick = 0;
                    gtkey.Event = EVE_CLICK;
                    gtkey.State = 2;
                }
                else if(gtkey.Tick >= KTICK_200MS)
                {
                    gtkey.Tick = 0;
                    //gtkey.Event = EVE_CLICK;
                    gtkey.State = 4;
                }
            break;
            case 2:
                //松手->按下(连按), 松手->超时完全释放
                if(gtkey.Map != NO_TKEY)
                {
                    gtkey.Tick  = 0;
                    gtkey.State = 3;
                }
                else if(gtkey.Tick >= KTICK_200MS)
                {
                    gtkey.Tick   = 0;
                    gtkey.Event  = EVE_NO;                    
                    gtkey.State  = 0;
                }
            break;
            case 3:
                //按下(连按)->松手(释放), 按下(连按)->按下超时->强制释放
                if(gtkey.Map == NO_TKEY)
                {
                    gtkey.Tick = 0;
                    gtkey.Event = EVE_REPEAT;
                    gtkey.State = 2;
                }
                else if(gtkey.Tick >= KTICK_200MS)
                {
                    gtkey.Tick       = 0;
                    gtkey.Event      = EVE_NO;                    
                    gtkey.State      = 0;
                }
            break;
            case 4:
                //长按->响应, 长按->松手(释放)
                if(gtkey.Map != NO_TKEY)
                {
                    if(gtkey.Tick == KTICK_3S)
                    {
                        //3s触发一次
                        gtkey.Event = EVE_HOLD;
                    }
                }
                else
                {
                    gtkey.State = 0;
                    gtkey.Tick = 0;
                }
            break;
            default:
                gtkey.State = 0;
                gtkey.Tick = 0;
            break;
        }   //end of switch(gtkey.State)
    
        //返回事件
        return gtkey.Event;
    }   //end of tkeyProc()
    
    /////////////////////////////////////触摸按键//////////////////////////////////////
    
    #ifndef __TKEY_H
    #define __TKEY_H
    
    ///////////////////////// include head file //////////////////////////////
    #include    "typedef.h"
    #include    "Touch_Kscan_Library.h"
    
    
    ///////////////////////// operater define //////////////////////////////
    #define     READ_TKEY()         (_CMS_KeyFlag[0] & 0x01)   //bit0
    
    
    ///////////////////////// constant define //////////////////////////////
    //4ms
    #define     KTICK_200MS         50
    #define     KTICK_3S            750
    #define     DEBOUNCE_TICK       10   //40ms, 抖动时间
    #define     NO_TKEY             0
    
    
    ///////////////////////// type define //////////////////////////////
    //事件
    enum e_EVE{
        EVE_NO      = 0x00,
        EVE_CLICK   = 0x01,     //短按松手、开始进入长按
        EVE_REPEAT  = 0x02,     //连按(重复)
        EVE_HOLD    = 0x10,     //长按(接触保持)
    };
    //type
    typedef struct{
        uint8_t Event;
        uint8_t Map;
    
        uint8_t State;
        uint8_t Debounce;
        uint8_t Tick;
    }TKEY_T;
    
    
    /**********************************************************
    函数名称: tkeyProc()
    函数功能: 按键处理
    入口参数: 无
    出口参数: 按键事件-event 
    备    注: 4MS
    **********************************************************/
    uint8_t tkeyProc();
    
    #endif
    

    isr

    #include "public.h"
    
    
    volatile    T_BYTE  mainRunF;
    
    
    volatile uint8_t gRun1msCnt;
    
    /***********************************************************************
    函数功能:中断入口函数
    ***********************************************************************/
    void interrupt isr()
    {
        //定时器2中断, 125us
        if(TMR2IF)
        {
            TMR2IF = 0;
    
            b250usFlgg = ~b250usFlgg;
    
            if(b250usFlgg)
            {
                if(++gRun1msCnt >= 4)
                {
                    gRun1msCnt = 0;
                    b1msFlgg = 1;
                }
            }
            else
            {
                //低电压检测
                #ifdef USE_LVD_MD
                if(isLowVolt())
                {
                    //计算持续时间
                    if(glvdCnt < 255) 
                        glvdCnt++;
                }
                else
                {
                    //计数清零
                    glvdCnt = 0;
                }
                #endif
    
                //软串口驱动
                suart_phydriver();
                //主板通讯驱动
                main_board_isr();
            }
    
            //获取触摸键值, 扫描时间125us
            __CMS_GetTouchKeyValue();
    
            //蜂鸣器输出
            #ifdef BUZZER_EN
                BUZ_OUT();
            #endif
        }
    #ifdef  LVD_INT_EN
        else 
        if(LVDIF)
        {
            //掉电标志
            LVDIF = 0;  //
        }
    #endif
        else
        {
            PIR1 = 0;
            PIR2 = 0;
        }
    }
    

    filter

    #include    "filter.h"
    
    //-----------------滤芯
    typedef struct{
        //滤芯1-PPC滤芯(PP棉+碳棒)
        filter_work_life_t PP_work;
    //    filter_use_life_t  PP_use;
    
        //滤芯2-RO滤芯(反渗透膜)
        filter_work_life_t RO_work;
    //    filter_use_life_t RO_use;
    
        //标志
    }filter_t;
    
    ///////////////////////variable define/////////////////////////
    filter_t    gFilter;    //滤芯对象
    T_BYTE        filterF;    //滤芯标志
    
    
    //pp滤芯工作计时
    void PP_Work_Count(uint8_t cnt)
    {
        if(!PP_LIFE_DONE)   //寿命未到达
            {
            gFilter.PP_work.wLife += cnt;
            if(gFilter.PP_work.wLife >= PP_WORK_LIFE)
                {
                PP_LIFE_DONE = 1;
                gFilter.PP_work.wPercent = 0;
            }
            else
            {
                gFilter.PP_work.wPercent = (uint8_t)(gFilter.PP_work.wLife / PP_WORK_LIFE);
            }
        }
    }
    //RO滤芯计数函数
    void RO_Work_Count(uint8_t cnt)
    {
        if(!RO_LIFE_DONE)   //寿命未到达
            {
            gFilter.RO_work.wLife += cnt;
            if(gFilter.RO_work.wLife >= RO_WORK_LIFE)
                {
                RO_LIFE_DONE = 1;
                gFilter.RO_work.wPercent = 0;
            }
            else
            {
                gFilter.RO_work.wPercent = (uint8_t)(gFilter.RO_work.wLife / RO_WORK_LIFE);
            }
        }
    }
    
    #if 0
    uint8_t PP_Filter_CheckSum()
    {
        uint8_t checksum;
    
        checksum = (uint8_t)( HBYTE(gFilter.PP_work.wLife)
                            +LBYTE(gFilter.PP_work.wLife)
                            +HBYTE(gFilter.PP_work.wMinCnt)
                            +LBYTE(gFilter.PP_work.wMinCnt) );
    
       return checksum;
    }
    
    uint8_t RO_Filter_CheckSum()
    {
        uint8_t checksum;
    
        checksum = (uint8_t)( HBYTE(gFilter.RO_work.wLife)
                            +LBYTE(gFilter.RO_work.wLife)
                            +HBYTE(gFilter.RO_work.wMinCnt)
                            +LBYTE(gFilter.RO_work.wMinCnt) );
    
       return checksum;
    }
    #endif
    
    
    void filter_Init()  //初次上电
    {
        gFilter.PP_work.wLife = 0;
        gFilter.PP_work.wLifeSave = 0;
        gFilter.PP_work.wMinCnt = 0;
        gFilter.PP_work.wPercent = 100; //滤芯初始寿命百分百
    
        gFilter.RO_work.wLife = 0;
        gFilter.RO_work.wLifeSave = 0;
        gFilter.RO_work.wMinCnt = 0;
        gFilter.RO_work.wPercent = 100; //滤芯初始寿命百分百
    
    //清除标志
        filterF.byte = 0;
    }
    
    //滤芯寿命处理函数
    void filter_Process()   //500ms
    {
        //-----------------------------------使用寿命
        //预留
    
        //-----------------------------------工作寿命
        if(bPump_Booster)       //增压泵开启
        {
            gFilter.PP_work.wMinCnt++;
            gFilter.RO_work.wMinCnt++;
        }
        //快检
        if(FILTER_FAST)
        {
            //快检按1s代表1h计算, 0.5s代表30分钟
            //每次进入, +30
            PP_Work_Count(30);
            RO_Work_Count(30);
        }
        else
        if(gFilter.PP_work.wMinCnt >= COUNT_ONE_MIN)
        {
            //一分钟进入, +1
            PP_Work_Count(1);
            RO_Work_Count(1);
        }
    }
    
    //滤芯复位, 0-PP滤芯
    void filter_Reset(uint8_t type)
    {
        //PP滤芯
        if(0==type)
        {
            gFilter.PP_work.wLife = 0;
            gFilter.PP_work.wLifeSave = 0;
            gFilter.PP_work.wMinCnt = 0;
            gFilter.PP_work.wPercent = 100; //滤芯初始寿命百分百
    
            PP_LIFE_DONE = 0;
    
            //更新记忆数据
            //PP_Filter_Save(); 
            //仅掉电记忆数据
        }
        //RO滤芯
        else
        {
            gFilter.RO_work.wLife = 0;
            gFilter.RO_work.wLifeSave = 0;
            gFilter.RO_work.wMinCnt = 0;
            gFilter.RO_work.wPercent = 100; //滤芯初始寿命百分百
    
            RO_LIFE_DONE = 0;
    
            //更新记忆数据
           // RO_Filter_Save();
        }
    }
    
    
    //滤芯进入快检模式
    void filter_entr_FastCheck()
    {
        //进入快检
        FILTER_FAST = 1;
    
        //备份当前寿命
        gFilter.PP_work.wLifeSave = gFilter.PP_work.wLife;
        gFilter.RO_work.wLifeSave = gFilter.RO_work.wLife;
    }
    
    //滤芯退出快检模式
    //滤芯快检寿命到达
        //1. 报警指示完毕后
        //2. 报警指示中按键
    //机器断电
    void filter_exit_FastCheck()
    {
        //退出快检
        FILTER_FAST = 0;
    
        //恢复进入快检前寿命
        gFilter.PP_work.wLife = gFilter.PP_work.wLifeSave;
        gFilter.RO_work.wLife = gFilter.RO_work.wLifeSave;
    
        //检查快检期间增加使用的寿命
        while(gFilter.PP_work.wMinCnt >= COUNT_ONE_MIN)
        {
            gFilter.PP_work.wMinCnt -= COUNT_ONE_MIN;        
            gFilter.PP_work.wLife += 1;
        }
        if(gFilter.RO_work.wMinCnt >= COUNT_ONE_MIN)
        {
            gFilter.RO_work.wMinCnt -= COUNT_ONE_MIN;
            gFilter.RO_work.wLife += 1;
        }
    
        //清除滤芯寿命到达标志
        PP_LIFE_DONE = 0;
        RO_LIFE_DONE = 0;
    }
    
    
    //保存数据
    void filter_Save()
    {
    //------------------------------------------------------------------------------------
        ////////////////PP滤芯////////////////////
    //工作寿命
        eeprom_Write(EEP_ADDR_PP_WLIFE_H, HBYTE(gFilter.PP_work.wLife));
        eeprom_Write(EEP_ADDR_PP_WLIFE_L, LBYTE(gFilter.PP_work.wLife));
        eeprom_Write(EEP_ADDR_PP_WMIN_H, HBYTE(gFilter.PP_work.wMinCnt));
        eeprom_Write(EEP_ADDR_PP_WMIN_L, LBYTE(gFilter.PP_work.wMinCnt));
    //百分比
        eeprom_Write(EADR_PP_PERCENT, gFilter.PP_work.wPercent);
    
    //------------------------------------------------------------------------------------
        ////////////////PP滤芯////////////////////
    //工作寿命
        eeprom_Write(EEP_ADDR_RO_WLIFE_H, HBYTE(gFilter.RO_work.wLife));
        eeprom_Write(EEP_ADDR_RO_WLIFE_L, LBYTE(gFilter.RO_work.wLife));
        eeprom_Write(EEP_ADDR_RO_WMIN_H, HBYTE(gFilter.RO_work.wMinCnt));
        eeprom_Write(EEP_ADDR_RO_WMIN_L, LBYTE(gFilter.RO_work.wMinCnt));
    //百分比
        eeprom_Write(EADR_RO_PERCENT, gFilter.RO_work.wPercent);
    
    }
    
    //记忆恢复
    void filter_Memory()
    {
        uint8_t x, y;
    //------------------------------------------------------------------------------------
        ////////////////PP滤芯////////////////////
    //工作寿命
        x = eeprom_Read(EEP_ADDR_PP_WLIFE_H);
        y = eeprom_Read(EEP_ADDR_PP_WLIFE_L);
        gFilter.PP_work.wLife = (uint16_t)((x<<8) + y);
        if(0xffff == (gFilter.PP_work.wLife & 0xffff))          //读取数据全为1, 认为数据错误
            gFilter.PP_work.wLife = 0;
    //工作寿命分钟
        x = eeprom_Read(EEP_ADDR_PP_WMIN_H);
        y = eeprom_Read(EEP_ADDR_PP_WMIN_L);
        gFilter.PP_work.wMinCnt = (uint16_t)((x<<8) + y);
        if(0xffff == (gFilter.PP_work.wMinCnt & 0xffff))
            gFilter.PP_work.wMinCnt = 0;
    //百分比
        gFilter.PP_work.wPercent = eeprom_Read(EADR_PP_PERCENT);
        if(0xff == (gFilter.PP_work.wPercent & 0xff))
            gFilter.PP_work.wPercent = 0;
    
    //------------------------------------------------------------------------------------
        ////////////////PP滤芯////////////////////
    //工作寿命
        x = eeprom_Read(EEP_ADDR_RO_WLIFE_H);
        y = eeprom_Read(EEP_ADDR_RO_WLIFE_H);
        gFilter.RO_work.wLife = (uint16_t)((x<<8) + y);
        if(0xffff == (gFilter.RO_work.wLife & 0xffff))          //读取数据全为1, 认为数据错误
            gFilter.RO_work.wLife = 0;
    //工作寿命分钟
        x = eeprom_Read(EEP_ADDR_RO_WMIN_H);
        y = eeprom_Read(EEP_ADDR_RO_WMIN_L);
        gFilter.RO_work.wMinCnt = (uint16_t)((x<<8) + y);
        if(0xffff == (gFilter.RO_work.wMinCnt & 0xffff))
            gFilter.RO_work.wMinCnt = 0;
    
    //百分比
        gFilter.RO_work.wPercent = eeprom_Read(EADR_RO_PERCENT);
        if(0xff == (gFilter.RO_work.wPercent & 0xff))
            gFilter.RO_work.wPercent = 0;    
    }
    
    #ifndef     __FILTER_H
    #define     __FILTER_H
    
    #include    "typedef.h"
    
    //-------------------------工作寿命(制水或泵工作时间计数)
    typedef struct{
        uint16_t    wLife;      //工作寿命(分钟)
        uint16_t    wLifeSave;  //备份
        uint16_t    wMinCnt;    //分钟计数
        uint8_t     wPercent;   //寿命百分比
    }filter_work_life_t;
    
    //-------------------------使用寿命(机器通电时间计数)
    typedef struct{
        uint16_t    uLife;      //使用寿命(小时)
        uint16_t    uLifeSave;  //备份
        uint16_t    uHourCnt;   //小时计数
        uint8_t     uPercent;   //使用寿命百分比
    }filter_use_life_t;
    
    
    //滤芯1-PPC滤芯(PP棉+碳棒)
    #define     PP_WORK_LIFE        3000    //50小时, 50*60=3000分钟
    #define     PP_USE_LIFE         8640    //12个月, 12*30*24=8640小时
    //滤芯2-RO滤芯(反渗透膜)
    #define     RO_WORK_LIFE        7200    //120小时, 120*60=7200分钟
    #define     RO_USE_LIFE         43200   //60个月, 60*30*24=43200小时
    
    
    //counter
    #define     COUNT_ONE_HOUR      7200    //1H=60*60=3600s 3600/(0.5s)=7200
    #define     COUNT_ONE_MIN       120     //1M=60s 0.5s计数120
    
    //save in eeprom
    #define     EEP_CODE_START        0xa5
    
    #define     EEP_ADDR_START        0
    //PP
    //工作寿命
    #define     EEP_ADDR_PP_WLIFE_H   1
    #define     EEP_ADDR_PP_WLIFE_L   2
    #define     EEP_ADDR_PP_WMIN_H    3
    #define     EEP_ADDR_PP_WMIN_L    4
    //使用寿命
    #define     EEP_ADDR_PP_ULIFE_H   5
    #define     EEP_ADDR_PP_ULIFE_L   6
    #define     EEP_ADDR_PP_UHOUR_H   7
    #define     EEP_ADDR_PP_UHOUR_L   8
    //RO
    //工作寿命
    #define     EEP_ADDR_RO_WLIFE_H   9
    #define     EEP_ADDR_RO_WLIFE_L   10
    #define     EEP_ADDR_RO_WMIN_H    11
    #define     EEP_ADDR_RO_WMIN_L    12
    //使用寿命
    #define     EEP_ADDR_RO_ULIFE_H   13
    #define     EEP_ADDR_RO_ULIFE_L   14
    #define     EEP_ADDR_RO_UHOUR_H   15
    #define     EEP_ADDR_RO_UHOUR_L   16
    //校验
    #define     EEP_ADDR_PP_CHECK     17
    #define     EEP_ADDR_RO_CHECK     18
    
    //百分比
    #define     EADR_PP_PERCENT       19
    #define     EADR_RO_PERCENT       20
    
    //variable declear
    extern  filter_t    gFilter;    //滤芯对象
    extern  T_BYTE        filterF;    //滤芯标志
    //------------------
    #define    RO_LIFE_DONE    filterF.bit.b0        //RO寿命到达
    #define    PP_LIFE_DONE    filterF.bit.b1        //PP寿命到达
    #define    FILTER_FAST        filterF.bit.b2        //快检
    //#define    RO_LIFE_SAVE    filterF.bit.b3      //RO寿命记忆更新
    //#define    PP_LIFE_SAVE    filterF.bit.b4      //PP寿命记忆更新
    #define    FILTER_WORKING    filterF.bit.b5      //滤芯工作中(增压泵开启中)
    #define    RO_LIFE_RESET    filterF.bit.b6      //RO滤芯复位
    #define    PP_LIFE_RESET    filterF.bit.b7      //PP滤芯复位
    
    
    #endif
    

    mcu

    #include    "cms79f_mcu.h"
    
    //mcu操作
    
    void mcu_init()
    {
       //禁止中断
        INTCON = 0x00;
       //外设中断请求寄存器
        PIR1 = 0;
        PIR2 = 0;
       //外设中断允许寄存器
        PIE1 = 0;
        PIE2 = 0;
    
        //设置系统时钟
        OPTION_REG = 0;     //预分频器分配给 TIMER0 模块
        OSCCON = 0x61;      //振荡器控制, Fsys=Fosc/2=8MHz
    
        //看门狗
        WDTCON = 0x01;      //使能定时器, 18ms
        clrwdt();
    
        //GPIO
        PORTA = 0x00;
        PORTB = 0x00;
        PORTC = 0x00;
        PORTD = 0x00;
    
        TRISA = 0x00;
        TRISB = 0x00;
        TRISC = 0x00;
        //CMS79FT73x/CMS79F73x系列芯片使用触摸功能时RD2口需作为输出口
        //TRISD = 0x00;
        TRISD = 0x03;
    
        WPUA  = 0x00;
        WPUB  = 0x00;
        WPUC  = 0x00;
        WPUD  = 0x00;
    
        IOCB  = 0x00;
    
    #ifdef USE_ADC_MD
        //ADC
        ADCON0 = 0x01;  //使能ADC
        ADCON1 = 0x00;  //数据左对齐, 12bit
        ADIE   = 0;
    #endif
    
    #ifdef USE_TMR2_MD
        //timer2
        TMR2   = 0;
        T2CON  = T2_CTL_SET;    //使能TMR2, 预分频1:1, 后分频1:2
        PR2    = T2_COUNT;      //125us
        TMR2IE = 1;             //使能TMR2中断
    #endif
    
        //低电压检测
    #ifdef  USE_LVD_MD
        LVDCON = LVD_SET_VAL;   //设置掉电检测电压
    //不中断, 检测LVD_RES标志
    //    LVDIE = 1;              //允许LVD中断, 中断中检测LVDIF标志位
    #endif
    
        PEIE   = 1;
    }
    
    void mcu_refrush(void)
    {
        //asm("clrwdt");
        WDTCON = 0x01;
    
        OPTION_REG = 0;
    
        PR2 = T2_COUNT;
        if(T2_CTL_SET != T2CON)
            T2CON = T2_CTL_SET;
    
    //    INTCON = 0XC0;
    
    //系统时钟
        OSCCON = 0x61;
    }
    
    
    
    #ifdef USE_ADC_MD
        //作为ADC结果临时存储区
        uint16_t AD_DATA;
    
        /**********************************************************
        函数名称: ad_Convert()
        函数功能: 开始AD转换
        入口参数: frq-ADC时钟, ch-转换通道
        出口参数: 无 
        备    注: Analog-to-digital conversion
        **********************************************************/
        uint8_t ad_Convert(unsigned char frq, unsigned char ch)
        {
            uint16_t wt;
    
            ADCON0 = (frq<<6) | (ch&0x07 << 2) | (AD_EN<<0);
            if(ch & 0x08)
                ADCON1 |= (1<<6);
    
            wt = 0x0fff;
            clrwdt();
    
            nop(); nop();
            GODONE = 1;
            while(GODONE)
            {
                nop();
                if(0 == (--wt))
                    return 0;
            }
            AD_DATA = (uint16_t)((ADRESH + ADRESL)>>4);
            return 1;
        }
    #endif
    
    
    #ifdef USE_EEPROM_MD
        /***********************************************
        函数名称: eeprom_Write
        函数功能:写数据寄存器
        入口参数:Addr - 写入地址
                  Value - 写入数值
        出口参数:返回值 0 - 写未准备好 1 - 写完毕
        备注:
        ************************************************/
        unsigned char eeprom_Write(unsigned char Addr,unsigned char Value)
        {
            static volatile bit B_GIE_On;
            static volatile unsigned char i = 0;
    
            if(WR)                                    //写还没有结束直接返回
                return 0;
    
            B_GIE_On = 0;                            //记录进来前是否已经开启中断
            if(GIE)
                B_GIE_On = 1;
    
            //将要写入的地址放入EEADDR寄存器
            EEADR = Addr;
            EEDAT= Value;                           //将要写入的数据给EEPROM的数据寄存器
            EEPGD = 0;                                //访问数据存储器
    
            WREN = 1;                                //允许写周期
            GIE = 0;                                //关闭中断
    
            while(GIE)
            {
                GIE = 0;                            //确保中断已关闭
                if(0 == --i)
                    return 0;
            }
    
            EECON2 = 0x55;                            //给EECON2写入0x55
            EECON2 = 0xaa;                            //给EECON2写入0xaa
            WR = 1;                                    //启动写周期
            asm("nop");
            asm("nop");
    
            if(B_GIE_On)                            //若原来已开启中断的就开启中断    
                GIE = 1;                                                    
    
            WREN = 0;                                //禁止写入
            return 1;
        }
    
        /***********************************************
        函数名称: eeprom_Read
        函数功能:读数据寄存器
        入口参数:Addr - 读取地址
        出口参数:返回读取地址相应数值
        备注:
        ************************************************/
        unsigned char eeprom_Read(unsigned char Addr)
        {            
            //将要写入的地址放入EEADDR寄存器
            EEADR = Addr;
            EEPGD = 0;                            //访问数据存储器
    
            RD=1;                                //允许读操作
            asm("nop");
            asm("nop");
    
            return EEDAT;
        }
    #endif
    
    
    #ifdef  USE_LVD_MD
        enum e_D_VOLT{
            LVD_2V2 = 0,
            LVD_2V4,
            LVD_2V7,
            LVD_3V0,
            LVD_3V3,
            LVD_3V7,
            LVD_4V0,
            LVD_4V3,
        };
        enum e_D_LV_EN{
            D_LVOLT_EN = 1,
            D_LVOLT_DIS = 0,
        };
    
    //当 LVD 模块使能后,需要延时 1ms 的时间才能够读取 LVD_RES 位,
    //因为内部做了滤波处理,以减少在 VLVD 电压值附近时,LVD 输出结果的频繁波动。
        #define     LVD_SET_VAL ((LVD_4V0<<1) | (D_LVOLT_EN<<0))
    
        #define     isLowVolt()  {LVD_RES}
    
        #define     setLVDisr()     (LVDIE = 1)
    
    //LVD 模块有自己的中断标志位,
    //当设定好相关的中断使能位,电源电压低于设定的电压值时,会产生 LVD中断,
    //中断标志位 LVDIF 将被置 1,中断产生。
    #endif
    
    #ifndef __CMS79F_MCU_H
    #define __CMS79F_MCU_H
    
    #include    "typedef.h"
    
    //是否使用ADC模块
    //#define     USE_ADC_MD
    #define       USE_TMR2_MD
    #define       USE_EEPROM_MD
    #define       USE_LVD_MD    //低电压检测
    
    
    #ifdef  USE_TMR2_MD 
    //TMR2时钟源为系统时钟的四分之一
        enum e_TMR2_OPS{
            T2_OPS_1 = 0,
            T2_OPS_2,
            T2_OPS_3,
            T2_OPS_4,
            T2_OPS_5,
            T2_OPS_6,
            T2_OPS_7,
            T2_OPS_8,
            T2_OPS_9,
            T2_OPS_10,
            T2_OPS_11,
            T2_OPS_12,
            T2_OPS_13,
            T2_OPS_14,
            T2_OPS_15,
            T2_OPS_16,
        };
        enum e_TMR2_ON{
            T2_ON = 1,
            T2_OFF = 0,
        };
        enum e_TMR2_CPS{
            T2_CPS_1 = 0,
            T2_CPS_4,
            T2_CPS_16,
        };
    
        #define     T2_OUTPS(n)     (n<<3)  //后分频
        #define     T2_SET_ON(n)    (n<<2)  //使能
        #define     T2_CKPS(n)      (n<<0)  //预分频
    
        //系统时钟16M, T2时钟4M, 预分频1/4得到1MHz
        #define     T2_CTL_SET  T2_OUTPS(T2_OPS_1) | T2_SET_ON(T2_ON) | T2_CKPS(T2_CPS_4)
        #define     T2_COUNT    125     //125us
    #endif
    
    #ifdef USE_ADC_MD
        //ADC时钟
        enum e_AD_FOSC{
            FOSC_8  = 0,
            FOSC_16 = 1,
            FOSC_32 = 2,
            FOSC_RC = 3
        };
        enum e_AN_SEL{
            AD_AN0 = 0,
            AD_AN1 = 1,
            AD_AN2 = 2,
            AD_AN3 = 3,
            AD_AN4 = 4,
            AD_AN5 = 5,
            AD_AN6 = 6,
            AD_AN7 = 7,
            AD_AN8 = 8,
            AD_AN9 = 9,
            AD_AN10 = 10,
            AD_AN11 = 11,
            AD_AN12 = 12,
            AD_AN13 = 13,
            AD_AN14 = 14,
            AD_AN15 = 15,
            AD_AN16 = 16,
            AD_AN17 = 17,
            AD_AN18 = 18,
            AD_AN19 = 19,
            AD_AN20 = 20,
            AD_AN21 = 21,
            AD_AN22 = 22,
            AD_AN23 = 23,
            AD_AN24 = 24,
            AD_AN25 = 25,
            AD_AN_1V2 = 26, //1.2V固定参考看呀
        };
        //ADC使能
        enum e_ADEN{
            AD_DIS  = 0,
            AD_EN   = 1,
        };
        //ADC结果
        #define     AD_12BIT_DAT()      
        #define     AD_8BIT_DAT()       (uchar)(ADRESH)
    
        //临时结果区
        extern uint16_t AD_DATA;
        /**********************************************************
        函数名称: ad_Convert()
        函数功能: 开始AD转换
        入口参数: frq-ADC时钟, ch-转换通道
        出口参数: 无 
        备    注: Analog-to-digital conversion
        **********************************************************/
        uint8_t ad_Convert(unsigned char frq, unsigned char ch);
    
    #endif
    
    #ifdef USE_EEPROM_MD
        /***********************************************
        函数名称: eeprom_Write
        函数功能:写数据寄存器
        入口参数:Addr - 写入地址
                  Value - 写入数值
        出口参数:返回值 0 - 写未准备好 1 - 写完毕
        备注:
        ************************************************/
        unsigned char eeprom_Write(unsigned char Addr,unsigned char Value);
    
        /***********************************************
        函数名称: eeprom_Read
        函数功能:读数据寄存器
        入口参数:Addr - 读取地址
        出口参数:返回读取地址相应数值
        备注:
        ************************************************/
        unsigned char eeprom_Read(unsigned char Addr);
    #endif
    
    #endif
    

    main.c

    /***********************************************************************
    方案说明:
    ***********************************************************************/
    /**********************************************************************/
    /*修改说明*/
    
    /**********************************************************************/
    /**********************************************************************/
    /**********************************************************************/
    /*头文件*/
    #include    <cms.h>
    #include    "public.h"
    #include    "delay.h"
    #include    "Touch_Kscan_Library.h"
    /**********************************************************************/
    /*全局变量声明*/
    /**********************************************************************/
    
    /**********************************************************************/
    
    /***********************************************
    函数名称:system_init
    函数功能:系统初始化
    入口参数:无
    出口参数:无
    备注:
    ************************************************/
    void system_init()
    {
        clrwdt();
        EGI();
    
        //芯片初始化
        mcu_init();
        Delay_nms(200); //初始化MCU后延时200ms等待系统稳定
    
        //设备初始化
        //device_init();
        //////////////蜂鸣器////////////////////
        #ifdef  BUZZER_EN
            BUZ_INIT();
            bBuzOnOff = 0;
        #endif
    
        //应用初始化
        //app_init();
    
        //使能总中断
        DGI();
    }
    
    
    uint8_t gRun20msCnt;
    uint8_t gRun100msCnt;
    uint8_t gRun500msCnt;
    
    
    /***********************************************************************
    main主函数
    ***********************************************************************/
    void main(void)
    {
        /////////////////////////////////系统初始化/////////////////////////////////
        system_init();
    
        /////////////////////////////////大循环/////////////////////////////////    
        while(1)
        {
            clrwdt();
    
            //4ms基准
            if(b1msFlgg)
            {
                b1msFlgg = 0;
    
    
                if(++gRun4msCnt >= 4)
                {
                    gRun4msCnt = 0;
    
                    __CMS_CheckTouchKey();    //扫描按键, 4ms
                    input_Process();
                }
                else if(gRun4msCnt == 1)
                {
                    //
                }
    
                //20ms基准
    
                //100ms基准
    
                //500ms基准
            }
    
        }/////////////////the end while(1)//////////////////////
    }
    /**********************************************************************/
    
    
    uint8_t glvdCnt;    //lvd标志计数
    bit     blvdVerify; //低电压确认
    void lvd_Store()    //4ms
    {
        if(glvdCnt >= 4)    //持续检测到一段时间低电压, 认为拔掉了电源(掉电)
        {
            glvdCnt = 0;
            if(!blvdVerify)
            {
                blvdVerify = 1;
                if(FILTER_FAST)
                {
                    filter_exit_FastCheck();
                }
    
                PP_Filter_Save();
                RO_Filter_Save();
                filter_Save();
            }
        }
    }
    
    //上电恢复记忆
    void power_on_Restor()
    {
        if(EEP_CODE_START != eeprom_Read(EEP_ADDR_START))
        {
            //初次上电
            eeprom_Write(EEP_ADDR_START, EEP_CODE_START);
    
            filter_Init();
        }
        else
        {
            filter_Memory();
        }
    }
    
    //输入处理
    void input_Process()
    {
        uint8_t event;
        event = tkeyProc();
    
        switch()
    }
    
    //---------------------------- 电压状态
    uint8_t     gPowerOnCnt;
    T_BYTE      powerF;
    #define     bpowerOn        powerF.bit.b0       //上电延时等待系统稳定后确认
    #define     bpowerOn2s      powerF.bit.b1       //上电2s
    #define     bpowerOn10s     powerF.bit.b2       //上电10s
    
    void power_Process()    //100ms
    {
        if(gPowerOnCnt<255) gPowerOnCnt++;
    
        if(!bpowerOn)
        {
            if(gPowerOnCnt >= 2)
            {
                bpowerOn = 1;
            }
        }
        else if(!bpowerOn2s)
        {
            if(gPowerOnCnt >= 20)
            {
                bpowerOn2s = 1;
            }
        }
        else if(!bpowerOn10s)
        {
            if(gPowerOnCnt >= 100)
            {
                bpowerOn10s = 1;
            }
        }
    }