16

/*******************************************************
工 程 名:利用光电编码器实现转角、转速同步测试系统
功能介绍:按键选择功能,1键选择测量转角,2键选择测量转速,
         3键选择分频。F键确认,E键退出.
编译环境:KEIL+C
********************************************************/

/******************************************************
文件:main.c
******************************************************/
#include<reg51.h>
#include<intrins.h>
#include<zlg7290.c>
#include<lcd1602.c>

//#define uchar unsigned char
//#define uint unsigned int

sbit dir0=P2^5;     //74245读写控制端
sbit g1=P1^1;     //82C54定时器T0的门控信号
sbit g2=P1^2;     //82C54定时器T2的门控信号
sbit a1=P3^6;     //82C54通道选择控制端A1
sbit a0=P3^7;     //82C54通道选择控制端A0
sbit wr=P2^6;     //82C54的写允许端
sbit rd=P2^7;     //82C54的读允许端
uint mode;      //用以记录选择的功能模式

/*void delayms(uint z)
{
 uint y;
 for(;z>0;z–)
     for(y=0;y<124;y++);
}*/
/**************************************************
    82C54控制模块
***************************************************/
void wr_c(uchar com)      //82C54的写控制字函数
{
 uint i;
 a1=1;
 a0=1;
 P0=com;
 dir0=1;
 wr=0;
 for(i=0;i<1;i++);
 wr=1;
}

void wr_d(uchar dat,bit aa1,bit aa0)  //82C54的写入数据函数,aa1 aa0为00是通道00,为01是通道1,为10是通道2
{
 uint i;
 a1=aa1;
 a0=aa0;
 P0=dat;
 dir0=1;
 wr=0;
 for(i=0;i<2;i++);
 wr=1;
}

uint rd_d(bit aa1,bit aa0)     //82C54的读入数据函数,aa1 aa0为00是通道00,为01是通道1,为10是通道2
{
 uint dat;
 uint i;
 a1=aa1;
 a0=aa0;
 P0=0xff;
 dir0=0;
 rd=0;
 for(i=0;i<2;i++);
 dat=P0;
 rd=1;
 for(i=0;i<5;i++);
 rd=0;
 for(i=0;i<2;i++);
 dat|=P0<<8;
 rd=1;
 dir0=1;
 return dat;
}

void init8254()        //82C54的初始化函数
{
 wr_c(0×34);        //计数器0,工作方式2,二进制计数
 delay1(2);
 wr_c(0×74);        //计数器1,工作方式2,二进制计数
 delay1(2);
 wr_c(0xb6);        //计数器2,工作方式3,二进制计数
 delay1(2);
 wr_d(0,0,0);
 wr_d(0,0,0);
 wr_d(0,0,1);
 wr_d(0,0,1);
}

/************************************************
   三种功能模式的处理函数
*************************************************/
void zhuanjiao()  //选择功能1,测转角函数
{
 uint dat,i;
 uchar wan,qian,bai,shi,ge;
 lcd_write_com(0x0c);
 lcd_write_com(0×01);
 lcd_write_com(0×80);
 for(i=0;i<13;i++)
 {
  lcd_write_dat(display1[i]);
  delay1(5);
 }
 while(key!=14)
 {
  if(P3^2==0)
  dat=rd_d(0,1);
  dat=65536-dat;
  wan=dat/10000;
  qian=(dat/1000)%10;
  bai=(dat/100)%10;
  shi=(dat/10)%10;
  ge=dat%10;
  lcd_write_com(0×80+0×40+10);
  lcd_write_dat(number[wan]);
  lcd_write_dat(number[qian]);
  lcd_write_dat(number[bai]);
  lcd_write_dat(number[shi]);
  lcd_write_dat(number[ge]);
  delay1(1000);
 }
}

