搜索
bottom↓
回复: 0

《ATK-DFPGL22G之FPGA开发指南_V1.0》第二十七章 RTC实验

[复制链接]

出0入234汤圆

发表于 2023-7-6 10:41:51 | 显示全部楼层 |阅读模式
本帖最后由 正点原子 于 2023-7-6 10:41 编辑

1)实验平台:正点原子 DFZU2EG_4EV MPSoC开发板
2)购买链接:https://item.taobao.com/item.htm?&id=692368045899
3)全套实验源码+手册+视频下载地址:http://www.openedv.com/thread-340252-1-1.html
4)正点原子官方B站:https://space.bilibili.com/394620890
5)正点原子FPGA交流群:994244016 lQLPJxaFi2zaB4UWWrDAMgIsFEW2pwLb3abnwDMA_90_22.png
lQDPJxaFi2nfFizMjM0CbLCPlxn_FVheIQLb3aGrwFQA_620_140.jpg

lQLPJxaFi2nfFhLMkM0BXrDNvOUyeU_FPgLb3aGvQNIA_350_144.png

第二十七章 RTC实验


本章介绍APM32E103实时时钟(RTC)的使用,实时时钟能为系统提供一个准确的时间,即时系统复位或主电源断电,RTC依然能够运行,因此RTC也经常用于各种低功耗场景。通过本章的学习,读者将学习到RTC的使用。
本章分为如下几个小节:
27.1 硬件设计
27.2 程序设计
27.3 下载验证


27.1 硬件设计
27.1.1 例程功能

1. LED1每秒翻转一次,表示每秒产生一次RTC唤醒中断
2. 通过LCD实时显示RTC时间,并可通过USMART设置RTC时间等
3. LED0闪烁,指示程序正在运行
27.1.2 硬件资源
1. LED
        LED0 - PB5
2. USART1(PA9、PA10连接至板载USB转串口芯片上)
3. 正点原子 2.8/3.5/4.3/7/10寸TFTLCD模块(仅限MCU屏,16位8080并口驱动)
4. RTC
27.1.3 原理图
本章实验使用的RTC为APM32E103的片上资源,因此没有相应的连接原理图。
27.2 程序设计
27.2.1 Geehy标准库的PMU驱动

本章实验要使用到RTC,因此需要对RTC及其相关的寄存器进行配置,但是为了防止误操作,系统复位后备份区域(指RTC、备份寄存器)是被禁止写访问的,备份区域的写访问是由电源管理单元(PMU)进行配置的,具体的配置步骤如下:
①:使能写备份区域
在Geehy标准库中对应的驱动函数如下:
①:使能写备份区域
该函数用于使能写备份区域,其函数原型如下所示:
void PMU_EnableBackupAccess(void);
该函数的形参描述,如下表所示:
lQLPJw_3HgxD7EYizQHbsN2D0p2nPRddBJvVQkuA9AA_475_34.png
表27.2.1.1 函数PMU_EnableBackupAccess()形参描述

该函数的返回值描述,如下表所示:
lQLPJwDm3CeH_eYkzQHdsGkdVKp4Cgk_BJvSZ3yAowA_477_36.png
表27.2.1.2 函数PMU_EnableBackupAccess()返回值描述

该函数的使用示例,如下所示:
#include " apm32e10x.h"
#include "apm32e10x _pmu.h"

void example_fun(void)
{
    /* 使能写备份区域 */
    PMU_EnableBackupAccess();
}
27.2.2 Geehy标准库的RCM驱动
本章实验使用了RTC,因此需要配置RTC的时钟,RTC的时钟可以来自LSE、LSI或HSE的分频,以上均由RCM进行管理,其具体的配置步骤如下:
①:优先使能LSE
②:若LSE无法就绪,则使能LSI
③:配置RTC的时钟源为LSE或LSI
在Geehy标准库中对应的驱动函数如下:
①:使能LSE
该函数用于配置LSE,其函数原型如下所示:
void RCM_ConfigLSE(RCM_LSE_T state);
该函数的形参描述,如下表所示:
lQLPJwgvUtwuGEZCzQHdsDdGKGQTmDeGBJvS2DNAaAA_477_66.png
表27.2.2.1 函数RCM_ConfigLSE()形参描述

该函数的返回值描述,如下表所示:
lQLPJwQaUG-yfwYizQHdsDPG64KbAFuXBJvWY8vA9AA_477_34.png
表27.2.2.2 函数RCM_ConfigLSE()返回值描述

