蓝桥杯单片机学习笔记

1、 蜂鸣器

电路分析


①74HC138
是一个译码芯片,CBA二进制对应的十进制数值与Y0~Y7位置相符,Y输出端低电平有效
②CON3口
J13跳帽当1、2短接即存储器控制方式,2、3短接即IO口控制方式,习惯使用IO控制方式
③M74HC574M1R八路D型触发器
当LE为高电平时候Q输出与D输入一致,当LE为低电平,Q输出不随D输入改变,能够起到锁存数据的功能,因为P0口分时复用,所以为了不影响驱动蜂鸣器、继电器等器件,开发板电路中采用触发器进行数据锁存
④ULN2003达林顿管
起到一个加大驱动电流且取反的作用,若N_BUZZ为低电平为蜂鸣器响。因此IN7为高电平,Q7位高电平,D7位高电平,P06为高电平且Y5C为高电平,Y5C要为高电平,则需要Y5为低电平(WR与GND短接,74HC02为或非门),也就是CBA对应101

编程
//第一种方法
#include "reg52.h"
sbit buzzer = P0^6;

void main()
{
	P2 = 0xa0;	//选通触发器
	buzzer = 0;	//蜂鸣器不叫
	P2 = 0x00	//不选通触发器
}

&:与。作用是将某位置0
|:或。作用是将某位置1,且不影响其他位

//第二种方法
#include "reg52.h"

void main()
{
	P2 = ((P2&0x1f)|0xa0);
	P0 &= ~(0x01<<6);
	//P0 |= (0x01<<6);
	P2 &= 0x1f;
}

XBYTE[0XA000] = 0x00
把数据0x00送到外部存储器0xA000这个地址单元
①单片机把该地址的高8位送到P2口,P2=0xA0
②地址的低8位送到P0口,P0=0x00
③单片机地址锁存信号有效
④单片机把数据0x00送到P0口,P0=0x00
⑤地址锁存无效
tips:51单片机中P0口数据地址分时复用,P2口是地址高8位控制

#include "reg52.h"
#include "absacc.h"

void main()
{
	XBYTE[0xA000] = 0x00;	//关蜂鸣器
	while(1)
	{
		//...
	}

}

P2口操作完后一定要关闭(P2 = 0x00),不然单片机掉电后蜂鸣器会一直响
使用软件延时需要加上头文件intrins.h,因为使用到了_nop()_

=======================================================================

2、流水灯

电路分析

同蜂鸣器,详细见电路图

编程
#include "reg52.h"

void Delay100ms()		//@11.0592MHz
{
	unsigned char i, j;

	i = 180;
	j = 73;
	do
	{
		while (--j);
	} while (--i);
}

void main()
{
	int i=0;
	
	while(1)
	{
		P2 = 0x80;	//使能Y4C
		P0 = ~(0x01<<i);
		P2 = 0x00;	//不使能Y4C,给P0赋值后一定要不使能Y4C
		i++;
		if(i==8)
		{
			i=0;
		}
		Delay100ms();
		
	}
}

=======================================================================

3、独立按键和矩阵按键


J5按键功能选择。
KBD:1接2,矩阵键盘 BTN:2接3,独立键盘

扫描法原理介绍

当一个按键两端分别接一个IO口,一个IO口置高电平另一个置低电平,当按下按键时高电平IO口电平被拉低,另一端还是为低电平,这时检测IO口值就是两个低电平

把上述方法应用到矩阵键盘上,如果把4个行引脚接P3前4位IO口(P3.0 ~ P3.3),都置低电平,把4个列引脚接P3后4位IO口(P3.4~P3.7),都置高电平,这时P3=0xf0, 如果按下第一列第一行按键,那么第一列的IO口电平变低,其他IO口电平不变,这时保存P3值,确定了列值。同样,用这种方法确定行值,就是在保存列值后把4个行引脚置高电平,4个列引脚置低电平,P3=0x0f(这时按键还处于按下的状态),确定行值,最后把列值行值进行或运算得出一个保存了行值和列值的数(每个按键都有一个对应的数值)。

简单的说,要确定某行是否有按键按下,只要在列上置低电平在行上置高电平,若某行有被按下的,则该行会被拉低,列检测同理

按键消抖代码

方法一:延时去消抖
不推荐,这样会使得整个系统时钟推迟
方法二:状态机消抖

//此代码是独立按键下的消抖
#define key_input P3
#define key_state_0  0 	//判断按键是否按下
#define key_state_1  1	//判断按键是否抖动
#define key_state_2  2	//判断按键是否弹起
#define key_mask 0x0f 	//屏蔽不需要的IO,因为独立按键P3^4~P3^7接地是低电平
   
char read_key(void) 
{ 
 	static char key_state = 0; 
	char key_press, key_return = 0; 
 	key_press = key_input&key_mask; 
 	switch (key_state) 
	{ 	
	   case key_state_0:     
		   if (key_press!=key_mask) 	//若为真说明有按键按下
		   {
		   	key_state = key_state_1;
		   } 
	   break; 
  	   case key_state_1:    
	   	   if (key_press!=key_mask)
	  	   { 
	  			 if(key_press==0x0e) key_return = 1;  //S7
				 if(key_press==0x0d) key_return = 2;  //S6
				 if(key_press==0x0b) key_return = 3;  //S5
				 if(key_press==0x07) key_return = 4;  //S4
	  			 key_state = key_state_2;  
	 	    } 
	       else 
	   	 	 key_state = key_state_0;  
  	   break;  
       case key_state_2: 
	   	   if (key_press==0x0f) key_state = key_state_0; 
  	   break; 
	 } 
	return key_return; 
} 

方法三:三行代码

unsigned char Trg;	//trigger触发值(按下的瞬间会变化,然后会清楚)
unsigned char Cont;	//continue持续触发值(长按)
void Key_Read( void )
{
    unsigned char ReadData = KEYPORT^0xff; 	//KEYPORT就是P口
    Trg = ReadData & (ReadData ^ Cont);      
    Cont = ReadData;                         		
}
//详细参见博客
//https://blog.csdn.net/yhguo2008/article/details/51327524/
状态机消抖/三行代码法独立按键实现蜂鸣器、继电器、LED控制
#include "reg52.h"
#include "intrins.h"

#define key_input P3
#define key_state_0 0	//按键按下
#define key_state_1 1	//按键消抖
#define key_state_2 2	//按键弹起
#define key_mask 0x0f

#define ON 1
#define OFF 0

