Mkdm的51单片机学习日记:RAM区域划分与长短按键的应用

10.4  51单片机RAM区域的划分

STC89C52一共有512字节的RAM,这512字节是分块的,块与块之间物理结构和用法有区别

51单片机的RAM分为片内和片外,片内RAM地址:0x00H到0x7F,一共128B

同时加上扩展片内RAM,总共是0x00到0xFF一共256B

片外RAM地址:0x0000到0xFFFF,一共64KB

在如今的51单片机内,片外RAM也一般封装在芯片内

我们可以使用以下关键字来实现数据存储到相应的RAM区域内:

data:片内,0x00到0x7F,默认位置,执行速度最快

idata:  片内,0x00到0xFF,间接寻址,速度较慢

pdata:片外,0x00到0xFF,间接寻址

xdata:片外:0x0000到0xFFFF,速度最慢

使用方法:unsigned char data a;    定义一个a变量在data区域

一般我们都使用data,data不够了就用xdata,如果要速度就用pdata

10.5  长短按键的应用

长按的定义:按下超过1s

长短按键的实现:我们定义了一个全局中的long类型数组keyDownTime用来存储每一个按键按下的时间,具体就是在keyScan函数的判断抖动环节中每次达到后四位是0说明被按下时间有4ms,所以每次都加上4ms,而如果有一次判断为后四位全是1,那么可以keyDownTime归零

在main函数一直在调用的keyDriver函数中定义了一个long类型的二维数组timeThr用来存储每个按键按下的阈值,当达到阈值时候去执行一次keyAction,而阈值一定要有所增加,防止main函数很快又循环到这个地方再进行一次keyAction

在上面我们定义了两个long类型的16个元素的数组,而我们平常所使用的data只有256B,所以我们在定义这两个大数组的时候我们要加上pdata关键字,把他们放到片外的RAM里面

而我们使用的proteus中当我使用了xdata或者pdata以后(在下面有操作方法)发现明显数码管和按键扫描变慢,数码管不能完成动态显示,按键按下也不能有很好的反应

使用xdata或者pdata操作方法:keil中:project→options for target→memory model换成xdata

proteus中:点击芯片→advanced properties→pdata改为00-FF,xdata改成0000-FFFF

proteus中跑不出来的解决办法:压缩程序的占用空间,不使用pdata和xdata,保证运行速度

1)我们原来调用了一个定时器,led,按键还有到达1s的计算都用了一个1ms的定时器,到达1s需要1000次,导致了我们必须使用long的keyDownTime和timeThr,造成了极大的空间占用                所以我们再调用一个定时器,把keyScan,ledScan与1s的计算分成两个定时器操作,Timer1负责1s的计算,每50ms中断一次,这样keyDownTime数组初值只需要20就可以,我们就可以把这两个数组的类型改为char

但是这样只解决了内存的问题,还有一个严重的问题:我们通过1ms定时器去调用keyScan函数,keyScan函数中又包含了keyDownTime的更新,每次消抖都加上4ms,但是我们的数组初值是20*50ms,加上4ms甚至不能变成21*50ms,所以我们选择我们选择250*4ms的中断来判断是否到达1s,但这样也会导致250ms的阈值加上一点就超过了char的255极限,不能实现阈值的更新,所以我们这里只能改变一下长按的时间了(这里是proteus这个老仿真跑不出来的无奈方法,如果跑不出来再尝试这个):我的定时器为50ms,数组阈值为150,并且每过4ms,keyDownTime加1直到150,也就是说过了150个4ms也就是0.6s的时间开始算长按,但是我们在更新阈值时很容易加到溢出255,所以一直按的时候会有卡顿感,是因为溢出以后又用时间到达150的阈值

2)将configTimer1和configTimer0函数给删除了,改成了手动计算时间,节约了两个long的空间

3)countDown从long改成了char,所以我们只能使用255s以内的定时功能