该函数的使用示例,如下所示:
#include "apm32e10x.h"
#include "apm32e10x_rcm.h"

void example_fun(void)
{
    /* 使能LSE */
    RCM_ConfigLSE(RCM_LSE_OPEN);
   
    /* 禁止LSE */
    RCM_ConfigLSE(RCM_LSE_CLOSE);
}
②:使能LSI
该函数用于使能LSI,其函数原型如下所示:
void RCM_EnableLSI(void);
该函数的形参描述,如下表所示:
lQLPJxDtlxGnsCYizQHdsKOpUvn-6E0HBJvSWLDAowA_477_34.png
表27.2.2.3 函数RCM_EnableLSI()形参描述

该函数的返回值描述,如下表所示:
lQLPJwuYcFZsWEYjzQHbsOkmDPrIi2qcBJvVVJlAEgA_475_35.png
表27.2.2.4 函数RCM_EnableLSI()返回值描述

该函数的使用示例,如下所示:
#include "apm32e10x.h"
#include "apm32e10x_rcm.h"

void example_fun(void)
{
    RCM_EnableLSI(); /* 使能LSI */
}
③:配置RTC的时钟源
该函数用于配置RTC的时钟源,其函数原型如下所示:
void RCM_ConfigRTCCLK(RCM_RTCCLK_T rtcClkSelect);
该函数的形参描述,如下表所示:
lQLPJwuqoPp4pkZBzQHdsHFBCv3hPYOsBJvVaUSAwwA_477_65.png
表27.2.2.5 函数RCM_ConfigRTCCLK()形参描述

该函数的返回值描述,如下表所示:
lQLPJwvYGms7-hIhzQHcsDBofiSquKVXBJCELThADAA_476_33.png
表27.2.2.6 函数RCM_ConfigRTCCLK()返回值描述

该函数的使用示例,如下所示:
#include "apm32e10x.h"
#include "apm32e10x_rcm.h"

void example_fun(void)
{
    /* 配置RTC的时钟源为LSE */
    RCM_ConfigRTCCLK(RCM_RTCCLK_LSE);
}
27.2.3 Geehy标准库的RTC驱动
本章实验使用了RTC,RTC最基本的操作就是设置和获取时间和日期,同时还需要读写RTC备份寄存器保存是否已经在初始化过程中设置过时间的标志,其具体的步骤如下:
①:初始化配置RTC
②:读取RTC备份寄存器判断是否进行设置过时间
③:若未设置过时间,则设置RTC的时间
④:若未设置过时间,则设置RTC的日期
⑤:将设置过时间的标志写入RTC备份寄存器
⑥:读取RTC的时间
⑦:读取RTC的日期
在Geehy标准库中对应的驱动函数如下:
①:读取RTC备份寄存器
该函数用于读取RTC备份寄存器,其函数原型如下所示:
uint16_t BAKPR_ReadBackupRegister(BAKPR_DATA_T bakrData);
该函数的形参描述,如下表所示:
lQLPJxgZ3Bp2UwZEzQHdsJS3plJDaTAaBJvVlSTAEgA_477_68.png
表27.2.3.3 函数BAKPR_ReadBackupRegister ()形参描述

该函数的返回值描述,如下表所示:
lQLPJwyOAJthTYYizQHcsCbmF9Wl8xJJBJvVo1bAwwA_476_34.png
表27.2.3.4 函数BAKPR_ReadBackupRegister ()返回值描述

该函数的使用示例,如下所示:
#include "apm32e10x.h"
#include "apm32e10x_rtc.h"

void example_fun(void)
{
    uint32_t rtc_backup_data1;
   
    /* 读取RTC备份寄存器1 */
    rtc_backup_data1 = BAKPR_ReadBackupRegister (BAKPR_DATA1);
   
    /* Do something. */
}
②:写入RTC备份寄存器
该函数用于写入RTC备份寄存器,其函数原型如下所示:
void BAKPR_ConfigBackupRegister(BAKPR_DATA_T bakrData, uint16_t data);
该函数的形参描述,如下表所示:
lQLPJwdwVGWBZcZUzQHesI_Fm1YiJqEhBJvWJ7pA9AA_478_84.png
表27.2.3.9 函数BAKPR_ConfigBackupRegister ()形参描述