/*
#define KEYPORT P3
unsigned char Trg;
unsigned char Cont;

void Key_Read( void )
{
    unsigned char ReadData = KEYPORT^0xff; 
    Trg = ReadData & (ReadData ^ Cont);      
    Cont = ReadData;                         		
}
*/

void Delay100ms()		//@11.0592MHz
{
	unsigned char i, j;

	i = 180;
	j = 73;
	do
	{
		while (--j);
	} while (--i);
}


char key_read(void)
{
	char key_press;
	char key_return = 0;
	static char key_state = key_state_0;
	key_press = key_input&key_mask;
	
	switch(key_state)
	{
		case key_state_0:
			if(key_press != 0x0f)
			{
				key_state = key_state_1;	//初步确定按下按键后要进入消抖环节
			}
			break;
		case key_state_1:
			if(key_press != 0x0f)
			{
				if(key_press == 0x0e)key_return = 7;//S7
				if(key_press == 0x0d)key_return = 6;//S6
				if(key_press == 0x0b)key_return = 5;//S5
				if(key_press == 0x07)key_return = 4;//S4
				key_state = key_state_2;  
			}
			else
				key_state = key_state_0;
			break;
		case key_state_2:
			if(key_press == 0x0f)	//有次写错成0xff,键盘按键就只能使用一次
			{
				key_state = key_state_0;
			}
			break;
	}
	return key_return;
}

void control_buzzer(int two_value_switch)
{
	P2 = 0xa0;
	if(two_value_switch == ON)
	{
		P0 = 0x40;	//开蜂鸣器
	}
	else
	{
		P0 = 0x00;	//关蜂鸣器
	}
	P2 = 0x00;
}

void control_relay(int two_value_switch)
{
	P2 = 0xa0;
	if(two_value_switch == ON)
	{
		P0 = 0x10;	//开继电器
	}
	else
	{
		P0 = 0x00;	//关继电器
	}
	P2 = 0x00;
}

void control_led(int two_value_switch)
{
	P2 = 0x80;
	if(two_value_switch == ON)
	{
		P0 = 0x00;	//打开所有灯
	}
	else
	{
		P0 = 0xff;	//关闭所有灯
	}
	
	P2 = 0x00;
}

void main()
{
	unsigned char key_value;
	while(1)
	{
		key_value = key_read();
		if(key_value == 7)control_led(ON);//control_buzzer(ON)//control_relay(ON)
		if(key_value == 6)control_led(OFF);//control_buzzer(OFF)//control_relay(OFF)
		delay10ms();//未定义,之后再定时器一节再讲述
		//三行代码实验程序
		//		Key_Read();
		//		if(Trg & 0x08)//S4
		//		{
		//			P2=0xa0;buzzer=1;P2=0x00;
		//		}
		//		if(Trg & 0x04)//S5
		//		{
		//			P2=0xa0;buzzer=0;P2=0x00;
		//		}
		
	}		
}
矩阵键盘代码
#include "reg52.h"
#define KEY P3
#define key_state_0 0	//按键按下
#define key_state_1 1	//按键消抖
#define key_state_2 2	//按键弹起
   
char read_KBD(void) 
{ 
 static char key_state = 0; 
 unsigned char key_return=0, key_press;
 unsigned char key1,key2;
	KEY=0xf0;
	key1=KEY&0xf0; 
	KEY=0x0f;
	key2=KEY&0x0f; 
	key_press =key1|key2;

 switch (key_state) 
{ 	
   case key_state_0:    // 
   if (key_press!=0xff) key_state = key_state_1; 
   break; 
	 
   case key_state_1:     
   if (key_press !=0xff) 
   { 
			if(key_press==0xde) key_return = 1;  //S15  
			if(key_press==0xdd) key_return = 2;  //S14
			key_state = key_state_2;  
   } 
   else 
			key_state = key_state_0;  
   break;  
   case key_state_2: 
   if (key_press==0xff) key_state = key_state_0; 
   break; 
} 
return key_return; 
} 

sbit buzzer = P0^6;
void main()
{
	unsigned char key_val;
	while(1)
	{
		key_val=read_KBD();
		if(key_val==1)//S15
		{
			P2=0xa0;buzzer=1;P2=0x00;
		}
		if(key_val==2)//S14
		{
			P2=0xa0;buzzer=0;P2=0x00;
		}
	}
}
任务练习

1、独立按键实现蜂鸣器、继电器控制、LED亮灭

//注意短接口J5不要接错
/*
 * 出错的地方:
 * ①key_state 没有定义为static变量
 * ②只能一个开关起作用,若要另一个开关也起作用,则需要重启:说明出错在按键弹起来,果然问题在判断语句写成了0xff,独立按键应该写0x0f
 * ③检测独立函数写错也是因为判断是否按下写成了0xff,应该写成0x0f
 */


#include "reg52.h"


#define key_input P3
#define key_state_0 0	//检查是否按下
#define key_state_1 1	//检查是否抖动
#define key_state_2 2	//检查是否弹起

#define ON  1
#define OFF 0

typedef unsigned char BYTE;
typedef unsigned int WORD;
unsigned char temp_key_compare;

//-----------------------------------------------

/* define constants */
#define FOSC 11059200L

#define T1MS (65536-FOSC/12/1000)   //1ms timer calculation method in 12T mode

/* define SFR */
sbit TEST_LED = P1^0;               //work LED, flash once per second

/* define variables */
WORD count;                         //1000 times counter


/*
 *	蜂鸣器驱动函数
 */
void control_buzzer(unsigned char bi_val_control)
{
	P2 = 0xa0;
	if(bi_val_control == ON)
	{
		P0 = 0x40;	//开蜂鸣器
	}
	else
	{
		P0 = 0x00;	//关蜂鸣器
	}
	P2 = 0x00;
}

/*
 *	独立按键驱动函数
 */
unsigned char read_control_key(void)
{
	unsigned char return_key_val=0;
	unsigned char key_press;
	static char key_state = key_state_0; //错过这里,未定义成静态变量
	key_press = P3&0x0f;
	
	switch(key_state)
	{
		case key_state_0:
			{
				if(key_press != 0x0f)	//错过这里,错写0xff,误当为矩阵键盘
				{
					key_state = key_state_1;
				}
			}
			break;
		case key_state_1:
			{
				if(key_press != 0x0f)//错过这里,错写0xff,误当为矩阵键盘
				{
					if(key_press == 0x0e)return_key_val = 7;//S7
					if(key_press == 0x0d)return_key_val = 6;//S6
					if(key_press == 0x0b)return_key_val = 5;//S5
					if(key_press == 0x07)return_key_val = 4;//S4
					key_state = key_state_2;
				}
				else 
					key_state = key_state_0;
			}
			break;
		case key_state_2:
			{
				if(key_press == 0x0f)//错过这里,错写0xff,误当为矩阵键盘
				{
					key_state = key_state_0;
				}
			}
			break;

	}
	return return_key_val;
}