void zhuansu()  //选择功能2,测转速函数
{
 uint dat,i;
 uchar wan,qian,bai,shi,ge;
 lcd_write_com(0x0c);
 lcd_write_com(0×01);
 lcd_write_com(0×80);
 for(i=0;i<13;i++)
 {
  lcd_write_dat(display2[i]);
  delay1(5);
 }
 while(key!=14)
 {
  g1=1;
  delay1(1000);
  g1=0;
  dat=rd_d(0,0);
  dat=65536-dat;
  wan=dat/10000;
  qian=(dat/1000)%10;
  bai=(dat/100)%10;
  shi=(dat/10)%10;
  ge=dat%10;
  lcd_write_com(0×80+0×40+10);
  lcd_write_dat(number[wan]);
  lcd_write_dat(number[qian]);
  lcd_write_dat(number[bai]);
  lcd_write_dat(number[shi]);
  lcd_write_dat(number[ge]);
  delay1(1000);
 }
}

void fenpin()  //选择功能3,分频函数
{
 uint dat,i;
 uchar dath,datl,bai,shi,ge;
 bit flag;
 lcd_write_com(0x0c);
 lcd_write_com(0×01);
 lcd_write_com(0×80);
 for(i=0;i<16;i++)
 {
  lcd_write_dat(display3[i]);
  delay1(5);
 }
 flag=1;
 while(flag)
 {
  switch(key)
  {
   case 0:
    bai=0;
    lcd_write_com(0×80+0×40+10);
    lcd_write_dat(number[0]);
    break;
   case 1:
    bai=1;
    lcd_write_com(0×80+0×40+10);
    lcd_write_dat(number[1]);
    break;
   case 2:
    bai=2;
    lcd_write_com(0×80+0×40+10);
    lcd_write_dat(number[2]);
    break;
   case 3:
    bai=3;
    lcd_write_com(0×80+0×40+10);
    lcd_write_dat(number[3]);
    break;
   case 4:
    bai=4;
    lcd_write_com(0×80+0×40+10);
    lcd_write_dat(number[4]);
    break;
   case 5:
    bai=5;
    lcd_write_com(0×80+0×40+10);
    lcd_write_dat(number[5]);
    break;
   case 6:
    bai=6;
    lcd_write_com(0×80+0×40+10);
    lcd_write_dat(number[6]);
    break;
   case 7:
    bai=7;
    lcd_write_com(0×80+0×40+10);
    lcd_write_dat(number[7]);
    break;
   case 8:
    bai=8;
    lcd_write_com(0×80+0×40+10);
    lcd_write_dat(number[8]);
    break;
   case 9:
    bai=9;
    lcd_write_com(0×80+0×40+10);
    lcd_write_dat(number[9]);
    break;
   case 15:
    flag=0;
    break;
  }
 }
 key=16;
 flag=1;
 while(flag)
 {
  switch(key)
  {
   case 0:
    shi=0;
    lcd_write_com(0×80+0×40+11);
    lcd_write_dat(number[0]);
    break;
   case 1:
    shi=1;
    lcd_write_com(0×80+0×40+11);
    lcd_write_dat(number[1]);
    break;
   case 2:
    shi=2;
    lcd_write_com(0×80+0×40+11);
    lcd_write_dat(number[2]);
    break;
   case 3:
    shi=3;
    lcd_write_com(0×80+0×40+11);
    lcd_write_dat(number[3]);
    break;
   case 4:
    shi=4;
    lcd_write_com(0×80+0×40+11);
    lcd_write_dat(number[4]);
    break;
   case 5:
    shi=5;
    lcd_write_com(0×80+0×40+11);
    lcd_write_dat(number[5]);
    break;
   case 6:
    shi=6;
    lcd_write_com(0×80+0×40+11);
    lcd_write_dat(number[6]);
    break;
   case 7:
    shi=7;
    lcd_write_com(0×80+0×40+11);
    lcd_write_dat(number[7]);
    break;
   case 8:
    shi=8;
    lcd_write_com(0×80+0×40+11);
    lcd_write_dat(number[8]);
    break;
   case 9:
    shi=9;
    lcd_write_com(0×80+0×40+11);
    lcd_write_dat(number[9]);
    break;
   case 15:
    flag=0;
    break;
  }
 }
 key=16;
 flag=1;
 while(flag)
 {
  switch(key)
  {
   case 0:
    ge=0;
    lcd_write_com(0×80+0×40+12);
    lcd_write_dat(number[0]);
    break;
   case 1:
    ge=1;
    lcd_write_com(0×80+0×40+12);
    lcd_write_dat(number[1]);
    break;
   case 2:
    ge=2;
    lcd_write_com(0×80+0×40+12);
    lcd_write_dat(number[2]);
    break;
   case 3:
    ge=3;
    lcd_write_com(0×80+0×40+12);
    lcd_write_dat(number[3]);
    break;
   case 4:
    ge=4;
    lcd_write_com(0×80+0×40+12);
    lcd_write_dat(number[4]);
    break;
   case 5:
    ge=5;
    lcd_write_com(0×80+0×40+12);
    lcd_write_dat(number[5]);
    break;
   case 6:
    ge=6;
    lcd_write_com(0×80+0×40+12);
    lcd_write_dat(number[6]);
    break;
   case 7:
    ge=7;
    lcd_write_com(0×80+0×40+12);
    lcd_write_dat(number[7]);
    break;
   case 8:
    ge=8;
    lcd_write_com(0×80+0×40+12);
    lcd_write_dat(number[8]);
    break;
   case 9:
    ge=9;
    lcd_write_com(0×80+0×40+12);
    lcd_write_dat(number[9]);
    break;
   case 15:
    flag=0;
    break;
  }
 }
 key=16;
 flag=1;
 dat=ge*2+shi*20+bai*200;
 g2=1;
 datl=dat;
 dath=dat>>8;
 wr_d(datl,1,0);
 wr_d(dath,1,0);
 while(key!=14);
}

