蓝桥杯单片机利用PWM实现呼吸灯

对于STC15F2K60S2以及比赛用的板子来说,单纯的LED灯并不算难,这次我们就结合PWM实现呼吸灯的操作。

在展示写法前,我们先来介绍一下呼吸灯。单片机对于LED灯的操控一般是0/1,也就是0/5V,呼吸灯的亮度为从0缓慢增加至全亮,再缓慢减小至0,这是一个呼吸的过程。同样的,要想实现亮度的渐变,单片机对于LED所连接的IO口的输出电压也应该逐渐变化。

然而单片机对于IO口的输出只有两种情况,0或者1,因此我们选择利用PWM。

先看一下官方说法。

PWM,全称是Pulse Width Modulation,即脉冲宽度调制。它是一种数字信号,主要由占空比和频率来定义。占空比是指在一个周期内,信号处于高电平的时间占据整个信号周期的百分比,而频率则代表PWM完成一个周期的速度,决定了信号在高低电平状态之间的切换速度。

PWM技术通过调节占空比的变化来调节信号、能量等的变化。在实际应用中,例如,当一个数字信号的高电平为5V,低电平为0V时,若需要这个数字信号源输出相当于3V的模拟信号,那么可以通过PWM占空比60%的方式来实现,即一个信号周期内有60%的时间输出5V,40%的时间输出0V。只要信号周期足够短,频率足够快,就可以得到一个输出电平无限接近3V的信号源。

PWM控制技术是变频技术的核心技术之一,具有控制简单、灵活和动态响应好等优点,因此在各种应用场合中占据主导地位,成为电力电子技术最广泛应用的控制方式。其应用领域包括测量、通信、功率控制与变换、电动机控制、伺服控制、调光、开关电源,甚至某些音频放大器。

如需更多关于PWM的详细信息,建议查阅电子工程或相关领域的专业书籍,或者咨询该领域的专家,以获取更准确、更深入的解释和指导。

这一段话中,我们需要抓住的关键词就是占空比。调节占空比,也就是调节周期内输出高电平所在的时间,就能够实现最终呈现(高电平*占空比)的电压效果。

原理了解了,我们首先完成通过按键调节LED亮度的练手任务。

#include <STC15F2K60S2.H>
#include <intrins.h>
typedef unsigned char u8;
typedef unsigned int u16;
typedef unsigned long u32;
u8 key=0;
u8 flag_key=0;
u8 point=50;
u8 count=0;
void ctrl(u8 ctrl)
{
	 u8 p2data=P2;
	 P2=ctrl<<5|(P2&0x1f);
   P2=p2data;
}
void light(u8 count)
{
  if(count<point)P0=0xfe;
	else P0=0xff;ctrl(4);

}
u8 key_val(void)
{
	 u8 adc=0;
   P3=0x0f;
	 P42=0;P44=0;
	 if(P30==0)adc=7;
	 if(P31==0)adc=6;
	 if(P32==0)adc=5;
	 if(P33==0)adc=4;
	 return adc;
}

u8 key_sta(void)
{
   static u8 sta=0;
 	u8 val=key_val(),ret=0;
	 switch(sta)
	 {
		 case 0:if(val!=0)sta=1;break;
		 case 1:if(val==0)sta=0;else{sta=2;ret=val;}break;
		 case 2:if(val==0)sta=0;break;
		 default:break;
		 	 
	 }
	 return ret;


}
void Timer2_Init(void)		//100??@12.000MHz
{
	AUXR &= 0xFB;			//?????12T??
	T2L = 0xFF;				//???????
	T2H = 0xFF;				//???????
	AUXR |= 0x10;			//???2????
  IE2|=0X04;
	EA=1;
}

void Timer0_Init(void)		//10??@12.000MHz
{
	AUXR |= 0x80;			//?????1T??
	TMOD &= 0xF0;			//???????
	TL0 = 0x88;				//???????
	TH0 = 0xFF;				//???????
	TF0 = 0;				//??TF0??
	TR0 = 1;				//???0????
	ET0 = 1;				//?????0??
}

void service2(void)  interrupt 12
{
	flag_key++;
}
void service0(void)  interrupt 1
{
  count++;
	count=count%100;
	light(count);
}
void Process(void)
{
  if(flag_key>10){flag_key=0;key=key_sta();}
}
void main()
{
   P0=0x00;ctrl(5);
	 P0=0xff;ctrl(4);
	 P0=0x00;ctrl(6);
	 Timer2_Init();
 	 Timer0_Init();
	 while(1)
	{
		Process();
		if(key==4){point=point+10;key=0;}
		if(key==5){if(point<=10){point+100;point=point-10;key=0;}else{point=point-10;}}
		point=point%100;
	
	}
   

}

占空比的初值设置为50,即50%的亮度,通过按键4增亮,按键5变暗。除了板子上的外设,我还通过万用电表检测P1^0的电压,因为LED属于共阳极接法,所测电压为(1-占空比)*5V。

完成了练手任务,设置呼吸灯就显得比较简单了。我们在设置占空比的同时,也要注意设置呼吸的频率。

设频率=0.25HZ,则周期=4S。代码如下:

