单片机软件工程(一)--FIFO设计  



中午调一个程序,一个比较简单的程序,就是几个按键,一个数码管,使得用按键控制数码管上的数字,前提是不阻塞CPU!!(本来整个程序设计是不准备利用延时的,但是为了方便起见,数码管的扫描过程中,还是用了一个延时,有点阻塞CPU)对按键的扫描的过程中不能使用延时,而是利用前后台程序的思想进行设计,让按键扫描程序在定时中断10ms内进行,后台程序获取键值。因为单片机执行速度很快,为了防止漏键,设计一个FIFO隔离软件与硬件层,即:让后台程序只是从FIFO里面取键值,而前台也只是将键值保存在FIFO中,这样,可以防止漏键可惜,一不小心,在防止中断影响共享时,关了中断,就忘记了打开,结果一直没调试出来,后来一行一行找,才发现了这个低级错误,浪费了一中午的时间!!!!

FIFO设计:在单片机的程序设计过程 中,通常为了防止数据的丢失,利用FIFO来缓冲高速与低速设备的差异,这样可以保证数据在传输的过程中不会丢失。

程序设计如下:

/*********************************************************************************************
       
 /*********************************************************************************************
说明: 按键的设计:利用FIFO队列来进行数据的缓冲,这样CPU不直接操作硬件,而是通过键盘缓冲区来
 获取键盘的值。这样,可以将前台与后台程序隔离开来。消除了按键扫描与读键之间的时间关联性/*********************************************************************************************/
 /**********************************************************************************************/
 #include<reg51.h>      //常用的头文件
 #include <intrins.h> //51基本运算(包括_nop_空函数)
 //#include<dispy.h>    //模块接口 :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_keyif((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();
   
   }
 /**********************************************************************************************/
 /**********************************************************************************************/
 /**********************************************************************************************/
 /**********************************************************************************************/
 /**********************************************************************************************/