头文件
delay.h
#define uchar unsigned char
#define uint unsigned int
#include <intrins.h>
void delay_10us(uint i) //i=1,10us
{
while(i--);
}
void delay_ms(uint n)
{
unsigned int i=0,j=0;
for(i=0;i<n;i++)
for(j=0;j<123;j++);
}
void delay_s(uint n)
{
unsigned int i=0,j=0;
for(i=0;i<n;i++)
for(j=0;j<21738;j++);
}
主函数
main.c
#include <reg51.h>
#include <delay.h>
#define GPIO P0 //数码管显示数字
sbit led=P2^0;
sbit k1=P1^0;
sbit k2=P1^1;
sbit k3=P1^2;
sbit k4=P1^3; //按键
sbit LSA=P2^2;
sbit LSB=P2^3;
sbit LSC=P2^4; //138位选
uchar key,keyflag,s,direct,flag;
uint speed,dutyfactor; //闪烁速度 ,占空比
uchar code smgduan[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07, 0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0x40,0x00}; //显示0~F、负号‘-’¡¯
uchar wei[8]={0}; //用来存放每一位数码管数字的数组
void Timer0Init()
{
TMOD|=0X01; //选择为定时器0模式,工作方式1,仅用TR0打开启动。
TL0 = 0x38; //设置定时初值 200us
TH0 = 0xFF; //设置定时初值
ET0=1;//打开定时器0中断允许
EA=1;//打开总中断
TR0=1;//打开定时器
}
void keydown() //独立按键检测
{
if(k1==0)
{
delay_ms(10); //消抖
if(k1==0)
{key=1;}
while(!k1); //判断是否松下
}
if(k2==0)
{
delay_ms(10);
if(k2==0)
{ key=2;}
while(!k2);
}
if(k3==0)
{
delay_ms(10);
if(k3==0)
{ key=3;}
while(!k3);
}
if(k4==0)
{
delay_ms(10);
if(k4==0)
{key=4;}
while(!k4);
}
if(key==1||key==2||key==3||key==4)
{ keyflag=1; } //有按键按下标志keyflag
}
void display() //扫描显示动态数码管
{
LSA=0; LSB=0; LSC=0; GPIO=smgduan[wei[7]];delay_10us(50); GPIO=0x00; //消隐
LSA=1; LSB=0; LSC=0; GPIO=smgduan[wei[6]];delay_10us(50); GPIO=0x00;
LSA=0; LSB=1; LSC=0; GPIO=smgduan[wei[5]];delay_10us(50); GPIO=0x00;
LSA=1; LSB=1; LSC=0; GPIO=smgduan[wei[4]];delay_10us(50); GPIO=0x00;
LSA=0; LSB=0; LSC=1; GPIO=smgduan[wei[3]];delay_10us(50); GPIO=0x00;
LSA=1; LSB=0; LSC=1; GPIO=smgduan[wei[2]];delay_10us(50); GPIO=0x00;
LSA=0; LSB=1; LSC=1; GPIO=smgduan[wei[1]];delay_10us(50); GPIO=0x00;
LSA=1; LSB=1; LSC=1; GPIO=smgduan[wei[0]];delay_10us(50); GPIO=0x00;
}
void main()
{
Timer0Init(); //定时器初始化
while(1)
{
display(); //数码管显示
}
}
void Timer0() interrupt 1
{
static uint i,j;
TL0 = 0x38; //设置定时初值 200us
TH0 = 0xFF; //设置定时初值
i++; j++;
keydown(); //扫描按键
if(key==1) //k1按下 更改呼吸速度
{
speed=1;
}
if(key==2) //k2按下 更改呼吸速度
{
speed=10;
}
if(i==5000) //i=5000 计时满1秒
{
s++; //s计秒
i=0;
wei[0]=s%10;
wei[1]=s/10%10;
if(s==30)
{s=0;}
}
if(j >= 100) //一个PWM周期(100次*200us)
{
j= 0; //下一个PWM周期内,重新计数
if(direct == 0) //根据方向判断占空比增加或减少
{ //正方向,占空比增加
dutyfactor+=speed; //下一个PWM周期,占空比增加speed
} else if(direct == 1) //负方向,占空比减少
{
dutyfactor--; //下一个PWM周期,占空比减少1
}
}
//根据占空比值判断方向是否需要改变
if(dutyfactor <= 0) //占空比减少到0
{
direct = 0; //正方向,占空比开始增加
}
else if(dutyfactor >= 100) //占空比增加到100
{
direct = 1; //负方向,占空比开始减少
}
//占空比:通电时间相对于总时间所占的比例(此程序中:低电平时间相对于PWM周期所占的比例)
//一个PWM周期计数100次,占空比相当于低电平的计数周期次数。即:0~占空比:低电平,灯亮;占空比~100:高电平,灯灭
//在一个PWM周期内,根据周期计数是否小于占空比,判断LED灯的亮灭
if(j < dutyfactor) //周期计数值<占空比
{
led = 0; //当前PWM周期的当前计数周期内灯亮
}
else
{
led = 1; //当前PWM周期的当前计数周期内灯灭
}
/* for(on=0;on<=speed;on++) //含延时呼吸灯方法
{
off=speed-on;
led=0;
delay_10us(off);
led=1;
delay_10us(on);
}
for(off=0;off<=speed;off++)
{
on=speed-off;
led=1;
delay_10us(on);
led=0;
delay_10us(off);
} */
}