⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 8574keyboard.c

📁 aduc834单片机PCF8574 4*5键盘驱动程序
💻 C
字号:
//#include <reg52.h>
#include <ADI/ADuC834.h>
#include <intrins.h>

#define uchar unsigned char
#define uint unsigned int

//1602移植过来的
sbit rs=P2^3;    //1602的数据/指令选择控制线 
sbit rw=P2^4;        //1602的读写控制线 
sbit en=P2^5;        //1602的使能控制线 
/*P2口接1602的D0~D7,注意不要接错了顺序,我以前可在这上面吃过亏~*/ 
uchar code table[]="LCD1602 check ok"; //要显示的内容1放入数组tablel 
uchar code table1[]="study up";             //要显示的内容2放入数组table1 
uchar code esc[]="ESC";
uchar code light[]="LIGHT";
uchar code avc[]="AVC";
uchar code memo[]="MEMO";
uchar code hold[]="HOLD";
uchar code setup[]="SETUP";
uchar code pgdn[]="PgDn";

uchar n,m=0;

uchar slvadr=0x40 ;      //被控器地址
uchar ack;
uchar key;
uchar curkey;
uchar key_right_flag=1;
uchar KeyPort;
uchar RBT[8];

//1602移植过来的
void delay(uint n)       //延时函数                       
{ 
    uint x,y; 
    for(x=n;x>0;x--) 
        for(y=110;y>0;y--); 
} 
void lcd_wcom(uchar com)  //1602写命令函数                 
{ 
    rs=0;            //选择指令寄存器 
    rw=0;            //选择写 
    P0=com;            //把命令字送入P2 
    delay(5);            //延时一小会儿,让1602准备接收数据 
    en=1;           //使能线电平变化,命令送入1602的8位数据口 
    en=0; 
} 
void lcd_wdat(uchar dat)        //1602写数据函数       
{ 
    rs=1;        //选择数据寄存器 
    rw=0;        //选择写 
    P0=dat;        //把要显示的数据送入P2 
    delay(5);        //延时一小会儿,让1602准备接收数据 
    en=1;        //使能线电平变化,数据送入1602的8位数据口 
    en=0; 
} 
void lcd_init()              //1602初始化函数       
{ 
    lcd_wcom(0x38);       //8位数据,双列,5*7字形       
    lcd_wcom(0x0F);      //开启显示屏,关光标,光标不闪烁 
    lcd_wcom(0x06);    //显示地址递增,即写一个数据后,显示位置右移一位 
    lcd_wcom(0x01);    //清屏 
} 

void PCF8574init(void)
{
	I2CM=1;
}

void delay1ms(uchar x)
{  
unsigned char i,j;
        while(x--)
           {
             for(i=5;i>0;i--)
          for(j=132;j>0;j--);
        }
}

void Delay_Cycles(char delay)
{
  while(delay--);
}

/*---------------------------------------------------------------------------------------------------
开始:START
描述:启动I2C 总线子程序--发送I2C 起始条件
---------------------------------------------------------------------------------------------------*/
void start(void)
{
  MDE=1;
  MCO=1;
  MDO=1;
  _nop_();
  _nop_();
  _nop_();
  _nop_();
  _nop_();
  MDO=0;
  _nop_();
  _nop_();
  _nop_();
  _nop_();
  _nop_();
  MCO=0;
}

void Ack_I2c(uchar a) //a=0发送应答信号,=1发送非应答信号
{ 
	MDE=1;
  if(a==0)MDO=0; /*在此发出应答或非应答信号 */ 
  else MDO=1; 
  _nop_(); 
  _nop_(); 
  _nop_(); 
  MCO=1; 
  _nop_();
  _nop_(); /*时钟低电平周期大于4μs*/ 
  _nop_(); 
  _nop_(); 
  _nop_(); 
  MCO=0; /*清时钟线,钳住I2C总线以便继续接收*/ 
  _nop_(); 
  _nop_(); 
}

void wrbyt(uchar shu)
{
  uchar i;
  ack=0;
  MDE=1;			//        SETB    MDE           ; to enable SDATA pin as an output	
  MCO=0;
  for(i=0;i<8;i++)
  {
    if(shu&0x80)
    {
      MDO=1;
      _nop_();
      MCO=1;
      _nop_();    
      _nop_();
      _nop_();
      MCO=0;
      //MDO=0;
    }
    else
    {
      MDO=0;
      _nop_();
      MCO=1;
      _nop_();
      _nop_();
      _nop_();
      MCO=0;
    }
  shu=shu<<1;
  }
  MDO=1;
  MDE=0;			//      CLR     MDE           	; release data line for acknowledge
  MCO=1;			//      SETB    MCO           	; send clock for acknowledge
  Delay_Cycles(3);
  MCO=0;
}