下面我们用一个定时炸弹的例子来说明,长按向上键countDown持续加,长按向下键countDown持续减,按下回车开始计时,到达0以后蜂鸣器响并且led灯全闪烁模拟爆炸:

代码如下:

#include <reg52.h>

sbit BUZZ  = P1^6;
sbit ADDR3 = P1^3;
sbit ENLED = P1^4;
sbit KEY_IN_1  = P2^4;
sbit KEY_IN_2  = P2^5;
sbit KEY_IN_3  = P2^6;
sbit KEY_IN_4  = P2^7;
sbit KEY_OUT_1 = P2^3;
sbit KEY_OUT_2 = P2^2;
sbit KEY_OUT_3 = P2^1;
sbit KEY_OUT_4 = P2^0;



unsigned char code ledChar[] = {  
    0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8,
    0x80, 0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E
};


unsigned char ledBuff[7] = {  
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};


unsigned char code keyCodeMap[4][4] = { 
    { 0x31, 0x32, 0x33, 0x26 }, //Êý×Ö¼ü1¡¢Êý×Ö¼ü2¡¢Êý×Ö¼ü3¡¢ÏòÉϼü
    { 0x34, 0x35, 0x36, 0x25 }, //Êý×Ö¼ü4¡¢Êý×Ö¼ü5¡¢Êý×Ö¼ü6¡¢Ïò×ó¼ü
    { 0x37, 0x38, 0x39, 0x28 }, //Êý×Ö¼ü7¡¢Êý×Ö¼ü8¡¢Êý×Ö¼ü9¡¢Ïòϼü
    { 0x30, 0x1B, 0x0D, 0x27 }  //Êý×Ö¼ü0¡¢ESC¼ü¡¢  »Ø³µ¼ü¡¢ ÏòÓÒ¼ü
};


unsigned char keySta[4][4] = {  
    {1, 1, 1, 1},  {1, 1, 1, 1},  {1, 1, 1, 1},  {1, 1, 1, 1}
};


unsigned char  keyDownTime[4][4]=
{
	{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}
};


bit enBuzz=0;
bit flag1s=0;
bit flagStart=0;
//unsigned char T0RH=0;
//unsigned char T0RL=0;
unsigned int countDown=0;

//void configTimer0(unsigned int ms);
void keyDriver();
void showNumber(unsigned char num);

void main()
{
	EA=1;
	ENLED=0;
	ADDR3=1;
	TH0=0xFC;
	TL0=0x67;
	TH1=0x4C;
	TL1=0x00;
	TMOD=0x11;
	ET0=1;
	TR0=1;
	ET1=1;
	TR1=1;
	
	showNumber(0);
	while(1)
	{
		keyDriver();
		if(flag1s&&flagStart)
		{
			flag1s=0;
			if(countDown>0)
			{
				countDown--;
				showNumber(countDown);
				
				
				if(countDown==0)
				{
					ledBuff[6]=0x00;
					enBuzz=1;
				}
			}
			
			
			
		}
		
	}
}
/*
void configTimer0(unsigned int ms)
{
	unsigned long tmp=0;
	
	tmp=ms*11059200/12/1000;
	tmp=65536-tmp;
	T0RH=(unsigned char)(tmp>>8);
	T0RL=(unsigned char)tmp;
	
	TH0=T0RH;
	TL0=T0RL;
	TMOD&=0xF0;
	TMOD|=0x01;
	ET0=1;
	TR0=1;
}
*/
void showNumber(unsigned char num)
{
	unsigned char buf[6];
	signed char i=0;
	
	for(i=0;i<6;i++)
	{
		buf[i]=num%10;
		num/=10;
	}
	
	for(i=5;i>=1;i--)
	{
		if(buf[i]==0)ledBuff[i]=0xFF;
		else break;
	}
	
	for(;i>=0;i--)
	{
		ledBuff[i]=ledChar[buf[i]];
	}
	
}


