本帖最后由 zl101lz 于 2015-8-9 19:49 编辑
以下代码是运行OK的 atmega16接了一个eeprom(AT240C02A)
会记录开机的次数
#include <iom16v.h>
#include <macros.h>
#define uchar unsigned char
#define uint unsigned int
//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_DEVICE_ADDR 0xA1 //前4位器件固定,后三位看连线,最后1位是读写指令位
#define WD_DEVICE_ADDR 0xA0
//常用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);} //写数
unsigned char smg_du[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0x00};
unsigned char smg_we[]={0x08,0x18,0x28,0x38,0x48,0x58,0x68,0x78};
uchar table[8]={0,0,0,0,0,0,0,0};
void init(void)
{
DDRB=0xff;
PORTB=0;
DDRC=0x78;//01111000
PORTC=0;
}
void delay(void)
{
uint a;
for(a=0;a<300;a++);
}
void display(uchar *p)
{
uchar i;
for(i=0;i<8;i++)
{
PORTB=smg_du[*p];
p++;
PORTC=smg_we[i];
delay();
}
}
void twi_init(void)
{
TWBR=0x20;
TWCR=0x04;
TWSR=0;
}
uchar IIC_Write(uchar wdata,uchar addr)
{
Start();
Wait();
if(TestAck()!=START)
return 1;
Write8Bit(WD_DEVICE_ADDR);
Wait();
if(TestAck()!=MT_SLA_ACK)
return 1;
Write8Bit(addr);
Wait();
if(TestAck()!=MT_DATA_ACK)
return 1;
Write8Bit(wdata);
Wait();
if(TestAck()!=MT_DATA_ACK)
return 1;
Stop();
return 0;
}
uchar IIC_Read(uchar addr)
{
uchar temp;
Start();
Wait();
if(TestAck()!=START)
return 1;
Write8Bit(WD_DEVICE_ADDR);
Wait();
if(TestAck()!=MT_SLA_ACK)
return 1;
Write8Bit(addr);
Wait();
if(TestAck()!=MT_DATA_ACK)
return 1;
Start();
Wait();
if(TestAck()!=RE_START)
return 1;
Write8Bit(RD_DEVICE_ADDR);
Wait();
if(TestAck()!=MR_SLA_ACK)
return 1;
Twi();
Wait();
if(TestAck()!=MR_DATA_NOACK)
return 1;
temp=TWDR;
Stop();
return temp;
}
void main(void)
{
uchar i;
init();
twi_init();
i=IIC_Read(0x03);
table[1]=i;
i++;
i=i%10;
IIC_Write(i,0x03);
table[0]=i;
我修改成以下的样子,其实就是加了两行代码,原来是IIC_READ→IIC_WRITE,现在改成IIC_READ→IIC_WRITE→IIC_READ结果就不行了
#include <iom16v.h>
#include <macros.h>
#define uchar unsigned char
#define uint unsigned int
//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_DEVICE_ADDR 0xA1 //前4位器件固定,后三位看连线,最后1位是读写指令位
#define WD_DEVICE_ADDR 0xA0
//常用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);} //写数
unsigned char smg_du[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0x00};
unsigned char smg_we[]={0x08,0x18,0x28,0x38,0x48,0x58,0x68,0x78};
uchar table[8]={0,0,0,0,0,0,0,0};
void init(void)
{
DDRB=0xff;
PORTB=0;
DDRC=0x78;//01111000
PORTC=0;
}
void delay(void)
{
uint a;
for(a=0;a<300;a++);
}
void display(uchar *p)
{
uchar i;
for(i=0;i<8;i++)
{
PORTB=smg_du[*p];
p++;
PORTC=smg_we[i];
delay();
}
}
void twi_init(void)
{
TWBR=0x20;
TWCR=0x04;
TWSR=0;
}
uchar IIC_Write(uchar wdata,uchar addr)
{
Start();
Wait();
if(TestAck()!=START)
return 1;
Write8Bit(WD_DEVICE_ADDR);
Wait();
if(TestAck()!=MT_SLA_ACK)
return 1;
Write8Bit(addr);
Wait();
if(TestAck()!=MT_DATA_ACK)
return 1;
Write8Bit(wdata);
Wait();
if(TestAck()!=MT_DATA_ACK)
return 1;
Stop();
return 0;
}
uchar IIC_Read(uchar addr)
{
uchar temp;
Start();
Wait();
if(TestAck()!=START)
return 9;
Write8Bit(WD_DEVICE_ADDR);
Wait();
if(TestAck()!=MT_SLA_ACK)
return 8;
Write8Bit(addr);
Wait();
if(TestAck()!=MT_DATA_ACK)
return 7;
Start();
Wait();
if(TestAck()!=RE_START)
return 6;
Write8Bit(RD_DEVICE_ADDR);
Wait();
if(TestAck()!=MR_SLA_ACK)
return 5;
Twi();
Wait();
if(TestAck()!=MR_DATA_NOACK)
return 4;
temp=TWDR;
Stop();
return temp;
}
void main(void)
{
uchar i;
init();
twi_init();
i=IIC_Read(0x03);
table[1]=i;
i++;
i=i%10;
IIC_Write(i,0x03);
table[0]=i;
i=IIC_Read(0x03); ☆
table[2]=i; ☆
while(1)
{
display(table);
}
}
就是五角星的那两行,从返回的代码上看是第二次IIC_READ函数里的(TestAck()!=START)返回错误,
是不是IIC当前非空闲所以不能再读啊?
求解决方法
|