12.Led彩灯控制系统(micu)

12.3 Led彩灯控制系统(micu)

0.总流程

Led四个模式——模式流转——模式流转时间——1ms的时长计算——数码管运行状态——矩阵键盘启动暂停按键——矩阵键盘设置切换按键——数码管流转时间设置界面——中断400ms,闪烁标志位取反——矩阵键盘加减,保存参数并退出——矩阵键盘长按——数码管显示界面——Led数据读取

1.彩灯控制系统

a.位移操作:

crol_(位移变量,位移次数) a = crol(a,1);
不要对寄存器直接进行操作,使用中间变量过渡

unsigned char Led_Mode;//Led模式标志位
unsigned char ucLed = 0xfe;//Led数据存放数组
unsigned char ucLed_Data[4] = {0x7e,0xbd,0xdb,0xe7};//模式3、4数据存放数组
unsigned char ucLed_Data_Index;//模式3、4数组指针

P1=ucLed;
switch(Led_Mode)//根据Led_Mode的不同 选择不同的彩灯运行模式
{
	case 0:
		if(ucLed == 0x7e)//判断是否从模式4切换至模式1 若是,则复位ucLed数据
			ucLed = 0xfe;//避免第一个灯不亮
		else
		{
			ucLed = _crol_(ucLed,1);//模式1 L1-L8
			if(ucLed == 0x7f) Led_Mode = 1;//当L8点亮时 跳转到模式2
		}
	break;
	case 1:
		ucLed = _cror_(ucLed,1);//模式2 L8-L1
		if(ucLed == 0xfe) Led_Mode = 2;//当L1点亮时 跳转到模式3
	break;
	case 2:
    	ucLed = ucLed_Data[ucLed_Data_Index];//模式3 从外往内
		if(++ucLed_Data_Index == 4)//当指针溢出 即完成一次循环时 跳转到模式4
		{
			Led_Mode = 3;
			ucLed_Data_Index = 3;//指针复位至模式四初始数据
		}
	break;
	case 3:
		ucLed = ucLed_Data[ucLed_Data_Index];//模式4 从内往外
		if(--ucLed_Data_Index == 255)//当指针溢出 即完成一次循环时 跳转到模式1
		{	
			Led_Mode = 0;
			ucLed_Data_Index = 0;	//指针复位至模式三初始数据
		}
	break;
}

b.Led流转时间

unsigned int Led_Time_Data[4] = {400,400,400,400};//Led流转时间数据存放数组
if(Sys_Tick == Led_Time_Data[Led_Mode])//当计时器走到当前模式设定的流转时间间隔时
{
	Sys_Tick = 0;//计时器复位 便于下次循环
}

c.数据读取

Led模式12

ucLed取反之后,用0x01左移i位&(相乘)ucLed取反,等于0之后i++,直到不等于0,Led状态为i+1.

0 i+1

while((~ucLed & (0x01 << i)) != (0x01 << i))
	i++;
		
while((~ucLed & (0x01 << i)) == 0)
	i++;
	
Led_Data = i+1;

Led模式34

对称变换,1、8亮,2、7亮,3、6亮,4、5亮,9-高位的值(后四位)——9-(i+1)——8-i

8-i i+1

Led_Data = (i+1)*10+(9-(i+1));//若处于后两种模式,则高位数据等于i+1,根据对称变换,低位加高位的数值之和等于9

Led模式1~4

{
	unsigned char i;//用于循环判断
	/* 数据读取设计思路 */
	i = 0;//每次循环判断前将i置0,便于读取Led状态
	while((~ucLed & (0x01 << i)) != (0x01 << i))
		i++;
	if(Led_Mode < 2)//若处于前两种模式,则数据直接等于i+1
		Led_Data = i+1;
	else
		Led_Data = (i+1)*10+(9-(i+1));//若处于后两种模式,则高位数据等于i+1,根据对称变换,低位加高位的数值之和等于9
}

总代码