该函数的返回值描述,如下表所示:
lQLPJxyd0_aU-wYjzQHesGOxsCpd-80vBJvVhwEA9AA_478_35.png
表27.2.3.10 函数BAKPR_ConfigBackupRegister ()返回值描述

该函数的使用示例,如下所示:
#include "apm32e10x.h"
#include "apm32e10x_rtc.h"

void example_fun(void)
{
    /* 往RTC备份寄存器0写入0x50505050 */
    BAKPR_ConfigBackupRegister(BAKPR_DATA1, 0x50505050);
}
③:使能RTC指定中断
该函数用于使能RTC的指定中断,其函数原型如下所示:
void RTC_EnableInterrupt(uint32_t interrupt);
该函数的形参描述,如下表所示:
lQLPJxJzw36YRgZDzQHesIcv3C5iTPzwBJvWU7MAMAA_478_67.png
表27.2.3.19 函数RTC_EnableInterrupt()形参描述

该函数的返回值描述,如下表所示:
lQLPJwZFG0Oj-kYjzQHdsCCPGTyNW9KEBJvS8QEAowA_477_35.png
表27.2.3.20 函数RTC_EnableInterrupt()返回值描述

该函数的使用示例,如下所示:
#include "apm32e10x.h"
#include "apm32e10x_rtc.h"

void example_fun(void)
{
    /* 使能RTC唤醒中断 */
    RTC_EnableInterrupt(RTC_INT_OVR);
}
④:使能RTC中断
请见第12.2.3小节中配置中断的相关内容。
本实验同时也使能了RTC的闹钟功能,闹钟功能可以在RTC时间到达设定值时触发中断,其具体的使用步骤如下:
①:配置RTC闹钟
②:配置RTC闹钟对应的EINT线
③:使能RTC闹钟中断
④:使能RTC闹钟中断,并配置其相关的中断优先级
⑤:使能RTC闹钟
在Geehy标准库中对应的驱动函数如下:
①:配置RTC闹钟
该函数用于配置RTC的闹钟,其函数原型如下所示:
void RTC_ConfigAlarm(uint32_t value);
该函数的形参描述,如下表所示:
lQLPJyGXHuGf5eYjzQHdsNZ50ThssHd7BJvWmZDAEgA_477_35.png
表27.2.3.23 函数RTC_ConfigAlarm()形参描述

该函数的返回值描述,如下表所示:
lQLPJyHe-I0DZYYhzQHdsMBqvuJSoatuBJvWOb2AEgA_477_33.png
表27.2.3.24 函数RTC_ConfigAlarm()返回值描述

该函数使用数值变量传入RTC闹钟的配置参数,并未用到具体的结构体。
#include "apm32e10x.h"
#include "apm32e10x_rtc.h"

