第四周学习笔记

决赛试题与过渡模拟一

决赛试题

设计思路

  1. 不要对寄存器直接进行操作,使用中间变量过度

    unsigned char ucLed;
    
  2. 面对多个模式,时间不同时,设置系统计时变量,还可以用模式的变化改变运行时间

    if(Sys_Tick == Led_Time_Mode[Led_Mode])//当计时器走到当前模式设定的流转时间变量
        Sys_Tick = 0;//系统计时变量重置,方便下一次循环 
    
  3. 避免模式4到模式1时,忽略L1

    if(ucLed == 0x7e)//判断是否从模式4切换到模式1,若是,则复位ucLed数据
        ucLed = 0xfe;
    else
    {
        ucLed = _crol_(ucLed,1);//模式1 L1-L8
        if(ucLed == 0x7f)Led_Mode = 1;//当L8点亮时跳转到抹使2
    }
    
  4. 高位熄灭,判断最高位是否为0

    if(Seg_Buf[2] == 0)Seg_Buf[2] = 10;
    
  5. 避免按下切换按键后默认多执行一次,if和else if只会执行一个

    if(Seg_Mode == 0)
    {
    	for(i=0;i<4;i++)
    	Lea_Time_Set[i] = Led_Time_Mode[i];//读取当前设置数据
    	Seg_Mode = 1;
    }
    else if(Seg_Mode == 1)//else-为了避免第一次按下后直接执行下列程序 所以需要另外加else使得在执行完if语句后跳出判断主体
    {
    	Set_Flag ^= 1;
    	if(Set_Flag == 0)//第二次跳转到模式设置状态
    	{
    		for(i=0;i<4;i++)
    			Led_Time_Mode[i] = Lea_Time_Set[i];//保存当前的数据
    		Seg_Mode = 0;				
    	}
    }
    
  6. Led数据读取

    i = 0;//每次循环判断前将i置0,便于读取Led状态
    while((~ucLed & (0x01 << i)) != (0x01 << i))
    	i++;
    if(Led_Mode < 2)
    	Led_Data = i+ 1;
    else
    	Led_Data = (i+1)*10 + (9-(i+1));
    
  7. 在流转时间设置界面时候区分Led_Mode和Led_Time_Set_Index,不可以混用

    unsigned char Led_Time_Set_Index;
    

    总程序

    /*头文件声明区域*/
    #include <REGX52.H>
    #include "key.h"
    #include "Seg.h"
    #include <intrins.h>
    
    /*变量声明区域*/
    unsigned char Key_Slow_Down;//按键减速专业变量
    unsigned int Seg_Slow_Down;//数码管减速专业变量
    unsigned char Key_Val,Key_Up,Key_Down,Key_Old;//按键扫描专业变量
    unsigned char Seg_Pos;//数码管扫描变量
    unsigned char Seg_Buf[6] = {10,10,10,10,10,10};//数码管显示数据存放数组
    unsigned char Seg_Point[6] = {0,0,0,0,0,0};//小数点点亮存放数组
    unsigned char ucLed = 0xfe;//Led数组存放数组
    unsigned char ucLed_Data[4] = {0x7e,0xbd,0xdb,0xe7};//模式3、4数据存放数组
    unsigned char ucLed_Data_Index;//Led数据存放数组索引值
    unsigned int Sys_Tick;//系统计时变量
    unsigned char Led_Mode;//Led模式
    unsigned int Led_Time_Mode[4] = {400,400,400,400};//Led流转时间存放数组
    unsigned int Lea_Time_Set[4];//Led流转时间设置数组
    unsigned char Led_Time_Set_Index;//Led流转时间设置数组索引值
    unsigned char Seg_Mode;//数码管显示模式0-运行状态界面 1-流转时间设置界面
    unsigned int Timer_400ms;//400ms计时
    unsigned char Led_Data;//Led灯数据
    bit System_Flag;//系统标志位0-停止 1-启动
    bit Set_Flag;//设置界面标志位0-运行模式编号 1-流转时间间隔
    bit Seg_Flag;//数码管闪烁标志位
    bit Data_Disp_Flag;//数据显示界面标志位
    /*按键处理函数*/
    void Key_Proc()
    {
    	unsigned char i;//循环变量
    	if(Key_Slow_Down)return;
    	Key_Slow_Down = 1;//按键减速程序
    	
    	Key_Val = Key_Read();//读取键码值
    	Key_Down = Key_Val & (Key_Val ^ Key_Old);//检测下降沿
    	Key_Up = ~Key_Val & (Key_Val ^ Key_Old);//检测上升沿
    	Key_Old = Key_Val;//扫描辅助沿
    	
    	if(System_Flag == 0)//系统处于暂停状态
    	{
    		if(Key_Old == 4 && Seg_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_Mode == 0)
    			{
    				for(i=0;i<4;i++)
    					Lea_Time_Set[i] = Led_Time_Mode[i];//读取当前设置数据
    				Seg_Mode = 1;
    			}
    			else if(Seg_Mode == 1)//else-为了避免第一次按下后直接执行下列程序 所以需要另外加else使得在执行完if语句后跳出判断主体
    			{
    				Set_Flag ^= 1;
    				if(Set_Flag == 0)//第二次跳转到模式设置状态
    				{
    					for(i=0;i<4;i++)
    						Led_Time_Mode[i] = Lea_Time_Set[i];//保存当前的数据
    					Seg_Mode = 0;				
    				}
    			}
    		break;
    		case 5:
    			if(Seg_Mode == 1)
    			{
    				if(Set_Flag == 0)
    				{
    					if(++Led_Time_Set_Index == 4)Led_Time_Set_Index = 0;
    				}
    				else
    				{
    					Lea_Time_Set[Led_Time_Set_Index] = Lea_Time_Set[Led_Time_Set_Index] + 100;
    					if(Lea_Time_Set[Led_Time_Set_Index] >= 1300)
    						Lea_Time_Set[Led_Time_Set_Index] = 400;
    				}
    			}
    		break;
    		case 4:
    			if(Seg_Mode == 1)
    			{
    				if(Set_Flag == 0)
    				{
    					if(--Led_Time_Set_Index == 255)Led_Time_Set_Index = 3;
    				}
    				else
    				{
    					Lea_Time_Set[Led_Time_Set_Index] = Lea_Time_Set[Led_Time_Set_Index] - 100;
    					if(Lea_Time_Set[Led_Time_Set_Index] <= 400)
    						Lea_Time_Set[Led_Time_Set_Index] = 1300;
    				}
    			}
    		break;
    	}
    }
    
    /*信息处理函数*/
    void Seg_Proc()
    {
    	if(Seg_Slow_Down)return;
    	Seg_Slow_Down = 1;//按键减速程序
    	
    	switch(Seg_Mode)
    	{
    		case 0://运行状态界面
    			if(Data_Disp_Flag == 0)
    			{
    				Seg_Point[0] = 0;
    				Seg_Point[1] = 0;
    				Seg_Buf[0] = System_Flag?13:12;//12-R 13-S
    				Seg_Buf[1] = Led_Mode + 1;
    				Seg_Buf[2] = Led_Time_Mode[Led_Mode] / 1000 % 10;
    				Seg_Buf[3] = Led_Time_Mode[Led_Mode] / 100 % 10;
    				Seg_Buf[4] = Led_Time_Mode[Led_Mode] / 10 % 10;
    				Seg_Buf[5] = Led_Time_Mode[Led_Mode] % 10;
    				if(Seg_Buf[2] == 0)Seg_Buf[2] = 10; 	
    			}
    			else
    			{
    				Seg_Point[0] = 1;
    				Seg_Point[1] = 1;
    				Seg_Buf[0] = 0;//D
    				Seg_Buf[1] = 12;//R
    				Seg_Buf[2] = 11;//-
    				Seg_Buf[3] = Led_Mode + 1;
    				Seg_Buf[4] = Led_Data / 10 % 10;
    				Seg_Buf[5] = Led_Data % 10;
    			}
    		break;
    		case 1://流转时间设置界面
    			Seg_Point[0] = 0;
    			Seg_Point[1] = 0;
    			Seg_Buf[0] = 11;//-
    			Seg_Buf[1] = Led_Time_Set_Index + 1;
    			Seg_Buf[2] = Lea_Time_Set[Led_Time_Set_Index] / 1000 % 10;
    			Seg_Buf[3] = Lea_Time_Set[Led_Time_Set_Index] / 100 % 10;
    			Seg_Buf[4] = Lea_Time_Set[Led_Time_Set_Index] / 10 % 10;
    			Seg_Buf[5] = Lea_Time_Set[Led_Time_Set_Index] % 10;
    			if(Set_Flag == 0)
    			{
    				Seg_Buf[0] = Seg_Flag?11:10;
    				Seg_Buf[1] = Seg_Flag?Led_Time_Set_Index + 1:10;	
    			}
    			else
    			{
    				Seg_Buf[2] = Seg_Flag?Lea_Time_Set[Led_Time_Set_Index] / 1000 % 10:10;
    				Seg_Buf[3] = Seg_Flag?Lea_Time_Set[Led_Time_Set_Index] / 100 % 10:10;
    				Seg_Buf[4] = Seg_Flag?Lea_Time_Set[Led_Time_Set_Index] / 10 % 10:10;
    				Seg_Buf[5] = Seg_Flag?Lea_Time_Set[Led_Time_Set_Index] % 10:10;
    			}
    			if(Seg_Buf[2] == 0)Seg_Buf[2] = 10; 	
    		break;
    	}
    }
    
    /*其他显示函数*/
    void Led_Proc()
    {
    	unsigned char i;//循环变量
    	P1 = ucLed;
    	if(Sys_Tick == Led_Time_Mode[Led_Mode])//计时器时间等于设置的流转时间
    	{
    		Sys_Tick = 0;
    		switch(Led_Mode)
    		{
    			case 0://模式1,从L1-L8
    				if(ucLed == 0x7e)//判断是否从模式4到模式1
    					ucLed = 0xfe;
    				else
    				{
    					ucLed = _crol_(ucLed,1);
    					if(ucLed == 0x7f)Led_Mode = 1;
    				}
    			break;
    			case 1:
    				ucLed = _cror_(ucLed,1);
    				if(ucLed == 0xfe)Led_Mode = 2;	
    			break;
    			case 2:
    				ucLed = ucLed_Data[ucLed_Data_Index];
    				if(++ucLed_Data_Index == 4)
    				{
    					ucLed_Data_Index = 3;
    					Led_Mode = 3;
    				}	
    			break;
    			case 3:
    				ucLed = ucLed_Data[ucLed_Data_Index];
    				if(--ucLed_Data_Index == 255)
    				{
    					ucLed_Data_Index = 0;
    					Led_Mode = 0;
    				}
    			break;
    		}
    	}
    	i = 0;//每次循环判断前将i置0,便于读取Led状态
    	while((~ucLed & (0x01 << i)) != (0x01 << i))
    		i++;
    	if(Led_Mode < 2)
    		Led_Data = i+ 1;
    	else
    		Led_Data = (i+1)*10 + (9-(i+1));
    	
    }
    
    /*定时器0初始化函数*/
    void Timer0_Init(void)		//1毫秒@12.000MHz
    {
    	TMOD &= 0xF0;			//设置定时器模式
    	TMOD |= 0x01;			//设置定时器模式
    	TL0 = 0x18;				//设置定时初始值
    	TH0 = 0xFC;				//设置定时初始值
    	TF0 = 0;				//清除TF0标志
    	TR0 = 1;				//定时器0开始计时
    	ET0 = 1;
    	EA = 1;
    }
    
    /*定时器0中断服务函数*/
    void Timer0Sever() 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)
    	{
    		Timer_400ms = 0;
    		Seg_Flag ^= 1;
    	}
    			
    }
    
    /*Main*/
    void main()
    {
    	Timer0_Init();
    	while(1)
    	{
    		Key_Proc();
    		Seg_Proc();
    		Led_Proc();
    	
    	}
    
    }
    