unsigned char Led_Mode;//Led模式标志位
unsigned int Led_Time_Data[4] = {400,400,400,400};//Led流转时间数据存放数组
unsigned int Sys_Tick;//系统计时器专用变量
unsigned char ucLed = 0xfe;//Led数据存放数组
unsigned char ucLed_Data[4] = {0x7e,0xbd,0xdb,0xe7};//模式3、4数据存放数组
unsigned char ucLed_Data_Index;//模式3、4数组指针

/* 其他显示函数 */
void Led_Proc()
{
	unsigned char i;//用于循环判断
	P1 = ucLed;
	if(Sys_Tick == Led_Time_Data[Led_Mode])//当计时器走到当前模式设定的流转时间间隔时
	{
		Sys_Tick = 0;//计时器复位 便于下次循环
		switch(Led_Mode)//根据Led_Mode的不同 选择不同的彩灯运行模式
		{
			case 0:
				if(ucLed == 0x7e)//判断是否从模式4切换至模式1 若是,则复位ucLed数据
					ucLed = 0xfe;
				else
				{
					ucLed = _crol_(ucLed,1);//模式1 L1-L8
					if(ucLed == 0x7f) Led_Mode = 1;//当L8点亮时 跳转到模式2
				}
			break;
			case 1:
				ucLed = _cror_(ucLed,1);//模式2 L8-L1
				if(ucLed == 0xfe) Led_Mode = 2;//当L1点亮时 跳转到模式3
			break;
			case 2:
				ucLed = ucLed_Data[ucLed_Data_Index];//模式3 从外往内
				if(++ucLed_Data_Index == 4)//当指针溢出 即完成一次循环时 跳转到模式4
				{
					Led_Mode = 3;
					ucLed_Data_Index = 3;//指针复位至模式四初始数据
				}
			break;
			case 3:
				ucLed = ucLed_Data[ucLed_Data_Index];//模式4 从内往外
				if(--ucLed_Data_Index == 255)//当指针溢出 即完成一次循环时 跳转到模式1
				{	
					Led_Mode = 0;
					ucLed_Data_Index = 0;	//指针复位至模式三初始数据
				}
			break;
		}
	}
	/* 数据读取设计思路 */
	i = 0;//每次循环判断前将i置0,便于读取Led状态
	while((~ucLed & (0x01 << i)) != (0x01 << i))
		i++;
	if(Led_Mode < 2)//若处于前两种模式,则数据直接等于i+1
		Led_Data = i+1;
	else
		Led_Data = (i+1)*10+(8-(i+1));//若处于后两种模式,则高位数据等于i+1,根据对称变换,低位加高位的数值之和等于8
}

2.数码管

a.多界面显示

运行状态和显示状态

unsigned char Seg_Disp_Mode;//数码管显示模式变量 0-运行状态界面 1-流转时间设置界面 2-数据显示界面
bit System_Flag;//系统使能标志位 0-暂停 1-启动 上电默认处于暂停状态
bit Data_Disp_Flag;//数据显示标志位 0-不显示 1-显示

case 0://运行状态显示界面
	if(Data_Disp_Flag == 0)
	{
		Seg_Buf[0] = System_Flag?11:12;//11-S 12-R
		Seg_Buf[1] = Led_Mode+1;
		Seg_Buf[2] = Led_Time_Data[Led_Mode] / 1000 % 10;
		Seg_Buf[3] = Led_Time_Data[Led_Mode] / 100 % 10;
		Seg_Buf[4] = Led_Time_Data[Led_Mode] / 10 % 10;
		Seg_Buf[5] = Led_Time_Data[Led_Mode] % 10;
		while(Seg_Buf[i] == 0)//使用循环体结构令高位为0的数码管熄灭 直到不为0时退出
		{
			Seg_Buf[i] = 10;
			i++;
		}
	}
	else
	{
		Seg_Buf[0] = 0;
		Seg_Buf[1] = 12;
		Seg_Buf[2] = 13;
		Seg_Buf[3] = Led_Mode+1;
		Seg_Buf[4] = Led_Data / 10;
		Seg_Buf[5] = Led_Data % 10;
	}
