第三周第零讲笔记心得

蓝桥杯单片机第三周笔记

模块化编程

User-用户层(main)

Driver-底层(固定)

底层函数

新建,保存到Driver文件夹,建立工程模板图 - 编写底层函数Key、Seg

.c

引用底层头文件

编写底层函数

.h

引用51单片机头文件

声明底层函数

添加已有文件到Driver

Main函数区

  1. 头文件

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

    /*变量声明区域*/
    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]={1,2,3,4,5,6};//数码管显示数据存放数组
    
  3. Key_Proc()

    /*按键处理函数*/
    void Key_Proc()
    {
    	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;//扫描辅助沿
    	
    	switch(Key_Down)
    	{
    	
    	}
    }
    
  4. Seg_Proc()

    /*信息处理函数*/
    void Seg_Proc()
    {
    	if(Seg_Slow_Down)return;
    	Seg_Slow_Down = 1;//按键减速程序
    	
    }
    
  5. Led_Proc()

    /*其他显示函数*/
    void Led_Proc()
    {
    	
    }
    
  6. Timer0Init

    /*定时器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;
    }
    
  7. Timer0Sever

    /*定时器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]);
    	
    }
    
  8. main

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

基于定时器的倒计时程序设计

程序设计

先从数码管显示界面下手,设置显示模式变量,再配合按键

写一步烧录一步,方便查错

  1. 面对数码管显示里的多个数据切换时,定义一个数组和对应的索引值

    unsigned char Set_Dat[3] = {15,30,60};//设置参数数组
    unsigned char Set_Dat_Index = 1;//设置参数数组索引值
    
  2. 定时器中以秒为单位的倒计时“unsigned char”类型的数据范围0~255,减到0是下一个是255

    if(++Timer_1000ms == 1000)
    {
    	Timer_1000ms = 0;
    	Timer_Count--;//Timer_Count = 60
    	if(Timer_Count == 255)
    	Timer_Count = 0;
    }
    
  3. 数码管闪烁标志位

    if(++Timer_500ms == 500)
    {
    	Timer_500ms = 0;
    	Seg_Flag ^= 1;
    }
    

总程序

/*头文件声明区域*/
#include <REGX52.H>
#include "key.h"
#include "Seg.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_Mode;//数码管显示模式0-显示界面 1-设置界面
unsigned int Timer_1000ms;//1s计时变量
unsigned int Timer_500ms;//0.5s计时变量
unsigned char Timer_Count = 30;//计时变量
unsigned char Set_Dat[3] = {15,30,60};//设置参数数组
unsigned char Set_Dat_Index = 1;//设置参数数组索引值
bit System_Flag;//系统标志位0-复位 1-开始倒计时
bit Seg_Flag;//数码管标志位

/*按键处理函数*/
void Key_Proc()
{
	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;//扫描辅助沿
	
	switch(Key_Down)
	{
		case 1://按下1系统开始倒计时
			if(Seg_Mode == 0)
				System_Flag = 1;
		break;
		case 2://按下2系统复位
			if(Seg_Mode == 0)
				Timer_Count = Set_Dat[Set_Dat_Index];	
		break;
		case 3://显示界面和设置界面的切换
			if(Seg_Mode == 1)
				Timer_Count = Set_Dat[Set_Dat_Index];
			Seg_Mode ^= 1;
		break;
		case 4://设置参数切换
			if(Seg_Mode == 1)
			{
				if(++Set_Dat_Index == 3)
					Set_Dat_Index = 0;
			}
		break;
	}
}

/*信息处理函数*/
void Seg_Proc()
{
	if(Seg_Slow_Down)return;
	Seg_Slow_Down = 1;//按键减速程序
	
	Seg_Buf[0] = Seg_Mode + 1;//模式标识
	
	if(Seg_Mode == 0)//倒计时显示界面
	{
		Seg_Buf[4] = Timer_Count / 10 % 10;
		Seg_Buf[5] = Timer_Count % 10;
	}
	else //倒计时设置界面
	{
		if(Seg_Flag == 0)
		{
			Seg_Buf[4] = Set_Dat[Set_Dat_Index] / 10 % 10;
			Seg_Buf[5] = Set_Dat[Set_Dat_Index] % 10;	
		}
		else
		{
			Seg_Buf[4] = 10;
			Seg_Buf[5] = 10;
		}

	}
}

/*其他显示函数*/
void Led_Proc()
{
	if(Timer_Count == 0)
	{
		P2_3 = 0;
		P1 = 0x00;
	}
	else
	{
		P2_3 = 0;
		P1 = 0xff;
	}
}

