1、利用SysTick定时器编写倒计时程序,如初始设置为2分30秒,每秒在屏幕上输出一次时间,倒计时为0后,红灯亮,停止屏幕输出,并关闭SysTick定时器的中断。
程序源码:
main.c:
#define GLOBLE_VAR
#include "includes.h" //包含总头文件
//----------------------------------------------------------------------
//主函数,一般情况下可以认为程序从此开始运行(实际上有启动过程见书稿)
int main(void)
{
//关总中断
DISABLE_INTERRUPTS;
wdog_stop();
//"时分秒"缓存初始化(00:02:30)
gTime[0] = 0; //时
gTime[1] = 2; //分
gTime[2] = 30; //秒
gpio_init(LIGHT_RED,GPIO_OUTPUT,LIGHT_OFF);
gpio_init(LIGHT_GREEN,GPIO_OUTPUT,LIGHT_OFF);
gpio_init(LIGHT_BLUE,GPIO_OUTPUT,LIGHT_OFF); //初始化灯,全灭
//初始化 SysTick
SysTick->CTRL = 0; //清零,包括禁止中断以及计时
SysTick->LOAD = SystemCoreClock * 0.1; //写入重载值,计时时长为0.1秒
SysTick->VAL = 999UL; //清除当前值
while(SysTick->VAL != 0); //等待 SysTick 当前值清零完成
printf("SysTick 当前值:%d\n", SysTick->VAL);
SysTick->CTRL |= (1UL << 2U); //选择内核时钟
SysTick->CTRL |= (1UL << 1) | 1UL; //使能 SysTick 中断和计时
//开总中断
ENABLE_INTERRUPTS;
printf("LH,32106100047\n");
printf("倒计时:%d:%d:%d\n",gTime[0],gTime[1],gTime[2]);
gpio_set(LIGHT_BLUE,LIGHT_ON); //设置蓝灯亮。
//主循环部分
for(;;)
{
}
}
isr.c:
void SysTick_Handler()
{
static uint8_t SysTickCount = 0; // 静态变量,记录SysTick中断次数
SysTickCount++; // Tick单元+1
wdog_feed(); // 喂狗,重置看门狗计时器
if (SysTickCount >= 10) // 如果SysTickCount达到10次(即10ms)
{
SysTickCount = 0; // 重置SysTickCount
if(gTime[2] == 0) // 如果秒数为0
{
if(gTime[1] == 0) // 如果分钟数为0
{
if(gTime[0] == 0) // 如果小时数为0
{
printf("倒计时结束,红灯亮\n"); // 输出倒计时结束,红灯亮
gpio_set(LIGHT_BLUE,LIGHT_OFF); // 设置蓝灯暗
gpio_set(LIGHT_RED,LIGHT_ON); // 设置红灯亮
SysTick->CTRL = 0; // 关闭SysTick定时器
printf("LH,32106100047\n"); // 输出标识符
return; // 结束函数
}
gTime[0]--; // 小时数减1
gTime[1] = 59U; // 分钟数重置为59
}
gTime[1]--; // 分钟数减1
gTime[2] = 59U; // 秒数重置为59
}
else
{
gTime[2]--; // 秒数减1
}
printf("倒计时:%d:%d:%d\n",gTime[0],gTime[1],gTime[2]); // 输出当前倒计时时间
if((gTime[2] % 2) == 0) // 如果当前秒数为偶数
{
gpio_set(LIGHT_BLUE,LIGHT_ON); // 设置蓝灯亮
}
else
{
gpio_set(LIGHT_BLUE,LIGHT_OFF); // 设置蓝灯暗
}
}
}
运行结果:
顺利地编写了倒计时程序。
2、利用RTC显示日期(年月日、时分秒),每秒更新。并设置某个时间的闹钟。闹钟时间到时,屏幕上显示有你的姓名的文字,并点亮绿灯。
main.c:
//(1.4)给全局变量赋初值
g_RTC_Flag=0;
//(1.5)用户外设模块初始化
gpio_init(LIGHT_BLUE,GPIO_OUTPUT,LIGHT_ON); //初始化蓝灯
uart_init(UART_User,115200);
RTC_Init(); //RTC初始化
RTC_Set_Time(11,17,00); //设置时间为11:17:0
RTC_Set_Date(24,6,7,5); //设置日期
//(1.6)使能模块中断
RTC_PeriodWKUP_Enable_Int(); //使能唤醒中断
uart_enable_re_int(UART_User);
RTC_Alarm_Enable_Int(0);
RTC_Set_Alarm(0,5,11,18,0); //设置闹钟时间为11:18:0
//(1.7)【不变】开总中断
ENABLE_INTERRUPTS;
RTC_Set_PeriodWakeUp(1); //配置WAKE UP中断,每秒中断一次
isr.c:
void RTC_Alarm_IRQHandler(void)
{
if(RTC_Alarm_Get_Int(A)) //闹钟A的中断标志位
{
gpio_init(LIGHT_GREEN,GPIO_OUTPUT,LIGHT_OFF);
RTC_Alarm_Clear(A); //清闹钟A的中断标志位
printf("闹钟触发\n");
gpio_set(LIGHT_GREEN,LIGHT_ON);
printf("LH-32106100047\n");
}
}
运行后结果:
闹钟可以正确触发
3、利用PWM脉宽调制,交替显示红灯的5个短闪和5个长闪。
main.c:
gpio_init(LIGHT_RED,GPIO_OUTPUT,LIGHT_OFF); //初始化红灯
pwm_init(PWM_USER,1500,1000,10.0,PWM_CENTER,PWM_MINUS); //PWM输出初始化
//(1.6)使能模块中断
//(1.7)【不变】开总中断
ENABLE_INTERRUPTS;
m_K=0;
m_duty=20.0;
uint8_t flag = 1;
uint8_t i=1;
// 无限循环
for (;;)
{
// 更新 PWM(脉冲宽度调制)信号,设置占空比为 m_duty
pwm_update(PWM_USER, m_duty);
// 将占空比每次递增5
m_duty = m_duty + 5.0;
// 当占空比大于等于90后置为1,重新进行循环。
if (m_duty >= 90.0)
m_duty = 1.0;
// 循环执行3次,控制未知周期内相同占空比的波形只打印三次
for (m_i = 0; m_i < 3; m_i++)
{
// 重置 m_K,以确保每次输出完整的 PWM 波形后再进入下一个循环
m_K = 0;
do
{
// 获取 PWM_USER 端口的状态标志
mFlag = gpio_get(PWM_USER);
// 如果当前状态为高电平且之前状态也为高电平
if ((mFlag == 1) && (Flag == 1))
{
// 将标志位 Flag 设为低电平
Flag = 0;
// m_K 自增
m_K++;
// 小灯反转
gpio_reverse(LIGHT_RED);
// 如果 flag 等于 1
if (flag == 1)
{
// 延时 1000 毫秒
Delay_ms(1000);
// 打印长闪信息,并增加 i
printf("第%d次长闪\n", i);
// flag 设为 0
flag = 0;
// 继续执行循环
continue;
}
// flag 设为 1
flag = 1;
// 打印短闪信息,并增加 i
printf("第%d次短闪\n", i);
i++;
}
// 如果当前状态为低电平且之前状态也为低电平
else if ((mFlag == 0) && (Flag == 0))
{
// 将标志位 Flag 设为高电平
Flag = 1;
// m_K 自增
m_K++;
// 反转小灯状态
gpio_reverse(LIGHT_RED);
}
}
// 等待直到输出完整的 PWM 波形
while (m_K < 1);
}
}
运行后结果:
4、GEC39定义为输出引脚,GEC10定义为输入引脚,用杜邦线将两个引脚相连,验证捕捉实验程序Incapture-Outcmp-20211110,观察输出的时间间隔。
用杜邦线连接开发板上的39和10孔
运行捕捉实验程序Incapture-Outcmp-20211110