void main()
{

	  TMOD = 0x01;                    //set timer0 as mode1 (16-bit)
    TL0 = T1MS;                     //initial timer0 low byte
    TH0 = T1MS >> 8;                //initial timer0 high byte
    TR0 = 1;                        //timer0 start running
    ET0 = 1;                        //enable timer0 interrupt
    EA = 1;                         //open global interrupt switch
    count = 0;                      //initial counter

    while (1);                      //loop	

}

/* Timer0 interrupt routine */
void tm0_isr() interrupt 1 using 1
{
    TL0 = T1MS;                     //reload timer0 low byte
    TH0 = T1MS >> 8;                //reload timer0 high byte
    if (count-- == 0)               //1ms * 10 -> 10ms
    {
        count = 10;               //reset counter
        temp_key_compare = key_read();
				if(temp_key_compare==7)
				{
					control_buzzer(ON);
				}
				if(temp_key_compare==5)
				{
					control_buzzer(OFF);
				}
    }
}

2、矩阵键盘控制蜂鸣器

//注意短接口J
/*
 * 出错的地方:
 * ①key_state 没有定义为static变量
 * ②只能一个开关起作用,若要另一个开关也起作用,则需要重启:说明出错在按键弹起来,果然问题在判断语句写成了0xff,独立按键应该写0x0f
 * ③检测独立函数写错也是因为判断是否按下写成了0xff,应该写成0x0f
 */


#include "reg52.h"

#define KEY P3
#define key_input P3
#define key_state_0 0	//检查是否按下
#define key_state_1 1	//检查是否抖动
#define key_state_2 2	//检查是否弹起

#define ON  1
#define OFF 0

typedef unsigned char BYTE;
typedef unsigned int WORD;
unsigned char temp_key_compare;

//-----------------------------------------------

/* define constants */
#define FOSC 11059200L

#define T1MS (65536-FOSC/12/1000)   //1ms timer calculation method in 12T mode

/* define SFR */
sbit TEST_LED = P1^0;               //work LED, flash once per second

/* define variables */
WORD count;                         //1000 times counter


/*
 *	蜂鸣器驱动函数
 */
void control_buzzer(unsigned char bi_val_control)
{
	P2 = 0xa0;
	if(bi_val_control == ON)
	{
		P0 = 0x40;	//开蜂鸣器
	}
	else
	{
		P0 = 0x00;	//关蜂鸣器
	}
	P2 = 0x00;
}



/*
 *	矩阵按键驱动函数
 */
unsigned char matrix_read_control_key(void)
{
	unsigned char return_key_val=0;
	unsigned char key_press;
	static char key_state = key_state_0; //错过这里,未定义成静态变量
	unsigned char key1,key2;
	KEY=0xf0;
	key1=KEY&0xf0; 
	KEY=0x0f;
	key2=KEY&0x0f; 
	key_press =key1|key2;
	
	switch(key_state)
	{
		case key_state_0:
			{
				if(key_press != 0xff)	//错过这里,错写0xff,误当为矩阵键盘
				{
					key_state = key_state_1;
				}
			}
			break;
		case key_state_1:
			{
				if(key_press != 0xff)//错过这里,错写0xff,误当为矩阵键盘
				{
					if(key_press == 0x7e)return_key_val = 7;//S7
					if(key_press == 0xbe)return_key_val = 11;//S11
					if(key_press == 0xdd)return_key_val = 14;//S14
					if(key_press == 0xde)return_key_val = 15;//S15
					if(key_press == 0xee)return_key_val = 19;//S19
					key_state = key_state_2;
				}
				else 
					key_state = key_state_0;
			}
			break;
		case key_state_2:
			{
				if(key_press == 0xff)//错过这里,错写0xff,误当为矩阵键盘
				{
					key_state = key_state_0;
				}
			}
			break;

	}
	return return_key_val;
}


void main()
{

	  TMOD = 0x01;                    //set timer0 as mode1 (16-bit)
    TL0 = T1MS;                     //initial timer0 low byte
    TH0 = T1MS >> 8;                //initial timer0 high byte
    TR0 = 1;                        //timer0 start running
    ET0 = 1;                        //enable timer0 interrupt
    EA = 1;                         //open global interrupt switch
    count = 0;                      //initial counter

    while (1);                      //loop	

}

/* Timer0 interrupt routine */
void tm0_isr() interrupt 1 using 1
{
    TL0 = T1MS;                     //reload timer0 low byte
    TH0 = T1MS >> 8;                //reload timer0 high byte
    if (count-- == 0)               //1ms * 10 -> 10ms
    {
        count = 10;               //reset counter
        temp_key_compare = matrix_read_control_key();
				if(temp_key_compare==14)
				{
					control_buzzer(ON);
				}
				if(temp_key_compare==15)
				{
					control_buzzer(OFF);
				}
    }
}

=======================================================================

4、数码管

共阳接法,高电平是暗低电平是亮

原理介绍

根据CT107D的原理图我们可以看出,数码管显示同样涉及到74HC573、74HC138和74HC02,这与上一节中的LED灯、继电器和蜂鸣器的控制大同小异。如下图,蓝色标注为位选控制端口,由锁存器U6来控制,需配置红色标注的Y6C来控制锁存;黄色标注为段选控制端口,由锁存器U7来控制,需配置红色标注的Y7C来控制锁存。而控制Y6C与Y7C则需要通过74HC18和74HC02来进行控制,如下图,Y6C由Y6和WR共同控制,74HC02是一个4路2输入或非门功能,WR为低电平,要使Y6C为高,则Y6必须为低电平,即74HC138译码器的三个输入端应该为100,即P2^ 7=1,P2^ 6=0,P2^5=0。又只需要操作P2口的这三位,不需要配置其他的五位,所以P2端口应该配置为:P2 = ((P2&0x1f)|0xC0)。同理,控制Y7C时P2端口应该置为:P2 = ((P2&0x1f)|0xE0)。

数码管静态显示
//软件延时是stc89c51的,IAP不一样
#include "reg52.h"

void Delay100ms()		//@11.0592MHz
{
	unsigned char i, j;

	i = 180;
	j = 73;
	do
	{
		while (--j);
	} while (--i);
}

