找回密码
 立即注册
查看: 1025|回复: 9

STC8H4K64TL主时钟停振省电模式唤醒:触摸按键唤醒 + 串口接收引脚唤醒 + 外部中断唤

[复制链接]
  • TA的每日心情
    奋斗
    5 小时前
  • 签到天数: 127 天

    [LV.7]常住居民III

    26

    主题

    1281

    回帖

    3985

    积分

    论坛元老

    积分
    3985
    发表于 2023-10-12 19:01:10 | 显示全部楼层 |阅读模式
    STC8H4K64TL主时钟停振省电模式唤醒
    ===触摸按键唤醒 + 串口接收引脚等触发休眠唤醒 + 外部中断唤醒 + 定时器外部时钟输入脚唤醒

    截图202310121900284463.jpg

    附件是参考例程


    STC8H4K64Txx-触摸按键校验检测例程-低功耗-外部唤醒.zip

    20.15 KB, 下载次数: 80

    回复 送花

    使用道具 举报

  • TA的每日心情
    奋斗
    5 小时前
  • 签到天数: 127 天

    [LV.7]常住居民III

    26

    主题

    1281

    回帖

    3985

    积分

    论坛元老

    积分
    3985
     楼主| 发表于 2023-10-13 14:05:42 | 显示全部楼层
    STC8H4K64TL【主时钟停振省电模式】唤醒
    对比了部分不行的代码(启动触摸按键唤醒,外部中断唤醒却不行了)
    ===发现在进【主时钟停振省电模式】之前需要


    进休眠之前关闭TSGO,休眠唤醒后再开启
    截图202310131403334990.jpg
    这样在使能触摸按键休眠唤醒功能情况下,
    也可以支持串口接收引脚等触发休眠唤醒、外部中断唤醒、定时器外部时钟输入脚等其它脚位唤醒。
    回复 支持 反对 送花

    使用道具 举报

    该用户从未签到

    0

    主题

    2

    回帖

    20

    积分

    新手上路

    积分
    20
    发表于 2023-10-13 15:40:52 | 显示全部楼层
    说明书中,配置TSWAIT为0是错误的!如果配置为0,触摸可以唤醒,其他就唤醒不了!
    回复 支持 反对 送花

    使用道具 举报

  • TA的每日心情
    奋斗
    5 小时前
  • 签到天数: 127 天

    [LV.7]常住居民III

    26

    主题

    1281

    回帖

    3985

    积分

    论坛元老

    积分
    3985
     楼主| 发表于 2023-10-13 15:56:15 | 显示全部楼层
    szjacky 发表于 2023-10-13 15:40
    说明书中,配置TSWAIT为0是错误的!如果配置为0,触摸可以唤醒,其他就唤醒不了! ...

    实测跟TSWAIT没有关系
    只要做到进休眠之前关闭TSGO,休眠唤醒后再开启,TSWAIT不管设0还是1都可以。
    回复 支持 反对 送花

    使用道具 举报

    该用户从未签到

    550

    主题

    9235

    回帖

    1万

    积分

    管理员

    积分
    13946
    发表于 2023-10-13 18:44:49 | 显示全部楼层
    STC8H系列数据手册更新,2023/10/13
    截图202310131845423940.jpg
    www.STCAI.com

    截图202310131843406225.jpg

    截图202310131844136253.jpg




    回复 支持 反对 送花

    使用道具 举报

    该用户从未签到

    45

    主题

    2922

    回帖

    6570

    积分

    超级版主

    积分
    6570
    发表于 2023-10-16 00:37:45 | 显示全部楼层
    本帖最后由 梁工 于 2023-10-16 09:55 编辑

    梁工的例子:
    截图202310160728461767.jpg
    截图202310160954238955.jpg

    STC8H-RTC唤醒-触摸按键及唤醒-相关程序.rar

    701.42 KB, 下载次数: 35

    回复 支持 反对 送花

    使用道具 举报

    该用户从未签到

    550

    主题

    9235

    回帖

    1万

    积分

    管理员

    积分
    13946
    发表于 2023-10-16 07:31:13 | 显示全部楼层
    截图202310160730099862.jpg



    /*------------------------------------------------------------------*/
    /* --- STC MCU International Limited -------------------------------*/
    /* --- STC 1T Series MCU Demo --------------------------------------*/
    /* --- Fax: 86-0513-55012956,55012947,55012969 ---------------------*/
    /* --- Tel: 86-0513-55012928,55012929,55012966 ---------------------*/
    /* --- Web: www.stcai.com ------------------------------------------*/
    /* --- BBS: www.stcaimcu.com ---------------------------------------*/
    /* If you want to use the program or the program referenced in the  */
    /* article, please specify in which data and procedures from STC    */
    /*------------------------------------------------------------------*/


    /*********************************************************/
    #define MAIN_Fosc                11059200L        //定义主时钟

    #include        "..\..\STC8Hxxx.h"


    /*************        功能说明        **************

    请先别修改程序, 直接下载"rtc.hex"测试, 主频选择11.0592MHZ. 测试正常后再修改移植.
    由于使用的中断号超过了31,所以KEIL编译器要拓展Keil的C代码中断号, 运行一下拓展Keil的C代码中断号.exe即可。

    RTC每秒唤醒一次,通过串口返回日期时间。
    上位机通过串口发送数据给MCU也会唤醒MCU,并且连续运行5秒。由于唤醒需要点时间(80~100us),所以当波特率大约2400时,唤醒后收到的数据通常会错误,再发一次即可正确接收。
    上位机通过串口设置RTC日期时间和闹铃时间。

    MCU通过串口1返回: 年 月 日 时 分 秒:  21-6-19 12:34:56
    通过串口发送设置值: 21-6-19 12:34:56
    通过串口发送闹钟值: A12:34:56

    默认参数:
    串口1设置均为 1位起始位, 8位数据位, 1位停止位, 无校验.
    串口1(P3.0 P3.1): 115200bps.

    串口要发送数据2次(间隔4秒内), 第一次唤醒(唤醒需要时间, 第一次接收数据将会错误), 第二次数据才会正确接收.

    ******************************************/

    /*************        本地常量声明        **************/
    #define        RX1_Length        32                /* 接收缓冲长度 */


    /*************        本地变量声明        **************/
    u8        xdata        RX1_Buffer[RX1_Length];        //接收缓冲
    u8        RX1_Cnt;                //串口接收计数.
    u8        RX1_TimeOut;        //串口接收超时
    bit        B_TX1_Busy;        // 发送忙标志

    u8        year, month, day, hour, minute, second;        //RTC实时时间
    bit        B_1S;        //秒中断, 秒有变化
    bit        B_1ms;        //1ms标志
    u16        OpTime;                // 此变量非0时, 不睡眠, 连续运行程序(本例串口唤醒后连续运行5秒, 以便正确接收串口数据)

    u8        GetDataIndex;        //获取数据索引仅仅用于读取计数
    u8        GetDataState;        //获取数据状态, 非0则错误

    u8                ALARM_hour;                 // RTC闹钟的小时值
    u8                ALARM_minute;                // RTC闹钟的分钟值
    u8                ALARM_second;                // RTC闹钟的秒值
    bit                B_ALARM;


    /*************        本地函数声明        **************/
    void        UART1_config(u32 brt, u8 timer, u8 io);        // brt: 通信波特率,  timer=2: 波特率使用定时器2, 其它值: 使用Timer1做波特率. io=0: 串口1切换到P3.0 P3.1,  =1: 切换到P3.6 P3.7,  =2: 切换到P1.6 P1.7.
    void         UART1_TxByte(u8 dat);
    void         UART1_PrintString(u8 *puts);
    u8                SetRTC(void);                //设置RTC时间函数
    void        RTC_config(void);        //RTC初始化函数
    void        RTC_read(void);                //读RTC时间函数
    void        ReturnRTC(void);        //返回时间信息
    u8                GetData(void);                //获取数据, 设置时间命令: 21-6-19 12:34:56
    void          delay_ms(u8 ms);
    u8                Timer0_Config(u8 t, u32 reload);        //t=0: reload值是主时钟周期数,  t=1: reload值是时间(单位us), 返回0正确, 返回1装载值过大错误.




    //========================================================================
    // 函数: void main(void)
    // 描述: 主函数
    // 参数: none.
    // 返回: none.
    // 版本: VER1.0
    // 日期: 2018-4-2
    // 备注:
    //========================================================================
    void main(void)
    {
            P0M1 = 0;        P0M0 = 0;
            P1M1 = 0;        P1M0 = 0;
            P2M1 = 0;        P2M0 = 0;
            P3M1 = 0;        P3M0 = 0;
            P4M1 = 0;        P4M0 = 0;
            P5M1 = 0;        P5M0 = 0;
            P6M1 = 0;        P6M0 = 0;
            P7M1 = 0;        P7M0 = 0;

            UART1_config(115200UL, 1, 0);        // brt: 通信波特率,  timer=2: 波特率使用定时器2, 其它值: 使用Timer1做波特率. io=0: 串口1切换到P3.0 P3.1,  =1: 切换到P3.6 P3.7,  =2: 切换到P1.6 P1.7.
            Timer0_Config(0, MAIN_Fosc / 1000);        //t=0: reload值是主时钟周期数,  (中断频率, 1000次/秒)

            EA = 1;

            UART1_PrintString("STC8H RTC Test Prgramme!\r\n");

            OpTime    = 0;
            RTC_config();


            while (1)
            {
                    if(B_1ms)        //1ms标志
                    {
                            B_1ms = 0;

                            if(OpTime != 0)        OpTime--;        //连续运行时间

                            if(RX1_TimeOut != 0)
                            {
                                    if(--RX1_TimeOut == 0)        //设置时间命令: 21-6-19 12:34:56
                                    {
                                            if(RX1_Buffer[0] == 'A')        //设置闹铃
                                            {
                                                    GetDataIndex = 1;        //获取数据索引仅仅用于读取计数
                                                    GetDataState = 0;        //获取数据状态, 非0则错误
                                                    ALARM_hour   = GetData();                //获取数据 时
                                                    ALARM_minute = GetData();                //获取数据 分
                                                    ALARM_second = GetData();                //获取数据 秒
                                                    if(GetDataState == 0)        //获取数据状态, 为0则正确, 非0则错误
                                                    {
                                                            ALAHOUR = ALARM_hour;                 // RTC闹钟的小时值
                                                            ALAMIN  = ALARM_minute;                // RTC闹钟的分钟值
                                                            ALASEC  = ALARM_second;                // RTC闹钟的秒值
                                                            ALASSEC = 0;                                // RTC闹钟的1/128秒值
                                                            RTCIEN  |= 0x80;        //中断使能, 0x80:闹钟中断, 0x40:日中断, 0x20:小时中断, 0x10:分钟中断, 0x08:秒中断, 0x04:1/2秒中断, 0x02:1/8秒中断, 0x01:1/32秒中断
                                                            UART1_PrintString("已设置闹铃!\r\n");
                                                    }
                                                    else
                                                    {
                                                            UART1_PrintString("设置闹铃数据错误!\r\n");
                                                            UART1_PrintString("错误代码: ");
                                                            UART1_TxByte(GetDataState+'0');
                                                            UART1_PrintString("\r\n");
                                                    }
                                            }
                                            else        //设置时间
                                            {
                                                    GetDataIndex = 0;        //获取数据索引仅仅用于读取计数
                                                    GetDataState = 0;        //获取数据状态, 非0则错误
                                                    year   = GetData();                //获取数据 年
                                                    month  = GetData();                //获取数据 月
                                                    day    = GetData();                //获取数据 日
                                                    hour   = GetData();                //获取数据 时
                                                    minute = GetData();                //获取数据 分
                                                    second = GetData();                //获取数据 秒
                                                    if(GetDataState == 0)        //获取数据状态, 为0则正确, 非0则错误
                                                    {
                                                            UART1_PrintString("获取设置时间: ");        ReturnRTC();
                                                            if(SetRTC() == 0)        UART1_PrintString("已设置时间!\r\n");
                                                            else                                UART1_PrintString("设置时间数据错误!\r\n");
                                                    }
                                                    else
                                                    {
                                                            UART1_PrintString("设置时间数据错误!\r\n");
                                                            UART1_PrintString("错误代码: ");
                                                            UART1_TxByte(GetDataState+'0');
                                                            UART1_PrintString("\r\n");
                                                    }
                                            }
                                            RX1_Cnt = 0;
                                    }
                            }
                    }

                    if(B_ALARM)                //闹铃
                    {
                            B_ALARM = 0;
                            UART1_PrintString("滴滴滴! 闹铃! \r\n");
                    }

                    if(B_1S)        //秒有变化
                    {
                            B_1S = 0;
                            RTC_read();
                            ReturnRTC();                                //从串口返回时间信息
                    }

                    if(OpTime == 0)                // OpTime==0才进入掉电模式
                    {
                            PCON |= 0x02;        //睡眠
                            NOP(5);
                    }
            }
    }


    /********************** 获取串口数据 *****************************/
    u8        GetData(void)
    {
            u8 i,j,k;

            if(GetDataIndex >= RX1_Cnt)
            {
                    GetDataState = 1;
                    return 0;
            }
    //        if(RX1_Cnt < 11)        //数据长度错误 设置时间
            if(RX1_Cnt < 6)                //数据长度错误 设置时间 设置闹铃
            {
                    GetDataState = 2;
                    return 0;
            }

            i = 0;
            k = 0;
            while(GetDataIndex <= RX1_Cnt)                //设置时间命令: 21-6-19 12:34:56
            {
                    j = RX1_Buffer[GetDataIndex];
                    if((j == '-') || (j == ' ') || (j == ':') || (GetDataIndex == RX1_Cnt))        //数据段结束
                    {
                            GetDataIndex++;
                            if(i == 0)        //数据错误
                            {
                                    GetDataState = 3;
                                    return 0;
                            }
                            else        return k;        //数据正确
                    }
                    if((j < '0') || (j > '9'))        //数据合法性检测
                    {
                            GetDataIndex++;
                            GetDataState = 4;
                            return 0;
                    }
                    k = k * 10 + j - '0';
                    i++;
                    GetDataIndex++;
            }

            GetDataState = 9;
            return 10;        //数据错误
    }

    /********************** 串口返回时间信息 *****************************/
    void        ReturnRTC(void)
    {
            UART1_TxByte(year/10+'0');        //年
            UART1_TxByte(year%10+'0');
            UART1_TxByte('-');
            UART1_TxByte(month/10+'0');        //月
            UART1_TxByte(month%10+'0');
            UART1_TxByte('-');
            UART1_TxByte(day/10+'0');        //日
            UART1_TxByte(day%10+'0');
            UART1_TxByte(' ');
            UART1_TxByte(hour/10+'0');        //时
            UART1_TxByte(hour%10+'0');
            UART1_TxByte(':');
            UART1_TxByte(minute/10+'0');        //分
            UART1_TxByte(minute%10+'0');
            UART1_TxByte(':');
            UART1_TxByte(second/10+'0');        //秒
            UART1_TxByte(second%10+'0');
            UART1_TxByte(0x0d);
            UART1_TxByte(0x0a);
    }


    /********************** 设置RTC时间 *****************************/
    u8        SetRTC(void)
    {
            P_SW2 |= 0x80;                //SFR enable
            if(year > 99)                                                return 1;
            if((month == 0) || (month > 12))        return 2;
            if((day == 0) || (day > 31))                return 3;
            if(hour > 23)                                        return 4;
            if(minute > 59)                                        return 5;
            if(second > 59)                                        return 6;
            INIYEAR  = year;
            INIMONTH = month;
            INIDAY   = day;
            INIHOUR  = hour;
            INIMIN   = minute;
            INISEC   = second;
            INISSEC  = 0;
            RTCCFG   = 0x01 | 0x00;        //设置RTC时间, |0x00:选择外部32K时钟, |0x02:选择内部32K时钟.
            while(RTCCFG & 0x01);        //等待初始化完成. 设置RTC时间需要32768Hz的1个周期时间,大约30.5us. 由于同步, 所以实际等待时间是0~30.5us.
                                                            //如果不等待设置完成就睡眠, 则RTC会由于设置没完成, 停止计数, 唤醒后才继续完成设置并继续计数.
            return 0;
    }

    /********************** RTC配置函数 *****************************/
    void        RTC_config(void)        //RTC初始化函数
    {
            P_SW2  |= 0x80;                //SFR enable
            P1n_pure_input(0xc0);                //P1.6 P1.7设置为高阻输入
            P1IE = ~0xc0;                                //P1.6 P1.7关闭数字输入功能
            X32KCR = 0x80 + 0x40;                //启动外部32K晶振, 低增益+0x00, 高增益+0x40.

            year    = 21;
            month   = 6;
            day     = 18;
            hour    = 12;
            minute  = 0;
            second  = 0;

            RTCCR   = 0x01;        //使能RTC, 并开始RTC计数
            SetRTC();                //设置RTC时间
            RTCIF   = 0;        //中断标志, 0x80:闹钟中断, 0x40:日中断, 0x20:小时中断, 0x10:分钟中断, 0x08:秒中断, 0x04:1/2秒中断, 0x02:1/8秒中断, 0x01:1/32秒中断
            RTCIEN  = 0x08;        //中断使能, 0x80:闹钟中断, 0x40:日中断, 0x20:小时中断, 0x10:分钟中断, 0x08:秒中断, 0x04:1/2秒中断, 0x02:1/8秒中断, 0x01:1/32秒中断
            ALAHOUR = 8;        //闹钟小时
            ALAMIN  = 30;        //闹钟分钟
            ALASEC  = 0;        //闹钟秒
            ALASSEC = 0;        //闹钟1/128秒
    }

    /********************** 读取RTC时间信息 *****************************/
    void        RTC_read(void)
    {
            P_SW2  |= 0x80;                //SFR enable
            year    = RTC_YEAR;                // RTC的年计数值
            month   = RTC_MONTH;        // RTC的月计数值
            day     = RTC_DAY;                // RTC的日计数值
            hour    = RTC_HOUR;                // RTC的时计数值
            minute  = RTC_MIN;                // RTC的分计数值
            second  = RTC_SEC;                // RTC的秒计数值
    //        ssecond = RTC_SSEC;                // RTC的1/128秒计数值
    }



    //========================================================================
    // 函数: SetTimer2Baudraye(u16 dat)
    // 描述: 设置Timer2做波特率发生器。
    // 参数: dat: Timer2的重装值.
    // 返回: none.
    // 版本: VER1.0
    // 日期: 2018-4-2
    // 备注:
    //========================================================================
    void        SetTimer2Baudraye(u16 dat)        // 选择波特率, 2: 使用Timer2做波特率, 其它值: 使用Timer1做波特率.
    {
            AUXR &= ~(1<<4);        //Timer stop
            AUXR &= ~(1<<3);        //Timer2 set As Timer
            AUXR |=  (1<<2);        //Timer2 set as 1T mode
            TH2 = (u8)(dat >> 8);
            TL2 = (u8)dat;
            IE2  &= ~(1<<2);        //禁止中断
            AUXR |=  (1<<4);        //Timer run enable
    }


    //========================================================================
    // 函数: void        UART1_config(u32 brt, u8 timer, u8 io)
    // 描述: UART1初始化函数。
    // 参数:   brt: 通信波特率.
    //       timer: 波特率使用的定时器, timer=2: 波特率使用定时器2, 其它值: 使用Timer1做波特率.
    //          io: 串口1切换到的IO,  io=1: 串口1切换到P3.0 P3.1,  =1: 切换到P3.6 P3.7,  =2: 切换到P1.6 P1.7.
    // 返回: none.
    // 版本: VER1.0
    // 日期: 2018-4-2
    // 备注:
    //========================================================================
    void        UART1_config(u32 brt, u8 timer, u8 io)        // brt: 通信波特率,  timer=2: 波特率使用定时器2, 其它值: 使用Timer1做波特率. io=0: 串口1切换到P3.0 P3.1,  =1: 切换到P3.6 P3.7.
    {
            brt = 65536UL - (MAIN_Fosc / 4) / brt;
            if(timer == 2)        //波特率使用定时器2
            {
                    AUXR |= 0x01;                //S1 BRT Use Timer2;
                    SetTimer2Baudraye((u16)brt);
            }

            else                //波特率使用定时器1
            {
                    TR1 = 0;
                    AUXR &= ~0x01;                //S1 BRT Use Timer1;
                    AUXR |=  (1<<6);        //Timer1 set as 1T mode
                    TMOD &= ~(1<<6);        //Timer1 set As Timer
                    TMOD &= ~0x30;                //Timer1_16bitAutoReload;
                    TH1 = (u8)(brt >> 8);
                    TL1 = (u8)brt;
                    ET1 = 0;                        // 禁止Timer1中断
                    INT_CLKO &= ~0x02;        // Timer1不输出高速时钟
                    TR1  = 1;                        // 运行Timer1
            }

                     if(io == 1)        {S1_USE_P36P37();        P3n_standard(0xc0);}        //切换到 P3.6 P3.7
            else if(io == 2)        {S1_USE_P16P17();        P1n_standard(0xc0);}        //切换到 P1.6 P1.7
            else                                {S1_USE_P30P31();        P3n_standard(0x03);}        //切换到 P3.0 P3.1

            SCON = (SCON & 0x3f) | (1<<6);        // 8位数据, 1位起始位, 1位停止位, 无校验
    //        PS  = 1;        //高优先级中断
            ES  = 1;        //允许中断
            REN = 1;        //允许接收
    }


    //========================================================================
    // 函数: void UART1_TxByte(u8 dat)
    // 描述: 串口1发送一个字节数据函数
    // 参数: dat: 要发送的一个字节数据.
    // 返回: none.
    // 版本: VER1.0
    // 日期: 2018-4-2
    // 备注:
    //========================================================================
    void UART1_TxByte(u8 dat)
    {
            B_TX1_Busy = 1;                //标志发送忙
            SBUF = dat;                        //发一个字节
            while(B_TX1_Busy);        //等待发送完成
    }

    //========================================================================
    // 函数: void UART1_PrintString(u8 *puts)
    // 描述: 串口1字符串打印函数
    // 参数: puts: 字符串指针.
    // 返回: none.
    // 版本: VER1.0
    // 日期: 2018-4-2
    // 备注:
    //========================================================================
    void UART1_PrintString(u8 *puts)
    {
        for (; *puts != 0;        puts++)        UART1_TxByte(*puts);
    }


    //========================================================================
    // 函数: void UART1_int (void) interrupt UART1_VECTOR
    // 描述: 串口1中断函数
    // 参数: none.
    // 返回: none.
    // 版本: VER1.0
    // 日期: 2018-4-2
    // 备注:
    //========================================================================
    void UART1_ISR (void) interrupt UART1_VECTOR
    {
            if(RI)
            {
                    RI = 0;
                    if(RX1_Cnt >= RX1_Length)        RX1_Cnt = 0;
                    RX1_Buffer[RX1_Cnt++] = SBUF;
                    RX1_TimeOut = 5;
                    OpTime = 5000;        //串口一旦唤醒, 接着5秒不睡眠, 以便正确接收数据. 唤醒帧将不能正确接收(因为唤醒需要计时us时间), 除非用很慢的速度(比如2400).
            }

            if(TI)
            {
                    TI = 0;
                    B_TX1_Busy = 0;
            }
    }


    //========================================================================
    // 函数:u8        Timer0_Config(u8 t, u32 reload)
    // 描述: timer0初始化函数.
    // 参数:      t: 重装值类型, 0表示重装的是系统时钟数, 其余值表示重装的是时间(us).
    //       reload: 重装值.
    // 返回: 0: 初始化正确, 1: 重装值过大, 初始化错误.
    // 版本: V1.0, 2018-3-5
    //========================================================================
    u8        Timer0_Config(u8 t, u32 reload)        //t=0: reload值是主时钟周期数,  t=1: reload值是时间(单位us)
    {
            TR0 = 0;        //停止计数

            if(t != 0)        reload = (u32)(((float)MAIN_Fosc * (float)reload)/1000000UL);        //重装的是时间(us), 计算所需要的系统时钟数.
            if(reload >= (65536UL * 12))        return 1;        //值过大, 返回错误
            if(reload < 65536UL)        AUXR |= 0x80;                //1T mode
            else
            {
                    AUXR &= ~0x80;        //12T mode
                    reload = reload / 12;
            }
            reload = 65536UL - reload;
            TH0 = (u8)(reload >> 8);
            TL0 = (u8)(reload);

            ET0 = 1;        //允许中断
    //        PT0 = 1;        //高优先级中断
            TMOD = (TMOD & ~0x03) | 0;        //工作模式, 0: 16位自动重装, 1: 16位定时/计数, 2: 8位自动重装, 3: 16位自动重装, 不可屏蔽中断
            TR0 = 1;                        //开始运行
            return 0;
    }

    //========================================================================
    // 函数: void timer0_int (void) interrupt TIMER0_VECTOR
    // 描述:  timer0中断函数.
    // 参数: none.
    // 返回: none.
    // 版本: V1.0, 2016-5-12
    //========================================================================
    void timer0_ISR (void) interrupt TIMER0_VECTOR
    {
       B_1ms = 1;        //1ms标志
    }


    //========================================================================
    // 函数: AUXR_ISR(void) interrupt 13
    // 描述: 扩展中断函数(中断号>=32的中断)
    // 参数: none.
    // 返回: none.
    // 版本: VER1.0
    // 日期: 2018-4-2
    // 备注:
    //========================================================================
    void        RTC_ISR(void) interrupt 36
    {
            u8        i;
            i = RTCIF;
            RTCIF = 0;                //中断标志, 0x80:闹钟中断, 0x40:日中断, 0x20:小时中断, 0x10:分钟中断, 0x08:秒中断, 0x04:1/2秒中断, 0x02:1/8秒中断, 0x01:1/32秒中断
            if(i & 0x08)        //秒中断
            {
                    B_1S = 1;        //秒标志
            }
            if(i & 0x80)        //闹铃中断
            {
                    B_ALARM = 1;        //闹铃标志
            }
    }


    回复 支持 反对 送花

    使用道具 举报

    该用户从未签到

    550

    主题

    9235

    回帖

    1万

    积分

    管理员

    积分
    13946
    发表于 2023-10-16 07:33:23 | 显示全部楼层
    截图202310160732032647.jpg



    /*------------------------------------------------------------------*/
    /* --- STC MCU International Limited -------------------------------*/
    /* --- STC 1T Series MCU Demo --------------------------------------*/
    /* --- Fax: 86-0513-55012956,55012947,55012969 ---------------------*/
    /* --- Tel: 86-0513-55012928,55012929,55012966 ---------------------*/
    /* --- Web: www.stcai.com ------------------------------------------*/
    /* --- BBS: www.stcaimcu.com ---------------------------------------*/
    /* If you want to use the program or the program referenced in the  */
    /* article, please specify in which data and procedures from STC    */
    /*------------------------------------------------------------------*/


    /*********************************************************/
    #define MAIN_Fosc                11059200L        //定义主时钟

    #include        "..\..\STC8Hxxx.h"


    /*************        功能说明        **************

    请先别修改程序, 直接下载"rtc.hex"测试, 主频选择11.0592MHZ. 测试正常后再修改移植.
    由于使用的中断号超过了31,所以KEIL编译器要拓展Keil的C代码中断号, 运行一下拓展Keil的C代码中断号.exe即可。

    RTC每秒唤醒一次,通过串口返回日期时间。
    上位机通过串口发送数据给MCU也会唤醒MCU,并且连续运行5秒。由于唤醒需要点时间(80~100us),所以当波特率大约2400时,唤醒后收到的数据通常会错误,再发一次即可正确接收。
    上位机通过串口设置RTC日期时间和闹铃时间。
    同时传统的INT0~INT3均可唤醒MCU;

    INT0唤醒后在中断服务函数里取反P2.0指示.
    INT1唤醒后在中断服务函数里取反P2.1指示.
    INT2唤醒后在中断服务函数里取反P2.2指示.
    INT3唤醒后在中断服务函数里取反P2.3指示.
    INT4唤醒后在中断服务函数里取反P2.4指示.

    MCU通过串口1返回: 年 月 日 时 分 秒:  21-6-19 12:34:56
    通过串口发送设置值: 21-6-19 12:34:56
    通过串口发送闹钟值: A12:34:56

    默认参数:
    串口1设置均为 1位起始位, 8位数据位, 1位停止位, 无校验.
    串口1(P3.0 P3.1): 115200bps.

    串口要发送数据2次(间隔4秒内), 第一次唤醒(唤醒需要时间, 第一次接收数据将会错误), 第二次数据才会正确接收.

    ******************************************/

    /*************        本地常量声明        **************/
    #define        RX1_Length        32                /* 接收缓冲长度 */


    /*************        本地变量声明        **************/
    u8        xdata        RX1_Buffer[RX1_Length];        //接收缓冲

    u8        RX1_Cnt;                //串口接收计数.
    u8        RX1_TimeOut;        //串口接收超时

    bit        B_TX1_Busy;        // 发送忙标志

    u8        year, month, day, hour, minute, second;        //RTC实时时间
    bit        B_1S;        //秒中断, 秒有变化
    bit        B_1ms;        //1ms标志
    u16        OpTime;                // 此变量非0时, 不睡眠, 连续运行程序(本例串口唤醒后连续运行5秒, 以便正确接收串口数据)

    u8        GetDataIndex;        //获取数据索引仅仅用于读取计数
    u8        GetDataState;        //获取数据状态, 非0则错误

    u8        ALARM_hour;                 // RTC闹钟的小时值
    u8        ALARM_minute;                // RTC闹钟的分钟值
    u8        ALARM_second;                // RTC闹钟的秒值
    bit        B_ALARM;


    /*************        本地函数声明        **************/
    void        UART1_config(u32 brt, u8 timer, u8 io);        // brt: 通信波特率,  timer=2: 波特率使用定时器2, 其它值: 使用Timer1做波特率. io=0: 串口1切换到P3.0 P3.1,  =1: 切换到P3.6 P3.7,  =2: 切换到P1.6 P1.7.
    void         UART1_TxByte(u8 dat);
    void         UART1_PrintString(u8 *puts);
    u8                SetRTC(void);                //设置RTC时间函数
    void        RTC_config(void);        //RTC初始化函数
    void        RTC_read(void);                //读RTC时间函数
    void        ReturnRTC(void);        //返回时间信息
    u8                GetData(void);                //获取数据, 设置时间命令: 21-6-19 12:34:56
    void          delay_ms(u8 ms);
    u8                Timer0_Config(u8 t, u32 reload);        //t=0: reload值是主时钟周期数,  t=1: reload值是时间(单位us), 返回0正确, 返回1装载值过大错误.




    //========================================================================
    // 函数: void main(void)
    // 描述: 主函数
    // 参数: none.
    // 返回: none.
    // 版本: VER1.0
    // 日期: 2018-4-2
    // 备注:
    //========================================================================
    void main(void)
    {
            P0M1 = 0;        P0M0 = 0;
            P1M1 = 0;        P1M0 = 0;
            P2M1 = 0;        P2M0 = 0;
            P3M1 = 0;        P3M0 = 0;
            P4M1 = 0;        P4M0 = 0;
            P5M1 = 0;        P5M0 = 0;
            P6M1 = 0;        P6M0 = 0;
            P7M1 = 0;        P7M0 = 0;

            UART1_config(115200UL, 1, 0);        // brt: 通信波特率,  timer=2: 波特率使用定时器2, 其它值: 使用Timer1做波特率. io=0: 串口1切换到P3.0 P3.1,  =1: 切换到P3.6 P3.7,  =2: 切换到P1.6 P1.7.
            Timer0_Config(0, MAIN_Fosc / 1000);        //t=0: reload值是主时钟周期数,  (中断频率, 1000次/秒)

            EA = 1;

            UART1_PrintString("STC8H RTC Test Prgramme!\r\n");

            OpTime    = 0;
            RTC_config();


            while (1)
            {
                    if(B_1ms)        //1ms标志
                    {
                            B_1ms = 0;

                            if(OpTime != 0)        OpTime--;        //连续操作时间

                            if(RX1_TimeOut != 0)
                            {
                                    if(--RX1_TimeOut == 0)        //设置时间命令: 21-6-19 12:34:56
                                    {
                                            if(RX1_Buffer[0] == 'A')        //设置闹铃
                                            {
                                                    GetDataIndex = 1;        //获取数据索引仅仅用于读取计数
                                                    GetDataState = 0;        //获取数据状态, 非0则错误
                                                    ALARM_hour   = GetData();                //获取数据 时
                                                    ALARM_minute = GetData();                //获取数据 分
                                                    ALARM_second = GetData();                //获取数据 秒
                                                    if(GetDataState == 0)        //获取数据状态, 为0则正确, 非0则错误
                                                    {
                                                            ALAHOUR = ALARM_hour;                 // RTC闹钟的小时值
                                                            ALAMIN  = ALARM_minute;                // RTC闹钟的分钟值
                                                            ALASEC  = ALARM_second;                // RTC闹钟的秒值
                                                            ALASSEC = 0;                                // RTC闹钟的1/128秒值
                                                            RTCIEN  |= 0x80;        //中断使能, 0x80:闹钟中断, 0x40:日中断, 0x20:小时中断, 0x10:分钟中断, 0x08:秒中断, 0x04:1/2秒中断, 0x02:1/8秒中断, 0x01:1/32秒中断
                                                            UART1_PrintString("已设置闹铃!\r\n");
                                                    }
                                                    else
                                                    {
                                                            UART1_PrintString("设置闹铃数据错误!\r\n");
                                                            UART1_PrintString("错误代码: ");
                                                            UART1_TxByte(GetDataState+'0');
                                                            UART1_PrintString("\r\n");
                                                    }
                                            }
                                            else        //设置时间
                                            {
                                                    GetDataIndex = 0;        //获取数据索引仅仅用于读取计数
                                                    GetDataState = 0;        //获取数据状态, 非0则错误
                                                    year   = GetData();                //获取数据 年
                                                    month  = GetData();                //获取数据 月
                                                    day    = GetData();                //获取数据 日
                                                    hour   = GetData();                //获取数据 时
                                                    minute = GetData();                //获取数据 分
                                                    second = GetData();                //获取数据 秒
                                                    if(GetDataState == 0)        //获取数据状态, 为0则正确, 非0则错误
                                                    {
                                                            UART1_PrintString("获取设置时间: ");        ReturnRTC();
                                                            if(SetRTC() == 0)        UART1_PrintString("已设置时间!\r\n");
                                                            else                                UART1_PrintString("设置时间数据错误!\r\n");
                                                    }
                                                    else
                                                    {
                                                            UART1_PrintString("设置时间数据错误!\r\n");
                                                            UART1_PrintString("错误代码: ");
                                                            UART1_TxByte(GetDataState+'0');
                                                            UART1_PrintString("\r\n");
                                                    }
                                            }
                                            RX1_Cnt = 0;
                                    }
                            }
                    }

                    if(B_ALARM)        //闹铃
                    {
                            B_ALARM = 0;
                            UART1_PrintString("滴滴滴! 闹铃! \r\n");
                    }

                    if(B_1S)        //秒有变化
                    {
                            B_1S = 0;
                            RTC_read();
                            ReturnRTC();        //从串口返回时间信息
                    }

                    if(OpTime == 0)                // OpTime==0才进入掉电模式
                    {
                            IT0 = 1;                                //INT0 下降沿中断
                            IT1 = 1;                                //INT1 下降沿中断
                            IE0  = 0;                                //清除外中断0标志位
                            IE1  = 0;                                //清除外中断1标志位
                            AUXINTIF &= ~INT2IF;        //清除外中断2标志位
                            AUXINTIF &= ~INT3IF;        //清除外中断3标志位
                            AUXINTIF &= ~INT4IF;        //清除外中断4标志位
                            NOP(3);
                            EX0 = 1;                                //INT0 允许中断
                            EX1 = 1;                                //INT1 允许中断
                            INT_CLKO |= (1 << 4);        //INT2 允许中断
                            INT_CLKO |= (1 << 5);        //INT3 允许中断
                            INT_CLKO |= (1 << 6);        //INT4 允许中断
                            NOP(3);

                            PCON |= 0x02;        //睡眠
                            NOP(5);

                            EX0 = 0;                                //INT0 禁止中断        (按用户程序需要)
                            EX1 = 0;                                //INT1 禁止中断        (按用户程序需要)
                            INT_CLKO &= ~(1 << 4);        //INT2 禁止中断        (按用户程序需要)
                            INT_CLKO &= ~(1 << 5);        //INT3 禁止中断        (按用户程序需要)
                            INT_CLKO &= ~(1 << 6);        //INT4 禁止中断        (按用户程序需要)
                    }
            }
    }

    /********************* INT0中断函数 *************************/
    void INT0_ISR (void) interrupt 0
    {
            P20 = ~P20;                        //取反指示引脚
    }

    /********************* INT1中断函数 *************************/
    void INT1_ISR (void) interrupt 2
    {
            P21 = ~P21;                        //取反指示引脚
    }

    /********************* INT2中断函数 *************************/
    void INT2_ISR (void) interrupt 10
    {
            P22 = ~P22;                        //取反指示引脚
    }

    /********************* INT3中断函数 *************************/
    void INT3_ISR (void) interrupt 11
    {
            P23 = ~P23;                        //取反指示引脚
    }

    /********************* INT4中断函数 *************************/
    void INT4_ISR (void) interrupt 16
    {
            P24 = ~P24;                        //取反指示引脚
    }


    /********************** 获取串口数据 *****************************/
    u8        GetData(void)
    {
            u8 i,j,k;

            if(GetDataIndex >= RX1_Cnt)
            {
                    GetDataState = 1;
                    return 0;
            }
    //        if(RX1_Cnt < 11)        //数据长度错误 设置时间
            if(RX1_Cnt < 6)                //数据长度错误 设置时间 设置闹铃
            {
                    GetDataState = 2;
                    return 0;
            }

            i = 0;
            k = 0;
            while(GetDataIndex <= RX1_Cnt)                //设置时间命令: 21-6-19 12:34:56
            {
                    j = RX1_Buffer[GetDataIndex];
                    if((j == '-') || (j == ' ') || (j == ':') || (GetDataIndex == RX1_Cnt))        //数据段结束
                    {
                            GetDataIndex++;
                            if(i == 0)        //数据错误
                            {
                                    GetDataState = 3;
                                    return 0;
                            }
                            else        return k;        //数据正确
                    }
                    if((j < '0') || (j > '9'))        //数据合法性检测
                    {
                            GetDataIndex++;
                            GetDataState = 4;
                            return 0;
                    }
                    k = k * 10 + j - '0';
                    i++;
                    GetDataIndex++;
            }

            GetDataState = 9;
            return 10;        //数据错误
    }

    /********************** 串口返回时间信息 *****************************/
    void        ReturnRTC(void)
    {
            UART1_TxByte(year/10+'0');        //年
            UART1_TxByte(year%10+'0');
            UART1_TxByte('-');
            UART1_TxByte(month/10+'0');        //月
            UART1_TxByte(month%10+'0');
            UART1_TxByte('-');
            UART1_TxByte(day/10+'0');        //日
            UART1_TxByte(day%10+'0');
            UART1_TxByte(' ');
            UART1_TxByte(hour/10+'0');        //时
            UART1_TxByte(hour%10+'0');
            UART1_TxByte(':');
            UART1_TxByte(minute/10+'0');        //分
            UART1_TxByte(minute%10+'0');
            UART1_TxByte(':');
            UART1_TxByte(second/10+'0');        //秒
            UART1_TxByte(second%10+'0');
            UART1_TxByte(0x0d);
            UART1_TxByte(0x0a);
    }


    /********************** 设置RTC时间 *****************************/
    u8        SetRTC(void)
    {
            P_SW2 |= 0x80;                //SFR enable
            if(year > 99)                                                return 1;
            if((month == 0) || (month > 12))        return 2;
            if((day == 0) || (day > 31))                return 3;
            if(hour > 23)                                        return 4;
            if(minute > 59)                                        return 5;
            if(second > 59)                                        return 6;
            INIYEAR  = year;
            INIMONTH = month;
            INIDAY   = day;
            INIHOUR  = hour;
            INIMIN   = minute;
            INISEC   = second;
            INISSEC  = 0;
            RTCCFG   = 0x01 | 0x00;        //设置RTC时间, |0x00:选择外部32K时钟, |0x02:选择内部32K时钟.
            while(RTCCFG & 0x01);        //等待初始化完成. 设置RTC时间需要32768Hz的1个周期时间,大约30.5us. 由于同步, 所以实际等待时间是0~30.5us.
                                                            //如果不等待设置完成就睡眠, 则RTC会由于设置没完成, 停止计数, 唤醒后才继续完成设置并继续计数.
            return 0;
    }

    /********************** RTC配置函数 *****************************/
    void        RTC_config(void)        //RTC初始化函数
    {
            P_SW2  |= 0x80;                //SFR enable
            P1n_pure_input(0xc0);                //P1.6 P1.7设置为高阻输入
            P1IE = ~0xc0;                                //P1.6 P1.7关闭数字输入功能
            X32KCR = 0x80 + 0x40;                //启动外部32K晶振, 低增益+0x00, 高增益+0x40.

            year    = 21;
            month   = 6;
            day     = 18;
            hour    = 12;
            minute  = 0;
            second  = 0;

            RTCCR   = 0x01;        //使能RTC, 并开始RTC计数
            SetRTC();                //设置RTC时间
            RTCIF   = 0;        //中断标志, 0x80:闹钟中断, 0x40:日中断, 0x20:小时中断, 0x10:分钟中断, 0x08:秒中断, 0x04:1/2秒中断, 0x02:1/8秒中断, 0x01:1/32秒中断
            RTCIEN  = 0x08;        //中断使能, 0x80:闹钟中断, 0x40:日中断, 0x20:小时中断, 0x10:分钟中断, 0x08:秒中断, 0x04:1/2秒中断, 0x02:1/8秒中断, 0x01:1/32秒中断
            ALAHOUR = 8;        //闹钟小时
            ALAMIN  = 30;        //闹钟分钟
            ALASEC  = 0;        //闹钟秒
            ALASSEC = 0;        //闹钟1/128秒
    }

    /********************** 读取RTC时间信息 *****************************/
    void        RTC_read(void)
    {
            P_SW2  |= 0x80;                //SFR enable
            year    = RTC_YEAR;                // RTC的年计数值
            month   = RTC_MONTH;        // RTC的月计数值
            day     = RTC_DAY;                // RTC的日计数值
            hour    = RTC_HOUR;                // RTC的时计数值
            minute  = RTC_MIN;                // RTC的分计数值
            second  = RTC_SEC;                // RTC的秒计数值
    //        ssecond = RTC_SSEC;                // RTC的1/128秒计数值
    }



    //========================================================================
    // 函数: SetTimer2Baudraye(u16 dat)
    // 描述: 设置Timer2做波特率发生器。
    // 参数: dat: Timer2的重装值.
    // 返回: none.
    // 版本: VER1.0
    // 日期: 2018-4-2
    // 备注:
    //========================================================================
    void        SetTimer2Baudraye(u16 dat)        // 选择波特率, 2: 使用Timer2做波特率, 其它值: 使用Timer1做波特率.
    {
            AUXR &= ~(1<<4);        //Timer stop
            AUXR &= ~(1<<3);        //Timer2 set As Timer
            AUXR |=  (1<<2);        //Timer2 set as 1T mode
            TH2 = (u8)(dat >> 8);
            TL2 = (u8)dat;
            IE2  &= ~(1<<2);        //禁止中断
            AUXR |=  (1<<4);        //Timer run enable
    }


    //========================================================================
    // 函数: void        UART1_config(u32 brt, u8 timer, u8 io)
    // 描述: UART1初始化函数。
    // 参数:   brt: 通信波特率.
    //       timer: 波特率使用的定时器, timer=2: 波特率使用定时器2, 其它值: 使用Timer1做波特率.
    //          io: 串口1切换到的IO,  io=1: 串口1切换到P3.0 P3.1,  =1: 切换到P3.6 P3.7,  =2: 切换到P1.6 P1.7.
    // 返回: none.
    // 版本: VER1.0
    // 日期: 2018-4-2
    // 备注:
    //========================================================================
    void        UART1_config(u32 brt, u8 timer, u8 io)        // brt: 通信波特率,  timer=2: 波特率使用定时器2, 其它值: 使用Timer1做波特率. io=0: 串口1切换到P3.0 P3.1,  =1: 切换到P3.6 P3.7.
    {
            brt = 65536UL - (MAIN_Fosc / 4) / brt;
            if(timer == 2)        //波特率使用定时器2
            {
                    AUXR |= 0x01;                //S1 BRT Use Timer2;
                    SetTimer2Baudraye((u16)brt);
            }

            else                //波特率使用定时器1
            {
                    TR1 = 0;
                    AUXR &= ~0x01;                //S1 BRT Use Timer1;
                    AUXR |=  (1<<6);        //Timer1 set as 1T mode
                    TMOD &= ~(1<<6);        //Timer1 set As Timer
                    TMOD &= ~0x30;                //Timer1_16bitAutoReload;
                    TH1 = (u8)(brt >> 8);
                    TL1 = (u8)brt;
                    ET1 = 0;                        // 禁止Timer1中断
                    INT_CLKO &= ~0x02;        // Timer1不输出高速时钟
                    TR1  = 1;                        // 运行Timer1
            }

                     if(io == 1)        {S1_USE_P36P37();        P3n_standard(0xc0);}        //切换到 P3.6 P3.7
            else if(io == 2)        {S1_USE_P16P17();        P1n_standard(0xc0);}        //切换到 P1.6 P1.7
            else                                {S1_USE_P30P31();        P3n_standard(0x03);}        //切换到 P3.0 P3.1

            SCON = (SCON & 0x3f) | (1<<6);        // 8位数据, 1位起始位, 1位停止位, 无校验
    //        PS  = 1;        //高优先级中断
            ES  = 1;        //允许中断
            REN = 1;        //允许接收
    }


    //========================================================================
    // 函数: void UART1_TxByte(u8 dat)
    // 描述: 串口1发送一个字节数据函数
    // 参数: dat: 要发送的一个字节数据.
    // 返回: none.
    // 版本: VER1.0
    // 日期: 2018-4-2
    // 备注:
    //========================================================================
    void UART1_TxByte(u8 dat)
    {
            B_TX1_Busy = 1;                //标志发送忙
            SBUF = dat;                        //发一个字节
            while(B_TX1_Busy);        //等待发送完成
    }

    //========================================================================
    // 函数: void UART1_PrintString(u8 *puts)
    // 描述: 串口1字符串打印函数
    // 参数: puts: 字符串指针.
    // 返回: none.
    // 版本: VER1.0
    // 日期: 2018-4-2
    // 备注:
    //========================================================================
    void UART1_PrintString(u8 *puts)
    {
        for (; *puts != 0;        puts++)        UART1_TxByte(*puts);
    }


    //========================================================================
    // 函数: void UART1_int (void) interrupt UART1_VECTOR
    // 描述: 串口1中断函数
    // 参数: none.
    // 返回: none.
    // 版本: VER1.0
    // 日期: 2018-4-2
    // 备注:
    //========================================================================
    void UART1_ISR (void) interrupt UART1_VECTOR
    {
            if(RI)
            {
                    RI = 0;
                    if(RX1_Cnt >= RX1_Length)        RX1_Cnt = 0;
                    RX1_Buffer[RX1_Cnt++] = SBUF;
                    RX1_TimeOut = 5;
                    OpTime = 5000;        //串口一旦唤醒, 接着5秒不睡眠, 以便正确接收数据. 唤醒帧将不能正确接收(因为唤醒需要计时us时间), 除非用很慢的速度(比如2400).
            }

            if(TI)
            {
                    TI = 0;
                    B_TX1_Busy = 0;
            }
    }


    //========================================================================
    // 函数:u8        Timer0_Config(u8 t, u32 reload)
    // 描述: timer0初始化函数.
    // 参数:      t: 重装值类型, 0表示重装的是系统时钟数, 其余值表示重装的是时间(us).
    //       reload: 重装值.
    // 返回: 0: 初始化正确, 1: 重装值过大, 初始化错误.
    // 版本: V1.0, 2018-3-5
    //========================================================================
    u8        Timer0_Config(u8 t, u32 reload)        //t=0: reload值是主时钟周期数,  t=1: reload值是时间(单位us)
    {
            TR0 = 0;        //停止计数

            if(t != 0)        reload = (u32)(((float)MAIN_Fosc * (float)reload)/1000000UL);        //重装的是时间(us), 计算所需要的系统时钟数.
            if(reload >= (65536UL * 12))        return 1;        //值过大, 返回错误
            if(reload < 65536UL)        AUXR |= 0x80;                //1T mode
            else
            {
                    AUXR &= ~0x80;        //12T mode
                    reload = reload / 12;
            }
            reload = 65536UL - reload;
            TH0 = (u8)(reload >> 8);
            TL0 = (u8)(reload);

            ET0 = 1;        //允许中断
    //        PT0 = 1;        //高优先级中断
            TMOD = (TMOD & ~0x03) | 0;        //工作模式, 0: 16位自动重装, 1: 16位定时/计数, 2: 8位自动重装, 3: 16位自动重装, 不可屏蔽中断
            TR0 = 1;                        //开始运行
            return 0;
    }

    //========================================================================
    // 函数: void timer0_int (void) interrupt TIMER0_VECTOR
    // 描述:  timer0中断函数.
    // 参数: none.
    // 返回: none.
    // 版本: V1.0, 2016-5-12
    //========================================================================
    void timer0_ISR (void) interrupt TIMER0_VECTOR
    {
       B_1ms = 1;        //1ms标志
    }


    //========================================================================
    // 函数: AUXR_ISR(void) interrupt 13
    // 描述: 扩展中断函数(中断号>=32的中断)
    // 参数: none.
    // 返回: none.
    // 版本: VER1.0
    // 日期: 2018-4-2
    // 备注:
    //========================================================================
    void        RTC_ISR(void) interrupt 36
    {
            u8        i;
            i = RTCIF;
            RTCIF = 0;                //中断标志, 0x80:闹钟中断, 0x40:日中断, 0x20:小时中断, 0x10:分钟中断, 0x08:秒中断, 0x04:1/2秒中断, 0x02:1/8秒中断, 0x01:1/32秒中断
            if(i & 0x08)        //秒中断
            {
                    B_1S = 1;        //秒标志
            }
            if(i & 0x80)        //闹铃中断
            {
                    B_ALARM = 1;        //闹铃标志
            }
    }


    回复 支持 反对 送花

    使用道具 举报

    该用户从未签到

    550

    主题

    9235

    回帖

    1万

    积分

    管理员

    积分
    13946
    发表于 2023-10-16 07:34:57 | 显示全部楼层
    截图202310160734028919.jpg



    /*------------------------------------------------------------------*/
    /* --- STC MCU International Limited -------------------------------*/
    /* --- STC 1T Series MCU Demo --------------------------------------*/
    /* --- Fax: 86-0513-55012956,55012947,55012969 ---------------------*/
    /* --- Tel: 86-0513-55012928,55012929,55012966 ---------------------*/
    /* --- Web: www.stcai.com ------------------------------------------*/
    /* --- BBS: www.stcaimcu.com ---------------------------------------*/
    /* If you want to use the program or the program referenced in the  */
    /* article, please specify in which data and procedures from STC    */
    /*------------------------------------------------------------------*/


    /*********************************************************/
    #define MAIN_Fosc                11059200L        //定义主时钟

    #include        "..\..\STC8Hxxx.h"


    /*************        功能说明        **************

    请先别修改程序, 直接下载"rtc.hex"测试, 主频选择11.0592MHZ. 测试正常后再修改移植.
    由于使用的中断号超过了31,所以KEIL编译器要拓展Keil的C代码中断号, 运行一下拓展Keil的C代码中断号.exe即可。

    RTC每秒唤醒一次,通过串口返回日期时间。
    上位机通过串口发送数据给MCU也会唤醒MCU,并且连续运行5秒。由于唤醒需要点时间(80~100us),所以当波特率大约2400时,唤醒后收到的数据通常会错误,再发一次即可正确接收。
    上位机通过串口设置RTC日期时间和闹铃时间。
    P0~P7所有IO中断测试程序.
    P0.0~P0.7中断对应取反P1.0~P1.7输出指示。
    P1.0~P1.7中断对应取反P0.0~P0.7输出指示。
    P2.0~P2.7中断对应取反P4.0~P4.7输出指示。
    P3.0~P3.7中断对应取反P4.0~P4.7输出指示。
    P4.0~P4.7中断对应取反P2.0~P2.7输出指示。
    P5.0~P5.7中断对应取反P4.0~P4.7输出指示。
    P6.0~P6.7中断对应取反P7.0~P7.7输出指示。
    P7.0~P7.7中断对应取反P6.0~P6.7输出指示。

    本例子只设置了P4.0~P4.7的中断, 中断函数分别取反P2.0~P2.7来指示进入中断.
    用户可以根据例子随意设置自己需要的IO中断.

    MCU通过串口1返回: 年 月 日 时 分 秒:  21-6-19 12:34:56
    通过串口发送设置值: 21-6-19 12:34:56
    通过串口发送闹钟值: A12:34:56

    默认参数:
    串口1设置均为 1位起始位, 8位数据位, 1位停止位, 无校验.
    串口1(P3.0 P3.1): 115200bps.

    串口要发送数据2次(间隔4秒内), 第一次唤醒(唤醒需要时间, 第一次接收数据将会错误), 第二次数据才会正确接收.

    ******************************************/

    /*************        本地常量声明        **************/
    #define        RX1_Length        32                /* 接收缓冲长度 */


    /*************        本地变量声明        **************/
    u8        xdata        RX1_Buffer[RX1_Length];        //接收缓冲
    u8        RX1_Cnt;                //串口接收计数.
    u8        RX1_TimeOut;        //串口接收超时
    bit        B_TX1_Busy;        // 发送忙标志

    u8        year, month, day, hour, minute, second;        //RTC实时时间
    bit        B_1S;        //秒中断, 秒有变化
    bit        B_1ms;        //1ms标志
    u16        OpTime;                // 此变量非0时, 不睡眠, 连续运行程序(本例串口唤醒后连续运行5秒, 以便正确接收串口数据)

    u8        GetDataIndex;        //获取数据索引仅仅用于读取计数
    u8        GetDataState;        //获取数据状态, 非0则错误

    u8                ALARM_hour;                 // RTC闹钟的小时值
    u8                ALARM_minute;                // RTC闹钟的分钟值
    u8                ALARM_second;                // RTC闹钟的秒值
    bit                B_ALARM;


    /*************        本地函数声明        **************/
    void        UART1_config(u32 brt, u8 timer, u8 io);        // brt: 通信波特率,  timer=2: 波特率使用定时器2, 其它值: 使用Timer1做波特率. io=0: 串口1切换到P3.0 P3.1,  =1: 切换到P3.6 P3.7,  =2: 切换到P1.6 P1.7.
    void         UART1_TxByte(u8 dat);
    void         UART1_PrintString(u8 *puts);
    u8                SetRTC(void);                //设置RTC时间函数
    void        RTC_config(void);        //RTC初始化函数
    void        RTC_read(void);                //读RTC时间函数
    void        ReturnRTC(void);        //返回时间信息
    u8                GetData(void);                //获取数据, 设置时间命令: 21-6-19 12:34:56
    void          delay_ms(u8 ms);
    u8                Timer0_Config(u8 t, u32 reload);        //t=0: reload值是主时钟周期数,  t=1: reload值是时间(单位us), 返回0正确, 返回1装载值过大错误.

    void        GPIO_INT_Config(u8 gpio, u8 mode, u8 pin);        //普通IO中断配置函数, 中断模式(只取其一): INT_FALL, INT_RISE, INT_LOW, INT_HIGH. 分别是 上升沿 下降沿 低电平  高电平 中断.



    //========================================================================
    // 函数: void main(void)
    // 描述: 主函数
    // 参数: none.
    // 返回: none.
    // 版本: VER1.0
    // 日期: 2018-4-2
    // 备注:
    //========================================================================
    void main(void)
    {
            P_SW2 = 0x80;        //允许访问扩展寄存器

            P0M1 = 0;        P0M0 = 0;
            P1M1 = 0;        P1M0 = 0;
            P2M1 = 0;        P2M0 = 0;
            P3M1 = 0;        P3M0 = 0;
            P4M1 = 0;        P4M0 = 0;
            P5M1 = 0;        P5M0 = 0;
            P6M1 = 0;        P6M0 = 0;
            P7M1 = 0;        P7M0 = 0;

            UART1_config(115200UL, 1, 0);        // brt: 通信波特率,  timer=2: 波特率使用定时器2, 其它值: 使用Timer1做波特率. io=0: 串口1切换到P3.0 P3.1,  =1: 切换到P3.6 P3.7,  =2: 切换到P1.6 P1.7.
            Timer0_Config(0, MAIN_Fosc / 1000);        //t=0: reload值是主时钟周期数,  (中断频率, 1000次/秒)

            GPIO_INT_Config(GPIO_P4, INT_FALL, Pin0 | Pin1 | Pin2 | Pin3);        //普通IO中断配置函数, 中断模式(只取其一): INT_FALL, INT_RISE, INT_LOW, INT_HIGH. 分别是 上升沿 下降沿 低电平  高电平 中断.
            GPIO_INT_Config(GPIO_P4, INT_RISE, Pin4 | Pin5 | Pin6 | Pin7);        //普通IO中断配置函数, 中断模式(只取其一): INT_FALL, INT_RISE, INT_LOW, INT_HIGH. 分别是 上升沿 下降沿 低电平  高电平 中断.
            P4WKUE = 0xff;        //允许所有P4口中断唤醒.

            EA = 1;

            UART1_PrintString("STC8H RTC Test Prgramme!\r\n");

            OpTime    = 0;
            RTC_config();


            while (1)
            {
                    if(B_1ms)
                    {
                            B_1ms = 0;

                            if(OpTime != 0)        OpTime--;        //连续运行时间

                            if(RX1_TimeOut != 0)
                            {
                                    if(--RX1_TimeOut == 0)        //设置时间命令: 21-6-19 12:34:56
                                    {
                                            if(RX1_Buffer[0] == 'A')        //设置闹铃
                                            {
                                                    GetDataIndex = 1;        //获取数据索引仅仅用于读取计数
                                                    GetDataState = 0;        //获取数据状态, 非0则错误
                                                    ALARM_hour   = GetData();                //获取数据 时
                                                    ALARM_minute = GetData();                //获取数据 分
                                                    ALARM_second = GetData();                //获取数据 秒
                                                    if(GetDataState == 0)        //获取数据状态, 为0则正确, 非0则错误
                                                    {
                                                            ALAHOUR = ALARM_hour;                 // RTC闹钟的小时值
                                                            ALAMIN  = ALARM_minute;                // RTC闹钟的分钟值
                                                            ALASEC  = ALARM_second;                // RTC闹钟的秒值
                                                            ALASSEC = 0;                                // RTC闹钟的1/128秒值
                                                            RTCIEN  |= 0x80;        //中断使能, 0x80:闹钟中断, 0x40:日中断, 0x20:小时中断, 0x10:分钟中断, 0x08:秒中断, 0x04:1/2秒中断, 0x02:1/8秒中断, 0x01:1/32秒中断
                                                            UART1_PrintString("已设置闹铃!\r\n");
                                                    }
                                                    else
                                                    {
                                                            UART1_PrintString("设置闹铃数据错误!\r\n");
                                                            UART1_PrintString("错误代码: ");
                                                            UART1_TxByte(GetDataState+'0');
                                                            UART1_PrintString("\r\n");
                                                    }
                                            }
                                            else        //设置时间
                                            {
                                                    GetDataIndex = 0;        //获取数据索引仅仅用于读取计数
                                                    GetDataState = 0;        //获取数据状态, 非0则错误
                                                    year   = GetData();                //获取数据 年
                                                    month  = GetData();                //获取数据 月
                                                    day    = GetData();                //获取数据 日
                                                    hour   = GetData();                //获取数据 时
                                                    minute = GetData();                //获取数据 分
                                                    second = GetData();                //获取数据 秒
                                                    if(GetDataState == 0)        //获取数据状态, 为0则正确, 非0则错误
                                                    {
                                                            UART1_PrintString("获取设置时间: ");        ReturnRTC();
                                                            if(SetRTC() == 0)        UART1_PrintString("已设置时间!\r\n");
                                                            else                                UART1_PrintString("设置时间数据错误!\r\n");
                                                    }
                                                    else
                                                    {
                                                            UART1_PrintString("设置时间数据错误!\r\n");
                                                            UART1_PrintString("错误代码: ");
                                                            UART1_TxByte(GetDataState+'0');
                                                            UART1_PrintString("\r\n");
                                                    }
                                            }
                                            RX1_Cnt = 0;
                                    }
                            }
                    }

                    if(B_ALARM)                //闹铃
                    {
                            B_ALARM = 0;
                            UART1_PrintString("滴滴滴! 闹铃! \r\n");
                    }

                    if(B_1S)        //秒有变化
                    {
                            B_1S = 0;
                            RTC_read();
                            ReturnRTC();                                //从串口返回时间信息
                    }

                    if(OpTime == 0)                // OpTime==0才进入掉电模式
                    {
                            AUXINTIF &= ~INT4IF;        //清除外中断4标志位
                            NOP(3);
                            INT_CLKO |= (1 << 6);        //INT4 允许中断, 唤醒配合串口接收。
                            NOP(3);

                            PCON |= 0x02;        //睡眠
                            NOP(5);

                            INT_CLKO &= ~(1 << 6);        //INT4 禁止中断        (按用户程序需要)
                    }
            }
    }

    /********************* INT4中断函数 *************************/
    void INT4_ISR (void) interrupt 16
    {
            OpTime = 5000;        //取反指示引脚
    }


    /********************** 获取串口数据 *****************************/
    u8        GetData(void)
    {
            u8 i,j,k;

            if(GetDataIndex >= RX1_Cnt)
            {
                    GetDataState = 1;
                    return 0;
            }
    //        if(RX1_Cnt < 11)        //数据长度错误 设置时间
            if(RX1_Cnt < 6)                //数据长度错误 设置时间 设置闹铃
            {
                    GetDataState = 2;
                    return 0;
            }

            i = 0;
            k = 0;
            while(GetDataIndex <= RX1_Cnt)                //设置时间命令: 21-6-19 12:34:56
            {
                    j = RX1_Buffer[GetDataIndex];
                    if((j == '-') || (j == ' ') || (j == ':') || (GetDataIndex == RX1_Cnt))        //数据段结束
                    {
                            GetDataIndex++;
                            if(i == 0)        //数据错误
                            {
                                    GetDataState = 3;
                                    return 0;
                            }
                            else        return k;        //数据正确
                    }
                    if((j < '0') || (j > '9'))        //数据合法性检测
                    {
                            GetDataIndex++;
                            GetDataState = 4;
                            return 0;
                    }
                    k = k * 10 + j - '0';
                    i++;
                    GetDataIndex++;
            }

            GetDataState = 9;
            return 10;        //数据错误
    }

    /********************** 串口返回时间信息 *****************************/
    void        ReturnRTC(void)
    {
            UART1_TxByte(year/10+'0');        //年
            UART1_TxByte(year%10+'0');
            UART1_TxByte('-');
            UART1_TxByte(month/10+'0');        //月
            UART1_TxByte(month%10+'0');
            UART1_TxByte('-');
            UART1_TxByte(day/10+'0');        //日
            UART1_TxByte(day%10+'0');
            UART1_TxByte(' ');
            UART1_TxByte(hour/10+'0');        //时
            UART1_TxByte(hour%10+'0');
            UART1_TxByte(':');
            UART1_TxByte(minute/10+'0');        //分
            UART1_TxByte(minute%10+'0');
            UART1_TxByte(':');
            UART1_TxByte(second/10+'0');        //秒
            UART1_TxByte(second%10+'0');
            UART1_TxByte(0x0d);
            UART1_TxByte(0x0a);
    }


    /********************** 设置RTC时间 *****************************/
    u8        SetRTC(void)
    {
            P_SW2 |= 0x80;                //SFR enable
            if(year > 99)                                                return 1;
            if((month == 0) || (month > 12))        return 2;
            if((day == 0) || (day > 31))                return 3;
            if(hour > 23)                                        return 4;
            if(minute > 59)                                        return 5;
            if(second > 59)                                        return 6;
            INIYEAR  = year;
            INIMONTH = month;
            INIDAY   = day;
            INIHOUR  = hour;
            INIMIN   = minute;
            INISEC   = second;
            INISSEC  = 0;
            RTCCFG   = 0x01 | 0x00;        //设置RTC时间, |0x00:选择外部32K时钟, |0x02:选择内部32K时钟.
            while(RTCCFG & 0x01);        //等待初始化完成. 设置RTC时间需要32768Hz的1个周期时间,大约30.5us. 由于同步, 所以实际等待时间是0~30.5us.
                                                            //如果不等待设置完成就睡眠, 则RTC会由于设置没完成, 停止计数, 唤醒后才继续完成设置并继续计数.
            return 0;
    }

    /********************** RTC配置函数 *****************************/
    void        RTC_config(void)        //RTC初始化函数
    {
            P_SW2  |= 0x80;                //SFR enable
            P1n_pure_input(0xc0);                //P1.6 P1.7设置为高阻输入
            P1IE = ~0xc0;                                //P1.6 P1.7关闭数字输入功能
            X32KCR = 0x80 + 0x40;                //启动外部32K晶振, 低增益+0x00, 高增益+0x40.

            year    = 21;
            month   = 6;
            day     = 18;
            hour    = 12;
            minute  = 0;
            second  = 0;

            RTCCR   = 0x01;        //使能RTC, 并开始RTC计数
            SetRTC();                //设置RTC时间
            RTCIF   = 0;        //中断标志, 0x80:闹钟中断, 0x40:日中断, 0x20:小时中断, 0x10:分钟中断, 0x08:秒中断, 0x04:1/2秒中断, 0x02:1/8秒中断, 0x01:1/32秒中断
    //        RTCIEN  = 0x08;        //中断使能, 0x80:闹钟中断, 0x40:日中断, 0x20:小时中断, 0x10:分钟中断, 0x08:秒中断, 0x04:1/2秒中断, 0x02:1/8秒中断, 0x01:1/32秒中断
            RTCIEN  = 0x10;        //中断使能, 0x80:闹钟中断, 0x40:日中断, 0x20:小时中断, 0x10:分钟中断, 0x08:秒中断, 0x04:1/2秒中断, 0x02:1/8秒中断, 0x01:1/32秒中断
            ALAHOUR = 8;        //闹钟小时
            ALAMIN  = 30;        //闹钟分钟
            ALASEC  = 0;        //闹钟秒
            ALASSEC = 0;        //闹钟1/128秒
    }

    /********************** 读取RTC时间信息 *****************************/
    void        RTC_read(void)
    {
            P_SW2  |= 0x80;                //SFR enable
            year    = RTC_YEAR;                // RTC的年计数值
            month   = RTC_MONTH;        // RTC的月计数值
            day     = RTC_DAY;                // RTC的日计数值
            hour    = RTC_HOUR;                // RTC的时计数值
            minute  = RTC_MIN;                // RTC的分计数值
            second  = RTC_SEC;                // RTC的秒计数值
    //        ssecond = RTC_SSEC;                // RTC的1/128秒计数值
    }



    //========================================================================
    // 函数: SetTimer2Baudraye(u16 dat)
    // 描述: 设置Timer2做波特率发生器。
    // 参数: dat: Timer2的重装值.
    // 返回: none.
    // 版本: VER1.0
    // 日期: 2018-4-2
    // 备注:
    //========================================================================
    void        SetTimer2Baudraye(u16 dat)        // 选择波特率, 2: 使用Timer2做波特率, 其它值: 使用Timer1做波特率.
    {
            AUXR &= ~(1<<4);        //Timer stop
            AUXR &= ~(1<<3);        //Timer2 set As Timer
            AUXR |=  (1<<2);        //Timer2 set as 1T mode
            TH2 = (u8)(dat >> 8);
            TL2 = (u8)dat;
            IE2  &= ~(1<<2);        //禁止中断
            AUXR |=  (1<<4);        //Timer run enable
    }


    //========================================================================
    // 函数: void        UART1_config(u32 brt, u8 timer, u8 io)
    // 描述: UART1初始化函数。
    // 参数:   brt: 通信波特率.
    //       timer: 波特率使用的定时器, timer=2: 波特率使用定时器2, 其它值: 使用Timer1做波特率.
    //          io: 串口1切换到的IO,  io=1: 串口1切换到P3.0 P3.1,  =1: 切换到P3.6 P3.7,  =2: 切换到P1.6 P1.7.
    // 返回: none.
    // 版本: VER1.0
    // 日期: 2018-4-2
    // 备注:
    //========================================================================
    void        UART1_config(u32 brt, u8 timer, u8 io)        // brt: 通信波特率,  timer=2: 波特率使用定时器2, 其它值: 使用Timer1做波特率. io=0: 串口1切换到P3.0 P3.1,  =1: 切换到P3.6 P3.7.
    {
            brt = 65536UL - (MAIN_Fosc / 4) / brt;
            if(timer == 2)        //波特率使用定时器2
            {
                    AUXR |= 0x01;                //S1 BRT Use Timer2;
                    SetTimer2Baudraye((u16)brt);
            }

            else                //波特率使用定时器1
            {
                    TR1 = 0;
                    AUXR &= ~0x01;                //S1 BRT Use Timer1;
                    AUXR |=  (1<<6);        //Timer1 set as 1T mode
                    TMOD &= ~(1<<6);        //Timer1 set As Timer
                    TMOD &= ~0x30;                //Timer1_16bitAutoReload;
                    TH1 = (u8)(brt >> 8);
                    TL1 = (u8)brt;
                    ET1 = 0;                        // 禁止Timer1中断
                    INT_CLKO &= ~0x02;        // Timer1不输出高速时钟
                    TR1  = 1;                        // 运行Timer1
            }

                     if(io == 1)        {S1_USE_P36P37();        P3n_standard(0xc0);}        //切换到 P3.6 P3.7
            else if(io == 2)        {S1_USE_P16P17();        P1n_standard(0xc0);}        //切换到 P1.6 P1.7
            else                                {S1_USE_P30P31();        P3n_standard(0x03);}        //切换到 P3.0 P3.1

            SCON = (SCON & 0x3f) | (1<<6);        // 8位数据, 1位起始位, 1位停止位, 无校验
    //        PS  = 1;        //高优先级中断
            ES  = 1;        //允许中断
            REN = 1;        //允许接收
    }


    //========================================================================
    // 函数: void UART1_TxByte(u8 dat)
    // 描述: 串口1发送一个字节数据函数
    // 参数: dat: 要发送的一个字节数据.
    // 返回: none.
    // 版本: VER1.0
    // 日期: 2018-4-2
    // 备注:
    //========================================================================
    void UART1_TxByte(u8 dat)
    {
            B_TX1_Busy = 1;                //标志发送忙
            SBUF = dat;                        //发一个字节
            while(B_TX1_Busy);        //等待发送完成
    }

    //========================================================================
    // 函数: void UART1_PrintString(u8 *puts)
    // 描述: 串口1字符串打印函数
    // 参数: puts: 字符串指针.
    // 返回: none.
    // 版本: VER1.0
    // 日期: 2018-4-2
    // 备注:
    //========================================================================
    void UART1_PrintString(u8 *puts)
    {
        for (; *puts != 0;        puts++)        UART1_TxByte(*puts);
    }


    //========================================================================
    // 函数: void UART1_int (void) interrupt UART1_VECTOR
    // 描述: 串口1中断函数
    // 参数: none.
    // 返回: none.
    // 版本: VER1.0
    // 日期: 2018-4-2
    // 备注:
    //========================================================================
    void UART1_ISR (void) interrupt UART1_VECTOR
    {
            if(RI)
            {
                    RI = 0;
                    if(RX1_Cnt >= RX1_Length)        RX1_Cnt = 0;
                    RX1_Buffer[RX1_Cnt++] = SBUF;
                    RX1_TimeOut = 5;
                    OpTime = 5000;        //串口一旦唤醒, 接着5秒不睡眠, 以便正确接收数据. 唤醒帧将不能正确接收(因为唤醒需要计时us时间), 除非用很慢的速度(比如2400).
            }

            if(TI)
            {
                    TI = 0;
                    B_TX1_Busy = 0;
            }
    }


    //========================================================================
    // 函数:u8        Timer0_Config(u8 t, u32 reload)
    // 描述: timer0初始化函数.
    // 参数:      t: 重装值类型, 0表示重装的是系统时钟数, 其余值表示重装的是时间(us).
    //       reload: 重装值.
    // 返回: 0: 初始化正确, 1: 重装值过大, 初始化错误.
    // 版本: V1.0, 2018-3-5
    //========================================================================
    u8        Timer0_Config(u8 t, u32 reload)        //t=0: reload值是主时钟周期数,  t=1: reload值是时间(单位us)
    {
            TR0 = 0;        //停止计数

            if(t != 0)        reload = (u32)(((float)MAIN_Fosc * (float)reload)/1000000UL);        //重装的是时间(us), 计算所需要的系统时钟数.
            if(reload >= (65536UL * 12))        return 1;        //值过大, 返回错误
            if(reload < 65536UL)        AUXR |= 0x80;                //1T mode
            else
            {
                    AUXR &= ~0x80;        //12T mode
                    reload = reload / 12;
            }
            reload = 65536UL - reload;
            TH0 = (u8)(reload >> 8);
            TL0 = (u8)(reload);

            ET0 = 1;        //允许中断
    //        PT0 = 1;        //高优先级中断
            TMOD = (TMOD & ~0x03) | 0;        //工作模式, 0: 16位自动重装, 1: 16位定时/计数, 2: 8位自动重装, 3: 16位自动重装, 不可屏蔽中断
            TR0 = 1;                        //开始运行
            return 0;
    }

    //========================================================================
    // 函数: void timer0_int (void) interrupt TIMER0_VECTOR
    // 描述:  timer0中断函数.
    // 参数: none.
    // 返回: none.
    // 版本: V1.0, 2016-5-12
    //========================================================================
    void timer0_ISR (void) interrupt TIMER0_VECTOR
    {
       B_1ms = 1;        //1ms标志
    }


    //========================================================================
    // 函数: AUXR_ISR(void) interrupt 13
    // 描述: 扩展中断函数(中断号>=32的中断)
    // 参数: none.
    // 返回: none.
    // 版本: VER1.0
    // 日期: 2018-4-2
    // 备注:
    //========================================================================
    void        RTC_ISR(void) interrupt 36
    {
            u8        i;
            i = RTCIF;
            RTCIF = 0;                //中断标志, 0x80:闹钟中断, 0x40:日中断, 0x20:小时中断, 0x10:分钟中断, 0x08:秒中断, 0x04:1/2秒中断, 0x02:1/8秒中断, 0x01:1/32秒中断
    //        if(i & 0x08)        //秒中断
            if(i & 0x10)        //分中断
            {
                    B_1S = 1;        //秒标志
            }
            if(i & 0x80)        //闹铃中断
            {
                    B_ALARM = 1;        //闹铃标志
            }
    }


    //========================================================================
    // 函数: void        GPIO_INT_Config(u8 gpio, u8 pin, u8 mode)
    // 描述: IO中断初始化函数.
    // 参数: gpio: 要初始化的IO组, 参数取值(只取其一): GPIO_P0, GPIO_P1, GPIO_P2, GPIO_P3, GPIO_P4, GPIO_P5, GPIO_P6, GPIO_P7, GPIO_P8, GPIO_P9.
    //       mode: 中断模式,       参数取值(只取其一): INT_FALL, INT_RISE, INT_LOW, INT_HIGH. 分别是 上升沿 下降沿 低电平  高电平 中断.
    //       pin:  要初始化的引脚, 参数取值(多个值时用或操作): Pin0, Pin1, Pin2, Pin3, Pin4, Pin5, Pin6, Pin7. PinAll.
    // 返回: none.
    // 版本: VER1.0
    // 日期: 2020-5-20
    // 备注:
    //========================================================================
    void        GPIO_INT_Config(u8 gpio, u8 mode, u8 pin)
    {
            u8        xdata        *pt;
            u8        j;

            if(gpio >= 10)        return;        //IO口错误
            if(mode >= 4)        return;        //模式错误
            P_SW2 |= 0x80;                        //访问XFR

            pt  = 0xfd00 + gpio;
            *pt |= pin;                                //允许IO中断

            pt  = 0xfd30 + gpio;
            if(mode & 0x02)        j = 0xff & pin;        //设置模式
            else                        j = 0;
            *pt = (*pt & ~pin) | j;
            pt  = 0xfd20 + gpio;
            if(mode & 0x01)        j = 0xff & pin;
            else                        j = 0;
            *pt = (*pt & ~pin) | j;
    }



    //========================================================================
    // 函数: void        P0INT_ISR(void) interrupt 37
    // 描述: P0(P0.0~P0.7)中断处理函数.
    // 参数: none.
    // 返回: none.
    // 版本: VER1.0
    // 日期: 2020-5-20
    // 备注:
    //========================================================================
    void        P0INT_ISR(void) interrupt 37        //P0.0~P0.7 IO中断处理代码
    {
            u8        i;
            i = P0INTF;                //读取中断标志
            P0INTF &= ~i;        //清除中断标志

            if((i & INTF_0) != 0)        //P0.0中断
            {
                    P10 = ~P10;                        //取反P1.0指示
            }
            if((i & INTF_1) != 0)        //P0.1中断
            {
                    P11 = ~P11;                        //取反P1.1指示
            }
            if((i & INTF_2) != 0)        //P0.2中断
            {
                    P12 = ~P12;                        //取反P1.2指示
            }
            if((i & INTF_3) != 0)        //P0.3中断
            {
                    P13 = ~P13;                        //取反P1.3指示
            }
            if((i & INTF_4) != 0)        //P0.4中断
            {
                    P14 = ~P14;                        //取反P1.4指示
            }
            if((i & INTF_5) != 0)        //P0.5中断
            {
                    P15 = ~P15;                        //取反P1.5指示
            }
            if((i & INTF_6) != 0)        //P0.6中断
            {
                    P16 = ~P16;                        //取反P1.6指示
            }
            if((i & INTF_7) != 0)        //P0.7中断
            {
                    P17 = ~P17;                        //取反P1.7指示
            }
    }

    //========================================================================
    // 函数: void        P1INT_ISR(void) interrupt 38
    // 描述: P1(P1.0~P1.7)中断处理函数.
    // 参数: none.
    // 返回: none.
    // 版本: VER1.0
    // 日期: 2020-5-20
    // 备注:
    //========================================================================
    void        P1INT_ISR(void) interrupt 38                //P1.0~P1.7 IO中断处理代码
    {
            u8        i;
            i = P1INTF;                //读取中断标志
            P1INTF &= ~i;        //清除中断标志

            if((i & INTF_0) != 0)        //P1.0中断
            {
                    P00 = ~P00;                        //取反P0.0指示
            }
            if((i & INTF_1) != 0)        //P1.1中断
            {
                    P01 = ~P01;                        //取反P0.1指示
            }
            if((i & INTF_2) != 0)        //P1.2中断
            {
                    P02 = ~P02;                        //取反P0.2指示
            }
            if((i & INTF_3) != 0)        //P1.3中断
            {
                    P03 = ~P03;                        //取反P0.3指示
            }
            if((i & INTF_4) != 0)        //P1.4中断
            {
                    P04 = ~P04;                        //取反P0.4指示
            }
            if((i & INTF_5) != 0)        //P1.5中断
            {
                    P05 = ~P05;                        //取反P0.5指示
            }
            if((i & INTF_6) != 0)        //P1.6中断
            {
                    P06 = ~P06;                        //取反P0.6指示
            }
            if((i & INTF_7) != 0)        //P1.7中断
            {
                    P07 = ~P07;                        //取反P0.7指示
            }
    }

    //========================================================================
    // 函数: void        P2INT_ISR(void) interrupt 39
    // 描述: P2(P2.0~P2.7)中断处理函数.
    // 参数: none.
    // 返回: none.
    // 版本: VER1.0
    // 日期: 2020-5-20
    // 备注:
    //========================================================================
    void        P2INT_ISR(void) interrupt 39                //P2.0~P2.7 IO中断处理代码
    {
            u8        i;
            i = P2INTF;                //读取中断标志
            P2INTF &= ~i;        //清除中断标志

            if((i & INTF_0) != 0)        //P2.0中断
            {
                    P40 = ~P40;                        //取反P4.0指示
            }
            if((i & INTF_1) != 0)        //P2.1中断
            {
                    P41 = ~P41;                        //取反P4.1指示
            }
            if((i & INTF_2) != 0)        //P2.2中断
            {
                    P42 = ~P42;                        //取反P4.2指示
            }
            if((i & INTF_3) != 0)        //P2.3中断
            {
                    P43 = ~P43;                        //取反P4.3指示
            }
            if((i & INTF_4) != 0)        //P2.4中断
            {
                    P44 = ~P44;                        //取反P4.4指示
            }
            if((i & INTF_5) != 0)        //P2.5中断
            {
                    P45 = ~P45;                        //取反P4.5指示
            }
            if((i & INTF_6) != 0)        //P2.6中断
            {
                    P46 = ~P46;                        //取反P4.6指示
            }
            if((i & INTF_7) != 0)        //P2.7中断
            {
                    P47 = ~P47;                        //取反P4.7指示
            }
    }

    //========================================================================
    // 函数: void        P3INT_ISR(void) interrupt 40
    // 描述: P3(P3.0~P3.7)中断处理函数.
    // 参数: none.
    // 返回: none.
    // 版本: VER1.0
    // 日期: 2020-5-20
    // 备注:
    //========================================================================
    void        P3INT_ISR(void) interrupt 40                //P3.0~P3.7 IO中断处理代码
    {
            u8        i;
            i = P3INTF;                //读取中断标志
            P3INTF &= ~i;        //清除中断标志

            if((i & INTF_0) != 0)        //P3.0中断
            {
                    P40 = ~P40;                        //取反P4.0指示
            }
            if((i & INTF_1) != 0)        //P3.1中断
            {
                    P41 = ~P41;                        //取反P4.1指示
            }
            if((i & INTF_2) != 0)        //P3.2中断
            {
                    P42 = ~P42;                        //取反P4.2指示
            }
            if((i & INTF_3) != 0)        //P3.3中断
            {
                    P43 = ~P43;                        //取反P4.3指示
            }
            if((i & INTF_4) != 0)        //P3.4中断
            {
                    P44 = ~P44;                        //取反P4.4指示
            }
            if((i & INTF_5) != 0)        //P3.5中断
            {
                    P45 = ~P45;                        //取反P4.5指示
            }
            if((i & INTF_6) != 0)        //P3.6中断
            {
                    P46 = ~P46;                        //取反P4.6指示
            }
            if((i & INTF_7) != 0)        //P3.7中断
            {
                    P47 = ~P47;                        //取反P4.7指示
            }
    }

    //========================================================================
    // 函数: void        P4INT_ISR(void) interrupt 41
    // 描述: P4(P4.0~P4.7)中断处理函数.
    // 参数: none.
    // 返回: none.
    // 版本: VER1.0
    // 日期: 2020-5-20
    // 备注:
    //========================================================================
    void        P4INT_ISR(void) interrupt 41                //P4.0~P4.7 IO中断处理代码
    {
            u8        i;
            i = P4INTF;                //读取中断标志
            P4INTF &= ~i;        //清除中断标志

            if((i & INTF_0) != 0)        //P4.0中断
            {
                    P20 = ~P20;                        //取反P2.0指示
            }
            if((i & INTF_1) != 0)        //P4.1中断
            {
                    P21 = ~P21;                        //取反P2.1指示
            }
            if((i & INTF_2) != 0)        //P4.2中断
            {
                    P22 = ~P22;                        //取反P2.2指示
            }
            if((i & INTF_3) != 0)        //P4.3中断
            {
                    P23 = ~P23;                        //取反P2.3指示
            }
            if((i & INTF_4) != 0)        //P4.4中断
            {
                    P24 = ~P24;                        //取反P2.4指示
            }
            if((i & INTF_5) != 0)        //P4.5中断
            {
                    P25 = ~P25;                        //取反P2.5指示
            }
            if((i & INTF_6) != 0)        //P4.6中断
            {
                    P26 = ~P26;                        //取反P2.6指示
            }
            if((i & INTF_7) != 0)        //P4.7中断
            {
                    P27 = ~P27;                        //取反P2.7指示
            }
    }

    //========================================================================
    // 函数: void        P5INT_ISR(void) interrupt 42
    // 描述: P5(P5.0~P5.4)中断处理函数.
    // 参数: none.
    // 返回: none.
    // 版本: VER1.0
    // 日期: 2020-5-20
    // 备注:
    //========================================================================
    void        P5INT_ISR(void) interrupt 42                //P5.0~P5.4 IO中断处理代码
    {
            u8        i;
            i = P5INTF;                //读取中断标志
            P5INTF &= ~i;        //清除中断标志

            if((i & INTF_0) != 0)        //P5.0中断
            {
                    P40 = ~P40;                        //取反P4.0指示
            }
            if((i & INTF_1) != 0)        //P5.1中断
            {
                    P41 = ~P41;                        //取反P4.1指示
            }
            if((i & INTF_2) != 0)        //P5.2中断
            {
                    P42 = ~P42;                        //取反P4.2指示
            }
            if((i & INTF_3) != 0)        //P5.3中断
            {
                    P43 = ~P43;                        //取反P4.3指示
            }
            if((i & INTF_4) != 0)        //P5.4中断
            {
                    P44 = ~P44;                        //取反P4.4指示
            }
            if((i & INTF_5) != 0)        //P5.5中断
            {
                    P45 = ~P45;                        //取反P4.5指示
            }
    }

    //========================================================================
    // 函数: void        P6INT_ISR(void) interrupt 43
    // 描述: P6(P6.0~P6.7)中断处理函数.
    // 参数: none.
    // 返回: none.
    // 版本: VER1.0
    // 日期: 2020-5-20
    // 备注:
    //========================================================================
    void        P6INT_ISR(void) interrupt 43                //P6.0~P6.7 IO中断处理代码
    {
            u8        i;
            i = P6INTF;                //读取中断标志
            P6INTF &= ~i;        //清除中断标志

            if((i & INTF_0) != 0)        //P6.0中断
            {
                    P70 = ~P70;                        //取反P7.0指示
            }
            if((i & INTF_1) != 0)        //P6.1中断
            {
                    P71 = ~P71;                        //取反P7.1指示
            }
            if((i & INTF_2) != 0)        //P6.2中断
            {
                    P72 = ~P72;                        //取反P7.2指示
            }
            if((i & INTF_3) != 0)        //P6.3中断
            {
                    P73 = ~P73;                        //取反P7.3指示
            }
            if((i & INTF_4) != 0)        //P6.4中断
            {
                    P74 = ~P74;                        //取反P7.4指示
            }
            if((i & INTF_5) != 0)        //P6.5中断
            {
                    P75 = ~P75;                        //取反P7.5指示
            }
            if((i & INTF_6) != 0)        //P6.6中断
            {
                    P76 = ~P76;                        //取反P7.6指示
            }
            if((i & INTF_7) != 0)        //P6.7中断
            {
                    P77 = ~P77;                        //取反P7.7指示
            }
    }

    //========================================================================
    // 函数: void        P7INT_ISR(void) interrupt 44
    // 描述: P0(P7.0~P7.7)中断处理函数.
    // 参数: none.
    // 返回: none.
    // 版本: VER1.0
    // 日期: 2020-5-20
    // 备注:
    //========================================================================
    void        P7INT_ISR(void) interrupt 44                //P7.0~P7.7 IO中断处理代码
    {
            u8        i;
            i = P7INTF;                //读取中断标志
            P7INTF &= ~i;        //清除中断标志

            if((i & INTF_0) != 0)        //P7.0中断
            {
                    P60 = ~P60;                        //取反P6.0指示
            }
            if((i & INTF_1) != 0)        //P7.1中断
            {
                    P61 = ~P61;                        //取反P6.1指示
            }
            if((i & INTF_2) != 0)        //P7.2中断
            {
                    P62 = ~P62;                        //取反P6.2指示
            }
            if((i & INTF_3) != 0)        //P7.3中断
            {
                    P63 = ~P63;                        //取反P6.3指示
            }
            if((i & INTF_4) != 0)        //P7.4中断
            {
                    P64 = ~P64;                        //取反P6.4指示
            }
            if((i & INTF_5) != 0)        //P7.5中断
            {
                    P65 = ~P65;                        //取反P6.5指示
            }
            if((i & INTF_6) != 0)        //P7.6中断
            {
                    P66 = ~P66;                        //取反P6.6指示
            }
            if((i & INTF_7) != 0)        //P7.7中断
            {
                    P67 = ~P67;                        //取反P6.7指示
            }
    }


    回复 支持 反对 送花

    使用道具 举报

  • TA的每日心情
    开心
    2024-3-25 18:16
  • 签到天数: 8 天

    [LV.3]偶尔看看II

    0

    主题

    9

    回帖

    76

    积分

    注册会员

    积分
    76
    发表于 2023-11-28 00:57:07 | 显示全部楼层
    谢谢分享
    回复 送花

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

    GMT+8, 2024-4-29 14:36 , Processed in 0.266168 second(s), 68 queries .

    Powered by Discuz! X3.5

    © 2001-2024 Discuz! Team.

    快速回复 返回顶部 返回列表