//查询选择什么功能的函数
void chaxun()
{
 uint i;
 bit flag=1;
 lcd_write_com(0×01);
 lcd_write_com(0×80);
 for(i=0;i<16;i++)
 {
  lcd_write_dat(init1[i]);
  delay1(5);
 }
 lcd_write_com(0×80+0×40);
 for(i=0;i<11;i++)
 {
  lcd_write_dat(init2[i]);
  delay1(5);
 }
 while(flag)
 {
  switch(key)
  {
   case 1:
   {
    lcd_write_com(0x0f);
    lcd_write_com(0×80);
    lcd_write_dat(number[1]);
    mode=1;
    break;
   }
   case 2:
   { 
    lcd_write_com(0x0f);
    lcd_write_com(0×80+9);
    lcd_write_dat(number[2]);
    mode=2;
    break;
   }
   case 3:
   { 
    lcd_write_com(0x0f);
    lcd_write_com(0×80+40);
    lcd_write_dat(number[3]);
    mode=3;
    break;
   }
   case 15: flag=0;
   default:  key=16;
  }
 }
 switch(mode)
 {
  case 1:
  {
   while(key!=14)
    zhuanjiao();
   break;
  }
  case 2:
  {
   while(key!=14)
    zhuansu();
   break;
  }
  case 3:
  {
   while(key!=14)
    fenpin();
   break;
  }
 }
 key=16;
}

//主函数入口
void main()
{
 init8254();
 init_lcd();
 EA=1;
 EX1=1;
 while(1)
  chaxun();
}

//外部中断1的处理函数,当有按键按下后自动调用该函数
void zhongduan() interrupt 2
{
 uchar getkey;
 EX1=0;
 getkey=ZLG7290_GetKey();
 switch(getkey)
 {
  case 25: key=12;break;
  case 26: key=13;break;
  case 27: key=14;break;
  case 28: key=15;break;
  case 17: key=9;break;
  case 18: key=0;break;
  case 19: key=10;break;
  case 20: key=11;break;
  case  9: key=5;break;
  case 10: key=6;break;
  case 11: key=7;break;
  case 12: key=8;break;
  case  1: key=1;break;
  case  2: key=2;break;
  case  3: key=3;break;
  case  4: key=4;break;
  default: key=16;
 }
 EX1=1;
}

/*******************************************************
文件:zlg7290.c
********************************************************/

#include <reg51.h>
#include <intrins.h>

#define uchar unsigned char
#define uchar unsigned char
#define uint  unsigned int

/*———————————–ZLG7290键盘接口——————————————–*/
#define  _Nop()  _nop_()        /*定义空指令*/
#define zlg7290 0×70 //ZLG7290的IIC地址

#define SubKey  0×01
#define SubCmdBuf 0×07
#define SubDpRam 0×10

sbit ZLG_INT = P3^3;
sbit SCL = P3^4;
sbit SDA = P3^5;

