07嵌入式第七章作业

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

运行结果

倒计时进行中,绿灯亮

倒计时结束,红灯亮

main.c

#define GLOBLE_VAR
#include "includes.h"  
int main(void)
{
    uint8_t  mSec;	//记当前秒的值
    //关总中断
    DISABLE_INTERRUPTS;
   	//"时分秒"缓存初始化(00:02:30)
   	gTime[0] = 0;       //时
   	gTime[1] = 2;	  	//分
   	gTime[2] = 30;	  	//秒
   	mSec = 0;	//记住当前秒的值

    //用户外设模块初始化
    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_init(10);      //设置systick为10ms中断
   
 //开总中断
    ENABLE_INTERRUPTS;

    printf("------------------------------------------------------\n"); 
    printf("利用SysTick定时器编写倒计时程序                        \n");
   	printf("初始设置为2分30秒,每秒在屏幕上输出一次时间,倒计时为0后,红灯亮,停止屏幕输出,并关闭SysTick定时器的中断\n");
    printf("------------------------------------------------------\n"); 
    
    for(;;)     //for(;;)(开头)
    {
   		if (gTime[2] == mSec) continue;
   		mSec=gTime[2];
        //以下是1秒到的处理
        if (gTime[0]!=0||gTime[1]!=0||gTime[2]!=0)   //不为0正常倒计时且绿灯亮
        {
            gpio_set(LIGHT_GREEN,LIGHT_ON);   //设置绿灯亮
            printf("%d:%d:%d\n",gTime[0],gTime[1],gTime[2]);
        }
        else//倒计时为0,亮红灯并关闭SysTick定时器的中断
        {
            printf("%d:%d:%d\n",gTime[0],gTime[1],gTime[2]);
            gpio_set(LIGHT_GREEN,LIGHT_OFF);  //关闭绿灯
            gpio_set(LIGHT_RED,LIGHT_ON);  //设置红灯亮
            // 倒计时结束,关闭SysTick中断
            SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;
            break;
        }	
    }    
}

isr.c

#include "includes.h"
//声明使用到的内部函数
void SecSub1(uint8_t *p);

void SysTick_Handler()
{
	//printf("***\n");
	static uint8_t SysTickCount = 0;
	SysTickCount++;    //Tick单元+1
	wdog_feed();      //看门狗“喂狗”
	if (SysTickCount >= 100)
	{
		SysTickCount = 0;
		SecSub1(gTime);
	}
}

void SecSub1(uint8_t *p)
{
    if (*(p+2) > 0) {
        *(p+2)-=1;  // 秒 -1
    } else {
        if (*(p+1) > 0) {
            *(p+1)-=1;  // 分 -1
            *(p+2) = 59;  // 秒 设为59
        } else {
            if (*(p) > 0) {
                *(p)-=1;  	  // 时 -1
                *(p+1) = 59;  // 分 设为59
                *(p+2) = 59;  // 秒 设为59
           	}
        }
    }
}

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

运行结果

main.c

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

int main(void)
{
//关总中断
	DISABLE_INTERRUPTS;

//用户外设模块初始化
    gpio_init(LIGHT_RED,GPIO_OUTPUT,LIGHT_OFF);	//初始化红灯
	gpio_init(LIGHT_GREEN,GPIO_OUTPUT,LIGHT_OFF);	//初始化绿灯
	gpio_init(LIGHT_BLUE,GPIO_OUTPUT,LIGHT_OFF);	//初始化蓝灯
    RTC_Init();							//RTC初始化
	RTC_Set_Time(23,59,59);				//设置时间
    RTC_Set_Date(24,6,5,3);				//设置日期
    
//使能模块中断
    RTC_PeriodWKUP_Enable_Int();   //使能唤醒中断
    RTC_Alarm_Enable_Int(0); //0:闹钟A,1:闹钟B
    
//开总中断
	ENABLE_INTERRUPTS;
    RTC_Set_PeriodWakeUp(1);  //配置WAKE UP中断,每秒中断一次
    RTC_Set_Alarm(0,4,0,0,6);//设置闹钟A
    
    printf("------------------------------------------------------\n"); 
    printf("利用RTC显示日期                        \n");
   	printf("闹钟时间到时,显示姓名,并点亮绿灯\n");
    printf("------------------------------------------------------\n"); 
	for(;;)
	{
	}  
}  

isr.c