过渡模拟一

  1. 输入限制

    if(Key_Down >= 1 && Key_Down <= 10)
    {
    	if(Seg_Mode == 0 && Voltage_Input_Index < 4)
    	{
    		Voltage_Input[Voltage_Input_Index] = Key_Down - 1;
    		Voltage_Input_Index++;
    		Key_Error_Count = 0;
    	}
    	else
    		Key_Error_Count++;
    }
    
  2. 闪烁避免程序卡死

    if (Seg_Buf[5] == 11)//只有当最后一位为-时 才实现数码管闪烁功能
    	Seg_Buf[2 + Voltage_Input_Index] = Seg_Flag?Voltage_Input[Voltage_Input_Index] : 10;
    
  3. 四舍五入

    Voltage = (Voltage_Input[0]*1000 + Voltage_Input[1]*100 + Voltage_Input[2]*10 + Voltage_Input[3] + 5) / 1000.0;
    
  4. float数码管显示

    Seg_Buf[3] = ((int)Voltage / 10) ? 1:(unsigned int)Voltage % 10;
    Seg_Buf[4] = (unsigned int)(Voltage*10) % 10;
    Seg_Buf[5] = (unsigned int)(Voltage*100) % 10;
    
  5. 9999mv进位之后10.0v小数点显示

    Seg_Point[3+(int)Voltage_Set / 10] = 1;//小数点
    
  6. 数码管数据刷新

  7. 高位熄灭

    while(Seg_Buf[j] == 0)
    {
    	Seg_Buf[j] = 10;
    	if(++j == 5)break;
    }
    
  8. 计数值增加

    if(Voltage > Volagee_Set_Ctrol)//实际电压大于电压设置参数
    	Voltage_Flag = 1;
    else if(Voltage_Flag == 1)
    {
    	Voltage_Flag = 0;
    	Count++;
    }
    
  9. 高阶Led

    #include "Led.h"
    
    void Led_Disp(unsigned char addr,enable)
    {
    	static unsigned char temp = 0x00;
    	static unsigned char temp_old = 0xff;
    	if(enable)
    		temp |= 0x01 << addr;
    	else
    		temp &= ~(0x01 << addr);
    	if(temp != temp_old)
    	{
    		P1 = ~temp;
    		temp_old = temp;
    	}
    }
    
    