bit ack;
unsigned char key;
void Delay(unsigned int count)
{
 unsigned int i,j;
 for(i=0;i<count;i++)
 for(j=0;j<120;j++);
}

/****************************IIC程序*******************************/
/*******************************************************************
                     起动总线函数              
函数原型: void  Start_I2c(); 
功能:       启动I2C总线,即发送I2C起始条件.
 
********************************************************************/
void Start_I2c()
{
  SDA=1;        /*发送起始条件的数据信号*/
  Delay(1); 
  SCL=1;
  Delay(5);          /*起始条件建立时间大于4.7us,延时*/
  _Nop();
  _Nop();
  _Nop();
  _Nop();   
  SDA=0;        /*发送起始信号*/
  Delay(5);          /* 起始条件锁定时间大于4μs*/
  _Nop();
  _Nop();
  _Nop();
  _Nop();      
  SCL=0;        /*钳住I2C总线,准备发送或接收数据 */
  Delay(2); 
  _Nop();
}

 
/*******************************************************************
                      结束总线函数              
函数原型: void  Stop_I2c(); 
功能:       结束I2C总线,即发送I2C结束条件.
 
********************************************************************/
void Stop_I2c()
{
  SDA=0;       /*发送结束条件的数据信号*/
  _Nop();        /*发送结束条件的时钟信号*/
  SCL=1;       /*结束条件建立时间大于4μs*/
  Delay(5); 
  SDA=1;       /*发送I2C总线结束信号*/
  Delay(4); 
}

 
/*******************************************************************
                 字节数据传送函数              
函数原型: void  SendByte(uchar c);
功能:  将数据c发送出去,可以是地址,也可以是数据,发完后等待应答,并对
     此状态位进行操作.(不应答或非应答都使ack=0 假)    
     发送数据正常,ack=1; ack=0表示被控器无应答或损坏。
********************************************************************/
void  SendByte(unsigned char c)
{
 uchar BitCnt;
 
 for(BitCnt=0;BitCnt<8;BitCnt++)  /*要传送的数据长度为8位*/
    {
     if((c<<BitCnt)&0×80)SDA=1;   /*判断发送位*/
       else  SDA=0;               
     Delay(1); 
     SCL=1;               /*置时钟线为高,通知被控器开始接收数据位*/
      Delay(5);                 /*保证时钟高电平周期大于4μs*/
      _Nop();
      _Nop();
      _Nop();        
     SCL=0;
    }
   
    Delay(2); 
    SDA=1;               /*8位发送完后释放数据线,准备接收应答位*/
    Delay(2);    
    SCL=1;
    Delay(2); 
    if(SDA==1)ack=0;    
       else ack=1;        /*判断是否接收到应答信号*/
    SCL=0;
    Delay(2); 
}

 

 
/*******************************************************************
                 字节数据传送函数              
函数原型: uchar  RcvByte();
功能:  用来接收从器件传来的数据,并判断总线错误(不发应答信号),
     发完后请用应答函数。 
********************************************************************/ 
uchar  RcvByte()
{
  uchar retc;
  uchar BitCnt;
 
  retc=0;
  SDA=1;             /*置数据线为输入方式*/
  for(BitCnt=0;BitCnt<8;BitCnt++)
      {
        Delay(1);            
        SCL=0;       /*置时钟线为低,准备接收数据位*/
        Delay(5);           /*时钟低电平周期大于4.7μs*/
        SCL=1;       /*置时钟线为高使数据线上数据有效*/
        Delay(2); 
        retc=retc<<1;
        if(SDA==1)retc=retc+1; /*读数据位,接收的数据位放入retc中 */
        Delay(2);  
      }
  SCL=0;   
  Delay(2);  ;
  return(retc);
}

 
/********************************************************************
                     应答子函数
原型:  void Ack_I2c(bit a);
 
功能:主控器进行应答信号,(可以是应答或非应答信号)
********************************************************************/
void Ack_I2c(bit a)
{
 
  if(a==0)SDA=0;     /*在此发出应答或非应答信号 */
        else SDA=1;
  _Nop();
  _Nop();
  _Nop();     
  SCL=1;
    Delay(5);             /*时钟低电平周期大于4μs*/
 SCL=0;                /*清时钟线,钳住I2C总线以便继续接收*/
    Delay(2); 
}

 

 
/*******************************************************************
                    向无子地址器件发送字节数据函数              
函数原型: bit  ISendByte(uchar sla,ucahr c); 
功能:     从启动总线到发送地址,数据,结束总线的全过程,从器件地址sla.
           如果返回1表示操作成功,否则操作有误。
注意:    使用前必须已结束总线。
********************************************************************/
bit ISendByte(uchar sla,uchar c)
{
   Start_I2c();               /*启动总线*/
   SendByte(sla);            /*发送器件地址*/
     if(ack==0)return(0);
   SendByte(c);               /*发送数据*/
     if(ack==0)return(0);
  Stop_I2c();                 /*结束总线*/
  return(1);
}

 
/*******************************************************************
                    向有子地址器件发送多字节数据函数              
函数原型: bit  ISendStr(uchar sla,uchar suba,ucahr *s,uchar no); 
功能:     从启动总线到发送地址,子地址,数据,结束总线的全过程,从器件
          地址sla,子地址suba,发送内容是s指向的内容,发送no个字节。
           如果返回1表示操作成功,否则操作有误。
注意:    使用前必须已结束总线。
********************************************************************/
bit ISendStr(uchar sla,uchar suba,uchar *s,uchar no)
{
   uchar i;

   Start_I2c();               /*启动总线*/
   SendByte(sla);            /*发送器件地址*/
     if(ack==0)return(0);
   SendByte(suba);            /*发送器件子地址*/
     if(ack==0)return(0);

   for(i=0;i<no;i++)
    {  
     SendByte(*s);               /*发送数据*/
       if(ack==0)return(0);
     s++;
    }
 Stop_I2c();                 /*结束总线*/
  return(1);
}

 

 
/*******************************************************************
                    向无子地址器件读字节数据函数              
函数原型: bit  IRcvByte(uchar sla,ucahr *c); 
功能:     从启动总线到发送地址,读数据,结束总线的全过程,从器件地
          址sla,返回值在c.
           如果返回1表示操作成功,否则操作有误。
注意:    使用前必须已结束总线。
********************************************************************/
bit IRcvByte(uchar sla,uchar *c)
{
   Start_I2c();                /*启动总线*/
   SendByte(sla+1);           /*发送器件地址*/
     if(ack==0)return(0);
   *c=RcvByte();               /*读取数据*/
     Ack_I2c(1);               /*发送非就答位*/
  Stop_I2c();                  /*结束总线*/
  return(1);
}

 

