蓝桥杯国赛备赛

常用需记忆处

蜂鸣器
	P2 = 0xa0;	//选通触发器
	buzzer = 0;	//蜂鸣器不叫		//sbit buzzer = P0^6;
	P2 = 0x00	//不选通触发器
流水灯
	P2 = 0x80;	//使能Y4C
	P0 = ~(0x01<<i);
	P2 = 0x00;	//不使能Y4C,给P0赋值后一定要不使能Y4C
蜂鸣器、继电器
	P2 = 0xa0;
	P0 = 0x40;	//开蜂鸣器	//     P0 = 0x00;	//关蜂鸣器
	P2 = 0x00;
	P2 = 0xa0;
	P0 = 0x10;	//开蜂鸣器	//     P0 = 0x00;	//关蜂鸣器
	P2 = 0x00;

继电器和蜂鸣器最好一起操作,一个好的解决方法如下:设置连个人标志位,然后根据flag不同情况,写出四个函数放在while1的最后面

//bit buzzer_flag=0,relay_flag=0; //定义好变量
				if(buzzer_flag==1 && relay_flag==1)
				{
					P2 = 0xa0;P0 = 0x10;P2 = 0x00;//
					P2 = 0xa0;buzzer = 1;	P2 = 0x00;
					
				}
				if(buzzer_flag==0 && relay_flag==0)
				{
					P2 = 0xa0;P0 = 0x00;P2 = 0x00;//
					P2 = 0xa0;buzzer = 0;	P2 = 0x00;
				}
				if(buzzer_flag==1 && relay_flag==0)
				{
					P2 = 0xa0;P0 = 0x00;P2 = 0x00;//
					P2 = 0xa0;buzzer = 1;	P2 = 0x00;
					
				}
				if(buzzer_flag==0 && relay_flag==1)
				{
					P2 = 0xa0;P0 = 0x10;P2 = 0x00;//
					P2 = 0xa0;buzzer = 0;	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;
}

矩阵键盘

P4.2替代P3.6
P4.4替代P3.7

程序结构

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;
	}
}
经验

//数码管显示小数,例如显示8.,直接在显示之前让这个东西|0x80
//u8 float小数的位数
//u8范围是0~255,9999应该定义成unsigned int型
//ADC读取和发送时最好关闭中断,例如不关的话小灯会频繁的乱闪烁
ADC转化是除255,注意类型转换,humidity=(u8)(read_adc(0x03)/2.57f);
set_sfm(8,30,57);//在定时器初始化之前写,怕中断打扰
shi=Ds1302_Single_Byte_Read(0x85); //DS1302读取的是BCD,所以要除以16

1、u8 mode模式选择让变量为0,按下case7后让mode++;if(mode==2)mode=0; 让0和1切换
2、蜂鸣器和继电器需要一起操作,不然会受影响。假如要在一个情形下一个程序操作蜂鸣器,一个操作继电器,则最好定义relay_flag和buzzer_flag(1开0关)。写四个类似if(relay_flag==1 && buzzer_flag==1){}在while最后面
3、定义的显示界面数组是不用条件判断,直接在while循环里赋值就行,需要判断的中断函数里的显示数组选哪个。
4、数组不变的部分可以定义在while外

看省赛“程序思路对比”

关于仿真

因为按键会设计P30和P31所以会影响到仿真,只要把用了P30和P31的函数关掉就好了,就是注释掉key_temp=Read_Key();这一句即可

IIC

24c02讲解的很详细:
http://www.cnblogs.com/whik/p/6650092.html

关于以前读ad值出现的问题及分析

现象:
省赛时读Ad值时使用0x03控制,读AIN3通道三时只会出0/64/128或者旋转电位器数值不变,而改变成0x43时候就可以正常显示了
分析:

区别在bit2,自动增量使能位,如果自动增量(auto-increment)标志置1,每次A/D 转换后通道号将自动增加,原因就是没有修改IIC驱动里的延时时间,官方驱动适合12T单片机,而比赛板是1T,故延时函数应该改为原来的12倍才行,但现在没变,即速度太快,auto-increment置1后自动切换通道,4个通道为一组,看起来速度就慢了一些,勉强符合时序要求,于是显示成功

ad转换

#define fun(x) (int)(5x/255.0100+0.5) //数字电压x转换为模拟电压的公式
加0.5是可以让四舍五入,因为C里会舍弃小数部分

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值