void main()
{
	unsigned char i;
	P2=0x80;P0=0xaa;P2=0x00;
    while(1)
	{
		P2=0x80;P0=~(0x80>>i);P2=0x00;
		i++;
		if(i==8) i=0;
		Delay100ms();
	}
}
数码管动态显示
#include "reg51.h"
#include "intrins.h"
typedef unsigned char BYTE;
typedef unsigned int WORD;

//-----------------------------------------------

/* define constants */
#define FOSC 11059200L

#define T1MS (65536-FOSC/1000)   //1ms timer calculation method in 1T mode

/* define SFR */
sbit TEST_LED = P1^0;               //work LED, flash once per second

/* define variables */
WORD count;                         //1000 times counter

//-----------------------------------------------
unsigned char code T_display[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};
unsigned char code T_COM[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80}; 

/* Timer0 interrupt routine */
void tm0_isr() interrupt 1 using 1
{
		static char i;
    TL0 = T1MS;                     //reload timer0 low byte
    TH0 = T1MS >> 8;                //reload timer0 high byte
    if (count-- == 0)               //1ms * 1000 -> 1s
    {
			count = 1;               //reset counter
       		P2=0xe0;P0=~T_display[i];P2=0;
			P2=0xc0;P0=T_COM[i];P2=0;
			i++;
			if(i==8) i=0;
    }
}

//-----------------------------------------------

/* main program */
void main()
{
	
    TMOD = 0x01;                    //set timer0 as mode1 (16-bit)
    TL0 = T1MS;                     //initial timer0 low byte
    TH0 = T1MS >> 8;                //initial timer0 high byte
    TR0 = 1;                        //timer0 start running
    ET0 = 1;                        //enable timer0 interrupt
    EA = 1;                         //open global interrupt switch
    count = 0;                      //initial counter

	while(1);
}

定时器中断服务程序函数名命令规则

void 函数名() interrupt 中断号 [using 工作寄存器组号]

中断号中断源
0外部中断0
1定时器0
2外部中断1
3定时器1中断
4串行口中断
寄存器组号工作寄存器组
0工作寄存器组0
1工作寄存器组1
2工作寄存器组2
3工作寄存器组3
定时器初值确定

STC12内核是1T的,没有像51单片机进行12分频,晶振为11.0592MHZ
T机器周期 = T时钟周期 = 1/11.0592=0.09042us
假设定时时间为x毫秒
定时次数=x*1000/0.09042
初值=2^(定时器位数)-定时次数
例如定时器0方式1(16位计数)
定时时间=1毫秒
定时次数=1x1000/0.09042=11059.5001(C语言向下取整,实际定时是微长一点)
初值=2^16-11059=65536-11059=54477

定时器中断相关寄存器

TMOD寄存器

D7D6D5D4D3D2D1D0
GATEC/T’M1M0GATEC/T’M1M0

IE寄存器

D7D6D5D4D3D2D1D0
EAESET1EX1ET0EX0
任务练习

1、矩阵键盘控制数码管显示不同的数字

/*
 * 关于如何实现根据按键显示相应数字,思路如下。
 * 设置一个指定长度的数组,在中断函数里将读取的键值
 * 赋给数组,然后在显示
 * 提示点如下:
 * ①将想显示的不同数设为数组,这样多个数就有多个数组,这样是不可以的,由于按键读取判断会有逻辑问题
 * ②程序中的i可以改变显示位数
 * ③静态变量i初始值应该赋为0,不然会受到上一次烧写程序的影响
 * ④code定义的变量是写入ROM里的不能被修改
 */
#include "reg51.h"
#include "intrins.h"

#define KEY P3
#define key_state_0 0	//按键按下
#define key_state_1 1	//按键消抖
#define key_state_2 2	//按键弹起
   
typedef unsigned char BYTE;
typedef unsigned int WORD;

char read_KBD(void) 
{ 
	static char key_state = 0; 
	unsigned char key_return=0, key_press;
	unsigned char key1,key2;
	KEY=0xf0;
	key1=KEY&0xf0; 
	KEY=0x0f;
	key2=KEY&0x0f; 
	key_press =key1|key2;

	switch (key_state) 
	{ 	
		case key_state_0:    // 
		if (key_press!=0xff) key_state = key_state_1; 
		break; 
		
		case key_state_1:     
		if (key_press !=0xff) 
		{ 
			if(key_press==0xde) key_return = 15;  //S15  
			if(key_press==0xdd) key_return = 14;  //S14
			key_state = key_state_2;  
		} 
		else 
			key_state = key_state_0;  
		break;  
		case key_state_2: 
		if (key_press==0xff) key_state = key_state_0; 
		break; 
	} 
	return key_return; 
} 

//-----------------------------------------------

/* define constants */
#define FOSC 11059200L

#define T1MS (65536-FOSC/12/1000)   //1ms timer calculation method in 1T mode

/* define SFR */
sbit TEST_LED = P1^0;               //work LED, flash once per second

/* define variables */
WORD count;                         //1000 times counter

//-----------------------------------------------
unsigned char code T_display[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};
unsigned char code T_COM[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80}; 
unsigned char T_number1[8]={0};	//code定义的变量是写入ROM里的不能被修改
							
/* Timer0 interrupt routine */
void tm0_isr() interrupt 1 using 1
{
		
		static char i=0;	//初始化时应该赋值,不然还保留着上一次烧写的值
		unsigned char temp=read_KBD();
		if(temp != 0)
		{
			T_number1[0]=temp/10;
			T_number1[1]=temp%10;
		}
	
    TL0 = T1MS;                     //reload timer0 low byte
    TH0 = T1MS >> 8;                //reload timer0 high byte
    if (count-- == 0)               //1ms * 1000 -> 1s
    {
			
			count = 1;               //reset counter
			P2=0xe0;P0=~T_display[T_number1[i]];P2=0;			
			P2=0xc0;P0=T_COM[i];P2=0;
			i++;
			if(i==8) i=0;	//显示位数
    }
}

//-----------------------------------------------

/* main program */
void main()
{
	
    TMOD = 0x01;                    //set timer0 as mode1 (16-bit)
    TL0 = T1MS;                     //initial timer0 low byte
    TH0 = T1MS >> 8;                //initial timer0 high byte
    TR0 = 1;                        //timer0 start running
    ET0 = 1;                        //enable timer0 interrupt
    EA = 1;                         //open global interrupt switch
    count = 0;                      //initial counter

	while(1);
}

2、两个独立按键控制数码管数字的增减

#include "reg51.h"
#include "intrins.h"