/*******************************************************************
                    向有子地址器件读取多字节数据函数              
函数原型: bit  ISendStr(uchar sla,uchar suba,ucahr *s,uchar no); 
功能:     从启动总线到发送地址,子地址,读数据,结束总线的全过程,从器件
          地址sla,子地址suba,读出的内容放入s指向的存储区,读no个字节。
           如果返回1表示操作成功,否则操作有误。
注意:    使用前必须已结束总线。
********************************************************************/
bit IRcvStr(uchar sla,uchar suba,uchar *s,uchar no)
{
   uchar i;

   Start_I2c();               /*启动总线*/
   SendByte(sla);            /*发送器件地址*/
     if(ack==0)return(0);
   SendByte(suba);            /*发送器件子地址*/
     if(ack==0)return(0);

   Start_I2c();
   SendByte(sla+1);
      if(ack==0)return(0);

   for(i=0;i<no-1;i++)
    {  
     *s=RcvByte();               /*发送数据*/
      Ack_I2c(0);                /*发送就答位*/ 
     s++;
    }
   *s=RcvByte();
    Ack_I2c(1);                 /*发送非应位*/
 Stop_I2c();                    /*结束总线*/
  return(1);
}
/****************************IIC程序结束*****************************/

/****************************ZLG7290程序*****************************/

void delayMS(unsigned char i)
{
 unsigned char j,k;
 for(k=0;k<i;k++)
  for(j=0;j<120;j++);
}

/**************************************************************
** 函数名称:  ZLG7290_SendData
** 功能描述:  发送数据
** 输 入:SubAdd : 输入数据
**       DATA  : 输入值
**        
** 输 出: 0 : Fail
**        1 :  OK
** 全局变量: 无
** 调用模块:  delayMS
**
*******************************************************************/