break;

流转时间设置

case 1://流转时间设置界面
	Seg_Buf[0] = 13;
	Seg_Buf[1] = Led_Time_Set_Index+1;
	Seg_Buf[2] = Led_Time_Set[Led_Time_Set_Index] / 1000 % 10;
	Seg_Buf[3] = Led_Time_Set[Led_Time_Set_Index] / 100 % 10;
	Seg_Buf[4] = Led_Time_Set[Led_Time_Set_Index] / 10 % 10;
	Seg_Buf[5] = Led_Time_Set[Led_Time_Set_Index] % 10;
	if(Set_Flag == 0)
	{
		Seg_Buf[0] = Seg_Star_Flag?13:10;
		Seg_Buf[1] = Seg_Star_Flag?Led_Time_Set_Index+1:10;
	}
	else
	{
		Seg_Buf[2] = Seg_Star_Flag?Led_Time_Set[Led_Time_Set_Index] / 1000 % 10:10;
		Seg_Buf[3] = Seg_Star_Flag?Led_Time_Set[Led_Time_Set_Index] / 100 % 10:10;
		Seg_Buf[4] = Seg_Star_Flag?Led_Time_Set[Led_Time_Set_Index] / 10 % 10:10;
		Seg_Buf[5] = Seg_Star_Flag?Led_Time_Set[Led_Time_Set_Index] % 10:10;				
	}
	while(Seg_Buf[i] == 0)//使用循环体结构令高位为0的数码管熄灭 直到不为0时退出
	{
		Seg_Buf[i] = 10;
		i++;
	}		
break;

b.数码管熄灭

while(Seg_Buf[i] == 0)//使用循环体结构令高位为0的数码管熄灭 直到不为0时退出
{
	Seg_Buf[i] = 10;
	i++;
}

if(Seg_Buf[2] == 0)	Seg_Buf[2] = 10;

c.小数点

Seg_Point[0] = Seg_Point[1] = Data_Disp_Flag&(!Data_Disp_Flag)?0:1;//小数点

总代码

unsigned char Seg_Buf[6] = {10,10,10,10,10,10};//数码管显示数据存放数组
unsigned char Seg_Point[6] = {0,0,0,0,0,0};//数码管小数点数据存放数组
unsigned char Seg_Pos;//数码管扫描专用变量
unsigned int Seg_Slow_Down;//数码管减速专用变量
unsigned char Seg_Disp_Mode;//数码管显示模式变量 0-运行状态界面 1-流转时间设置界面 2-数据显示界面
bit System_Flag;//系统使能标志位 0-暂停 1-启动 上电默认处于暂停状态