总程序

/*头文件声明区域*/
#include <REGX52.H>
#include "key.h"
#include "Seg.h"
#include "Led.h"

/*变量声明区域*/
unsigned char Key_Slow_Down;//按键减速专业变量
unsigned int Seg_Slow_Down;//数码管减速专业变量
unsigned char Key_Val,Key_Up,Key_Down,Key_Old;//按键扫描专业变量
unsigned char Seg_Pos;//数码管扫描变量
unsigned char Seg_Buf[6] = {10,10,10,10,10,10};//数码管显示数据存放数组
unsigned char Seg_Point[6] = {0,0,0,0,0,0};//小数点点亮存放数组
unsigned char ucLed[8] = {0,0,0,0,0,0,0,0};//Led数据存放数组
unsigned char Led_Pos;//Led扫描变量
unsigned char Seg_Mode;//0-电压采集界面 1-数据显示界面 2-参数设置界面 3-计数统计系统
unsigned char Voltage_Input[4] = {11,11,11,11};//输入电压数组
unsigned char Voltage_Input_Index;//输入电压数组索引值
unsigned char Timer_500ms;//0.5s
unsigned char Key_Error_Count;//无效按键统计变量
unsigned char Count;//计数统计变量
unsigned char System_Tick;//系统计时变量
float Voltage_Set = 3.0;//电压设置参数
float Volagee_Set_Ctrol = 3.0;//设置电压控制参数
float Voltage;//实际电压值
bit Seg_Flag;//数码管闪烁标志位
bit Voltage_Flag;//计数标志位

