|
发表于 2006-4-18 19:47:02
|
显示全部楼层
这是我的源程序:
#include <iom16v.h>
#include <macros.h>
#define uchar unsigned char
#define uint unsigned int
#define zlg7290 0x70
//0x70是zlg7290的从地址
#define SubKey 0x01
//键值寄存器Key(地址:01H),码键值子地址
#define SubCmdBuf 0x07
//寄存器CmdBuf0(地址:07H),命令缓冲区子地址
#define SubDpRam 0x10
//显示缓冲区DpRam0(地址:0x10),显示子地址
/*状态标志*/
uchar disp_buf[8]={0,0,0,0,0,0,0,0};
uchar rd[8]={1,2,3,4,5,6,7,8}; //1234-56-78
uchar Table[16]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
void DelayMs(uint i) //1ms
{uint j;
for(;i!=0;i--)
{for(j=4000;j!=0;j--) {;}}
}
/*
void Display(uchar *p) //间隔5ms显示
{uchar i,sel=0x04;
for(i=0;i<4;i++)
{PORTC=~sel;
PORTB=Table[p[3-i]];
DelayMs(2);
sel=sel<<1;
}
}*/
void Init_IO(void) //A B C 口推挽1输出
{DDRA=0xff;
PORTA=0xff;
DDRC=0xff;
PORTC=0xff;
DDRB=0xff;
PORTB=0xff;
DDRD=0x00;
PORTD=0x00;
}
/*********************************************************************************************/
/********************以下是对ATmega16的自带I2C定义和使用**************************************/
/*********************************************************************************************/
//************TWI初始化*************//
void Init_TWI(void)
{TWCR= 0x00; //禁止TWI
TWBR= 15; //波特率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的访问。
}
/****************************************************
*****************************************************
向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);
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);
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);
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
disp_buf++;
DelayMs(10);
}
}
//***********取得按键编号****************//
/***********************************************************************
** 函数名称: ZLG7290_GetKey
** 功能描述: 读取键值
** 输 入: 无
**
** 输 出: >0 键值
** =0 无键按下
** 全局变量: 无
** 调用模块: TWI_Receive、delayMS
**
**-------------------------------------------------------------------------------------------------
***********************************************************************/
uchar ZLG7290_GetKey()
{uchar rece;
rece=0;
rece=TWI_Receive(zlg7290,1);//键值寄存器Key地址是01H,所以此处Address=1;zlg7290为从机
DelayMs(10);
return rece;
}
/*********************************************************************************************************
** 函数名称: display
** 功能描述: 7290 led显示
** 输 入: *sd : 显示缓冲区的头地址
**
** 输 出: 0 : OK;
** 1 : FAIL;
** 全局变量: 无
** 调用模块: ZLG7290_SendBuf
**
**-------------------------------------------------------------------------------------------------------
** 日 期:2006-4-11
**------------------------------------------------------------------------------------------------------*/
uchar display(uchar *sd)
{ uchar i;
for(i=0;i<8;i++)
disp_buf= (disp_buf&0xf0)|rd[7-i];//uchar rd[8]={1,2,3,4,5,6,7,8};
//取数组的高4位,取前一数组的高4位,然后再或上低4位
//取高4位,清0低4位
//取另一数组的低4位,或进来
//相当于两个数组拼接
/*以下是16进制转10进制输出,如果用下面两段程序就得之前定义的 rd[5]={0x12,0x48,0x30,0x03,0x04};
/*
disp_buf[0] = (disp_buf[0]&0xf0)|(sd[0]%16);
disp_buf[1] = (disp_buf[1]&0xf0)|(sd[0]/16);
disp_buf[2] = (disp_buf[2]&0xf0)|(sd[2]%16);//31;
disp_buf[3] = (disp_buf[3]&0xf0)|(sd[2]/16);
disp_buf[4] = (disp_buf[4]&0xf0)|(sd[3]%16);
disp_buf[5] = (disp_buf[5]&0xf0)|(sd[3]/16);//31;
disp_buf[6] = (disp_buf[6]&0xf0)|(sd[4]%16);
disp_buf[7] = (disp_buf[7]&0xf0)|(sd[4]/16);
*/
/*或者:
unsigned char display(unsigned char *sd)
{
disp_buf[0] = (disp_buf[0]&0xf0)|(sd[0]%16); // 装载" dp-932"
disp_buf[1] = (disp_buf[1]&0xf0)|(sd[0]/16);
disp_buf[2] = 31;
disp_buf[3] = (disp_buf[3]&0xf0)|(sd[1]%16);
disp_buf[4] = (disp_buf[4]&0xf0)|(sd[1]/16);
disp_buf[5] = 31;
disp_buf[6] = (disp_buf[6]&0xf0)|(sd[2]%16);
disp_buf[7] = (disp_buf[7]&0xf0)|(sd[2]/16);
ZLG7290_SendBuf(disp_buf,8);
return 0;
}
*/
ZLG7290_SendBuf(disp_buf,8);
return 0;
}
void Delay(uchar j)
{uchar k;
for(;j!=0;j--)
{for(k=0;k<=250;k++){;}}
}
void main(void)
{uchar key=0;
uchar i;
uchar k;
uchar FLASH=1;
//DDRC=0xff;
//PORTC=0xff;
//DDRD=0x00;定义PD3为输入
//PORTD=0x00;
//MCUCSR=MCUCSR|0x80;
//MCUCSR=MCUCSR|0x80;
Init_IO();
Init_TWI();
DelayMs(100);
while(1)
{//DelayMs(100);
i=display(rd);//显示12345678
if((PIND&0x08)==0) //如果有按键按下:PD3
// 键盘处理程序可由/INT引脚低电平中断触发,以提高程序效率
/* 系统寄存器的第0位(LSB)称作KeyAvi,标志着按键是否有效,0-没有按键被按下,
1-有某个按键被按下。SystemReg寄存器的其它位暂时没有定义。当按下某个键时,
ZLG7290B的INT引脚会产生一个低电平的中断请求信号。当读走键值后,中断信号就会自
动撤销。而KeyAvi也同时予以反映。正常情况下,微控制器只需要判断INT引脚就可以了。
通过不断查询KeyAvi位也能判断是否有键按下,这样就可以节省微控制器的一根I/O口线,
但是代价是I2C总线处于频繁的活动状态,多消耗电流并且不利于抗干扰.*/
{key=ZLG7290_GetKey(); //取得按键数值
switch(key)
{case 1://确定
{for(k=0;k<8;k++)
disp_buf[k]=disp_buf[k]&0xbf;//去除闪烁,只要令低四位全为0即可令所有数码管不闪烁
break;}
case 2: //光标左移,左移键用于选择要修改的位
{disp_buf[FLASH]=disp_buf[FLASH]&0xbf;
FLASH=FLASH+1;//FLASH位:0~7
if(FLASH==8) FLASH=0;
disp_buf[FLASH]=disp_buf[FLASH]|0x40;//闪烁
break;}
case 3: //光标右移,右移键用于选择要修改的位
{disp_buf[FLASH]=disp_buf[FLASH]&0xbf;
if(FLASH==0) FLASH=7;
else FLASH=FLASH-1;
disp_buf[FLASH]=disp_buf[FLASH]|0x40;//闪烁
break;}
case 4: //光标值加一
{i=7-FLASH;
rd=rd+1;
if(rd==16) rd=0;
Delay(50);
break;}
case 5: //光标值减一
{i=7-FLASH;
if(rd==0) rd=15;
else rd=rd-1;
break;}
case 6 :break;
case 7 :break;
case 8 :break;
default:break;}
while((PIND&0x08)==0) {;}
}
}
} |
|