void Seg_Proc()
{
	unsigned char i = 2;//用于熄灭高位未启用数码管
	if(Seg_Slow_Down) return;
	Seg_Slow_Down = 1;//数码管减速程序
	switch(Seg_Disp_Mode)
	{
		case 0://运行状态显示界面
			if(Data_Disp_Flag == 0)
			{
				Seg_Buf[0] = System_Flag?11:12;//11-S 12-R
				Seg_Buf[1] = Led_Mode+1;
				Seg_Buf[2] = Led_Time_Data[Led_Mode] / 1000 % 10;
				Seg_Buf[3] = Led_Time_Data[Led_Mode] / 100 % 10;
				Seg_Buf[4] = Led_Time_Data[Led_Mode] / 10 % 10;
				Seg_Buf[5] = Led_Time_Data[Led_Mode] % 10;
				while(Seg_Buf[i] == 0)//使用循环体结构令高位为0的数码管熄灭 直到不为0时退出
				{
					Seg_Buf[i] = 10;
					i++;
				}
			}
			else
			{
				Seg_Buf[0] = 0;
				Seg_Buf[1] = 12;
				Seg_Buf[2] = 13;
				Seg_Buf[3] = Led_Mode+1;
				Seg_Buf[4] = Led_Data / 10;
				Seg_Buf[5] = Led_Data % 10;
			}
		break;
		case 1://流转时间设置界面
			Seg_Buf[0] = 13;
			Seg_Buf[1] = Led_Time_Set_Index+1;
			Seg_Buf[2] = Led_Time_Set[Led_Time_Set_Index] / 1000 % 10;
			Seg_Buf[3] = Led_Time_Set[Led_Time_Set_Index] / 100 % 10;
			Seg_Buf[4] = Led_Time_Set[Led_Time_Set_Index] / 10 % 10;
			Seg_Buf[5] = Led_Time_Set[Led_Time_Set_Index] % 10;
			if(Set_Flag == 0)
			{
				Seg_Buf[0] = Seg_Star_Flag?13:10;
				Seg_Buf[1] = Seg_Star_Flag?Led_Time_Set_Index+1:10;
			}
			else
			{
				Seg_Buf[2] = Seg_Star_Flag?Led_Time_Set[Led_Time_Set_Index] / 1000 % 10:10;
				Seg_Buf[3] = Seg_Star_Flag?Led_Time_Set[Led_Time_Set_Index] / 100 % 10:10;
				Seg_Buf[4] = Seg_Star_Flag?Led_Time_Set[Led_Time_Set_Index] / 10 % 10:10;
				Seg_Buf[5] = Seg_Star_Flag?Led_Time_Set[Led_Time_Set_Index] % 10:10;				
			}
			
			while(Seg_Buf[i] == 0)//使用循环体结构令高位为0的数码管熄灭 直到不为0时退出
			{
				Seg_Buf[i] = 10;
				i++;
			}		
		break;
	}
	Seg_Point[0] = Seg_Point[1] = Data_Disp_Flag&(!Data_Disp_Flag)?0:1;
}

3.矩阵键盘

a.不同按键

按键7:启动暂停按键

case 7://启动暂停按键
	System_Flag ^= 1;
break;

按键6:设置切换按键

if和else if只会执行一个

case 6://设置切换按键
	if(Seg_Disp_Mode == 0)//若在显示界面下使能此按键
	{
		for(i=0;i<4;i++)//读取当前设置数据
			Led_Time_Set[i] = Led_Time_Data[i];
		Seg_Disp_Mode = 1;//跳转到参数设置界面
	}
	else if(Seg_Disp_Mode == 1)//else-为了避免第一次按下后直接执行下列程序 所以需要另外加else使得在执行完if语句后跳出判断主体
	{
		Set_Flag ^= 1;//用于判断设置处于哪个状态的变量                        
		if(Set_Flag == 0)//第二次跳转到模式设置状态
		{
			for(i=0;i<4;i++)
				Led_Time_Data[i] = Led_Time_Set[i];//保存当前设置数据
			Seg_Disp_Mode = 0;
		}
	}
break;

按键5:参数+

case 5://参数+
	if(Seg_Disp_Mode == 1)//处于参数设置界面
	{
		if(Set_Flag == 0)//编号设置
		{
			if(++Led_Time_Set_Index == 4)
				Led_Time_Set_Index = 0;
		}
		else
		{
			Led_Time_Set[Led_Time_Set_Index] = Led_Time_Set[Led_Time_Set_Index]+100;
			if(Led_Time_Set[Led_Time_Set_Index] >= 1300)
				Led_Time_Set[Led_Time_Set_Index] = 400;
		}
	}
break;

按键4:参数-

case 4://参数-
	if(Seg_Disp_Mode == 1)//处于参数设置界面
	{
		if(Set_Flag == 0)//编号设置
		{
			if(--Led_Time_Set_Index == 255)
				Led_Time_Set_Index = 3;
		}
		else
		{
			Led_Time_Set[Led_Time_Set_Index] = Led_Time_Set[Led_Time_Set_Index]-100;
			if(Led_Time_Set[Led_Time_Set_Index] <= 300)
				Led_Time_Set[Led_Time_Set_Index] = 1200;
		}
	}
break;		

长按按键4:数码管从运行状态切换至显示界面