#define key_input P3
#define key_state_0 0	//按键按下
#define key_state_1 1	//按键消抖
#define key_state_2 2	//按键弹起
#define key_mask 0x0f
   
typedef unsigned char BYTE;
typedef unsigned int WORD;

char read_KBD(void) 
{ 
 	static char key_state = 0; 
	char key_press, key_return = 0; 
 	key_press = key_input&key_mask; 
 	switch (key_state) 
	{ 	
	   case key_state_0:     
		   if (key_press!=key_mask) 	//若为真说明有按键按下
		   {
		   	key_state = key_state_1;
		   } 
	   break; 
  	   case key_state_1:    
	   	   if (key_press!=key_mask)
	  	   { 
	  			 if(key_press==0x0e) key_return = 1;  //S7
				 if(key_press==0x0d) key_return = 2;  //S6
				 if(key_press==0x0b) key_return = 3;  //S5
				 if(key_press==0x07) key_return = 4;  //S4
	  			 key_state = key_state_2;  
	 	    } 
	       else 
	   	 	 key_state = key_state_0;  
  	   break;  
       case key_state_2: 
	   	   if (key_press==0x0f) key_state = key_state_0; 
  	   break; 
	 } 
	return key_return; 
} 

//-----------------------------------------------

/* define constants */
#define FOSC 11059200L

#define T1MS (65536-FOSC/12/1000)   //1ms timer calculation method in 1T mode

/* define SFR */
sbit TEST_LED = P1^0;               //work LED, flash once per second

/* define variables */
WORD count;                         //1000 times counter

//-----------------------------------------------
unsigned char code T_display[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};
unsigned char code T_COM[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80}; 
unsigned char T_number1[8]={0};	//code定义的变量是写入ROM里的不能被修改
							
/* Timer0 interrupt routine */
void tm0_isr() interrupt 1 using 1
{
		
		static char i=0;	//初始化时应该赋值,不然还保留着上一次烧写的值
		static unsigned char display_temp=0;
		unsigned char temp=read_KBD();
		
		if(temp == 3)
		{
			display_temp++;
		}
		if(temp == 4)
		{
			display_temp--;
		}
		if(temp >= 0)
		{
			T_number1[0]=display_temp/10;
			T_number1[1]=display_temp%10;
		}
    TL0 = T1MS;                     //reload timer0 low byte
    TH0 = T1MS >> 8;                //reload timer0 high byte
    if (count-- == 0)               //1ms * 1000 -> 1s
    {
			
			count = 1;               //reset counter
			P2=0xe0;P0=~T_display[T_number1[i]];P2=0;			
			P2=0xc0;P0=T_COM[i];P2=0;
			i++;
			if(i==8) i=0;	//显示位数
    }
}

//-----------------------------------------------

/* main program */
void main()
{
	
    TMOD = 0x01;                    //set timer0 as mode1 (16-bit)
    TL0 = T1MS;                     //initial timer0 low byte
    TH0 = T1MS >> 8;                //initial timer0 high byte
    TR0 = 1;                        //timer0 start running
    ET0 = 1;                        //enable timer0 interrupt
    EA = 1;                         //open global interrupt switch
    count = 0;                      //initial counter

	while(1);
}

=======================================================================

5、DS18B20

温度传感器电路

电阻的作用:上拉电阻

单总线协议介绍

采用单根信号线,既可传输时钟,又能传输数据,而且数据传输是双向的(单片机<->18B20芯片)

DS18B20编程

此项中以下除了 rd_temperature_f程序比赛都会提供

#检测初始化是否成功
bit Init_DS18B20(void)
{
	bit initflag = 0;
	DQ = 1;
	Delay_OneWire(12);
	DQ = 0;
	Delay_OneWire(80); 
	DQ = 1;
	Delay_OneWire(10); 
	initflag = DQ;    
	Delay_OneWire(5);
  
	return initflag;
}

//给18B20写数据
//先写低位,低电平写入0高电平写入1
//dat是要写入的数据
void Write_DS18B20(unsigned char dat)
{
	unsigned char i;
	for(i=0;i<8;i++)
	{
		DQ = 0;
		DQ = dat&0x01;
		Delay_OneWire(5);
		DQ = 1;
		dat >>= 1;	//dat右移一位
	}
	Delay_OneWire(5);
}
 
//从DS18B20读取一个字节
unsigned char Read_DS18B20(void)
{
	unsigned char i;
	unsigned char dat;
  
	for(i=0;i<8;i++)
	{
		DQ = 0;
		dat >>= 1;
		DQ = 1;
		if(DQ)
		{
			dat |= 0x80;
		}	    
		Delay_OneWire(5);
	}
	return dat;
}
//这个函数不会提供
float rd_temperature_f(void)
{
    unsigned int temp;
    float temperature;
    unsigned char low,high;
  
  	Init_DS18B20();
  	Write_DS18B20(0xCC);	//挂很多18B20通过ID号区分,板子只有一个18B20,故忽略
  	Write_DS18B20(0x44); 	//启动温度转换
  	Delay_OneWire(200);

  	Init_DS18B20();
  	Write_DS18B20(0xCC);
  	Write_DS18B20(0xBE); //读取寄存器

  	low = Read_DS18B20(); //低字节
  	high = Read_DS18B20(); //高字节
	 /** 精度为0.0625摄氏度 */  
	temp = high;
	temp <<= 8;
	temp |= low;
	temperature = temp*0.0625;
  	return temperature;
}

任务练习

自行定义一个上限(如20摄氏度),超过上限L1亮,继电器打开;自行定义一个下限(如15摄氏度),低于下限,L2亮,蜂鸣器响

①出错在工程文件未导入onewire.c
②while(1)后加了一个:

#include "reg52.h"
#include "intrins.h"
#include "onewire.h"
typedef unsigned char BYTE;
typedef unsigned int WORD;

unsigned char temperature;
//-----------------------------------------------

/* define constants */
#define FOSC 11059200L

#define T1MS (65536-FOSC/12/1000)   //1ms timer calculation method in 12T mode

/* define SFR */
sbit TEST_LED = P1^0;               //work LED, flash once per second

/* define variables */
WORD count;                         //1000 times counter

//-----------------------------------------------
unsigned char code T_display[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};
unsigned char code T_COM[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80}; 

unsigned char temp_table[2];
/* Timer0 interrupt routine */
void tm0_isr() interrupt 1 using 1
{
		static char i;
    TL0 = T1MS;                     //reload timer0 low byte
    TH0 = T1MS >> 8;                //reload timer0 high byte
    if (count-- == 0)               //1ms * 1000 -> 1s
    {
					count = 1;               //reset counter
       		P2=0xe0;P0=~T_display[temp_table[i]];P2=0;
					P2=0xc0;P0=T_COM[i];P2=0;
					i++;
					if(i==2) i=0;
    }
}