/*定时器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]);
	if(System_Flag == 1)
	{
		if(++Timer_1000ms == 1000)
		{
			Timer_1000ms = 0;
			Timer_Count--;
			if(Timer_Count == 255)
				Timer_Count = 0;
		}	
	}
	if(++Timer_500ms == 500)
	{
		Timer_500ms = 0;
		Seg_Flag ^= 1;
	}
}

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

}

基于定时器的时钟程序设计

程序设计

  1. 数码管多个数据同时显示时,用数组,方便数组索引值的嵌套

    unsigned char Clock_Disp[3] = {23,59,55}//0-小时 1-分 2-秒
    
  2. 数码管小数点点亮,小数点0x80,数字+小数点(=数字|0x80)

    if(Point == 1)
    	P0 = Seg_Dula[Dula] | 0x80;
    else
    	P0 = Seg_Dula[Dula];
    
  3. 时钟设置和显示数组要分开,两个界面互不干扰

    unsigned char Clock_Set[3]
    

    时钟显示模式切换到设置模式时,设置数组等于显示数组

    //设置时
    Clock_Set[0] = Clock_Disp[0];
    Clock_Set[1] = Clock_Disp[1];
    Clock_Set[2] = Clock_Disp[2];
    //保存时
    Clock_Disp[0] = Clock_Set[0];
    Clock_Disp[1] = Clock_Set[1];
    Clock_Disp[2] = Clock_Set[2];
    
  4. 选中的数码管闪烁

    switch(Clock_Set_Index)
    {
        case 0:
            Seg_Buf[0] = Seg_Flag?Clock_Set[0] / 10 %10 : 10;
            Seg_Buf[1] = Seg_Flag?Clock_Set[0] %10 : 10;
        break;
        case 1:
            Seg_Buf[2] = Seg_Flag?Clock_Set[1] / 10 %10 : 10;
            Seg_Buf[3] = Seg_Flag?Clock_Set[1] %10 : 10;
        break;
        case 2:
            Seg_Buf[4] = Seg_Flag?Clock_Set[2] / 10 %10 : 10;
            Seg_Buf[5] = Seg_Flag?Clock_Set[2] %10 : 10;
        break;
    }
    
  5. 时钟加减的上限值

    if(Clock_Set[Clock_Set_Index] == (Clock_Set_Index?24:60))
    
  6. 闹钟的显示和设置与时钟的显示和设置思路完全一致

  7. 进入设置界面时候,要把索引值复位

    Clock_Set_Index = 0;
    
  8. 闹钟使能标志位,否则只有一瞬间满足闹钟条件

    bit Alarm_Enable_Flag
    

总程序

/*头文件声明区域*/
#include <REGX52.H>
#include "key.h"
#include "Seg.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,1,0,1,0,1};//小数点点亮存放数组
unsigned char Seg_Mode;//数码管显示模式0-时钟显示模式 1-时钟设置界面 2-闹钟设置界面
unsigned char Clock_Dsip[3] = {23,59,55};//时钟显示数组
unsigned int Timer_1000ms;//1s
unsigned int Timer_500ms;//0.5s
unsigned char Clock_Set[3];//时钟设置数组
unsigned char Clock_Set_Index;//时钟设置数组索引值0-时 1-分 2-秒
unsigned char Alarm[3] = {0,0,0};//闹钟显示数组
unsigned char Alarm_Set[3];//闹钟设置数组
unsigned char ucLed;//Led
bit Seg_Flag;//数码管闪烁标志位
bit Alarm_Flag;//闹钟开关标志位
bit Alarm_Enable_Flag;//闹钟使能标志位

/*按键处理函数*/
void Key_Proc()
{
	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 != 0)Alarm_Enable_Flag = 0;
	switch(Key_Down)
	{
		case 1:
			Clock_Set_Index = 0;
			Clock_Set[0] = Clock_Dsip[0];
			Clock_Set[1] = Clock_Dsip[1];
			Clock_Set[2] = Clock_Dsip[2];
			Seg_Mode = 1;
		break;
		case 2:
			Clock_Set_Index = 0;
			Alarm_Set[0] = Alarm[0];
			Alarm_Set[1] = Alarm[1];
			Alarm_Set[2] = Alarm[2];
			Seg_Mode = 2;
		break;
		case 3:
			if(++Clock_Set_Index == 3)
				Clock_Set_Index = 0;
		break;
		case 4:
			Alarm_Flag ^= 1;
		break;
		case 5:
			if(Seg_Mode == 1)
			{
				if(++Alarm_Set[Clock_Set_Index] == (Clock_Set_Index == 0?24:60))
					Alarm_Set[Clock_Set_Index] = 0;
			}
			if(Seg_Mode == 2)
			{
				if(++Alarm_Set[Clock_Set_Index] == (Clock_Set_Index == 0?24:60))
					Alarm_Set[Clock_Set_Index] = 0;
			}
		break;
		case 6:
			if(Seg_Mode == 1)
			{
				if(--Alarm_Set[Clock_Set_Index] == 255)
					Alarm_Set[Clock_Set_Index] = (Clock_Set_Index == 0?23:59);
			}
			if(Seg_Mode == 2)
			{
				if(--Alarm_Set[Clock_Set_Index] == 255)
					Alarm_Set[Clock_Set_Index] = (Clock_Set_Index == 0?23:59);
			}
		break;
		case 7:
			if(Seg_Mode == 1)
			{
				Clock_Dsip[0] = Clock_Set[0];
				Clock_Dsip[1] = Clock_Set[1];
				Clock_Dsip[2] = Clock_Set[2];
			}
			if(Seg_Mode == 2)
			{
				Alarm[0] = Alarm_Set[0];
				Alarm[1] = Alarm_Set[1];
				Alarm[2] = Alarm_Set[2];
			}
			Seg_Mode = 0;
		break;
		case 8:
			Seg_Mode = 0;
		break;
	}
}