#include <STC15F2K60S2.H>
#include <intrins.h>
typedef unsigned char u8;
typedef unsigned int u16;
typedef unsigned long u32;
u16 flag_point=0;
u8 final=1;
u8 key=0;
u8 flag_key=0;
u8 point=0;
u8 count=0;
void ctrl(u8 ctrl)
{
	 u8 p2data=P2;
	 P2=ctrl<<5|(P2&0x1f);
   P2=p2data;
}
void light(u8 count)
{
  if(count<point)P0=0xfe;
	else P0=0xff;ctrl(4);

}
u8 key_val(void)
{
	 u8 adc=0;
   P3=0x0f;
	 P42=0;P44=0;
	 if(P30==0)adc=7;
	 if(P31==0)adc=6;
	 if(P32==0)adc=5;
	 if(P33==0)adc=4;
	 return adc;
}

u8 key_sta(void)
{
   static u8 sta=0;
 	u8 val=key_val(),ret=0;
	 switch(sta)
	 {
		 case 0:if(val!=0)sta=1;break;
		 case 1:if(val==0)sta=0;else{sta=2;ret=val;}break;
		 case 2:if(val==0)sta=0;break;
		 default:break;
		 	 
	 }
	 return ret;


}

void live(void)
{
 if(point==0)final=1;
 if(point==100){point=99;final=0;}
 if(final)
 {
 point++;
 }
 else
 {
 point--;
 }
 
 
 
 

}
	
void Timer2_Init(void)		//100??@12.000MHz
{
	AUXR &= 0xFB;			//?????12T??
	T2L = 0xFF;				//???????
	T2H = 0xFF;				//???????
	AUXR |= 0x10;			//???2????
  IE2|=0X04;
	EA=1;
}

void Timer0_Init(void)		//10??@12.000MHz
{
	AUXR |= 0x80;			//?????1T??
	TMOD &= 0xF0;			//???????
	TL0 = 0x88;				//???????
	TH0 = 0xFF;				//???????
	TF0 = 0;				//??TF0??
	TR0 = 1;				//???0????
	ET0 = 1;				//?????0??
}

void service2(void)  interrupt 12
{
	flag_key++;
	flag_point++;
	if(flag_point>200)
  {
	flag_point=0;
  live();
	}
	
	
	
	
  
	
	
}
void service0(void)  interrupt 1
{
  count++;
	count=count%100;
	light(count);
}
void Process(void)
{
  if(flag_key>10){flag_key=0;key=key_sta();}
}
void main()
{
   P0=0x00;ctrl(5);
	 P0=0xff;ctrl(4);
	 P0=0x00;ctrl(6);
	 Timer2_Init();
 	 Timer0_Init();
	 while(1)
	{
		Process();
		
	
	}
   

}


 以上代码已经关闭了蜂鸣器、继电器,数码管保持全息,建议大家手打一遍,加深印象。如有问题欢迎私信!

  • 28
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
使用PCA可以方便地实现PWM呼吸灯效果,PCA模块可以生成高精度的PWM波形,并且不需要使用CPU的计算资源,可以提高系统的效率。以下是51单片机通过PCA实现PWM呼吸灯的方法: 1. 初始化PCA模块:设置PCA时钟源和计数器溢出时间,开启PCA模块。 2. 配置PCA模块:设置PCA模块为PWM模式,设置PWM的占空比和周期,并使能PWM输出口。 3. 实现呼吸灯效果:通过改变PWM的占空比和周期,可以实现呼吸灯效果。可以使用定时器或者其他方式来改变PWM的占空比和周期,从而控制LED的亮度和闪烁频率。 4. 中断处理:在PCA计数器溢出时,可以触发中断处理函数,在中断处理函数中可以实现PWM占空比和周期的改变,从而实现呼吸灯效果。 下面是基于PCA的PWM呼吸灯的代码示例: ```c #include <reg52.h> sbit LED = P1^0; void PCA_Init() { CMOD = 0x00; // 设置PCA时钟源为系统时钟 CL = 0x00; // 设置PCA计数器初值 CH = 0x00; // 设置PCA计数器初值 CCAPM0 = 0x42; // 设置PCA模块为PWM模式 CCAP0H = 0x7F; // 设置PWM的占空比 CCAP0L = 0x00; CCAPM0 |= 0x40; // 使能PWM输出口 CR = 1; // 开启PCA模块 } void main() { PCA_Init(); while(1) { for(int i=0;i<128;i++) { CCAP0H = i; // 逐渐增加PWM占空比 CCAP0L = 0x00; LED = 1; // 点亮LED delay(10); // 延时 } for(int i=128;i>0;i--) { CCAP0H = i; // 逐渐减小PWM占空比 CCAP0L = 0x00; LED = 1; // 点亮LED delay(10); // 延时 } } } void delay(int n) { int i,j; for(i=0;i<n;i++) for(j=0;j<120;j++); } ``` 在上面的代码中,使用PCA模块来生成PWM波形,通过改变PWM的占空比和周期,实现呼吸灯效果。在主函数中,使用循环来控制PWM的占空比,通过逐渐增加和减小PWM占空比,来实现呼吸灯效果。在delay函数中,使用嵌套循环来实现延时。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值