单片机软件工程(一)--FIFO设计
中午调一个程序,一个比较简单的程序,就是几个按键,一个数码管,使得用按键控制数码管上的数字,前提是不阻塞CPU!!(本来整个程序设计是不准备利用延时的,但是为了方便起见,数码管的扫描过程中,还是用了一个延时,有点阻塞CPU)对按键的扫描的过程中不能使用延时,而是利用前后台程序的思想进行设计,让按键扫描程序在定时中断10ms内进行,后台程序获取键值。因为单片机执行速度很快,为了防止漏键,设计一个FIFO隔离软件与硬件层,即:让后台程序只是从FIFO里面取键值,而前台也只是将键值保存在FIFO中,这样,可以防止漏键可惜,一不小心,在防止中断影响共享时,关了中断,就忘记了打开,结果一直没调试出来,后来一行一行找,才发现了这个低级错误,浪费了一中午的时间!!!!
FIFO设计:在单片机的程序设计过程 中,通常为了防止数据的丢失,利用FIFO来缓冲高速与低速设备的差异,这样可以保证数据在传输的过程中不会丢失。
程序设计如下:
/*********************************************************************************************
/*********************************************************************************************
说明: 按键的设计:利用FIFO队列来进行数据的缓冲,这样CPU不直接操作硬件,而是通过键盘缓冲区来
获取键盘的值。这样,可以将前台与后台程序隔离开来。消除了按键扫描与读键之间的时间关联性
/*********************************************************************************************/
/**********************************************************************************************/
#include //常用的头文件
#include //51基本运算(包括_nop_空函数)
//#include //模块接口 :display()扫描,send_dat(uint dat)显示数据,前者放在定时器里面,后者放在后台
#define uchar unsigned char
#define ulong unsigned long
#define uint unsigned int
#define size 4
void key_buffer(uchar key);
uchar key_get();
sbit KEY1_IN=P3^7;
sbit KEY2_IN=P3^6;
sbit dula=P2^6; //控制数码管位选的使能
sbit wela=P2^7; //控制数码管段选的使能,低电平位选中
//sbit KEY2_IN=P3^6;
//sbit KEY3_IN=P3^7;
uchar P_key1=255; //存放按键前一次状态的变量
uchar N_key1=255; // 存放下一次按键的状态,通过定时器中断(10ms)的扫描便可以确定是否被按下
uchar key_max=0;
uchar key_min=0;
uchar count=0; //定义FIFO的头指针,尾指针,与指针计数
uchar key_inbuff[size]; //定义FIFO的容量
static uchar temp;
uchar P_key2=255; //存放按键前一次状态的变量
uchar N_key2=255; // 存放下一次按键的状态,通过定时器中断(10ms)的扫描便可以确定是否被按下
//uchar P_key3=255; //存放按键前一次状态的变量
//uchar N_key3=255; // 存放下一次按键的状态,通过定时器中断(10ms)的扫描便可以确定是否被按下
unsigned char code table[11]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x40};//数码管数据
/**********************按键1扫描***************************************************************/
void key_scan() //放在10ms的中断函数里面执行
{
P_key1=N_key1; //每扫描一次,则把下一次的状态给当前(即把后一次的给前一次)
N_key1=KEY1_IN; //按键此时的状态给N_key
P_key2=N_key2; //每扫描一次,则把下一次的状态给当前(即把后一次的给前一次)
N_key2=KEY2_IN; //按键此时的状态给N_key
// P_key3=N_key3; //每扫描一次,则把下一次的状态给当前(即把后一次的给前一次)
// N_key3=KEY3_IN; //按键此时的状态给N_key
if((P_key1!=0)&&(N_key1==0)) //表示按键被按下
key_buffer(0x01); //可以代表键值,可也以用此表征键被按下
if((P_key2!=0)&&(N_key2==0)) //表示按键被按下
key_buffer(0x02); //可以代表键值,可也以用此表征键被按下
}
/**********************按键2扫描***************************************************************/
/***********************将键值数据压入FIFO****************************************************/
void key_buffer(uchar key) // 设计一FIFO,将键值压入FIFO
{
if (count>=size) return;
EA=0; //防止数据被 中断
count++; //按键次数递增
key_inbuff[key_max] =key; //压入FIFO
if (++key_max>=size) //如果越界,而从头部追加新的数据
{
key_max=0;
}
EA=1;
}
/**********************************************************************************************/
void delayms(uint z) //ms级延时函数
{ uint x,y;
for(x=z;x>0;x--)
for(y=110;y>0;y--);
}
/**********************************************************************************************/
void display(uchar a) //第一个数码管亮 位选
{
wela=0;
P0=0xfe;
wela=1;
wela=0;
dula=0;
P0=table[a]; //显示最高位
dula=1;
dula=0;
delayms(2);
}
/**********************************************************************************************/
uchar key_get(void) // 从FIFO里面取出键值
{
uchar key;
if(count==0) return(0); //如果没数据,返回0
EA=0;
count--;
key=key_inbuff[key_min];
if (++key_min>=size)
{
key_min=0;
}
EA=1;
return(key);
}
/**********************************************************************************************/
/**********************************************************************************************/
void timer_init(void)
{
TMOD=0x10;
TH1=(65536-15000)/256; //时间为1ms
TL1=(65536-15000)%256;
EA=1;
ET1=1;
TR1=1;
}
/**********************************************************************************************/
void main()
{
uchar i ;
timer_init();
while(1)
{
temp= key_get(); //获取键值
if(temp==0x01) //按键进行处理
{
i++;
if(i==9)
i=0;
display(i);
}
if (temp==0x02)
{
display(5);
}
}
}
/**********************************************************************************************/
void time1(void)interrupt 3 //以每15ms对按键进行扫描
{
TH1=(65536-15000)/256;
TL1=(65536-15000)%256;
key_scan();
}
/**********************************************************************************************/
/**********************************************************************************************/
/**********************************************************************************************/
/**********************************************************************************************/
/**********************************************************************************************/
原文地址http://li19910722.blog.163.com/blog/static/136856822201141814614750/