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;
}
2068

被折叠的 条评论
为什么被折叠?