/*按键处理函数*/
void Key_Proc()
{
	unsigned char i;//循环变量
	if(Key_Slow_Down)return;
	Key_Slow_Down = 1;//按键减速程序
	
	Key_Val = Key_Read();//读取键码值
	Key_Down = Key_Val & (Key_Val ^ Key_Old);//检测下降沿
	Key_Up = ~Key_Val & (Key_Val ^ Key_Old);//检测上升沿
	Key_Old = Key_Val;//扫描辅助沿
	
	if(Key_Down >= 1 && Key_Down <= 10)
	{
		if(Seg_Mode == 0 && Voltage_Input_Index < 4)
		{
			Voltage_Input[Voltage_Input_Index] = Key_Down - 1;
			Voltage_Input_Index++;
			Key_Error_Count = 0;
		}
		else
			Key_Error_Count++;
	}
	switch(Key_Down)
	{
		case 11:
			Key_Error_Count = 0;
			if(Seg_Mode == 0)
			{
				if(Voltage_Input_Index >= 4)//判断数据有效性
				{
					Voltage = (Voltage_Input[0]*1000 + Voltage_Input[1]*100 + Voltage_Input[2]*10 + Voltage_Input[3] + 5) / 1000.0;
					if(Voltage >= 0.01)
						Seg_Mode = 1;//跳转到电压显示界面
					else
					{
						Voltage_Input_Index = 0;//重新输入
						for(i=0;i<4;i++)
							Voltage_Input[i] = 11;
					}
				}
				else
				{
					Voltage_Input_Index = 0;//重新输入
					for(i=0;i<4;i++)
						Voltage_Input[i] = 11;			
				}
			}
			else//处于非电压采集界面
			{
				Seg_Mode = 0;//跳转到电压采集界面
				Voltage_Input_Index = 0;//重新输入
				for(i = 0;i < 4;i++)
					Voltage_Input[i] = 11;
			}
		break;
		case 12:
			if(Seg_Mode != 0)
			{
				Key_Error_Count = 0;
				if(Seg_Mode == 2)
					Voltage_Set = Volagee_Set_Ctrol;//保存当前设置参数
				if(++Seg_Mode == 4)
					Seg_Mode = 1;	
			}
			else
				Key_Error_Count++;
		break;
		case 14:
			if(Seg_Mode == 0)
			{
				Key_Error_Count = 0;
				Voltage_Input_Index = 0;//重新输入
				for(i=0;i<4;i++)
					Voltage_Input[i] = 11;
			}
			else if(Seg_Mode == 3)
			{
				Key_Error_Count = 0;
				Count = 0;
			}
			else
				Key_Error_Count++;
		break;
		case 15:
			if(Seg_Mode == 2)
			{
				Key_Error_Count = 0;
				Volagee_Set_Ctrol = Volagee_Set_Ctrol + 0.5;
				if(Volagee_Set_Ctrol == 6.0)
					Volagee_Set_Ctrol = 1.0;
			}
			else
				Key_Error_Count++;
		break;
		case 16:
			if(Seg_Mode == 2)
			{
				Key_Error_Count = 0;
				Volagee_Set_Ctrol = Volagee_Set_Ctrol - 0.5;
				if(Volagee_Set_Ctrol == 1)
					Volagee_Set_Ctrol = 6;
			}
			else
				Key_Error_Count++;
		break;
	}
}