//-----------------------------------------------



void Delay2ms()		//@11.0592MHz
{
	unsigned char i, j;

	_nop_();
	i = 4;
	j = 146;
	do
	{
		while (--j);
	} while (--i);
}

/* main program */
sbit relay = P0^4;
sbit buzzer = P0^6;
void main()
{
	
	TMOD = 0x01;                    //set timer0 as mode1 (16-bit)
	TL0 = T1MS;                     //initial timer0 low byte
	TH0 = T1MS >> 8;                //initial timer0 high byte
	TR0 = 1;                        //timer0 start running
	ET0 = 1;                        //enable timer0 interrupt
	EA = 1;                         //open global interrupt switch
	count = 0;                      //initial counter
	
	P2=0xa0;P0=0x00;P2=0x00;
	while(1)
	{
		EA=0;
		temperature= (unsigned char)rd_temperature_f();
		EA=1;
		if(temperature>25)
		{
			P2=0x80;P0=~0x01;P2=0x00;
			P2=0xa0;buzzer=0;relay=1;P2=0x00;
		}
		if(temperature<21)
		{
			P2=0x80;P0=~0x02;P2=0x00;
			P2=0xa0;buzzer=1;relay=0;P2=0x00;
		}
		temp_table[0]=temperature/10;
		temp_table[1]=temperature%10;
		Delay2ms();
	}
}

=======================================================================

6、SPI协议-DS1302编程

实时时钟电路

开头左上角Y3及U19

SPI协议介绍

比赛包会提供驱动
SPI是串行外设接口的缩写

DS1302编程

指令表格倒数第二行0x8E:写 丨 0x8F:读
这样对应数据传输协议中对位电平的限制
官方给的驱动函数写入的数据都要是BCD码,例如写入37s就是写入0x37h
但是我们自己定义的set_sfm()函数不是

 void set_sfm(unsigned char shi,unsigned char  fen,unsigned char  miao)
{
	Ds1302_Single_Byte_Write(0x8e,0);		//关掉写保护。不然无法写入
	Ds1302_Single_Byte_Write(0x80,(miao/10)*16+miao%10);
	Ds1302_Single_Byte_Write(0x82,(fen/10)*16+fen%10);
	Ds1302_Single_Byte_Write(0x84,(shi/10)*16+shi%10);
	Ds1302_Single_Byte_Write(0x8e,0x80);	//开启写保护
}
//读
shi = Read_Ds1302(0x85);	//BCD码
miao = Read_Ds1302(0x81);
fen = Read_Ds1302(0x83);
练习

1、编程实现DS1302实时时钟读写并用数码管显示
2、用两个独立按键分别控制时的增减;用两个独立按键分别控制分的增减
TIPS:
①独立按键程序若放在中断服务函数里,则中断函数执行时间增长,会导致主函数里的函数执行会到影响,所以尽量放在main函数里,通过设定全局变量bit flag;在中断服务函数里只进行加减数及标志位的改变,而具体执行程序放在main中,if flag==1 则执行
②注意时分秒都是16进制的BCD码,如果仅是++会出错,应该先将BCD码转换为10十进制数

=======================================================================

7、IIC协议

EEPROM、AD/DA电路


PCF8591是一个8位的AD/DA芯片,四路AD口和一路AD输出(15脚),主要用到部分的电路。比赛用到AIN1和AIN3两个AD输入,P20和P21用来通讯,
只需要两根线P20/P21,A0A1A2(电路中接地)是决定通讯地址的(24C02和8591的A0A1A2都接地但是内部本身的地址是一样,故编程可以区分)
AIN1是通过光敏电阻来调节输入1,AIN3是通过旋钮电阻来调节输入3的,

IIC协议介绍

SCL:SCLK时钟线
SDA:SDATA数据线
数据传送时候SCL需保持高电平

PCF8591、AT24C02编程

PCF8591:add是AD通道,通道0~通道4分别对应0x00 ~ 0x03
AT24C02:add是地址,0x00~0xff

void write_adc(unsigned char add)
{
	 IIC_Start();
	 IIC_SendByte(0x90);
	 IIC_WaitAck();
	 IIC_SendByte(add);
	 IIC_WaitAck();
	 IIC_Stop();
}

第一个图是地址
第二图是写函数定义方式:
S - 启动
ADDRESS - 地址(由第一个图写则是0x90,读则是0x91)
0 - ADDRESS是7位,最后一位写的话就是0
A - 等待回应IIC_WaitAck()

add - 通道值,例如通道0(0x00),通道3(0x03)

unsigned char read_adc(unsigned char add)
{
	 unsigned char temp; 
	 IIC_Start();
	 IIC_SendByte(0x90);
	 IIC_WaitAck();
	 IIC_SendByte(add);
	 IIC_WaitAck();
	 IIC_Start();
	 IIC_SendByte(0x91);
	 IIC_WaitAck();
	 temp=IIC_RecByte();
	 IIC_WaitAck();
	 IIC_Stop();
	 return temp;
}

要读的话需要先写控制字,告诉ADC采样哪一个通道然后再根据读时序写

void write_24c02(unsigned char add,unsigned char data1)
{
	IIC_Start();
	IIC_SendByte(0xa0);
	IIC_WaitAck();
	IIC_SendByte(add);	//存储单元地址0x00-0xFF
	IIC_WaitAck();
	IIC_SendByte(data1); //数据
	IIC_WaitAck();
	IIC_Stop();
}

unsigned char read_24c02(unsigned char add)
{
	unsigned char temp;
	IIC_Start();
	IIC_SendByte(0xa0);
	IIC_WaitAck();
	IIC_SendByte(add);
	IIC_WaitAck();
	IIC_Start();
	IIC_SendByte(0xa1);
	IIC_WaitAck();
	temp=IIC_RecByte();
	IIC_WaitAck();
	IIC_Stop();
	return temp;
}
练习

1、编程实现PCF8591读取通道1和通道3的电压值

/*
 * 显示小数点的数据,则写两套数模,一套带小数点一套不带
 * 如果要显示小数则实现小数乘10^x(x是小数的位数)这样就可以除不同值求出每一位的数值
 * 读数据调用函数时怕中断影响程序,可以先关闭中断,待会再打开
 */
#include "reg52.h"
#include "intrins.h"
#include "iic.h"
   
typedef unsigned char BYTE;
typedef unsigned int WORD;