if(System_Flag == 0)//系统处于暂停状态
{
	if(Key_Old == 4 && Seg_Disp_Mode == 0)//在显示界面下长按S4
		Data_Disp_Flag = 1;//显示数据
	else
		Data_Disp_Flag = 0;//显示状态
}
else
	Data_Disp_Flag = 0;

总代码

/* 键盘处理函数 */
void Key_Proc()
{
	unsigned char i;//For循环专用变量
	if(Key_Slow_Down) return;
	Key_Slow_Down = 1;//键盘减速程序

	Key_Val = Key_Read();//实时读取键码值
	Key_Down = Key_Val & (Key_Old ^ Key_Val);//捕捉按键下降沿
	Key_Old = Key_Val;//辅助扫描变量
	
	if(System_Flag == 0)//系统处于暂停状态
	{
		if(Key_Old == 4 && Seg_Disp_Mode == 0)//在显示界面下长按S4
			Data_Disp_Flag = 1;//显示数据
		else
			Data_Disp_Flag = 0;//显示状态
	}
	else
		Data_Disp_Flag = 0;
	
	switch(Key_Down)
	{
		case 7://启动暂停按键
			System_Flag ^= 1;
		break;
		case 6://设置切换按键
			if(Seg_Disp_Mode == 0)//若在显示界面下使能此按键
			{
				for(i=0;i<4;i++)//读取当前设置数据
					Led_Time_Set[i] = Led_Time_Data[i];
				Seg_Disp_Mode = 1;//跳转到参数设置界面
			}
			else if(Seg_Disp_Mode == 1)//else-为了避免第一次按下后直接执行下列程序 所以需要另外加else使得在执行完if语句后跳出判断主体
			{
				Set_Flag ^= 1;//用于判断设置处于哪个状态的变量                        
				if(Set_Flag == 0)//第二次跳转到模式设置状态
				{
					for(i=0;i<4;i++)
						Led_Time_Data[i] = Led_Time_Set[i];//保存当前设置数据
					Seg_Disp_Mode = 0;
				}
			}
		break;
		case 5://参数+
			if(Seg_Disp_Mode == 1)//处于参数设置界面
			{
				if(Set_Flag == 0)//编号设置
				{
					if(++Led_Time_Set_Index == 4)
						Led_Time_Set_Index = 0;
				}
				else
				{
					Led_Time_Set[Led_Time_Set_Index] = Led_Time_Set[Led_Time_Set_Index]+100;
					if(Led_Time_Set[Led_Time_Set_Index] >= 1300)
						Led_Time_Set[Led_Time_Set_Index] = 400;
				}
			}
		break;
		case 4://参数-
			if(Seg_Disp_Mode == 1)//处于参数设置界面
			{
				if(Set_Flag == 0)//编号设置
				{
					if(--Led_Time_Set_Index == 255)
						Led_Time_Set_Index = 3;
				}
				else
				{
					Led_Time_Set[Led_Time_Set_Index] = Led_Time_Set[Led_Time_Set_Index]-100;
					if(Led_Time_Set[Led_Time_Set_Index] <= 300)
						Led_Time_Set[Led_Time_Set_Index] = 1200;
				}
			}
		break;		
	}
}

4.Timer0

a.设置1ms的时间间隔

if(System_Flag == 1)//当系统启动时 计时器一毫秒自加一次	
		Sys_Tick++;

b.设置0.8秒为间隔闪烁时间和取反变量

unsigned int Timer_400Ms;//400毫秒变量
if(++Timer_400Ms == 400)//400毫秒触发一次
{
	Timer_400Ms = 0;
	Seg_Star_Flag ^= 1;
}

总代码

