第七章作业

1、利用SysTick定时器编写倒计时程序,如初始设置为2分30秒,每秒在屏幕上输出一次时间,倒计时为0后,红灯亮,停止屏幕输出,并关闭SysTick定时器的中断。

//includes.h

/**

 * 用户定义的全局变量

 */

G_VAR_PREFIX vuint8_t  cTime[3];  // 存储当前时间的数组,格式为时、分、秒

G_VAR_PREFIX vuint8_t  ctime;      // 总倒计时时间,单位为秒

G_VAR_PREFIX vuint8_t  ltime;      // 剩余时间,单位为秒

G_VAR_PREFIX vuint8_t  gtime;      // 系统时间,单位为秒

//isr.c

/**

 * 系统滴答中断处理函数

 */

void SysTick_Handler()

{

    // 模拟打印语句,实际使用时可注释掉

    // printf("***\n");

    static uint8_t SysTickCount = 0;  // 定义静态变量SysTickCount,用于计数滴答数

    SysTickCount++;  // 滴答计数器增加1

    wdog_feed();      // 重置看门狗定时器,防止看门狗复位

    if (SysTickCount >= 100)  // 当计数达到100时,更新时间

    {

        SysTickCount = 0;  // 重置滴答计数器

        // 计算当前系统时间(秒)

        gtime = gTime[0] * 3600 + gTime[1] * 60 + gTime[2];

        // 计算剩余时间(秒)

        ltime = ctime - gtime;

        // 更新当前时间数组

        cTime[0] = ltime / 3600;

        cTime[1] = (ltime % 3600) / 60;

        cTime[2] = ltime % 60;

        SecAdd1(gTime);  // 系统时间加1秒

    }

}

//main.c

int main(void)

{

    ctime = 61;      // 设置总倒计时时间为61秒

    ltime = 0;       // 初始化剩余时间为0

    cTime[0] = 0;    // 初始化小时为0

    cTime[1] = 0;    // 初始化分钟为0

    cTime[2] = 0;    // 初始化秒为0

    gpio_init(LIGHT_RED, GPIO_OUTPUT, LIGHT_OFF);  // 初始化红灯为关闭状态

    for(;;)     // 无限循环,程序的主循环

    {

        if (gTime[2] != mSec)  // 如果系统时间的秒数发生变化

        {

            mSec = gTime[2];   // 更新mSec为当前秒数

            if (ltime != 0)  // 如果倒计时未结束

            {

                printf("剩余时间:%d:%d:%d\n", cTime[0], cTime[1], cTime[2]);  // 打印剩余时间

            }

            else  // 倒计时结束

            {

                printf("倒计时结束,红灯亮\n");  // 打印提示信息

                gpio_set(LIGHT_RED, LIGHT_ON);  // 点亮红灯

                for(;;) {  }  // 无限循环,保持红灯亮状态

            }

        }

    }

    return 0;  // 主函数返回值,实际中可能不需要

}

2、利用RTC显示日期(年月日、时分秒),每秒更新。并设置某个时间的闹钟。闹钟时间到时,屏幕上显示有你的姓名的文字,并点亮绿灯。

main.c

#define GLOBLE_VAR  // 定义全局变量宏

#include "includes.h"  // 包含总头文件

int main(void)