//-----------------------------------------------

/* define constants */
#define FOSC 11059200L

#define T1MS (65536-FOSC/12/1000)   //1ms timer calculation method in 1T mode

/* define SFR */
sbit TEST_LED = P1^0;               //work LED, flash once per second

/* define variables */
WORD count;                         //1000 times counter

//-----------------------------------------------
unsigned char code T_display[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};
unsigned char code T_display_dian[]={0xbF,0x86,0xdB,0xcF,0xe6,0xeD,0xfD,0x87,0xfF,0xeF};
unsigned char code T_COM[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80}; 
unsigned char T_number1[8]={0};	//code定义的变量是写入ROM里的不能被修改
							
/* Timer0 interrupt routine */
void tm0_isr() interrupt 1 using 1
{
		
		static char i=0;	//初始化时应该赋值,不然还保留着上一次烧写的值

    TL0 = T1MS;                     //reload timer0 low byte
    TH0 = T1MS >> 8;                //reload timer0 high byte
    if (count-- == 0)               //1ms * 1000 -> 1s
    {
			
			count = 1;               //reset counter
			if(i==0)
			{
				P2=0xe0;P0=~T_display_dian[T_number1[i]];P2=0;			
			}
			else
			{
				P2=0xe0;P0=~T_display[T_number1[i]];P2=0;			
			}
			P2=0xc0;P0=T_COM[i];P2=0;
			i++;
			if(i==8) i=0;	//显示位数
    }
}

//-----------------------------------------------

/* main program */
void main()
{
	
    TMOD = 0x01;                    //set timer0 as mode1 (16-bit)
    TL0 = T1MS;                     //initial timer0 low byte
    TH0 = T1MS >> 8;                //initial timer0 high byte
    TR0 = 1;                        //timer0 start running
    ET0 = 1;                        //enable timer0 interrupt
    EA = 1;                         //open global interrupt switch
    count = 0;                      //initial counter

	while(1)
	{		
		unsigned char temp=read_adc(0x01);
		EA=0;
		temp = temp*50/255;
		EA=1;
		if(temp != 0)
		{
			T_number1[0]=temp/10;
			T_number1[1]=temp%10;
		}
	}
}

2、编程实现AT24C02的读写,让0x55单元的数值每次上电自加1

/*
 * 本项目需要是上电一次,数字加一,所以在未断电时这个数字不用改变,所以只要把读取和写入AT2402的部分写在while循环外,每一次上电只要执行一次
 */
#include "reg52.h"
#include "intrins.h"
#include "iic.h"
   
typedef unsigned char BYTE;
typedef unsigned int WORD;

//-----------------------------------------------

/* define constants */
#define FOSC 11059200L

#define T1MS (65536-FOSC/12/1000)   //1ms timer calculation method in 1T mode

/* define SFR */
sbit TEST_LED = P1^0;               //work LED, flash once per second

/* define variables */
WORD count;                         //1000 times counter

//-----------------------------------------------
unsigned char code T_display[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};
unsigned char code T_display_dian[]={0xbF,0x86,0xdB,0xcF,0xe6,0xeD,0xfD,0x87,0xfF,0xeF};
unsigned char code T_COM[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80}; 
unsigned char T_number1[8]={0};	//code定义的变量是写入ROM里的不能被修改
unsigned char count_number=0;
							
/* Timer0 interrupt routine */
void tm0_isr() interrupt 1 using 1
{
		
	  static char i=0;	//初始化时应该赋值,不然还保留着上一次烧写的值

    TL0 = T1MS;                     //reload timer0 low byte
    TH0 = T1MS >> 8;                //reload timer0 high byte
    if (count-- == 0)               //1ms * 1000 -> 1s
    {
			
			count = 1;               //reset counter
			P2=0xe0;P0=~T_display[T_number1[i]];P2=0;			
			P2=0xc0;P0=T_COM[i];P2=0;
			i++;
			if(i==8) i=0;	//显示位数
    }
}

//-----------------------------------------------

/* main program */
void main()
{
		unsigned char temp;

	
    TMOD = 0x01;                    //set timer0 as mode1 (16-bit)
    TL0 = T1MS;                     //initial timer0 low byte
    TH0 = T1MS >> 8;                //initial timer0 high byte
    TR0 = 1;                        //timer0 start running          
    ET0 = 1;                        //enable timer0 interrupt
    EA = 1;                         //open global interrupt switch
    count = 0;                      //initial counter
		EA=0;
		count_number =read_24c02(0x55);
		temp =count_number;
	  write_24c02(0x55,++count_number);
		EA=1;
		T_number1[0]=temp/10;
		T_number1[1]=temp%10;
	while(1)
	{		

	}
}

=======================================================================

8、项目补习的C语言知识点

bool变量

C语言里面没有bool类型,C++里面才有。C99标准里面,定义了bool类型变量,只需要引入头文件<stdbool.h>,bool变量只有两个值:一个为0.另外一个为1

共用类型union

结构体和共用体的区别在于:结构体的各个成员会占用不同的内存,互相之间没有影响;而共用体的所有成员占用同一段内存,修改一个成员会影响其余所有成员。
结构体占用的内存大于等于所有成员占用的内存的总和(成员之间可能会存在缝隙),共用体占用的内存等于最长的成员占用的内存。共用体使用了内存覆盖技术,同一时刻只能保存一个成员的值,如果对新的成员赋值,就会把原来成员的值覆盖掉。
详细见博客https://blog.csdn.net/u011974987/article/details/52305364

枚举类型

如果一个变量只有几种可能的值,则可以定义为“枚举类型”;所谓“枚举”就是把可能的值一一的列举出来,变量的值只限于列举出来的值的范围

	语法:
	enum 枚举类型{枚举成员列表};
	//其中的枚举成员列表是以逗号“,”相分隔
	如:
    enum Spectrum{red,black,yellow,blue,white};
    -------------------------------------------
    enum Spectrum{red,balck,yellow,blue,white};
                   0    1     2     3     4 
默认情况下:该枚举列表中的常量值分别为:0,1,2,3,4
宏定义

宏定义有弱点:其定义的只是预处理阶段的名字,在编译器的预处理阶段会进行简单的名字替换,而且不会进行类型的安全检查,其作用域是全局的,因此若程序中有变量true、false,则会被替换。为了避免这样的情况,采用将全部的宏用大写来命名,以区别于正常的代码。

9、IAP15使用的注意事项

STC89C52和IAP15的异同