/* 定时器0中断服务函数 */
void Timer0Server() interrupt 1
{
 	TL0 = 0x18;		//设置定时初始值
	TH0 = 0xFC;		//设置定时初始值   
	if(++Key_Slow_Down == 10) Key_Slow_Down = 0;//键盘减速专用
	if(++Seg_Slow_Down == 500) Seg_Slow_Down = 0;//数码管减速专用
	if(++Seg_Pos == 6) Seg_Pos = 0;//数码管显示专用
	Seg_Disp(Seg_Pos,Seg_Buf[Seg_Pos],Seg_Point[Seg_Pos]);
	if(System_Flag == 1)//当系统启动时 计时器一毫秒自加一次	
		Sys_Tick++;
	if(++Timer_400Ms == 400)//400毫秒触发一次
	{
		Timer_400Ms = 0;
		Seg_Star_Flag ^= 1;
	}
}

5.范例程序

/* 头文件声明区 */
#include <REGX52.H>//单片机寄存器专用头文件
#include <Key.h>//按键底层驱动专用头文件
#include <Seg.h>//数码管底层驱动专用头文件
#include <intrins.h>

/* 变量声明区 */
unsigned char Key_Val,Key_Down,Key_Old;//按键专用变量
unsigned char Key_Slow_Down;//按键减速专用变量
unsigned char Seg_Buf[6] = {10,10,10,10,10,10};//数码管显示数据存放数组
unsigned char Seg_Point[6] = {0,0,0,0,0,0};//数码管小数点数据存放数组
unsigned char Seg_Pos;//数码管扫描专用变量
unsigned int Seg_Slow_Down;//数码管减速专用变量
unsigned char Seg_Disp_Mode;//数码管显示模式变量 0-运行状态界面 1-流转时间设置界面 2-数据显示界面
bit System_Flag;//系统使能标志位 0-暂停 1-启动 上电默认处于暂停状态
unsigned char Led_Mode;//Led模式标志位
unsigned int Led_Time_Data[4] = {400,400,400,400};//Led流转时间数据存放数组
unsigned int Sys_Tick;//系统计时器专用变量
unsigned char ucLed = 0xfe;//Led数据存放数组
unsigned char ucLed_Data[4] = {0x7e,0xbd,0xdb,0xe7};//模式3、4数据存放数组
unsigned char ucLed_Data_Index;//模式3、4数组指针
bit Set_Flag;//设置标志位 0-模式编号 1-流转间隔
unsigned int Led_Time_Set[4];//Led流转数据设置数组
unsigned char Led_Time_Set_Index;//Led流转数据设置数组指针
bit Seg_Star_Flag;//数码管闪烁标志位
unsigned int Timer_400Ms;//400毫秒变量
bit Data_Disp_Flag;//数据显示标志位 0-不显示 1-显示
unsigned char Led_Data;//Led数据储存变量

/* 键盘处理函数 */
void Key_Proc()
{
	unsigned char i;//For循环专用变量
	if(Key_Slow_Down) return;
	Key_Slow_Down = 1;//键盘减速程序

	Key_Val = Key_Read();//实时读取键码值
	Key_Down = Key_Val & (Key_Old ^ Key_Val);//捕捉按键下降沿
	Key_Old = Key_Val;//辅助扫描变量
	
	if(System_Flag == 0)//系统处于暂停状态
	{
		if(Key_Old == 4 && Seg_Disp_Mode == 0)//在显示界面下长按S4
			Data_Disp_Flag = 1;//显示数据
		else
			Data_Disp_Flag = 0;//显示状态
	}
	else
		Data_Disp_Flag = 0;
	
	switch(Key_Down)
	{
		case 7://启动暂停按键
			System_Flag ^= 1;
		break;
		case 6://设置切换按键
			if(Seg_Disp_Mode == 0)//若在显示界面下使能此按键
			{
				for(i=0;i<4;i++)//读取当前设置数据
					Led_Time_Set[i] = Led_Time_Data[i];
				Seg_Disp_Mode = 1;//跳转到参数设置界面
			}
			else if(Seg_Disp_Mode == 1)//else-为了避免第一次按下后直接执行下列程序 所以需要另外加else使得在执行完if语句后跳出判断主体
			{
				Set_Flag ^= 1;//用于判断设置处于哪个状态的变量                        
				if(Set_Flag == 0)//第二次跳转到模式设置状态
				{
					for(i=0;i<4;i++)
						Led_Time_Data[i] = Led_Time_Set[i];//保存当前设置数据
					Seg_Disp_Mode = 0;
				}
			}
		break;
		case 5://参数+
			if(Seg_Disp_Mode == 1)//处于参数设置界面
			{
				if(Set_Flag == 0)//编号设置
				{
					if(++Led_Time_Set_Index == 4)
						Led_Time_Set_Index = 0;
				}
				else
				{
					Led_Time_Set[Led_Time_Set_Index] = Led_Time_Set[Led_Time_Set_Index]+100;
					if(Led_Time_Set[Led_Time_Set_Index] >= 1300)
						Led_Time_Set[Led_Time_Set_Index] = 400;
				}
			}
		break;
		case 4://参数-
			if(Seg_Disp_Mode == 1)//处于参数设置界面
			{
				if(Set_Flag == 0)//编号设置
				{
					if(--Led_Time_Set_Index == 255)
						Led_Time_Set_Index = 3;
				}
				else
				{
					Led_Time_Set[Led_Time_Set_Index] = Led_Time_Set[Led_Time_Set_Index]-100;
					if(Led_Time_Set[Led_Time_Set_Index] <= 300)
						Led_Time_Set[Led_Time_Set_Index] = 1200;
				}
			}
		break;		
	}
}

