最近在弄一个简单的ATMEGA8项目,其中有用到使用硬件TWI(兼容I2C)接口读写24LC512。在网上搜了一下,读写24C02的例子不少,不过,都不能正常读写24LC512。其原因主要因为24C02的字节地址是一个字节的,24C512的字节地址是两个字节的。这是两者最大的区别。注意到这个细节,你应该就可以在24c02程序的基础上写出24C512的程序了。不过,这又存在一个新的问题,那就是24C02的读写是按字节进行的。且每写一个字节,都需延时几毫秒,才能正常写入,这在写24C512时,就会耗费大量的时间。实际上,24C512,24C256这样的芯片,还提供了页写和连续读方式。即可以一次写入多个字节(分别是128,64字节),可以一次读出全部字节,中间是不需延时的,极大提高读写速度。网上能找到的读写24c512的例子,都是用字节读写的,效率较低。我自已写了一个以页写和连续读的方式来读写24C512,24C256的例子。在此放出,以供大家参考。
说明一下,例子中是用查询方式来操作I2C的,这种方式易于理解不易出错。但会过多占用CPU时间,如对CPU时间占用敏感,可改用中断方式。
TWI_I2C.C
#include
#include
#include
#include "TWI_I2C.h"
/*********************************************
I2C 总线读多个字节,使用24C512连续读方式,一次可读完全部数据,这里限定一次读255字节
返回0:读成功
返回1:读失败
**********************************************/
unsigned char I2C_Read_Bytes(unsigned int address,unsigned char *databuf,unsigned char len)
{
unsigned char posi;
I2C_Start();//I2C 启动
//Delay_1ms();
I2C_Wait();
if (I2C_TestAck()!=I2C_START)
return 1; //ACK
I2C_Write8Bit(WD_DEVICE_ADDR); //写I2C 从器件地址和写方式
I2C_Wait();
if (I2C_TestAck()!=MT_SLA_ACK)
return 1; //ACK
I2C_Write8Bit(address>>8); //写器件相应寄存器地址
I2C_Wait();
if (I2C_TestAck()!=MT_DATA_ACK)
return 1;
I2C_Write8Bit(address&0x00ff); //写器件相应寄存器地址
I2C_Wait();
if (I2C_TestAck()!=MT_DATA_ACK)
return 1;
I2C_Start(); //I2C 重新启动
I2C_Wait();
if (I2C_TestAck()!=I2C_RESTART)
return 1;
I2C_Write8Bit(RD_DEVICE_ADDR); //写I2C 从器件地址和读方式
I2C_Wait();
if(I2C_TestAck()!=MR_SLA_ACK)
return 1; //ACK
for(posi=0;posi {
I2C_Twi_Ack(); //启动主I2C 读方式
I2C_Wait();
if(I2C_TestAck()!=MR_DATA_ACK)
return 1; //ACK
*(databuf+posi)=TWDR;//读取I2C 接收数据
}
I2C_Twi_NoAck(); //启动主I2C 读方式
I2C_Wait();
if(I2C_TestAck()!=MR_DATA_NOACK)
return 1; //ACK
*(databuf+posi)=TWDR;//读取I2C 接收数据
I2C_Stop();//I2C 停止
/*********************************************
I2C 总线写多个字节,使用页写模式,对于24C512,一次最多写128字节
返回0:写成功
返回1:写失败
**********************************************/
unsigned char I2C_Write_Bytes(unsigned int address,unsigned char *databuf,unsigned char len)
{
unsigned char posi;
I2C_Start(); //I2C 启动
I2C_Wait();
if(I2C_TestAck()!=I2C_START)
return 1; //ACK
I2C_Write8Bit(WD_DEVICE_ADDR); //写I2C 从器件地址和写方式
I2C_Wait();
if(I2C_TestAck()!=MT_SLA_ACK)
return 1; //ACK
I2C_Write8Bit(address>>8); //写器件相应寄存器地址
I2C_Wait();
if(I2C_TestAck()!=MT_DATA_ACK)
return 1; //ACK
I2C_Write8Bit(address&0x00ff); //写器件相应寄存器地址
I2C_Wait();
if(I2C_TestAck()!=MT_DATA_ACK)
return 1; //ACK
for(posi=0;posi {
I2C_Write8Bit(*(databuf+posi)); //写数据到器件相应寄存器
I2C_Wait();
if(I2C_TestAck()!=MT_DATA_ACK)
return 1; //ACK
}
I2C_Stop(); //I2C 停止
_delay_ms(10); //延时
return 0;
}
void TWI_Init(void)
{
TWBR=0x03; //I2C 初始化,400kbps
TWSR|=(1<}
TWI_I2C.h
#ifndef TWI_I2C_H
#define TWI_I2C_H
/*TWI_I2C.h*/
//I2C 状态定义
//MT 主方式传输;MR 主方式接收
#define I2C_START 0x08
#define I2C_RESTART 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
//常用TWI 操作(主模式写和读)
#define I2C_Start() (TWCR=(1<#define I2C_Stop() (TWCR=(1<#define I2C_Wait() {while(!(TWCR&(1<#define I2C_TestAck() (TWSR&0xf8) //观察返回状态
#define I2C_SetAck (TWCR|=(1<#define I2C_SetNoAck (TWCR&=~(1<#define I2C_Twi_NoAck() (TWCR=(1<#define I2C_Twi_Ack() (TWCR=(1<#define I2C_Write8Bit(x) {TWDR=(x);TWCR=(1<#define RD_DEVICE_ADDR 0xA1 //前4 位器件固定,后三位看连线,最后1 位是读写指令位
#define WD_DEVICE_ADDR 0xA0
extern void TWI_Init(void);
extern unsigned char I2C_Read_Bytes(unsigned int address,unsigned char *databuf,unsigned char len);
extern unsigned char I2C_Write_Bytes(unsigned int address,unsigned char *databuf,unsigned char len);
#endif
上述例子用winavr20100110编译通过,读写正常。
阅读(8359) | 评论(0) | 转发(0) |