P4.2替代P3.6
P4.4替代P3.7
P4.1接
P4.5接 控制存储器编程比如锁存
P5.5接 中断使能
P4.1/P4.5/P5.5在比赛中一般不用

STC89C52RC为12T单片机而IAP15为1T单片机

特殊功能IO

内部RC振荡器(自带晶振)

IAP15仿真

参考教程“IAP15F2K61S2单片机仿真使用说明.pdf”19页
1、在stc-isp点击“Keil仿真设置”->“添加型号和头文件到Keil中”,将文件添加到目录中后,创建项目选择MCU型号为“STC15F2K60S2”(差不多)
2、在option里点击“Debug”设置仿真器选择呢“STC Monitor-51 Driver”,COM口选择相应的口,波特率选选最高或默认即可
3、创建仿真芯片选择“将IAP15F2K61S2设置为仿真芯片(5.0V版本)”
【注意】
1、P3.0和P3.1作为仿真使用的串口,如果操作P3.0和P3.1会导致仿真失败
2、软件延时指令集选择STC-Y5系统
3、断点是停止在此语句执行之前的

IAP15独有的功能

1、硬件PWM
2、ADC
3、定时器(数量更多功能更多)
4、串口(数量更多功能更多)

课后练习

1、熟悉如何使用IAP15单片机进行仿真
2、尝试用STC-ISP软件生成IAP15单片机的软件延时

=======================================================================

10、程序结构及注意事项

程序结构

1、定时器0:1ms中断一次
2、状态机消抖矩阵键盘函数
3、按键10ms中断
4、数码管3ms中断

#include "STC15F2K60S2.h"	 //不用再包含reg51.h
#define  u8 unsigned char

u8 code smg_du[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x00}; //0-9 
u8 code smg_wei[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};

#define KEY P3
#define NO_KEY  0xff  //无按键按下
#define KEY_STATE0  0   //判断按键按下
#define KEY_STATE1  1  //确认按键按下
#define KEY_STATE2  2  //释放
unsigned char Key_Scan()
{
 static unsigned char key_state=KEY_STATE0; 
 u8 key_value=0,key_temp;
 u8 key1,key2;
 
 P30=0;P31=0;P32=0;P33=0;P34=1;P35=1;P42=1;P44=1;
 if(P44==0)	key1=0x70;
 if(P42==0)	key1=0xb0;
 if(P35==0)	key1=0xd0;
 if(P34==0)	key1=0xe0;
 if((P34==1)&&(P35==1)&&(P42==1)&&(P44==1))	key1=0xf0;//没有按键
 
 P30=1;P31=1;P32=1;P33=1;P34=0;P35=0;P42=0;P44=0;
 if(P30==0)	key2=0x0e;
 if(P31==0)	key2=0x0d;
 if(P32==0)	key2=0x0b;
 if(P33==0)	key2=0x07;
 if((P30==1)&&(P31==1)&&(P32==1)&&(P33==1))	key2=0x0f;
 key_temp=key1|key2;
 
 switch(key_state)                                
 {
  case KEY_STATE0:
   if(key_temp!=NO_KEY)
   {
    key_state=KEY_STATE1;     //第一次确定有按键按下时后,给key_state赋值进入下一检查阶段     
   }
   break;

  case KEY_STATE1:
   if(key_temp==NO_KEY)
   {
    key_state=KEY_STATE0;//第二次检测没按下
   }
   else
   {
   switch(key_temp)                             
    {
		 case 0x77: key_value=4;break;
		 case 0x7b: key_value=5;break;
		 case 0x7d: key_value=6;break;
    	 case 0x7e: key_value=7;break;
			
		 case 0xb7: key_value=8;break;
		 case 0xbb: key_value=9;break;
		 case 0xbd: key_value=10;break;
    	 case 0xbe: key_value=11;break;
			
   	     case 0xd7: key_value=12;break;
		 case 0xdb: key_value=13;break;
		 case 0xdd: key_value=14;break;
		 case 0xde: key_value=15;break;
			
		 case 0xe7: key_value=16;break;
		 case 0xeb: key_value=17;break;
		 case 0xed: key_value=18;break;
		 case 0xee: key_value=19;break;	
    }
    key_state=KEY_STATE2;
   }
   break;
	 
   case KEY_STATE2:
   if(key_temp==NO_KEY)
   {
    key_state=KEY_STATE0;
   }
   break;
 }
 return key_value;
}

void Timer_Init(void) //1ms
{
		AUXR |= 0x80;	//1T timer	
		TMOD &= 0xF0;	// 16bit 
		TL0 = 0xCD;		
		TH0 = 0xD4;		
		TF0 = 0;		
		TR0 = 1;		
		ET0 = 1;
		EA=1; 
}

bit key_flag;
void main(void)
{
		u8 key_val=NO_KEY;	//检测的按键值
		P2=0xa0;P0=0x00;P2=0x00; // close buzzer and relay
		Timer_Init(); //1ms 
		while(1)
		{
			  if(key_flag) 	//10ms,每进一次中断key_flag加一,1ms中断进10次就是10ms
				{
					 key_flag=0;
					 key_val=Key_Scan();
					 switch(key_val)                       
					 {                                              
							case 4:  break;
							case 5:  break;
							case 6:  break;
							case 7:  break;
							case 8:  break;
							case 9:  break;
							case 10: break;
							case 11: break;
							case 12: break;
							case 13: break;
							case 14: break;
							case 15: break;
							case 16: break;
							case 17: break;
							case 18: break;
							case 19: break;
					 } 
				}
		 }
}

void timer0() interrupt 1  using 1                   
{
	static int key_count=0,smg_count=0,i=0;
	key_count++;smg_count++;
	if(key_count==10)			//10ms
	{
	 key_count=0;
	 key_flag=1;
	}
	
	if(smg_count==3)		//3ms
	{
			smg_count=0;
			P2=0xc0;P0=0;P2=0;				//消影
			P2=0xe0;P0=~smg_du[i];P2=0;
			P2=0xc0;P0=smg_wei[i];P2=0;
			i++;
			if(i==8) i=0;
	}
}
注意事项

1、头文件包含不同了。#include “STC15F2K6052.h”
2、使用STC-ISP软件中的定时器定时,语句中还要加上中断使能,例如ET0=1;EA=1;

课后练习

1、熟悉蓝桥杯模板的程序结构和函数
2、尝试自己编写类似的模板程序

11、客观题

1、熟悉CT107板子上的功能模块
2、熟悉8051系统单片机(微机原理)
3、熟悉SPI、IIC、Onewire、UART协议
4、熟悉运放基本原理和计算方法

  • 18
    点赞
  • 50
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值