void keyAction(unsigned char keycode)
{
	//static unsigned long current=0;
	
	if(keycode==0x26)
	{
		if(countDown<=9999)
		countDown++;
		showNumber(countDown);
	}
	
	else if(keycode==0x28)
	{
		if(countDown>0)
		{
			countDown--;
			showNumber(countDown);
		}
		
	}
	
	else if(keycode==0x1B)
	{
		enBuzz=0;
		ledBuff[6]=0xFF;
		flagStart=0;
		countDown=0;
		showNumber(countDown);
	}
	
	else if(keycode==0x0D)
	{
		flagStart=1;
	}
	
	else if(keycode>=0x30&&keycode<=0x39)
	{
		countDown=countDown*10+(keycode-0x30);
		showNumber(countDown);
	}
	
	
}



void keyDriver()
{
	unsigned char i,j;
	static unsigned char backup[4][4]=
	{
		{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1}
	};
	
	static unsigned char timeThr[4][4]=
	{
		{150, 150, 150, 150}, {150, 150, 150, 150},
        {150, 150, 150, 150},{150, 150, 150, 150}
	};
	
	for(i=0;i<4;i++)
	{
		for(j=0;j<4;j++)
		{
			if(backup[i][j]!=keySta[i][j])
			{
				if(backup[i][j]!=0)
				{
					keyAction(keyCodeMap[i][j]);
				}
				backup[i][j]=keySta[i][j];
			}
			if(keyDownTime[i][j]>0)
			{
				if(keyDownTime[i][j]>=timeThr[i][j])
				{
					keyAction(keyCodeMap[i][j]);
					timeThr[i][j]+=10;
				}
				
			}
			else
					timeThr[i][j]=200;
			
		}
	}
	
	
	
	
	
	
}

void keyScan()
{
	static unsigned char keybuf[4][4]={
		{0xFF,0xFF,0xFF,0xFF},{0xFF,0xFF,0xFF,0xFF},
		{0xFF,0xFF,0xFF,0xFF},{0xFF,0xFF,0xFF,0xFF}
	};
	unsigned char i;
	static unsigned char keyout=0;
	
	keybuf[keyout][0]=(keybuf[keyout][0]<<1)|KEY_IN_1;
	keybuf[keyout][1]=(keybuf[keyout][1]<<1)|KEY_IN_2;
	keybuf[keyout][2]=(keybuf[keyout][2]<<1)|KEY_IN_3;
	keybuf[keyout][3]=(keybuf[keyout][3]<<1)|KEY_IN_4;
	
	for(i=0;i<4;i++)
	{
		if((keybuf[keyout][i]&0x0F)==0x0F){keySta[keyout][i]=1;keyDownTime[keyout][i]=0;}
		if((keybuf[keyout][i]&0x0F)==0x00){keySta[keyout][i]=0;keyDownTime[keyout][i]+=1;}
	}
	
	keyout++;
	keyout&=0x03;
	switch(keyout)
	{
		case 0:KEY_OUT_4=1;KEY_OUT_1=0;break;
		case 1:KEY_OUT_1=1;KEY_OUT_2=0;break;
		case 2:KEY_OUT_2=1;KEY_OUT_3=0;break;
		case 3:KEY_OUT_3=1;KEY_OUT_4=0;break;
		default:break;
	}
	
	
}

void ledScan()
{
	static unsigned char i=0;
	
	P0=0xFF;
	P1=(P1&0xF8)|i;
	P0=ledBuff[i];
	
	if(i<6)i++;
	else i=0;
	
}

void InterruptTimer0() interrupt 1
{
	
	
	TH0=0xFC;
	TL0=0x67;
	
	
	if(enBuzz==1)BUZZ=~BUZZ;
	else BUZZ=1;
	
	ledScan();
	keyScan();
	
}

void InterruptTimer1() interrupt 3
{
	static unsigned int tmr1s=0;
	
	TH1=0x4C;
	TL1=0x00;
	
	if(flagStart)
	{
		tmr1s++;
		if(tmr1s>=50)
		{
			tmr1s=0;
			flag1s=1;
		}
		
	}
	else tmr1s=0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值