void example_fun(uint8_t hour, uint8_t min, uint8_t sec)
{
uint32_t seccount = 0;

    seccount += (date - 1) * 86400;
    seccount += hour * 3600;
    seccount += min * 60;
    seccount += sec;

    RTC_ConfigAlarm(seccount);
}
②:使能RTC指定中断
请见第27.2.3小节中使能RTC指定中断的内容。
③:使能RTC中断
请见第12.2.3小节中配置中断的相关内容。
27.2.4 RTC驱动
本章实验的RTC驱动主要负责向应用层提供RTC的初始化和配置自动唤醒及闹钟的函数。本章实验中,RTC的驱动代码包括rtc.c和rtc.h两个文件。
RTC驱动中,RTC的初始化函数,如下所示:
/**
* @brief       初始化RTC
* @param       无
* @retval      初始化结果
* @arg         0: 初始化成功
* @arg         1: 初始化失败
*/
uint8_t rtc_init(void)
{
    uint16_t bkpflag;
    uint16_t retry;
   
    RCM_EnableAPB1PeriphClock(RCM_APB1_PERIPH_PMU);    /* 使能PMU时钟 */
    RCM_EnableAPB1PeriphClock(RCM_APB1_PERIPH_BAKR);   /* 使能BAKPR时钟 */
    PMU_EnableBackupAccess();                          /* 使能访问备份寄存器 */
    bkpflag = rtc_read_bkr(BAKPR_DATA1);               /* 读取备份寄存器1的值 */
   
    retry = 0;
    RCM_ConfigLSE(RCM_LSE_OPEN);                       /* 尝试使能LSE */
   
    while ((retry < 200) && (RCM->BDCTRL_B.LSERDYFLG != SET))
    {
        retry++;
        delay_ms(5);
    }
   
    if (RCM->BDCTRL_B.LSERDYFLG != SET)                /* LSE无法就绪,改用LSI */
    {
        RCM_ConfigLSE(RCM_LSE_CLOSE);                  /* 禁用LSE */
        RCM_EnableLSI();                               /* 使能LSI */
        while (RCM->CSTS_B.LSIRDYFLG != SET)           /* 等待LSI就绪 */
        {
            delay_ms(5);
        }
        RCM_ConfigRTCCLK(RCM_RTCCLK_LSI);              /* 选择RTC的时钟源为LSI */
        rtc_write_bkr(BAKPR_DATA1, 0x5051);
    }
    else                                               /* LSE已就绪 */
    {
        RCM_ConfigRTCCLK(RCM_RTCCLK_LSE);              /* 选择RTC的时钟源为LSE */
        rtc_write_bkr(BAKPR_DATA1, 0x5050);
    }
   
    RCM_EnableRTCCLK();                                /* 使能RTC时钟 */
    RTC_WaitForSynchro();                              /* 等待RTC寄存器同步 */
    RTC_WaitForLastTask();                             /* 等待RTC操作完成 */
   
    RTC_ConfigPrescaler(32767);                        /* 配置RTC预分频寄存器 */
    RTC_WaitForLastTask();
   
    if ((bkpflag != 0x5050) && (bkpflag != 0x5051))    /* 之前从未配置过 */
    {
        rtc_set(22, 10, 22, 8, 8, 8);                  /* 设置RTC时间 */
    }
   
    RTC_EnableInterrupt(RTC_INT_SEC);                  /* 使能RTC秒中断 */
    RTC_WaitForLastTask();
    NVIC_EnableIRQRequest(RTC_IRQn, 2, 0);
   
    return 0;
}
从上面的代码中可以看出,RTC的初始化函数中,优先尝试使用LSE作为RTC的时钟源,若LSE无法就绪,则使用LSI作为RTC的时钟源。配置好RTC的时钟源后,配置RTC为24小时制,并配置RTC的预分频寄存器的数值为32767。最后根据RTC备份寄存器中的标志,决定是否配置RTC的时间,若之前已经配置过,则不会再次配置。
RTC驱动中设置、获取RTC时间、日期的三个函数,如下所示:
/**
* @brief       设置RTC时间
* @param       year : 年
* @param       month: 月
* @param       date : 日
* @param       hour : 小时
* @param       min  : 分钟
* @param       sec  : 秒钟
* @retval      设置结果
* @arg         0: 设置成功
* @arg         1: 设置失败
*/
uint8_t rtc_set(uint8_t year, uint8_t month,
                uint8_t date, uint8_t hour,
                uint8_t min,  uint8_t sec)
{
    uint16_t year_4;
    uint16_t index;
    uint32_t seccount = 0;
   
    year_4 = year + 2000;
    if ((year_4 < 1970) || (year_4 > 2099))
    {
        return 1;
    }
   
    for (index=1970; index<year_4; index++)
    {
        if (is_leap_year(index))
        {
            seccount += 31622400;
        }
        else
        {
            seccount += 31536000;
        }
    }
   
    month--;
    for (index=0; index<month; index++)
    {
        seccount += (uint32_t)month_table[index] * 86400;
        if (is_leap_year(year_4) && (index == 1))
        {
            seccount += 86400;
        }
    }
   
    seccount += (uint32_t)(date - 1) * 86400;
    seccount += (uint32_t)hour * 3600;
    seccount += (uint32_t)min * 60;
    seccount += sec;
   
    RCM_EnableAPB1PeriphClock(RCM_APB1_PERIPH_PMU);     /* 使能PMU时钟 */
    RCM_EnableAPB1PeriphClock(RCM_APB1_PERIPH_BAKR);    /* 使能BAKPR时钟 */
    PMU_EnableBackupAccess();                           /* 使能访问备份寄存器 */
   
    RTC_ConfigCounter(seccount);                        /* 设置RTC计数值 */
    RTC_WaitForLastTask();
   
    return 0;
}