{

    uint32_t mMainLoopCount;  // 主循环计数器

    // 关闭总中断,以确保初始化过程的原子性

    DISABLE_INTERRUPTS;

    // 初始化主函数使用的局部变量

    mMainLoopCount = 0;  // 初始化主循环计数器

    // 初始化全局变量

    g_RTC_Flag = 0;

    // 初始化用户外设模块

    gpio_init(LIGHT_GREEN, GPIO_OUTPUT, LIGHT_OFF);  // 初始化绿灯为关闭状态

    uart_init(UART_User, 115200);  // 初始化串口,设置波特率为115200

    RTC_Init();  // 初始化实时时钟(RTC)

    // 设置RTC时间为16:51:49

    RTC_Set_Time(16, 51, 49);

    // 设置RTC日期为2024年6月6日星期四

    RTC_Set_Date(24, 6, 6, 4);

    // 使能模块中断

    RTC_PeriodWKUP_Enable_Int();  // 使能周期性唤醒中断

    uart_enable_re_int(UART_User);  // 使能串口接收中断

    // 打开总中断,允许中断处理

    ENABLE_INTERRUPTS;

    // 使能RTC闹钟中断

    RTC_Alarm_Enable_Int(0);

    // 设置闹钟时间为星期四的16:52:00

    RTC_Set_Alarm(0, 4, 16, 52, 0);

    // 配置周期性唤醒中断,每秒触发一次

    RTC_Set_PeriodWakeUp(1);

    // 设置中断优先级

    NVIC_SetPriority(RTC_WKUP_IRQn, 1);  // 设置周期性唤醒中断优先级为1

    NVIC_SetPriority(RTC_Alarm_IRQn, 0);  // 设置闹钟中断优先级为0(更高优先级)

    // 主循环

    for(;;)

    {

        // 增加主循环计数器

        mMainLoopCount++;

        // 如果主循环计数器未达到设定值,继续循环

        if (mMainLoopCount <= 12888999) continue;

        // 如果达到设定值,重置计数器,并根据条件处理灯的状态

        mMainLoopCount = 0;

        if (g_RTC_Flag == 1)

        {

            // 处理接收到的时间设置

            g_RTC_Flag = 0;

            // 从串口接收的缓冲区解析日期和时间,并设置到RTC

            gcRTC_Date_Time.Year = (uint8_t)((gcRTCBuf[1] - '0') * 10 + (gcRTCBuf[2] - '0'));

            gcRTC_Date_Time.Month = (uint8_t)((gcRTCBuf[4] - '0') * 10 + (gcRTCBuf[5] - '0'));

            gcRTC_Date_Time.Date = (uint8_t)((gcRTCBuf[7] - '0') * 10 + (gcRTCBuf[8] - '0'));

            gcRTC_Date_Time.Hours = (uint8_t)((gcRTCBuf[10] - '0') * 10 + (gcRTCBuf[11] - '0'));

            gcRTC_Date_Time.Minutes = (uint8_t)((gcRTCBuf[13] - '0') * 10 + (gcRTCBuf[14] - '0'));

            gcRTC_Date_Time.Seconds = (uint8_t)((gcRTCBuf[16] - '0') * 10 + (gcRTCBuf[17] - '0'));

            gcRTC_Date_Time.Weekday = (uint8_t)((gcRTCBuf[23] - '0'));

            // 设置解析出的日期和时间到RTC

            RTC_Set_Time(gcRTC_Date_Time.Hours, gcRTC_Date_Time.Minutes, gcRTC_Date_Time.Seconds);

            RTC_Set_Date(gcRTC_Date_Time.Year, gcRTC_Date_Time.Month, gcRTC_Date_Time.Date, gcRTC_Date_Time.Weekday);

        }

    }

}

修改icr.c中的函数,完成 RTC闹钟中断后的一系列处理,闹钟中断的优先级必须高于周期性唤醒中断,以确保闹钟中断程序能够被正确处理。

/**

 * RTC周期性唤醒中断处理函数

 */

void RTC_WKUP_IRQHandler(void)

{

    uint8_t hour, min, sec;   // 定义变量以存储获取的时间

    uint8_t year, month, date, week;  // 定义变量以存储获取的日期

    char *p;  // 定义字符串指针,用于格式化日期和时间

    // 检查是否发生了周期性唤醒中断

    if (RTC_PeriodWKUP_Get_Int())

    {

        // 清除周期性唤醒中断标志

        RTC_PeriodWKUP_Clear();

       

        // 从RTC获取当前日期

        RTC_Get_Date(&year, &month, &date, &week);

        // 从RTC获取当前时间

        RTC_Get_Time(&hour, &min, &sec);

       

        // 使用NumToStr函数将日期和时间格式化为字符串

        // 此处NumToStr函数的实现未给出,假设它能够将数字转换为格式化的字符串

        p = NumToStr("%02d/%02d/%02d %02d:%02d:%02d 星期%d\n", year, month, date, hour, min, sec, week);

       

        // 通过串口发送格式化的日期和时间字符串

        uart_send_string(UART_User, p);

       

        // 打印当前日期和时间到控制台或调试接口

        printf("%02d/%02d/%02d %02d:%02d:%02d 星期%d\n", year, month, date, hour, min, sec, week);

    }

}