/*信息处理函数*/
void Seg_Proc()
{
	unsigned char i,j = 1;///循环变量
	if(Seg_Slow_Down)return;
	Seg_Slow_Down = 1;//数码管减速程序
	
	if(Voltage > Volagee_Set_Ctrol)//实际电压大于电压设置参数
		Voltage_Flag = 1;
	else if(Voltage_Flag == 1)
	{
		Voltage_Flag = 0;
		Count++;
	}
	
	switch(Seg_Mode)
	{
		case 0:
			Seg_Point[3+(int)Voltage / 10] = 0;
			Seg_Buf[0] = Seg_Buf[1] = 10;
			for(i=0;i<4;i++)
				Seg_Buf[2+i] = Voltage_Input[i];
			if (Seg_Buf[5] == 11)//只有当最后一位为-时 才实现数码管闪烁功能
				Seg_Buf[2 + Voltage_Input_Index] = Seg_Flag ? Voltage_Input[Voltage_Input_Index] : 10;
		break;
		case 1:
			Seg_Point[3+(int)Voltage / 10] = 1;//小数点
			Seg_Buf[0] = 12;//U
			Seg_Buf[1] = Seg_Buf[2] = 10;
			Seg_Buf[3] = ((int)Voltage / 10) ? 1:(unsigned int)Voltage % 10;
			Seg_Buf[4] = (unsigned int)(Voltage*10) % 10;
			Seg_Buf[5] = (unsigned int)(Voltage*100) % 10;
		break;
		case 2:
			Seg_Point[3+(int)Voltage_Set / 10] = 1;//小数点
			Seg_Buf[0] = 13;//P
			Seg_Buf[1] = Seg_Buf[2] = 10;
			Seg_Buf[3] = (unsigned int)Voltage_Set % 10;
			Seg_Buf[4] = (unsigned int)(Voltage_Set*10) % 10;
			Seg_Buf[5] = (unsigned int)(Voltage_Set*100) % 10;
		break;
		case 3:
			Seg_Point[3+(int)Voltage / 10] = 0;
			Seg_Buf[0] = 14;//N
			Seg_Buf[1] = Count / 10000 % 10;
			Seg_Buf[2] = Count / 1000 % 10;
			Seg_Buf[3] = Count / 100 % 10;
			Seg_Buf[4] = Count / 10 % 10;
			Seg_Buf[5] = Count % 10;
			while(Seg_Buf[j] == 0)
			{
				Seg_Buf[j] = 10;
				if(++j == 5)break;
			}
		break;
			
	}
}

/*其他显示函数*/
void Led_Proc()
{
	if(Voltage < Volagee_Set_Ctrol)
	{
		if(System_Tick >= 5000)
			ucLed[0] = 1;
	}
	else
	{
		ucLed[0] = System_Tick = 0;
	}
	ucLed[1] = Count % 2;
	ucLed[2] = Key_Error_Count / 3;
}

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

/*定时器0中断服务函数*/
void Timer0Sever() 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(++Led_Pos == 8)Led_Pos = 0;
	Led_Disp(Led_Pos,ucLed[Led_Pos]);
	if(++Timer_500ms == 500)
	{
		Timer_500ms = 0;
		Seg_Flag ^= 1;
	}
	if(Voltage < Volagee_Set_Ctrol)
		System_Tick++;
}

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

}