/**
* @brief       获取RTC时间
* @param       year : 年
* @param       month: 月
* @param       date : 日
* @param       week : 星期
* @param       hour : 小时
* @param       min  : 分钟
* @param       sec  : 秒钟
* @retval      无
*/
void rtc_get(uint8_t *year, uint8_t *month,
             uint8_t *date, uint8_t *week,
             uint8_t *hour, uint8_t *min,
             uint8_t *sec)

{
    uint32_t seccount;
    uint16_t daycount;
    static uint16_t last_daycount = 0;
    uint16_t index;
   
    /* 读取RTC计数值 */
    seccount = RTC_ReadCounter();
    daycount = seccount / 86400;
    if (last_daycount != daycount)
    {
        last_daycount = daycount;
        
        index = 1970;
        while (daycount >= 365)
        {
            if (is_leap_year(index))
            {
                if (daycount >= 366)
                {
                    daycount -= 366;
                }
                else
                {
                    index++;
                    break;
                }
            }
            else
            {
                daycount -= 365;
            }
            index++;
        }
        *year = index - 2000;
        
        index=0;
        while (daycount >= 28)
        {
            if (is_leap_year(*year + 2000) && (index == 1))
            {
                if (daycount >= 29)
                {
                    daycount -= 29;
                }
                else
                {
                    break;
                }
            }
            else
            {
                if (daycount >= month_table[index])
                {
                    daycount -= month_table[index];
                }
                else
                {
                    break;
                }
            }
            index++;
        }
        *month = index + 1;
        *date = daycount + 1;
    }
   
    daycount = seccount % 86400;
    *hour = daycount / 3600;
    *min = (daycount % 3600) / 60;
    *sec = (daycount % 3600) % 60;
    *week = rtc_get_week(*year + 2000, *month, *date);
}

/**
* @brief       通过日期计算星期
* @param       year : 年
* @param       month: 月
* @param       date : 日
* @retval      星期
*/
uint8_t rtc_get_week(uint16_t year, uint8_t month, uint8_t date)
{
    uint8_t year_l;
    uint8_t year_h;
    uint8_t week;
   
    year_h = year / 100;
    year_l = year % 100;
    if (year_h > 19)
    {
        year_l += 100;
    }
   
    week = (((year_l + (year_l >> 2)) % 7) + date + week_table[month - 1] - ((((year_l % 4) == 0) && (month < 3)) ? 1 : 0)) % 7;
   
    return week;
}

以上三个获取、设置RTC时间、日期的函数,均是对Geehy标准库中RTC驱动的简单封装。
RTC驱动中,配置RTC唤醒中断及其对应的中断回调函数,如下所示:
/**
* @breif       RTC中断服务函数
* @param       无
* @retval      无
*/
void RTC_IRQHandler(void)
{
    if (RTC_ReadIntFlag(RTC_INT_SEC) == SET)    /* 判断秒中断标志 */
    {
        LED1_TOGGLE();
        RTC_ClearIntFlag(RTC_INT_SEC);          /* 清除秒中断标志 */
    }
   
    if (RTC_ReadIntFlag(RTC_INT_ALR) == SET)    /* 判断闹钟中断标志 */
    {
        printf("ALARM!\r\n");
        RTC_ClearIntFlag(RTC_INT_ALR);          /* 清除闹钟中断标志 */
    }
   
    RTC_WaitForLastTask();
}
从上面的代码中可以看出,在RTC的秒中断中翻转了LED1的亮灭状态,并清除了秒中断标志,因此RTC时间将会周期性地发生,也就能看到LED1周期性地改变状态。同时,在进行判断秒中断标志时,也对闹钟中断标志位进行了判断。在该过程中,我们通过串口打印出的“ALARM”字样提示得知单片机正在响应该中断。
RTC驱动中,配置RTC闹钟中断及其对应的中断回调函数,如下所示:
/**
* @breif       设置RTC闹钟时间
* @param       year : 年
* @param       month: 月
* @param       date : 日
* @param       hour : 小时
* @param       min  : 分钟
* @param       sec  : 秒钟
* @retval      无
*/
void rtc_set_alarm(uint8_t year, uint8_t month,
                   uint8_t date, uint8_t hour,
                   uint8_t min,  uint8_t sec)