//======================================================================

// 程序名称:RTC_Alarm_IRQHandler

// 中断类型:RTC闹钟中断处理函数

//======================================================================

void RTC_Alarm_IRQHandler(void)

{

    // 检查是否发生了闹钟A的中断

    if (RTC_Alarm_Get_Int(A))  // A是闹钟的标识,具体值可能依赖于硬件

    {

        // 清除闹钟A的中断标志

        RTC_Alarm_Clear(A);

       

        // 打印闹钟响了的提示信息

        printf("闹钟触发了!\n");

       

        // 打印设置的姓名

        printf("蔡潮嘉\n");

       

        // 控制GPIO,点亮绿灯,指示闹钟时间到

        gpio_set(LIGHT_GREEN, LIGHT_ON);

    }

}

3、利用PWM脉宽调制,交替显示红灯的5个短闪和5个长闪。

uint8_t dFlag = 1;  // 定义并初始化标志变量dFlag,用于控制长闪和短闪的显示

// 主循环,用于控制PWM的占空比变化和闪烁模式

for (uint8_t i = 1; i <= 5; i++)

{

    // 更新PWM的占空比

    pwm_update(PWM_USER, m_duty);

    // 使占空比递增,每次增加5%

    m_duty = m_duty + 5.0;

    // 当占空比达到或超过90%时,将其重置为1%,以便循环使用

    if (m_duty >= 90.0) m_duty = 1.0;

    // 用于控制一个周期内相同占空比的PWM波形打印三次

    for (m_i = 0; m_i < 3; m_i++)

    {

        m_K = 0;  // 初始化m_K,用于控制do-while循环

        do

        {

            // 读取PWM_USER引脚的当前状态

            mFlag = gpio_get(PWM_USER);

           

            // 如果当前为高电平,并且Flag为1,表示应该显示长闪

            if ((mFlag == 1) && (Flag == 1))

            {

                Flag = 0;  // 切换Flag状态,准备显示短闪

                m_K++;     // 增加m_K,以便退出do-while循环

               

                // 反转LIGHT_RED引脚的状态,实现LED闪烁

                gpio_reverse(LIGHT_RED);

               

                // 如果dFlag为1,表示是第一次长闪,打印信息并延时

                if (dFlag == 1)

                {

                    Delay_ms(1000);  // 延时1秒

                    printf("第%d次长闪\n", i);  // 打印长闪次数

                    dFlag = 0;  // 重置dFlag,准备下一次短闪

                    continue;  // 跳过本次循环的剩余部分

                }

                // 重置dFlag,准备下一次长闪

                dFlag = 1;

                printf("第%d次短闪\n", i);  // 打印短闪次数

            }

            // 如果当前为低电平,并且Flag为0,表示应该显示短闪

            else if ((mFlag == 0) && (Flag == 0))

            {

                Flag = 1;  // 切换Flag状态,准备显示长闪

                m_K++;     // 增加m_K,以便退出do-while循环

               

                // 反转LIGHT_RED引脚的状态,实现LED闪烁

                gpio_reverse(LIGHT_RED);

            }

        }

        // 循环直到m_K大于等于1,即至少打印一次完整的PWM波形

        while (m_K < 1);

    }

}  // 结束for循环

4、GEC39定义为输出引脚,GEC10定义为输入引脚,用杜邦线将两个引脚相连,验证捕捉实验程序Incapture-Outcmp-20211110,观察输出的时间间隔。

for(;;)     //for(;;)(开头)

    {       

        flag = gpio_get(INCAP_USER);

        //灯状态标志mFlag为'L',改变灯状态及标志

                 if (mFlag=='L' && flag == 1)             //判断灯的状态标志

                 {

                         mFlag='A';                //灯的状态标志

                         gpio_set(LIGHT_BLUE,LIGHT_ON);             //灯“亮”

                 }

        //如灯状态标志mFlag为'A',改变灯状态及标志

                 else if(mFlag=='A' && flag == 0)     //判断灯的状态标志

                 {

                         mFlag='L';                         //灯的状态标志

                         gpio_set(LIGHT_BLUE,LIGHT_OFF);            //灯“暗”

                 }

        }

可以看到时间间隔逐渐减少

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值