unsigned char ZLG7290_SendData(unsigned char SubAdd,unsigned char Data)
{
 if(SubAdd>0×17)
  return 0;
 ISendStr(zlg7290,SubAdd,&Data,1);
 delayMS(2);
 return 1;
}
/********************************************************************
** 函数名称:  ZLG7290_SendCmd
** 功能描述:  发送命令(对子地址7、8)
** 输 入:DATA1  : 命令1
**       DATA2  : 命令2
**        
** 输 出: 0 : Fail
**        1 :  OK
** 全局变量: 无
** 调用模块:  ISendStr、delayMS
**
***************************************************************/

unsigned char ZLG7290_SendCmd(unsigned char Data1,unsigned char Data2)
{
unsigned char Data[2];
 Data[0]=Data1;
 Data[1]=Data2;
 ISendStr(zlg7290,0×07,Data,2);
 delayMS(2);
 return 1;

/************************************************************
** 函数名称:  ZLG7290_SendBuf
** 功能描述:  向显示缓冲区发送数据
** 输 入: * disp_buf   : 要发送数据的起始地址
**         num   : 发送个数
**        
** 输 出: 无
** 全局变量: 无
** 调用模块:  ZLG7290_SendCmd
**
**************************************************************/
void ZLG7290_SendBuf(unsigned char * disp_buf,unsigned char num)
{
 unsigned char i;
 for(i=0;i<num;i++)
 { 
  ZLG7290_SendCmd(0×60+i,*disp_buf);
  disp_buf++;
 }
}
/************************************************************
** 函数名称:  ZLG7290_GetKey
** 功能描述:  读取键值
** 输 入: 无
**        
** 输 出: >0  键值
**        =0  无键按下
** 全局变量: 无
** 调用模块:  IRcvStr、delayMS
**
********************************************************/

unsigned char ZLG7290_GetKey()
{
unsigned char rece;
 rece=0;
 IRcvStr(zlg7290,1,&rece,1);
 delayMS(2);
/* switch(rece)
 {
  case 25 : rece=1; break;
  case 17 :  rece=2; break;
  case 9  :  rece=3; break;
  case 1  :  rece=4; break;
  case 26 :  rece=5; break;
  case 18 :  rece=6;break;
  case 10 :  rece=7;break;
  case 2  :  rece=8;break;
  case 27 :  rece=9;break;
  case 19 :  rece=0;break;
  case 11 :  rece=10;break;
  case 3  :  rece=11;break;
  case 28 :  rece=12;break;
  case 20 :  rece=13;break;
  case 12 :  rece=14;break;
  case 4  :  rece=15;break;
 }*/
 return rece;
}
/****************************ZLG7290程序结束*************************/

/*******************************************************************
文件:lcd1602.c
*****************************************************************/
#include<reg51.h>
#define uchar unsigned char
#define uint unsigned int
sbit lcdrs=P2^0;
sbit lcdrw=P2^1;
sbit lcden=P2^2;
uchar code init1[]=”1.Angle  2.Speed”;
uchar code init2[]=”3.Frequency”;
uchar code display1[]=”Angle Measure”;
uchar code display2[]=”Speed Measure”;
uchar code display3[]=”Frequency Divide”;
uchar code number[]=”0123456789″;

void delay1(uint z)//延时函数
{
 uint x,y;
 for(x=z;x>0;x–)
  for(y=110;y>0;y–);
}

void lcd_write_com(uchar com)//LCD液晶写指令函数
{
 lcdrw=0;
 lcdrs=0;
 P0=com;
 delay1(5);
 lcden=1;
 delay1(5);
 lcden=0;
}

void lcd_write_dat(uchar dat)//LCD液晶写数据函数
{
 lcdrw=0;
 lcdrs=1;
 P0=dat;
 delay1(5);
 lcden=1;
 delay1(5);
 lcden=0;
}

void init_lcd()//LCD液晶初始化函数
{
 lcden=0;
 lcd_write_com(0×38);
 lcd_write_com(0x0c);
 lcd_write_com(0×06);
 lcd_write_com(0×01);
 lcd_write_com(0×80);
}

Leave a Reply

click to change 看不清?点击换一张!

备案号:晋ICP备08002207号