{
    uint16_t year_4;
    uint16_t index;
    uint32_t seccount = 0;
   
    year_4 = year + 2000;
    if ((year_4 < 1970) || (year_4 > 2099))
    {
        return;
    }
   
    for (index=1970; index<year_4; index++)
    {
        if (is_leap_year(index))
        {
            seccount += 31622400;
        }
        else
        {
            seccount += 31536000;
        }
    }
   
    month--;
    for (index=0; index<month; index++)
    {
        seccount += month_table[index] * 86400;
        if (is_leap_year(year_4) && (index == 1))
        {
            seccount += 86400;
        }
    }
   
    seccount += (date - 1) * 86400;
    seccount += hour * 3600;
    seccount += min * 60;
    seccount += sec;
   
    RCM_EnableAPB1PeriphClock(RCM_APB1_PERIPH_PMU);     /* 使能PMU时钟 */
    RCM_EnableAPB1PeriphClock(RCM_APB1_PERIPH_BAKR);    /* 使能BAKPR时钟 */
    PMU_EnableBackupAccess();                           /* 使能访问备份寄存器 */
   
    RTC_ConfigAlarm(seccount);                          /* 设置RTC闹钟 */
    RTC_WaitForLastTask();
}
从上面的代码中可以看到,通过传入的年,月,日,时,分,秒等参数对闹钟进行设置,而这些参数已经在RTC初始化函数中已经设置完成,用户只需调根据自己的需求进行函数调用即可,用户同时也可以在RTC初始化函数中对以上参数进行自定义设置。在这里便不做过多阐述。
27.2.5 实验应用代码
本章实验的应用代码,如下所示:
int main(void)
{
    uint8_t year;
    uint8_t month;
    uint8_t date;
    uint8_t week;
    uint8_t hour;
    uint8_t min;
    uint8_t sec;
    uint8_t tbuf[40];
    uint8_t t = 0;
   
    NVIC_ConfigPriorityGroup(NVIC_PRIORITY_GROUP_4);  /* 设置中断优先级分组为组4 */
    sys_apm32_clock_init(15);                         /* 配置系统时钟 */
    delay_init(120);                                  /* 初始化延时功能 */
    usart_init(115200);                               /* 初始化串口 */
    usmart_dev.init(120);                             /* 初始化USMART */
    led_init();                                       /* 初始化LED */
    lcd_init();                                       /* 初始化LCD */
    rtc_init();                                       /* 初始化RTC */
   
    lcd_show_string(30, 50, 200, 16, 16, "APM32", RED);
    lcd_show_string(30, 70, 200, 16, 16, "RTC TEST", RED);
    lcd_show_string(30, 90, 200, 16, 16, "ATOM@ALIENTEK", RED);
   
    while (1)
    {
        t++;
        if ((t % 10) == 0)                            /* 每100毫秒更新一次数据 */
        {
            rtc_get(&year, &month, &date, &week, &hour, &min, &sec);
            sprintf((char *)tbuf, "Time:%02d:%02d:%02d", hour, min, sec);
            lcd_show_string(30, 130, 210, 16, 16, (char *)tbuf, RED);
            sprintf((char *)tbuf, "Date:20%02d-%02d-%02d", year, month, date);
            lcd_show_string(30, 150, 210, 16, 16, (char *)tbuf, RED);
            sprintf((char *)tbuf, "Week:%d", week);
            lcd_show_string(30, 170, 210, 16, 16, (char *)tbuf, RED);
        }
        if ((t % 20) == 0)
        {
            LED0_TOGGLE();
        }
        
        delay_ms(10);
    }
}
从上面的代码中可以看到,在初始化完RTC后便每间隔100毫秒获取一次RTC的时间和日期,并在LCD上进行显示。
本实验同时也使用的USMART调试组件,并在usart_config.c文件中添加了RTC驱动中相关的函数,以便调试。
27.3 下载验证
在完成编译和烧录操作后,可以看到LCD上实时地显示着RTC的时间,并且可以看到LED1在RTC周期性唤醒的驱动下以0.5Hz的频率闪烁着,此时可以通过串口调试助手调用USMART调试组件的rtc_set_alarma()函数来设置RTC的闹钟,当通过LCD观察到RTC的时间达到设置的闹钟时间后,可以看到串口调试助手上打印了“ALARM A!\r\n”的字符串提示。

阿莫论坛20周年了!感谢大家的支持与爱护!!

有一句段子是这样说的,身家过亿的只关心自己的身体,身家千万的,在担心传承,勉强糊口度日才天天看国际新闻,关心国家大事。
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-12-11 11:47

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

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