基于单片机的PWM输出对Led的常见应用
目录
(1)让led以20%的亮度实现跑马效果(取消LedPwmTime=4的注释)。
(2)让led以12.5%的亮度来实现跑马效果,跑马时间间隔400ms.
(3)让led每隔0.5s亮度增加14%(1/7),实现持续3.5s的呼吸灯效果。
<吐槽>
继几天前做第九套蓝桥杯赛题彩灯控制器后,当时灯的亮度等级让我顿时不知道怎么操作,良久后才把它做出来。以“今天对明天而言永远都是早的一天,明天对于今天永远都是晚的一天” 的原则,趁早趁现在也就是在今天我把PWM琢磨了一遍,感觉还行。(然后第二天测试,老师认为PWM的亮度等级不应该是灯亮度等级太低在闪烁。我认为答案是定时的时间还是太长,在一个周期内,高电平的持续时间和低电平的持续时间并没有欺骗过人的眼睛,所以把pwm调低而灯在闪,所以要把pwm的一个周期的时间调得更低,经过测试7ms-15ms内操作pwm是可行的,再经过调试,发现达到了预期效果)。
所用的开发板是蓝桥杯单片机的一块基于stc15f2k60s2的stc开发板。
<引言>
对于PWM:简而言之:就是高电平的持续时间(脉冲宽度)占整个时钟周期的比例,对于单片机而言用定时是再好不过的了,比如要百分之20的亮度,定时器1ms产生一次中断,则在前20次中断的前5次中断让其为高电平,其余15次中断为低电平,又由于若是频繁的对led灯操作会电平不稳定,所以要在前5次中断中只对led灯操作一次,其余15次中断也只操作一次,怎么做?——设标志位。
在之前的彩灯控制器的里以一定亮度等级 进行流转跳跃显示。如下图
而操作LED的PWM就改变了其亮度。
<操作>
(1)让led以20%的亮度实现跑马效果(取消LedPwmTime=4的注释)。
/*******************
函数名称:LedTest1
功能:让led以20%的亮度实现跑马效果(取消LedPwmTime=4的注释)
作者:yzh
邮箱:2649483892@qq.com
***********************/
void LedTest1(){//
if(time<500){
if(LedTime<=LedPwmTime&&PwmFlag==1){//由于PwmFlag进判断后被赋予不同值,
以同20ms内的不同阶段只操作led一次
Led(leds);
PwmFlag=2;
}
else if(PwmFlag==2&&LedTime>LedPwmTime){
Led(8);
PwmFlag=3;
}
if(LedTime==20){
LedTime=0;
PwmFlag=1;
}
}
if(time==500){//每500ms
PwmFlag=1;
time=0;
leds++;
if(leds>7)leds=0;
}
}
(2)让led以12.5%递增的亮度来实现跑马效果,跑马时间间隔400ms.
/**********************
函数名称:LedTest2
功能:让led以12.5%递增的亮度来实现跑马效果,跑马时间间隔400ms
作者:yzh
邮箱:2649483892@qq.com
***********************/
void LedTest2(){
if(time<400){
if(LedTime<9){
if(PwmFlag==1&&LedPwmTime>=LedTime){//28ms内的高电平时间
//(由于有个等号,所以尽管为LedPwmTime为0也会有微光。
Led(leds);
PwmFlag=2;
}
else if(PwmFlag=2&&LedTime>LedPwmTime){//剩余低电平时间
Led(8);
PwmFlag=3;
}
}
if(LedTime==8){
LedTime=0;
PwmFlag=1;
}
}
if(time==400){
PwmFlag=1;
LedPwmTime+=1;
if(LedPwmTime==8)LedPwmTime=0;//0 1 2 3 4 5 6 7 8
time=0;
leds++;
if(leds>7)leds=0;
}
}
(3)让led每隔0.5s亮度增加14%(1/7),实现持续3.5s的呼吸灯效果。
/**********************
函数名称:LedTest3
功能:让led0实现3.5s呼吸灯效果
作者:yzh
邮箱:2649483892@qq.com
***********************/
void LedTest3(){
if(time<1000){
if(PwmFlag==1&&LedPwmTime>LedTime){
Led(leds);
PwmFlag=2;
}
else if(PwmFlag==2&&LedPwmTime<LedTime){
Led(8);//熄灭
PwmFlag=3;
}
if(LedTime==7){
LedTime=0;
PwmFlag=1;
}
}
if(time==500){
PwmFlag=1;
time=0;
LedPwmTime+=1;//每0.5s亮度增1/7
if(LedPwmTime==8)LedPwmTime=0;
}
}
整个测试工程:
main.c
#include "sys.h"
u16 time=0;
u8 s=0;
bit ledflag=0;
//u8 LedPwmTime=4;
u8 LedPwmTime=0;
u16 LedTime=0;
u8 PwmFlag=0;
u8 leds=0;
/*******************
函数名称:LedTest1
功能:让led以20%的亮度实现跑马效果(取消LedPwmTime=4的注释)
作者:yzh
邮箱:2649483892@qq.com
***********************/
void LedTest1(){//
if(time<500){
if(LedTime<=LedPwmTime&&PwmFlag==1){//由于PwmFlag进判断后被赋予不同值,
//所以同20ms内的不同阶段只操作led一次
Led(leds);
PwmFlag=2;
}
else if(PwmFlag==2&&LedTime>LedPwmTime){
Led(8);
PwmFlag=3;
}
if(LedTime==20){
LedTime=0;
PwmFlag=1;
}
}
if(time==500){//每500ms
PwmFlag=1;
time=0;
leds++;
if(leds>7)leds=0;
}
}
/**********************
函数名称:LedTest2
功能:让led以12.5%递增的亮度来实现跑马效果,跑马时间间隔400ms
作者:yzh
邮箱:2649483892@qq.com
***********************/
void LedTest2(){
if(time<400){
if(LedTime<28){
if(PwmFlag==1&&LedPwmTime>=LedTime){//28ms内的高电平时间
//(由于有个等号,所以尽管为LedPwmTime为0也会有微光。
Led(leds);
PwmFlag=2;
}
else if(PwmFlag=2&&LedTime>LedPwmTime){//剩余低电平时间
Led(8);
PwmFlag=3;
}
}
if(LedTime==8){
LedTime=0;
PwmFlag=1;
}
}
if(time==400){
PwmFlag=1;
LedPwmTime+=1;
if(LedPwmTime==8)LedPwmTime=0;//0 1 2 3 4 5 6 7 8
time=0;
leds++;
if(leds>7)leds=0;
}
}
/**********************
函数名称:LedTest3
功能:让led0实现3.5s呼吸灯效果
作者:yzh
邮箱:2649483892@qq.com
***********************/
void LedTest3(){
if(time<1000){
if(PwmFlag==1&&LedPwmTime>LedTime){
Led(leds);
PwmFlag=2;
}
else if(PwmFlag==2&&LedPwmTime<LedTime){
Led(8);//熄灭
PwmFlag=3;
}
if(LedTime==7){
LedTime=0;
PwmFlag=1;
}
}
if(time==500){
PwmFlag=1;
time=0;
LedPwmTime+=1;//每0.5s亮度增1/7
if(LedPwmTime==8)LedPwmTime=0;
}
}
void main(){
sys_init();
Timer0Init();
while(1){
LedTest3();//测试
}
}
void time0() interrupt 1{
time++;
LedTime++;
}
sys.c
#include "sys.h"
sbit buzz=P0^6;
sbit rely=P0^4;
void sys_init(){
P0=0xff;
P2=P2&0x1f|0x80;
P0=0xff;
P2=P2&0x1f;
P0=0xff;
P2=P2&0x1f|0xe0;
P0=0xff;
P2=P2&0x1f;
P0=0;
P2=P2&0x1f|0xc0;
P0=0;
P2=P2&0x1f;
P0=0;
P2=P2&0x1f|0xA0;
buzz=0;
rely=0;
P2=P2&0x1f;
}
void Timer0Init(void) //1000微秒@11.0592MHz
{
AUXR |= 0x80; //定时器时钟1T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0xCD; //设置定时初始值
TH0 = 0xD4; //设置定时初始值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
EA=1;
ET0=1;
}
void Led(u8 chi){//点亮任一led灯
P0=0xff;
P2=P2&0x1f|0x80;
if(chi<=7)P0=~(1<<chi);
else P0=0xff;
P2=P2&0x1f;
}
sys.h
#ifndef __SYS_H_
#define __SYS_H_
#include "stc15f2k60s2.h"
typedef unsigned char u8;
typedef unsigned int u16;
void Timer0Init(void);
void Led(u8 chi);
void sys_init();
#endif
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?