【题目要求】
通过单片机控制8个LED指示灯按照特定的顺序(工作模式)亮灭;指示灯的流转间隔可通过按键调整,亮度可由电位器RB2进行控制;各工作模式的流转间隔时间需在E2PROM中保存,并可在硬件重新上电后,自动载入。
检测电位器RB2的输出电压,控制8个LED指示灯的亮度,要求在0V~5V的可调区间内,实现4个均匀分布的LED指示灯亮度等级。
#include
#include
#include
unsigned char Read_AIN3();
void Write_24c02(unsigned char addr,unsigned char dat);
unsigned char Read_24c02(unsigned char dat);
sbit s7=P3^0; //启动/停止"按键,按下后启动或停止LED的流转。
sbit s6=P3^1; //S6定义为"设置"按键,按键按下后数码管进入"流转间隔"设置界面
sbit s5=P3^2; //S5定义为"加"按键
sbit s4=P3^3; //S4定义为"减"按键
unsigned char table[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xbf,0xff};
unsigned char dat_rb2; //保存电位器rb2的电压
unsigned int count=0; //长定时计数变量
unsigned int count_smg=0; //数码管闪烁计数变量
unsigned int time_m[4]; //四个模式的流转间隔时间数组
unsigned char stat=0; //彩灯当前状态
unsigned char mode=1; //彩灯工作模式
unsigned char mode_s6=1; //彩灯设置模式
unsigned char pwm_duty=20; //pwm的脉宽
unsigned char t_pwm=0; //pwm的计数变量
unsigned char level=0; //彩灯亮度等级
unsigned char dat_led=0; //彩灯当前的工作参数
unsigned char f_set=0; //按键s6的状态切换变量
unsigned char f_open=0; //启动与停止变量
unsigned char f_t800=0; //0.8秒时间间隔标志
void LED_Working(); //声明彩灯模式变换函数
/*===============================================数码管=================================================*/
void delaysmg(unsigned int n)
{
while(n--);
}
void displaysmg_bit(unsigned char pos,unsigned char value)
{
XBYTE[0xe000]=0xff;
XBYTE[0xc000]=0x01<<pos;
XBYTE[0xe000]=value;
}
void displaysmg_off()
{
XBYTE[0xc000]=0xff;
XBYTE[0xe000]=0xff;
}
/*========================================显示彩灯亮度等级============================================*/
void display_level()
{
displaysmg_bit(0,0xff);
delaysmg(100);
displaysmg_bit(1,0xff);
delaysmg(100);
displaysmg_bit(2,0xff);
delaysmg(100);
displaysmg_bit(3,0xff);
delaysmg(100);
displaysmg_bit(4,0xff);
delaysmg(100);
displaysmg_bit(5,0xff);
delaysmg(100);
displaysmg_bit(6,table[10]);
delaysmg(100);
displaysmg_bit(7,table[level]);
delaysmg(100);
displaysmg_bit(7,0xff);
delaysmg(100);
}
/*=======================================显示彩灯运行模式设置函数=======================================*/
void display_mode()
{
if(f_t800==0) //0.8秒闪烁,表示选中
{
displaysmg_bit(0,table[10]);
delaysmg(100);
displaysmg_bit(1,table[mode_s6]);
delaysmg(100);
displaysmg_bit(2,table[10]);
delaysmg(100);
}
else
{
displaysmg_bit(0,0xff);
displaysmg_bit(1,0xff);
displaysmg_bit(2,0xff);
}
if(time_m[mode_s6-1]/1000!=0)
{
displaysmg_bit(4,table[time_m[mode_s6-1]/1000]);
}
delaysmg(100);
displaysmg_bit(5,table[(time_m[mode_s6-1]%1000)/100]);
delaysmg(100);
displaysmg_bit(6,table[0]);
delaysmg(100);
displaysmg_bit(7,table[0]);
delaysmg(100);
}
/*=======================================显示彩灯流转间隔的设置函数=======================================*/
void display_time()
{
displaysmg_bit(0,table[10]);
delaysmg(100);
displaysmg_bit(1,table[mode_s6]);
delaysmg(100);
displaysmg_bit(2,table[10]);
delaysmg(100);
if(f_t800==0) //0.8秒闪烁,表示选中
{
if(time_m[mode_s6-1]/1000!=0)
{
displaysmg_bit(4,table[time_m[mode_s6-1]/1000]);
}
delaysmg(100);
displaysmg_bit(5,table[(time_m[mode_s6-1]%1000)/100]);
delaysmg(100);
displaysmg_bit(6,table[0]);
delaysmg(100);
displaysmg_bit(7,table[0]);
delaysmg(100);
}
else
{
displaysmg_bit(4,0xff);
displaysmg_bit(5,0xff);
displaysmg_bit(6,0xff);
displaysmg_bit(7,0xff);
}
}
/*=========================================初始化定时器0的函数=========================================*/
void InitTimer0()
{
TMOD=0X01;
TH0=(65536-1000)/256; //定时1ms
TL0=(65536-1000)%256;
ET0=1;
EA=1;
TR0=1;
}
/*=========================================定时器0中断服务函数=========================================*/
void ServiceTimer0() interrupt 1
{
TH0=(65536-1000)/256;
TL0=(65536-1000)%256;
t_pwm++; //产生PWM信号,控制灯光亮度
if(t_pwm<pwm_duty)
XBYTE[0X8000]=dat_led;
else if(t_pwm<20)
XBYTE[0X8000]=0XFF;
else
{
XBYTE[0X8000]=dat_led;
t_pwm=0;
LED_Working(); //彩灯工作模式控制
}
count++;
if(count==time_m[mode-1]) //流转间隔处理
{
count=0;
if(f_open==1)
stat++;
if(stat==25)
stat=0;
}
count_smg++;
if(count_smg==800) //0.8秒间隔定时
{
count_smg=0;
f_t800=~f_t800;
}
}
/*=========================================RB2电压彩灯亮度控制函数=========================================*/
void level_change()
{
if(dat_rb2<60)
{
pwm_duty=5;
level=1;
}
else if(dat_rb2<120)
{
pwm_duty=10;
level=2;
}
else if(dat_rb2<180)
{
pwm_duty=15;
level=3;
}
else
{
pwm_duty=20;
level=4;
}
}
/*=======================================彩灯的四种工作模式变化函数========================================*/
void LED_Working()
{
switch(stat)
{
//模式1的彩灯变化
case 0:dat_led=0xff; break;
case 1:dat_led=0xfe; break;
case 2:dat_led=0xfc; break;
case 3:dat_led=0xf8; break;
case 4:dat_led=0xf0; break;
case 5:dat_led=0xe0; break;
case 6:dat_led=0xc0; break;
case 7:dat_led=0x80; break;
case 8:dat_led=0x00; break;
//模式二的彩灯变化
case 9:dat_led=0x7f; break;
case 10:dat_led=0x3f; break;
case 11:dat_led=0x1f; break;
case 12:dat_led=0x0f; break;
case 13:dat_led=0x07; break;
case 14:dat_led=0x03; break;
case 15:dat_led=0x01; break;
case 16:dat_led=0x00; break;
//模式三的彩灯变化
case 17:dat_led=0x7e; break;
case 18:dat_led=0xbd; break;
case 19:dat_led=0xdb; break;
case 20:dat_led=0xe7; break;
//模式四的彩灯变化
case 21:dat_led=0xe7; break;
case 22:dat_led=0xdb; break;
case 23:dat_led=0xbd; break;
case 24:dat_led=0x7e; break;
//四种工作模式的循环切换
if(stat==0)
{
mode=1;
}
else if(stat==9)
{
mode=2;
}
else if(stat==17)
{
mode=3;
}
else if(stat==21)
{
mode=4;
}
}
}
/*==========================================按键扫描与处理函数===========================================*/
void scan_keys()
{
if(s7==0)
{
delaysmg(100);
if(s7==0)
{
if(f_open==0) //启动彩灯变化
{
f_open=1;
}
else //停止彩灯变化
{
f_open=0;
f_set=0;
stat=0;
mode=1;
}
while(s7==0);
}
}
if(s6==0)
{
delaysmg(100);
if(s6==0)
{
f_set++;
while(s6==0)
{
if(f_set==1)
{
display_mode();
}
else if(f_set==2)
{
display_time();
}
}
}
}
if(s5==0)
{
delaysmg(100);
if(s5==0)
{
if(f_set==1)
{
mode_s6+=1;//模式加1
if(mode_s6>4) //边界处理
{
mode_s6=4;
}
while(s5==0)
{
display_mode();
}
}
else if(f_set==2)
{
time_m[mode_s6-1]+=100; //流转间隔加100
if(time_m[mode_s6-1]>1200)
{
time_m[mode_s6-1]=1200;
}
while(s5==0)
{
display_time();
}
}
}
}
if(s4==0)
{
delaysmg(100);
if(s4==0)
{
if(f_set==1)
{
mode_s6-=1; //模式减一
if(mode_s6<1)
{
mode_s6=1;
}
while(s6==0)
{
display_mode();
}
}
else if(f_set==2)
{
time_m[mode_s6-1]-=100; //流转间隔减100
if(time_m[mode_s6-1]<400)
{
time_m[mode_s6-1]=400;
}
while(s4==0)
{
display_time();
}
}
else if(f_set==0)
{
while(s4==0)
{
display_level();
LED_Working();
}
}
}
}
}
/*===============================================================================*/
unsigned char Read_AIN3() //通道3:可调电阻Rb2控制
{
unsigned dat;
//进行写操作,选择电位器AIN3,通道3
IIC_Start();
IIC_SendByte(0x90); ///PCF8591的写设备地址
IIC_WaitAck();
IIC_SendByte(0x03); //写入PCF8591的控制字节
IIC_WaitAck();
IIC_Stop();
//进行读操作,通道3
IIC_Start();
IIC_SendByte(0x91); //PCF8591的读设备地址
IIC_WaitAck();
dat=IIC_RecByte(); //读取PCF8591通道1的数据
IIC_Ack(0); //产生非应答信号
IIC_Stop();
return dat;
}
/*===============================================================================*/
void Write_24c02(unsigned char addr,unsigned char dat)
{
IIC_Start();
IIC_SendByte(0xa0); //24c02的写设备地址
IIC_WaitAck();
IIC_SendByte(addr); //24c02的内存字节,即将数据写在哪一个内存地址
IIC_WaitAck();
IIC_SendByte(dat); //写入目标数据
IIC_WaitAck();
IIC_Stop();
}
/*===============================================================================*/
unsigned char Read_24c02(unsigned char dat)
{
unsigned char temp;
//先进行一个伪写操作
IIC_Start();
IIC_SendByte(0xa0); //写设备地址
IIC_WaitAck();
IIC_SendByte(dat);
//进行读字节
IIC_Start();
IIC_SendByte(0xa1); //写设备地址
IIC_WaitAck();
temp=IIC_RecByte();
IIC_Ack(0); //产生一个非应答信号
IIC_Stop();
return temp;
}
/*=======================================运行模式与流转间隔参数保存========================================*/
void sava_config()
{
switch(mode_s6)
{
case 1:Write_24c02(0x01,time_m[0]/10);break;
case 2:Write_24c02(0x02,time_m[1]/10);break;
case 3:Write_24c02(0x03,time_m[2]/10);break;
case 4:Write_24c02(0x04,time_m[3]/10);break;
}
delaysmg(1000); //等待数据写入到24c02完成
displaysmg_off();
mode_s6=1;
f_set=0;
}
/*=======================================系统初始化函数========================================*/
void init_system()
{
XBYTE[0XA000]=0X00;
displaysmg_off();
dat_led=0xff;//彩灯当前状态
time_m[0]=Read_24c02(0x01)*10; //读取模式1的流转间隔
time_m[1]=Read_24c02(0x02)*10; //读取模式2的流转间隔
time_m[2]=Read_24c02(0x03)*10; //读取模式3的流转间隔
time_m[3]=Read_24c02(0x04)*10; //读取模式4的流转间隔
InitTimer0();
}
/*========================================主函数==========================================*/
void main()
{
init_system();
while(1)
{
scan_keys();
dat_rb2=Read_AIN3();
level_change();
switch(f_set)
{
case 1: display_mode(); break;
case 2: display_time(); break;
case 3: sava_config(); break;
}
}
}