专注电子技术学习与研究
当前位置:单片机教程网 >> MCU设计实例 >> 浏览文章

AVR片内TWI总线(I2C总线协议)

作者:我行天下   来源:本站原创   点击数:  更新时间:2014年03月31日   【字体:


/*本程序为八位共阴极数码管且有两个573控制的动态扫描*/
/*此程序为开机记忆,可以每次开机分自动加一。如果加了,说明操作成功*/
/*本程序把24C08的SCL和SDA分别接在MCU的SCL(PC0第22脚)和SDA(PC1第23脚)*/
//24C08的第7脚WP接地
#include <iom16v.h>
#include <macros.h>//这里面有BIT(),所以要包含
#define uchar unsigned char
#define uint unsigned int
#pragma data:code //注code的功能是把后面的数据存在程序存贮器中,不用code就放到了随机存贮器中.
uchar const table[]={0x3f,0x06,0x5b,0x4f,0x66,
0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0x00} ;
/*如果用uchar table[]就放到了数据存贮器中。决不要这样用,这样占用空间多。*/
/*两个573,段码PA3,位码PA4*/
/****************************
 I2C 状态定义
 MT 主方式传输 MR 主方式接受
***************************/
#define START   0x08
#define RE_START  0x10
#define MT_SLA_ACK  0x18
#define MT_SLA_NOACK  0x20
#define MT_DATA_ACK  0x28
#define MT_DATA_NOACK 0x30
#define MR_SLA_ACK  0x40
#define MR_SLA_NOACK 0x48
#define MR_DATA_ACK  0x50
#define MR_DATA_NOACK 0x58
#define RD_24C08_add 0xaf 
//读24C08的地址,前4位器件固定,后三位看连线(本机全接高),最后1位是1读指令位
#define WD_24C08_add 0xae
//写24C08的地址,前4位器件固定,后三位看连线(本机全接高),最后1位是0写指令位
//上述定义中,MT为主机发送,MR为主机接收
//上述定义中,SLA是对地址操作,DATA是对数据操作
/*常用TWI操作(主模式写和读)*/
#define Start()   TWCR=(1<<TWINT)|(1<<TWSTA)|(1<<TWEN)  //启动I2C
#define Stop()   TWCR=(1<<TWINT)|(1<<TWSTO)|(1<<TWEN)  //停止I2C
#define Wait()   while(!(TWCR&(1<<TWINT)))    //等待中断发生
#define TestAck()  TWSR&0xf8        //观察返回状态
#define SetAck   TWCR|=(1<<TWEA)       //做出ACK应答
#define SetNoAck  TWCR&=~(1<<TWEA)       //做出Not Ack应答
#define Twi()  TWCR=(1<<TWINT)|(1<<TWEN)    //启动I2C
#define Write8Bit(x) TWDR=(x);TWCR=(1<<TWINT)|(1<<TWEN)  //写数据到TWDR
/*延时子程序*/
void delay_ms(int time)
{
 int i;
 for(;time>0;time--)
  for(i=0;i<1000;i++);
}
 
void show(uchar dat,uchar wei)
{
   DDRA|=BIT(3);//把PA3设为输出
   DDRA|=BIT(4);//把PA4设为输出
   DDRB=0XFF;//把PB口设为输出型,全为高
    PORTA|=BIT(3);
 PORTB=table[dat];
 PORTA&=~BIT(3);
 
 PORTB=0XFF;
 PORTB&=~BIT(wei);
 PORTA|=BIT(4);
 PORTA&=~BIT(4);
 delay_ms(1);
}
void TWI_init()//初始化TWI总线
{
TWBR=0X20;//TWIA 工作在主机模式下,TWRB的值不小于10,0X20一定大于10
TWCR=0X04;//把TWCR中,TWEN使能打开,所以是0X04
TWSR=0;//只用1分频就可以了,就是不用分频,就用晶振频率
}

/*********************************************
I2C总线写一个字节  返回0:写成功  返回1:写失败
**********************************************/

uchar  IIC_write(uchar add,uchar dat)
{
Start();//发送启始位
Wait();//等待
if(TestAck()!=START)//也可写成if(TestAck!=0X80)
return 1;
Write8Bit(WD_24C08_add);//告诉24C08,现在要写操作,也可写成Write8bit(0xA0);
Wait();//等待
if(TestAck()!=MT_SLA_ACK)//也可写成if(TestAck!=0X18)
return 1;
//LSA是对器件的应答
Write8Bit(add);//写入要写入数据的地址
Wait();//等待
if(TestAck()!=MT_DATA_ACK)//也可写成if(TestACK()!=0X28)
return 1;
//DATA是对数据应答
Write8Bit(dat);
Wait();//等待
if(TestAck()!=MT_DATA_ACK)//也可写成if(TestACK()!=0X28)
return 1;
Stop();//送出停止信号
return 0;
}

uchar IIC_rd(uchar add)
{
uchar temp;
Start();//发送启始位
Wait();//等待
if(TestAck()!=START)//也可写成if(TestAck!=0X80)
return 1;
Write8Bit(WD_24C08_add);//告诉24C08,现在要写操作,也可写成Write8bit(0xA0);
Wait();//等待
if(TestAck()!=MT_SLA_ACK)//也可写成if(TestAck!=0X18)
return 1;
//SLA是对器件的应答

Write8Bit(add);//写入要读出数据的地址
Wait();//等待
if(TestAck()!=MT_DATA_ACK)//也可写成if(TestACK()!=0X28)
return 1;
//DATA是对数据应答
Start();//重复发送启始位
Wait();//等待
if(TestAck()!=RE_START)//也可写成if(TestAck!=0X10)
return 1;
Write8Bit(RD_24C08_add);//告诉24C08,现在要读操作,也可写成Write8bit(0xA1);
Wait();//等待
if(TestAck()!=MR_SLA_ACK)//主机接收判断,也可写成if(TestAck!=0X40)
return 1;
Twi(); //须要重新启动
Wait();//等待
if(TestAck()!=MR_DATA_NOACK)
return 1;
 
temp=TWDR;
Stop();//送出停止信号
return temp;
}
void main()
{
uchar i;
TWI_init();
i=IIC_rd(2);
if(i>9)
i=0;
i++;
IIC_write(2,i);
  while(1)
     {
   show(i,2);
  }
}
 

关闭窗口

相关文章