/*信息处理函数*/
void Seg_Proc()
{
	if(Seg_Slow_Down)return;
	Seg_Slow_Down = 1;//按键减速程序
	
	switch(Seg_Mode)
	{
		case 0://时钟显示界面
			Seg_Buf[0] = Clock_Dsip[0] / 10 % 10;
			Seg_Buf[1] = Clock_Dsip[0] % 10;
			Seg_Buf[2] = Clock_Dsip[1] / 10 % 10;
			Seg_Buf[3] = Clock_Dsip[1] % 10;
			Seg_Buf[4] = Clock_Dsip[2] / 10 % 10;
			Seg_Buf[5] = Clock_Dsip[2] % 10;
		break;
		case 1://时钟设置界面
			Seg_Buf[0] = Clock_Set[0] / 10 % 10;
			Seg_Buf[1] = Clock_Set[0] % 10;
			Seg_Buf[2] = Clock_Set[1] / 10 % 10;
			Seg_Buf[3] = Clock_Set[1] % 10;
			Seg_Buf[4] = Clock_Set[2] / 10 % 10;
			Seg_Buf[5] = Clock_Set[2] % 10;	
			switch(Clock_Set_Index)
			{
				case 0:
					Seg_Buf[0] = Seg_Flag?Clock_Set[0] / 10 % 10 : 10;
					Seg_Buf[1] = Seg_Flag?Clock_Set[0] % 10 : 10;
				break;
				case 1:
					Seg_Buf[2] = Seg_Flag?Clock_Set[1] / 10 % 10 : 10;
					Seg_Buf[3] = Seg_Flag?Clock_Set[1] % 10 : 10;
				break;
				case 2:
					Seg_Buf[4] = Seg_Flag?Clock_Set[2] / 10 % 10 : 10;
					Seg_Buf[5] = Seg_Flag?Clock_Set[2] % 10 : 10;
				break;
			}
		break;
		case 2://闹钟设置界面
			Seg_Buf[0] = Alarm_Set[0] / 10 % 10;
			Seg_Buf[1] = Alarm_Set[0] % 10;
			Seg_Buf[2] = Alarm_Set[1] / 10 % 10;
			Seg_Buf[3] = Alarm_Set[1] % 10;
			Seg_Buf[4] = Alarm_Set[2] / 10 % 10;
			Seg_Buf[5] = Alarm_Set[2] % 10;	
			switch(Clock_Set_Index)
			{
				case 0:
					Seg_Buf[0] = Seg_Flag?Alarm_Set[0] / 10 % 10 : 10;
					Seg_Buf[1] = Seg_Flag?Alarm_Set[0] % 10 : 10;
				break;
				case 1:
					Seg_Buf[2] = Seg_Flag?Alarm_Set[1] / 10 % 10 : 10;
					Seg_Buf[3] = Seg_Flag?Alarm_Set[1] % 10 : 10;
				break;
				case 2:
					Seg_Buf[4] = Seg_Flag?Alarm_Set[2] / 10 % 10 : 10;
					Seg_Buf[5] = Seg_Flag?Alarm_Set[2] % 10 : 10;
				break;
			}
		break;
	}
}

/*其他显示函数*/
void Led_Proc()
{
	if(Alarm[0] > 12)
		ucLed = 0x0f;
	else
		ucLed = 0xf0;
	if(Alarm_Flag == 1)
	{
		if(Clock_Dsip[0] == Alarm[0] && Clock_Dsip[1] == Alarm[1] && Clock_Dsip[2] == Alarm[2])
			Alarm_Enable_Flag = 1;
		if(Alarm_Enable_Flag == 1)
		{
			P2_3 = 0;
			P1 = Seg_Flag?ucLed:0xff;
		}
		else
		{
			P2_3 = 1;
			P1 = 0xff;
		}
	}
	else
	{
		P2_3 = 1;
		P1 = 0xff;
	}
}

/*定时器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(Seg_Mode == 0)
	{
		if(++Timer_1000ms == 1000)
		{
			Timer_1000ms = 0;
			Clock_Dsip[2]++;
			if(Clock_Dsip[2] == 60)
			{
				Clock_Dsip[2] = 0;
				Clock_Dsip[1]++;
				if(Clock_Dsip[1] == 60)
				{
					Clock_Dsip[1] = 0;
					Clock_Dsip[0]++;
					if(Clock_Dsip[0] == 24)
						Clock_Dsip[0] = 0;
				}
			}
				
		}
	
	}
	if(++Timer_500ms == 500)
	{
		Timer_500ms = 0;
		Seg_Flag ^= 1;
	}
}

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

}