/* 信息处理函数 */
void Seg_Proc()
{
	unsigned char i = 2;//用于熄灭高位未启用数码管
	if(Seg_Slow_Down) return;
	Seg_Slow_Down = 1;//数码管减速程序

	switch(Seg_Disp_Mode)
	{
		case 0://运行状态显示界面
			if(Data_Disp_Flag == 0)
			{
				Seg_Buf[0] = System_Flag?11:12;//11-S 12-R
				Seg_Buf[1] = Led_Mode+1;
				Seg_Buf[2] = Led_Time_Data[Led_Mode] / 1000 % 10;
				Seg_Buf[3] = Led_Time_Data[Led_Mode] / 100 % 10;
				Seg_Buf[4] = Led_Time_Data[Led_Mode] / 10 % 10;
				Seg_Buf[5] = Led_Time_Data[Led_Mode] % 10;
				while(Seg_Buf[i] == 0)//使用循环体结构令高位为0的数码管熄灭 直到不为0时退出
				{
					Seg_Buf[i] = 10;
					i++;
				}
			}
			else
			{
				Seg_Buf[0] = 0;
				Seg_Buf[1] = 12;
				Seg_Buf[2] = 13;
				Seg_Buf[3] = Led_Mode+1;
				Seg_Buf[4] = Led_Data / 10;
				Seg_Buf[5] = Led_Data % 10;
			}
		break;
		case 1://流转时间设置界面
			Seg_Buf[0] = 13;
			Seg_Buf[1] = Led_Time_Set_Index+1;
			Seg_Buf[2] = Led_Time_Set[Led_Time_Set_Index] / 1000 % 10;
			Seg_Buf[3] = Led_Time_Set[Led_Time_Set_Index] / 100 % 10;
			Seg_Buf[4] = Led_Time_Set[Led_Time_Set_Index] / 10 % 10;
			Seg_Buf[5] = Led_Time_Set[Led_Time_Set_Index] % 10;
			if(Set_Flag == 0)
			{
				Seg_Buf[0] = Seg_Star_Flag?13:10;
				Seg_Buf[1] = Seg_Star_Flag?Led_Time_Set_Index+1:10;
			}
			else
			{
				Seg_Buf[2] = Seg_Star_Flag?Led_Time_Set[Led_Time_Set_Index] / 1000 % 10:10;
				Seg_Buf[3] = Seg_Star_Flag?Led_Time_Set[Led_Time_Set_Index] / 100 % 10:10;
				Seg_Buf[4] = Seg_Star_Flag?Led_Time_Set[Led_Time_Set_Index] / 10 % 10:10;
				Seg_Buf[5] = Seg_Star_Flag?Led_Time_Set[Led_Time_Set_Index] % 10:10;				
			}
			
			while(Seg_Buf[i] == 0)//使用循环体结构令高位为0的数码管熄灭 直到不为0时退出
			{
				Seg_Buf[i] = 10;
				i++;
			}		
		break;
	}
	Seg_Point[0] = Seg_Point[1] = Data_Disp_Flag&(!Data_Disp_Flag)?0:1;//小数点
}

/* 其他显示函数 */
void Led_Proc()
{
	unsigned char i;//用于循环判断
	P1 = ucLed;
	if(Sys_Tick == Led_Time_Data[Led_Mode])//当计时器走到当前模式设定的流转时间间隔时
	{
		Sys_Tick = 0;//计时器复位 便于下次循环
		switch(Led_Mode)//根据Led_Mode的不同 选择不同的彩灯运行模式
		{
			case 0:
				if(ucLed == 0x7e)//判断是否从模式4切换至模式1 若是,则复位ucLed数据
					ucLed = 0xfe;
				else
				{
					ucLed = _crol_(ucLed,1);//模式1 L1-L8
					if(ucLed == 0x7f) Led_Mode = 1;//当L8点亮时 跳转到模式2
				}
			break;
			case 1:
				ucLed = _cror_(ucLed,1);//模式2 L8-L1
				if(ucLed == 0xfe) Led_Mode = 2;//当L1点亮时 跳转到模式3
			break;
			case 2:
				ucLed = ucLed_Data[ucLed_Data_Index];//模式3 从外往内
				if(++ucLed_Data_Index == 4)//当指针溢出 即完成一次循环时 跳转到模式4
				{
					Led_Mode = 3;
					ucLed_Data_Index = 3;//指针复位至模式四初始数据
				}
			break;
			case 3:
				ucLed = ucLed_Data[ucLed_Data_Index];//模式4 从内往外
				if(--ucLed_Data_Index == 255)//当指针溢出 即完成一次循环时 跳转到模式1
				{	
					Led_Mode = 0;
					ucLed_Data_Index = 0;	//指针复位至模式三初始数据
				}
			break;
		}
	}
	/* 数据读取设计思路 */
	i = 0;//每次循环判断前将i置0,便于读取Led状态
	while((~ucLed & (0x01 << i)) != (0x01 << i))
		i++;
	if(Led_Mode < 2)//若处于前两种模式,则数据直接等于i+1
		Led_Data = i+1;
	else
		Led_Data = (i+1)*10+(8-(i+1));//若处于后两种模式,则高位数据等于i+1,根据对称变换,低位加高位的数值之和等于8
}

/* 定时器0中断初始化函数 */
void Timer0Init(void)		//1毫秒@12.000MHz
{
	TMOD &= 0xF0;		//设置定时器模式
	TMOD |= 0x01;		//设置定时器模式
	TL0 = 0x18;		//设置定时初始值
	TH0 = 0xFC;		//设置定时初始值
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
	ET0 = 1;    //定时器0中断打开
	EA = 1;     //总中断打开
}

/* 定时器0中断服务函数 */
void Timer0Server() interrupt 1
{
 	TL0 = 0x18;		//设置定时初始值
	TH0 = 0xFC;		//设置定时初始值   
	if(++Key_Slow_Down == 10) Key_Slow_Down = 0;//键盘减速专用
	if(++Seg_Slow_Down == 500) Seg_Slow_Down = 0;//数码管减速专用
	if(++Seg_Pos == 6) Seg_Pos = 0;//数码管显示专用
	Seg_Disp(Seg_Pos,Seg_Buf[Seg_Pos],Seg_Point[Seg_Pos]);
	if(System_Flag == 1)//当系统启动时 计时器一毫秒自加一次	
		Sys_Tick++;
	if(++Timer_400Ms == 400)//400毫秒触发一次
	{
		Timer_400Ms = 0;
		Seg_Star_Flag ^= 1;
	}
}

/* Main */
void main()
{
	Timer0Init();
	while (1)
	{
		Key_Proc();
		Seg_Proc();
		Led_Proc();
	}
}