//void SendByte_Upon_I2C(unsigned char byte)
//{
//	unsigned char send_bitdata;
//  unsigned char send_bytedata=byte;
//  uchar BITCNT=8;		//        MOV     BITCNT,#8     ; 8 bits in a byte
//  MDE=1;			//        SETB    MDE           ; to enable SDATA pin as an output	
//  MCO=0;			//        CLR     MCO           ; make sure that the clock line is low
//  Delay_Cycles(5);
//  while(BITCNT--)
//	{
//	  if(send_bytedata&0x80)send_bitdata=1;
//	  	else send_bitdata=0;
//	  MDO=send_bitdata;		//      MOV     MDO,C           ; put data bit on SDATA line
//	  MCO=1;		//      SETB    MCO             ; clock to send bit
//	  Delay_Cycles(1);
//	  Delay_Cycles(5);
//	  MCO=0;		//      CLR     MCO             ; clear clock 
//	  send_bytedata<<=1;
//	}        	//		DJNZ    BITCNT,SENDBIT	; jump back and send all eight bits
//  MDE=0;			//      CLR     MDE           	; release data line for acknowledge
//  MCO=1;			//      SETB    MCO           	; send clock for acknowledge
//  Delay_Cycles(3);
//  MCO=0;			//NEXT: CLR     MCO             ; clear clock 
//  return;			//	RET
//}

uchar RcvByte() 
{ 
uchar retc; 
uchar BitCnt; 

retc=0; 
MDE=0; /*置数据线为输入方式*/ 
for(BitCnt=0;BitCnt<8;BitCnt++) 
{ 
_nop_(); 
MCO=0; /*置时钟线为低,准备接收数据位*/ 
_nop_(); 
_nop_(); /*时钟低电平周期大于4.7μs*/ 
_nop_(); 
_nop_(); 
_nop_(); 
MCO=1; /*置时钟线为高使数据线上数据有效*/ 
_nop_(); 
_nop_(); 
retc=retc<<1; 
if(MDI==1)retc=retc+1; /*读数据位,接收的数据位放入retc中 */ 
_nop_(); 
_nop_(); 
} 
MCO=0; 
_nop_(); 
_nop_(); 
return(retc); 
} 

/*---------------------------------------------------------------------------------------------------
名称:STOP
描述:停止I2C 总线子程序--发送I2C 总线停止条件
---------------------------------------------------------------------------------------------------*/
void stop(void)
{
	     MDE=1;
       MDO=0;
       _nop_();
       MCO=1;
       _nop_();
       _nop_();
       _nop_();
       _nop_();
       _nop_();
       MDO=1;
       _nop_();
       _nop_();
       _nop_();
}
void checkack(void)
{
//  MDO=1; /*8位发送完后释放数据线,准备接收应答位*/ 
//  MDE=0;
//  _nop_(); 
//  _nop_(); 
//  MCO=1; 
//  _nop_(); 
//  _nop_(); 
//  _nop_(); 
  if(MDI==0)
  	ack=1; 
  else 
  	ack=0; /*判断是否接收到应答信号*/ 
  MCO=0; 
  MDE=1;
  _nop_(); 
  _nop_();
}

/*************************************************************************************
主程序
**************************************************************************************/
void ext0_int() interrupt 0//SPIandI2C_InterruptRoutine(void) interrupt 7//
{
//	if(key_right_flag<2)
//	{
	EX0=0;
	start();
  wrbyt(0x41);
	RBT[1]=RcvByte();
	Ack_I2c(1);
	stop();
	if(RBT[1]>=0x70)//如果接收的数正确
	key_right_flag++;
	KeyPort = (RBT[1] & 0xF0);
	//KeyPort=(0x70&0xF0);
	start();
	wrbyt(0x40);
	wrbyt(0x0F);
	checkack();
	stop();
	start();
  wrbyt(0x41);
  RBT[2]=RcvByte();
  Ack_I2c(1);
  stop();
  if(RBT[2]<=0x0F)//判断是否正确
  key_right_flag++;
	key = (RBT[2] & 0x0F);
	key|=KeyPort;
	if(key!=0xFF)
	curkey=key;
//  }
//  if(key_right_flag>=2)
//  {
  key_right_flag=0;
	start();//恢复8574初始状态
  wrbyt(0x40);
  wrbyt(0xF0);
  checkack();
  stop();
	EX0=1;
//  }
}

