//************TWI初始化*************// void Init_TWI(void) { DDRD&=~(1<<PD2); TWCR= 0x00; //禁止TWI TWBR= 38; //波特率15 //当电压为5V时, 上拉电阻为10K时, SCL和SDA的一个时钟周期为10us; 上拉电阻为1K时, SCL和SDA的一个时钟周期为2.5us; //TWBR值需要仔细调节以配合ZLG7290的IIC频率要求 TWSR= 0x00; //预分频系数1,或(0<<TWPS1)|(0<<TWSP0); // TWAR= 0xA0; //IIC从机地址SLAVE=0xa0 TWCR= 0x04; //使能TWI,禁止中断,即:TWCR =(1<<TWEN), //禁止中断即TWINT被清零,TWI立即开始工作,因此,在 //清零TWINT之前一定要首先完成对地址寄存器TWAR, //状态寄存器TWSR,以及数据寄存器TWDR的访问。 }
void DelayMs(uint i) //1ms { uint j; for(;i!=0;i--) {for(j=4000;j!=0;j--) {;}} }
/**************************************************** ***************************************************** 向IIC地址为Slave的从机的Address地址发送(写)一字节数据Data 返回0:写成功 返回非0:写失败 ****************************************************** ******************************************************/
uchar TWI_Send(uchar Slave,uchar Address,uchar Data) { TWCR=0x80|0x20|0x04; //或:TWCR=(1<<TWINT)|(1<<TWSTA)|(1<<TWEN);对TWINT写1清除,使能TWI,发出Start信号 while((TWCR&0x80)!=0x80) ; //或:while (!(TWCR & (1<<TWINT)));等待TWINT置位,表明Start信号已发出 if((TWSR&0xf8)!=0x08) //或:if ((TWSR & 0xF8) != START),检测状态寄存器,屏蔽预分频位,如果状态字不是START转出错处理 return(1); //返回值1,表明从机没有对Start信号作应答
//Slave即SLA+W,即是从机地址 ,可以是0x18或0x20,此处只用0x18 //所谓的应答是“从器件”在收到地址和“写”后,将SDA电压拉低,由“主器件”读取 //ATmge16如果读到这个“低”电压则返回0x18,否则返回0x20。 TWDR=Slave; //更新地址寄存器,装Slave入到TWDR寄存器 TWCR=0x80|0x04; //或:TWCR = (1<<TWINT) | (1<<TWEN);对TWINT写1清除,使能TWI;发出从机地址信息 while((TWCR&0x80)!=0x80) ; //或:while (!(TWCR & (1<<TWINT)));等待TWINT置位,表明Slave信号已发出 if((TWSR&0xf8)!=0x18) //或:if ((TWSR & 0xF8) != MT_SLA_ACK),检测状态寄存器, return(2); //返回值2,表明从机没有对Slave信号作应答
//Address是MT_SLA_ACK是否控发送器地址,可以是0x28或0x30, 此处只用0x28 TWDR=Address; TWCR=0x80|0x04; //或:TWCR = (1<<TWINT) | (1<<TWEN);对TWINT写1清除,使能TWI;发出寄存器地址信息 while((TWCR&0x80)!=0x80) ; //或:while (!(TWCR & (1<<TWINT)));等待TWINT置位,表明Address信号已发出 if((TWSR&0xf8)!=0x28) //检测状态寄存器(MT_DATA_ACK) return(3); //返回值3,表明从机没有对Address信号作应答 TWDR=Data;//写数据到ZLG7290 TWCR=0x80|0x04; //或:TWCR = (1<<TWINT) | (1<<TWEN);对TWINT写1清除,使能TWI;发出数据信息 while((TWCR&0x80)!=0x80) ; //或:while (!(TWCR & (1<<TWINT)));等待TWINT置位,表明Data信号已发出 if((TWSR&0xf8)!=0x28) //if ((TWSR & 0xF8) != MT_DATA_ACK);检测状态寄存器 return(4); //返回值3,表明从机没有对Data信号作应答 TWCR=0x80|0x04|0x10; //或:TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWSTO);对TWINT写1清除,使能TWI,发出Stop信号 return(0); }
/****************************************************************** ********************************************************************* 向IIC地址为Slave的从机的Address地址开始发送N字节数据Data ****************************************************************** *******************************************************************/ uchar TWI_Send_Mux(uchar Slave,uchar Address,uchar *Array,uchar CNT) {uchar Count; TWCR=0x80|0x20|0x04; //对TWINT写1清除,使能TWI,发出Start信号 while((TWCR&0x80)!=0x80) ; //等待TWINT置位,表明Start信号已发出 if((TWSR&0xf8)!=0x08) //检测状态寄存器 return(1); //返回值1,表明从机没有对Start信号作应答 TWDR=Slave; //更新地址寄存器 TWCR=0x80|0x04; //对TWINT写1清除,使能TWI;发出从机地址信息 while((TWCR&0x80)!=0x80) ; //等待TWINT置位,表明Slave信号已发出 if((TWSR&0xf8)!=0x18) //检测状态寄存器 return(2); //返回值2,表明从机没有对Slave信号作应答 TWDR=Address; TWCR=0x80|0x04; //对TWINT写1清除,使能TWI;发出寄存器地址信息 while((TWCR&0x80)!=0x80) ; //等待TWINT置位,表明Address信号已发出 if((TWSR&0xf8)!=0x28) //检测状态寄存器 return(3); //返回值3,表明从机没有对Address信号作应答 for(Count=0;Count<CNT;Count++) //连续写N个字节 ,实现发送N字节数据Data {TWDR=Array[Count]; //建立数组装载TWDR TWCR=0x80|0x04; //或(1<<TWINT)|(1<<TWEN);对TWINT写1清除,使能TWI;发出数据信息 while((TWCR&0x80)!=0x80) ; //等待TWINT置位,表明Data信号已发出 if((TWSR&0xf8)!=0x28) //检测状态寄存器 return(4);} //返回值4,表明从机没有对Data信号作应答 TWCR=0x80|0x04|0x10; //对TWINT写1清除,使能TWI,发出Stop信号 return(0); }
/********************************************************************** *********************************************************************** 从IIC地址为Slave的从机的Address地址读取一字节数据Data,返回值为读取的数据 ************************************************************************ ***********************************************************************/ //以下为主机接收模式 /*在主机接收模式,主机可以从从机接收数据,为进入主机模式,必须发送START信号。 紧接着的地址包格式决定进入MT或MR模式。 如果发送 SLA+W 进入MT模式;如果发送SLA+R则进入MR模式。*/ uchar TWI_Receive(uchar Slave,uchar Address) {//发送Start uchar Temp; TWCR=0x80|0x20|0x04; //或:TWCR=(1<<TWINT)|(1<<TWSTA)|(1<<TWEN);对TWINT写1清除;使能TWI;发出Start信号 while((TWCR&0x80)!=0x80) ; //等待TWINT置位,表明Start信号已发出 if((TWSR&0xf8)!=0x08) //检测状态寄存器,{0x08表示:主机的TWSR状态码(在预分频位为"0"情况下)} return(1); //返回值1,表明从机没有对Start信号作应答 //发送Slave+W TWDR=Slave; //更新地址寄存器 TWCR=0x80|0x04; //对TWINT写1清除,使能TWI;发出从机地址信息 while((TWCR&0x80)!=0x80) ; //等待TWINT置位,表明Slave信号已发出 if((TWSR&0xf8)!=0x18) //检测状态寄存器,(0x18表示:SLA+W从机已发送,接收到ACK) return(2); //返回值2,表明从机没有对Slave信号作应答 //发送Address TWDR=Address; TWCR=0x80|0x04; //对TWINT写1清除,使能TWI;发出寄存器地址信息 while((TWCR&0x80)!=0x80) ; //等待TWINT置位,表明Address信号已发出 if((TWSR&0xf8)!=0x28) //检测状态寄存器,(0x28表示:主控机地址已发送,接收到ACK) return(3); //返回值3,表明从机没有对Address信号作应答
//上面三段程序定义是主机方式后,以下就是接收信号的定义
//发送Start,重新启动TWI TWCR=0x80|0x20|0x04; //对TWINT写1清除;使能TWI;发出Start信号 while((TWCR&0x80)!=0x80) ; //等待TWINT置位,表明Start信号已发出 if((TWSR&0xf8)!=0x10) /*检测状态寄存器,在Repeat Start (状态0x10) 后,两线接口可以再次访问 相同的从机,或不发送STOP信号来访问新的从机。REPEATED START使得主机 可以在不丢失总线控制的条件下在从机、主机发送器及主机接收器模式间进行切换。*/ return(4); //返回值4,表明从机没有对Repeat Start信号作应答 //发送Slave+R TWDR=Slave+1; //更新地址寄存器 TWCR=0x80|0x04; //对TWINT写1清除,使能TWI;发出从机地址信息 while((TWCR&0x80)!=0x80) ; //等待TWINT置位,表明Slave信号已发出 if((TWSR&0xf8)!=0x40) //检测状态寄存器,(0x40表示:SLA+R(MR_SLA_ACK)已发送,接收到ACK) return(5); //返回值5,表明从机没有对Slave+R信号作应答 TWCR=0x80|0x04; //对TWINT写1清除,使能TWI;接受数据 while((TWCR&0x80)!=0x80) ; //等待TWINT置位,表明数据已经接收接受 if((TWSR&0xf8)!=0x50) ; //检测状态寄存器,(0x50表示:接收到数据,ACK已返回) // return(6); //返回值3,表明从机没有对Address信号作应答 Temp=TWDR; //读接收数据 TWCR=0x80|0x04; //发出NACK信号 TWCR=0x80|0x04|0x10; //发出Stop信号,或:TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWSTO); DelayMs(1*2); TWCR=0x80; //清除TWINT和禁止TWI(不加上这句程序只能读一次) return(Temp); }
/********************************************************************************************/ /*************************以下是对ZLG7290的定义和使用****************************************/ /********************************************************************************************/ /**************************ZLG7290库函数程序**************************************************/
/*ZLG7290的I2C接口传输速率可达32kbit/s,容易与处理器接口.并提供键盘中断信号,提高主处 理器时间效率.ZLG7290的从地址 (slave address)为70H(01110000B).*/
/*ZLG7290B的I2C总线器件地址是70H(写操作)和71H(读操作).*/
/*ZLG7290提供两种控制方式:寄存器映象控制和命令解释控制, 寄存器映象控制是指直接访问底层寄存器,实现基本控制功能,这些寄存器须字节操作 命令解释控制是指通过解释命令缓冲区(CmdBuf0CmdBuf1)中的指令,间接访问底层寄存器实 现扩展控制功能.如实现寄存器的位操作,对显示缓存循环,移位;对操作数译码等操作.*/
//***************寄存器映象控制******************// /*********************************************************************** ** 函数名称: ZLG7290_SendData ** 功能描述: 发送数据 ** 输 入:SubAdd : 输入数据 ** DATA : 输入值 ** ** 输 出: 0 : Fail ** 1 : OK ** 全局变量: 无 ** 调用模块: delayMS **-------------------------------------------------------------------------------------------------- ***********************************************************************/ //功能:向器件地址为zlg7290的ZLG7290芯片的SubAdd地址的寄存器写一字节Data uchar ZLG7290_SendData(uchar SubAdd,uchar Data) { if(SubAdd>0x17)//0x17表示:DpRam0~7的最大地址,它的范围是(0x10~0x17),共八位数码管 return 0;//超出于0x17的范围,即超出八位数码管数目就返回0 TWI_Send(zlg7290,SubAdd,Data);//TWI_Send()为发送一字节,zlg7290表示从机,SubAdd为地址,Data为数据 DelayMs(10*2); return 1; }
/************发送命令函数***********************/ /*********************************************************************** ** 函数名称: ZLG7290_SendCmd ** 功能描述: 发送命令(对子地址7、8) ** 输 入:DATA1 : 命令1 ** DATA2 : 命令2 ** ** 输 出: 0 : Fail ** 1 : OK ** 全局变量: 无 ** 调用模块: TWI_Send_Mux、delayMS **-------------------------------------------------------------------------------------------------- ***********************************************************************/
//功能:向命令缓冲区0x07、0x08发送命令,(0x07~0x08是CmdBuf0~2命令接口:包括译码,移位) // 寄存器CmdBuf0(地址:07H)和CmdBuf1(地址:08H)共同组成命令缓冲区。 //通过向命令缓冲区写入相关的控制命令可以实现段寻址、下载显示数据、控制闪烁等功能 uchar ZLG7290_SendCmd(uchar Data1,uchar Data2) {uchar Data[2]; Data[0]=Data1; Data[1]=Data2; TWI_Send_Mux(zlg7290,0x07,Data,2);//TWI_Send_Mux()发送N个字节(这里N为2),zlg7290为从机,0x07是地址 DelayMs(10*2); return 1; }
//***********向显示缓冲区送显示数据***************// /*********************************************************************** ** 函数名称: ZLG7290_SendBuf ** 功能描述: 向显示缓冲区发送数据 ** 输 入: * disp_buf : 要发送数据的起始地址 ** num : 发送个数 ** ** 输 出: 无 ** 全局变量: 无 ** 调用模块: ZLG7290_SendCmd **-------------------------------------------------------------------------------------------------- ***********************************************************************/
//功能:送显示数据。需要给出显示缓冲区首址和显示的数据个数(<8个) /*显示缓存寄存器(DpRam0~DpRam7):地址10H~17H,复位值00H~00H.缓存中一位置 1表示该像素亮,DpRam7~DpRam0的显示内容对应Dig7~Dig0引脚 */ void ZLG7290_SendBuf(uchar *disp_buf,uchar num) {uchar i; for(i=0;i<num;i++) { ZLG7290_SendCmd(0x60+i,*disp_buf);//在第i位数码管译码并显示DpBuf[i] disp_buf++; DelayMs(10*2); } }
//***********取得按键编号****************// /*********************************************************************** ** 函数名称: ZLG7290_GetKey ** 功能描述: 读取键值 ** 输 入: 无 ** ** 输 出: >0 键值 ** =0 无键按下 ** 全局变量: 无 ** 调用模块: TWI_Receive、delayMS ** **------------------------------------------------------------------------------------------------- ***********************************************************************/ uchar ZLG7290_Ledstatus(uchar status){switch(status) {case IDEL: ZLG7290_SendCmd(1,0x00); ZLG7290_SendCmd(1,0x01); ZLG7290_SendCmd(1,0x02); break; case RUN: ZLG7290_SendCmd(1,0x80); ZLG7290_SendCmd(1,0x01); ZLG7290_SendCmd(1,0x02); break; case WARING: ZLG7290_SendCmd(1,0x00); ZLG7290_SendCmd(1,0x81); ZLG7290_SendCmd(1,0x02); break; case FAULT: ZLG7290_SendCmd(1,0x00); ZLG7290_SendCmd(1,0x01); ZLG7290_SendCmd(1,0x82); break; } return 0;}uchar ZLG7290_GetKey() {uchar rece; rece=0; rece=TWI_Receive(zlg7290,1);//键值寄存器Key地址是01H,所以此处Address=1;zlg7290为从机 DelayMs(10*2); return rece; }
uchar ZLG7290_GetFuncKeyNum(){ uchar rece; rece=0; rece=TWI_Receive(zlg7290,3); DelayMs(10*2); return ~rece;}
uchar GetKey(){ uchar key=0xff; if((PIND&0x04)==0)
{ key=ZLG7290_GetKey(); //取得按键数值 if(key==0) key=0xf0|ZLG7290_GetFuncKeyNum(); } if(key!=0xff) return key; return 0;}