#include "includes.h"
//======================================================================
//程序名称:RTC_WKUP_IRQHandler
//函数参数:无
//中断类型:RTC闹钟唤醒中断处理函数
//======================================================================
 void RTC_WKUP_IRQHandler(void)
 {
 	 uint8_t hour,min,sec;
 	 uint8_t  year,month,date,week;
	 if(RTC_PeriodWKUP_Get_Int())         //唤醒中断的标志
	 {
	 	 RTC_PeriodWKUP_Clear();           //清除唤醒中断标志
	 	 RTC_Get_Date(&year,&month,&date,&week); //获取RTC记录的日期
		 RTC_Get_Time(&hour,&min,&sec);    		//获取RTC记录的时间
		 
		 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)
{
	gpio_set(LIGHT_GREEN,LIGHT_ON);//绿灯亮
	
	if(RTC_Alarm_Get_Int(0))            //闹钟A的中断标志位
	{
		RTC_Alarm_Clear(0);       //清闹钟A的中断标志位
		printf("闹钟A:800030\n");
	}
	
}

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

运行结果

小灯闪烁与输出一致

main.c

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

//main.c使用的内部函数声明处
void Delay_ms(uint16_t u16ms);

int main(void)
{
    uint8_t short_flash_count = 0;  // 计数短闪次数
    uint8_t long_flash_count = 0;   // 计数长闪次数
    uint8_t mode = 0;  // 0 表示短闪模式,1 表示长闪模式
    double m_duty;  // 占空比

    //关总中断
    DISABLE_INTERRUPTS;

    //用户外设模块初始化
    gpio_init(LIGHT_RED, GPIO_OUTPUT, LIGHT_OFF);  // 初始化红灯
    pwm_init(PWM_USER, 1500, 1000, 10.0, PWM_CENTER, PWM_MINUS);  // PWM 输出初始化

    //开总中断
    ENABLE_INTERRUPTS;

    printf("------------------------------------------------------\n");
    printf("利用PWM脉宽调制,交替显示红灯的5个短闪和5个长闪\n");
    printf("------------------------------------------------------\n");

    for (;;)  
    {
        if (mode == 0) {
            // 短闪模式
            m_duty = 10.0;
            short_flash_count++;
            printf("短闪 %d\n", short_flash_count);
            if (short_flash_count >= 5) {
                mode = 1;
                short_flash_count = 0;
            }
        } else {
            // 长闪模式
            m_duty = 90.0;
            long_flash_count++;
            printf("长闪 %d\n", long_flash_count);
            if (long_flash_count >= 5) {
                mode = 0;
                long_flash_count = 0;
            }
        }

        pwm_update(PWM_USER, m_duty);  // 调节占空比

        // 控制灯的状态
        gpio_reverse(LIGHT_RED);

        // 调整延时以实现短闪和长闪的效果
        if (mode == 0) {
            Delay_ms(100);  // 短闪延时 100 毫秒
        } else {
            Delay_ms(900);  // 长闪延时 900 毫秒
        }
    }  
}

//======以下为主函数调用的子函数存放处=====================================
void Delay_ms(uint16_t u16ms)
{
    uint32_t u32ctr;
    for (u32ctr = 0; u32ctr < 8000 * u16ms; u32ctr++)
    {
        __ASM("NOP");
    }
}

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

运行结果

每五秒为一周期,小灯闪烁频率不断提高

main.c

#define GLOBLE_VAR
#include "includes.h"      //包含总头文件
void Delay_ms(uint16_t u16ms);
int main(void)
{
   
    //声明main函数使用的局部变量
	uint8_t  mFlag;           //灯的状态标志
	uint8_t  flag;            //标记高低电平

    //关总中断
    DISABLE_INTERRUPTS;
    
    //给主函数使用的局部变量赋初值
	mFlag='A';           //灯的状态标志

    //给全局变量赋初值
  	gTime[0] = 0;       //分钟
   	gTime[1] = 0;	  	//秒
   	gTime[2] = 0;	  	//毫秒
    period = 1000;      //自动重装载寄存器初始值

    //用户外设模块初始化
    gpio_init(LIGHT_BLUE,GPIO_OUTPUT,LIGHT_ON);    //初始化蓝灯
    outcmp_init(OUTCMP_USER,3000,200,50.0,CMP_REV); //输出比较初始化
    incapture_init(INCAP_USER,375,1000,CAP_DOUBLE);   //上升沿捕捉初始化
    systick_init(1);      //设置systick为1ms中断

    //使能模块中断
    cap_enable_int(INCAP_USER);    //使能输入捕捉中断

    //开总中断
    ENABLE_INTERRUPTS;

    printf("------------------------------------------------------\n"); 
    printf(" (1)蓝灯每秒闪烁一次,作为运行指示\n");
   	printf(" (2)设置GEC39为输出比较引脚,\n");
   	printf("      设置GEC10为输入捕捉引脚,沿跳变捕捉\n");
   	printf(" (3)用导线将GEC39与GEC10连接 \n");
   	printf(" (4)程序使得输出比较引脚输出高低电平,输入捕捉引脚捕捉\n");
   	printf("      后用printf输出,PC机程序据此显示波形引脚捕捉\n");
    printf("------------------------------------------------------\n");

    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);            //灯“暗”
		}
	}
}

//======以下为主函数调用的子函数存放处
void Delay_ms(uint16_t u16ms)
{
    uint32_t u32ctr;
    for(u32ctr = 0; u32ctr < 8000*u16ms; u32ctr++)
    {
        __ASM("NOP");
    }
}

总结

1.关闭SysTick中断,SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;语句中,SysTick->CTRL是SysTick定时器的控制和状态寄存器,该寄存器有多个位用于不同的控制功能,其中包括:

  • SysTick_CTRL_ENABLE_Msk:使能位。当该位被设置时,SysTick定时器开始计数;当该位被清除时,定时器停止计数。
  • SysTick_CTRL_TICKINT_Msk:中断使能位。设置该位允许在计数到0时产生中断。

SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk将SysTick_CTRL_ENABLE_Msk位置0,即清除SysTick定时器的使能位,来停止SysTick定时器,从而关闭SysTick中断

2.查找使能闹钟中断函数定义

可以看到0代表闹钟A,1代表闹钟B。因此main.c使能闹钟中断函数中先代入0。即使能闹钟A中断。

3.设置闹钟的函数中,第一个参数0也是对应的闹钟A

RTC_Set_Alarm(0,4,0,0,6);//设置闹钟A,星期四,在第六秒时闹钟响

4.利用PWM脉宽调制时,初始化为pwm_init(PWM_USER, 1500, 1000, 10.0, PWM_CENTER, PWM_MINUS),即用的中心对齐方式,且负极性,分别利用占空比为10和90来控制灯的闪烁。可适当增加延迟函数以便更好的观察灯的闪烁。

  • 6
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值