最近剛買回一塊AT24C256 EEPROM ,容量為32K Byte ,數據地址寬度為 16Bit ,支持IIC 1M (5V)400K (2.7V) 速度模式 ,利用AVR M16 片內IIC 可以高速穩定地讀取數據! 經過調試的,與各位大蝦分享分享。
?
程序如下:(winavr)
#include
#include
#include
#include
#define FREQ 8
#include
#include
#include
#define uchar unsigned char
#define uint unsigned int
#define ulong unsigned long
//管腳定義
#define pinSCL 0 //PC0 SCL
#define pinSDA 1 //PC1 SDA
//為保險起見,最好在SCL/SDA接上1~10K的外部上拉電阻到VCC。
#define fSCL 1000000 //TWI時鐘為1000KHz
//預分頻系數=1(TWPS=0)
#if F_CPU 《 fSCL*36
#define TWBR_SET 2; //TWBR必須大于等于10
#else
#define TWBR_SET (F_CPU/fSCL-16)/2; //計算TWBR值
#endif
#define TW_ACT (1《//TWCR只能IN/OUT,直接賦值比邏輯運算(|= &=)更節省空間
#define SLA_24CXX 0xA0 //24Cxx系列的廠商器件地址(高四位)
#define ADDR_24C256 0x00
// AT24C256的地址線A2/1/0全部接地,SLAW=0xA0+0x00《《1+0x00,SLAR=0xA0+0x00《《1+0x01
//TWI_操作狀態
#define TW_BUSY 0
#define TW_OK 1
#define TW_FAIL 2
//TWI_讀寫命令狀態
#define OP_BUSY 0
#define OP_RUN 1
//TWI讀寫操作公共步驟
#define ST_FAIL 0 //出錯狀態
#define ST_START 1 //START狀態檢查
#define ST_SLAW 2 //SLAW狀態檢查
#define ST_WADDR_H 3 //ADDR狀態檢查
#define ST_WADDR_L 4 //ADDR狀態檢查
//TWI讀操作步驟
#define ST_RESTART 5 //RESTART狀態檢查
#define ST_SLAR 6 //SLAR狀態檢查
#define ST_RDATA 7 //讀取數據狀態檢查,循環n字節
//TWI寫操作步驟
#define ST_WDATA 8 //寫數據狀態檢查,循環n字節
#define FAIL_MAX 1 //重試次數最大值
void delay_nms(uint ms)//若干毫秒延時
{
int i;
for(i=0;i{
_delay_loop_2(FREQ*250);
}
}
unsigned char TWI_RW(unsigned char sla,unsigned int addr,unsigned char *ptr,unsigned int len);
unsigned char BUFFER[256]; //緩沖區
void Test(void);
struct str_TWI //TWI數據結構
{
volatile unsigned char STATUS; //TWI_操作狀態
unsigned char SLA; //從設備的器件地址
unsigned char ADDR_H; //從設備的數據地址
unsigned char ADDR_L; //從設備的數據地址
unsigned char *pBUF; //數據緩沖區指針
unsigned int DATALEN; //數據長度
unsigned char STATE; //TWI讀寫操作步驟
unsigned char FAILCNT; //失敗重試次數
};
struct str_TWI strTWI; //TWI的數據結構變量
//AT24C256的讀寫函數(包括隨機讀,連續讀,字節寫,頁寫)
//根據sla的最低位決定(由中斷程序中判斷)
//bit0=1 TW_READ 讀
//bit0=0 TW_WRITE 寫
// sla 器件地址(不能搞錯)
// addr EEPROM地址(0~32767)
// *ptr 讀寫數據緩沖區
// len 讀數據長度(1~32768),寫數據長度(1 or 8 or 16 or 32 or 64)
// 返回值 是否能執行當前操作
unsigned char TWI_RW(unsigned char sla,unsigned int addr,unsigned char *ptr,unsigned int len)
{
// unsigned char i;
if (strTWI.STATUS==TW_BUSY)
{//TWI忙,不能進行操作
return OP_BUSY;
}
strTWI.STATUS=TW_BUSY;
strTWI.SLA=sla;
strTWI.ADDR_H=(unsigned char)((addr》》8)&0xff);
strTWI.ADDR_L=(unsigned char)(addr&0xff);
strTWI.pBUF=ptr;
strTWI.DATALEN=len;
strTWI.STATE=ST_START;
strTWI.FAILCNT=0;
TWCR=(1《 return OP_RUN;
}
SIGNAL(SIG_2WIRE_SERIAL)
{//IIC中斷
unsigned char action,state,status;
action=strTWI.SLA&TW_READ; //取操作模式
state=strTWI.STATE;
status=TWSR&0xF8; //屏蔽預分頻位
if ((status》=0x60)||(status==0x00))
{//總線錯誤或從機模式引發的中斷,不予處理
return;
}
switch(state)
{
case ST_START: //START狀態檢查
if(status==TW_START)
{//發送start信號成功
TWDR=strTWI.SLA&0xFE; //發送器件地址寫SLAW
TWCR=TW_ACT; //觸發下一步動作,同時清start發送標志
}
else
{//發送start信號出錯
state=ST_FAIL;
}
break;
case ST_SLAW: //SLAW狀態檢查
if(status==TW_MT_SLA_ACK)
{//發送器件高位地址成功
TWDR=strTWI.ADDR_H; //發送eeprom地址
TWCR=TW_ACT; //觸發下一步動作
}
else
{//發送器件地址出錯
state=ST_FAIL;
}
break;
case ST_WADDR_H: //ADDR狀態檢查
if(status==TW_MT_DATA_ACK)
{//發送器件低位地址成功
TWDR=strTWI.ADDR_L; //發送eeprom地址
TWCR=TW_ACT; //觸發下一步動作
}
else
{//發送器件地址出錯
state=ST_FAIL;
}
break;
case ST_WADDR_L: //ADDR狀態檢查
if(status==TW_MT_DATA_ACK)
{//發送eeprom地址成功
if (action==TW_READ)
{//讀操作模式
TWCR=(1《 }
else
{//寫操作模式
TWDR=*strTWI.pBUF++; //寫第一個字節
strTWI.DATALEN--;
state=ST_WDATA-1; //下一步將跳到WDATA分支
TWCR=TW_ACT; //觸發下一步動作
}
}
else
{//發送eeprom地址出錯
state=ST_FAIL;
}
break;
case ST_RESTART: //RESTART狀態檢查,只有讀操作模式才能跳到這里
if(status==TW_REP_START)
{//發送restart信號成功
TWDR=strTWI.SLA; //發器件地址讀SLAR
TWCR=TW_ACT; //觸發下一步動作,同時清start發送標志
}
else
{//重發start信號出錯
state=ST_FAIL;
}
break;
case ST_SLAR: //SLAR狀態檢查,只有讀操作模式才能跳到這里
if(status==TW_MR_SLA_ACK)
{//發送器件地址成功
if (strTWI.DATALEN--)
{//多個數據
TWCR=(1《 }
else
{//只有一個數據
TWCR=TW_ACT; //設定NAK,觸發下一步動作
}
}
else
{//發送器件地址出錯
state=ST_FAIL;
}
break;
case ST_RDATA: //讀取數據狀態檢查,只有讀操作模式才能跳到這里
state--; //循環,直到讀完指定長度數據
if(status==TW_MR_DATA_ACK)
{//讀取數據成功,但不是最后一個數據
*strTWI.pBUF++=TWDR;
if (strTWI.DATALEN--)
{//還有多個數據
TWCR=(1《 }
else
{//準備讀最后一個數據
TWCR=TW_ACT; //設定NAK,觸發下一步動作
}
}
else if(status==TW_MR_DATA_NACK)
{//已經讀完最后一個數據
*strTWI.pBUF++=TWDR;
TWCR=(1《 strTWI.STATUS=TW_OK;
}
else
{//讀取數據出錯
state=ST_FAIL;
}
break;
case ST_WDATA: //寫數據狀態檢查,只有寫操作模式才能跳到這里
state--; //循環,直到寫完指定長度數據
if(status==TW_MT_DATA_ACK)
{//寫數據成功
if (strTWI.DATALEN)
{//還要寫
TWDR=*strTWI.pBUF++;
strTWI.DATALEN--;
TWCR=TW_ACT; //觸發下一步動作
}
else
{//寫夠了
TWCR=(1《 strTWI.STATUS=TW_OK;
//啟動寫命令后需要10ms(最大)的編程時間才能真正的把數據記錄下來
//編程期間器件不響應任何命令
}
}
else
{//寫數據失敗
state=ST_FAIL;
}
break;
default:
//錯誤狀態
state=ST_FAIL;
break;
}
評論