/*************************************************************************************
主程序
**************************************************************************************/
void main()
{
	EX0=1;
  PCF8574init();//主机模式
  start();
  wrbyt(slvadr);//发一个数据或地址
  wrbyt(0xF0);//端口初始化
  checkack();
  stop();
  delay1ms(1);
  delay1ms(1);
  delay1ms(1);
  start();
  wrbyt(0x41);
  RBT[0]=RcvByte();
  Ack_I2c(1);
  stop();
  EA=1;
//1602移植过来的    
    lcd_init();                 //液晶初始化 
    lcd_wcom(0x80);   //显示地址设为80H(即00H,)上排第一位       
    for(m=0;m<16;m++)     //将table[]中的数据依次写入1602显示 
    { 
            lcd_wdat(table[m]);           
            delay(1); 
    } 
    lcd_wcom(0x80+0x44); //重新设定显示地址为0xc4,即下排第5位 
    for(n=0;n<8;n++)   //将table1[]中的数据依次写入1602显示 
    {     
            lcd_wdat(table1[n]); 
           delay(1); 
    } 
    
  while(1)
  { 	
  			uchar i;
  	switch (curkey) 
  	{/*将按键码输出到显示*/  
  		case  0x7E:
  			 lcd_wcom(0x80);
  			 //lcd_wdat('L');
  			 for(i=0;i<5;i++)
  			 {
  				 lcd_wdat(light[i]);
  			 }  
  			 curkey=0;
  			 break;
  		case  0xBE: 
  			lcd_wcom(0x80);
  			 //lcd_wdat('A');  
  			 for(i=0;i<3;i++)
  			{
  				lcd_wdat(avc[i]);
  			}
  			 curkey=0;
  			 break;  
  		case  0xDE: 
  			lcd_wcom(0x80);
  			 //lcd_wdat('M'); 
  			 for(i=0;i<4;i++)
  			{
  				lcd_wdat(memo[i]);
  			}
  			 curkey=0; 
  			 break;  
  		case  0xEE: 
  			lcd_wcom(0x80);
  			 //lcd_wdat('H');
  			 for(i=0;i<4;i++)
  			{
  				lcd_wdat(hold[i]);
  			}
  			 curkey=0;  
  			 break;  
  
  		case  0xED: 
  			lcd_wcom(0x80);
  			 //lcd_wdat('S');
  			 for(i=0;i<5;i++)
  			{
  				lcd_wdat(setup[i]);
  			}  
  			 curkey=0;
  			 break;  
  		case  0xDD: 
  			lcd_wcom(0x80);
  			 lcd_wdat('9');
  			 curkey=0;  
  			 break;  
  		case  0xBD: 
  			lcd_wcom(0x80);
  			 lcd_wdat('8');  
  			 curkey=0;
  			 break;  
  		case  0x7D: 
  			lcd_wcom(0x80);
  			 lcd_wdat('7');  
  			 curkey=0;
  			 break;  
  			
  		case  0xEB: 
  			lcd_wcom(0x80);
  			 //lcd_wdat('P'); 
  			 for(i=0;i<4;i++)
  			{
  				lcd_wdat(pgdn[i]);
  			} 
  			 curkey=0;
  			 break;  
  		case  0xDB: 
  			lcd_wcom(0x80);
  			 lcd_wdat('6');  
  			 curkey=0;
  			 break;  
  		case  0xBB: 
  			lcd_wcom(0x80);
  			 lcd_wdat('5');  
  			 curkey=0;
  			 break;  
  		case  0x7B: 
  			lcd_wcom(0x80);
  			 lcd_wdat('4');  
  			 curkey=0;
  			 break;  
  		
  		case  0xE7:   			
  			lcd_wcom(0x80);
  			for(i=0;i<3;i++)
  			{
  				lcd_wdat(esc[i]);
  			}
  			 //lcd_wdat('E');  
  			 curkey=0;
  			 break;  
  		case  0xD7: 
  			lcd_wcom(0x80);
  			 lcd_wdat('3');  
  			 curkey=0;
  			 break;  
  		case  0xB7: 
  			lcd_wcom(0x80);
  			 lcd_wdat('2');  
  			 curkey=0;
  			 break;  
  		case  0x77: 
  			lcd_wcom(0x80);
  			 lcd_wdat('1');  
  			 curkey=0;
  			 break; 
  		
  		case  0x7F: 
  			lcd_wcom(0x80);
  			 lcd_wdat('0');  
  			 curkey=0;
  			 break;
  		case  0xBF: 
  			lcd_wcom(0x80);
  			 lcd_wdat('.');
  			 curkey=0;  
  			 break;
  		case  0xDF: 
  			lcd_wcom(0x80);
  			 lcd_wdat('+');  
  			 curkey=0;
  			 break;
  		case  0xEF: 
  			//lcd_wcom(0x80);
  			 lcd_wdat('*'); 
  			 lcd_wcom(0x80+0x44); 
  			 curkey=0;
  			 break;
  			 
  		default : 
  			break;  
  	} 
  	delay1ms(1);
  }
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -