?? 24cxx.c
字號:
#ifndef MCU_MODEL
#define MCU_MODEL avr //<----在此設定mcu類型, 51代表51系列; avr代表avr系列
#endif
//-----------------------51類MCU-------------------------------------------
#if MCU_MODEL==51
#include<reg51.h> //在此設定51類MCU的頭文件
#include<intrins.h> //_nop_()函數需要
#include"xd.h"
#include"xdprj.h"
//---------定義I2總線端口, 可根據實際使用改變-----------
sbit SCL=P1^0; //I2總線時鐘線
sbit SDA=P1^1; //I2總線數據線
#define SCL_L SCL=0
#define SCL_H SCL=1
#define SDA_L SDA=0
#define SDA_H SDA=1
#define SDA_TO_IN //為配合avr共用次程序而空定義的宏
#define SDA_TO_OUT //為配合avr共用次程序而空定義的宏
#define SDA_IF_L SDA==0 //如果sda為低
#define SDA_IF_H SDA==1 //如果sda為高
//------------------------------------------------------
#define DELAY_us _nop_(); _nop_(); _nop_(); _nop_(); _nop_() //延時用,如果要加長延時,可增加或減少 _nop_();
//------------------------avr類MCU-----------------------------------------
#elif MCU_MODEL==avr
#include<iom16v.h> //在此設定avr類MCU的頭文件
#include<macros.h>
#include"xd.h"
#include"xdprj.h"
//-----定義I2總線端口, 可根據實際使用改變----
#define SCL_L PORTC&=~BIT(0) //I2總線時鐘線
#define SCL_H PORTC|=BIT(0)
#define SDA_L PORTC&=~BIT(1) //I2總線數據線
#define SDA_H PORTC|=BIT(1)
#define SDA_TO_IN DDRC&=~BIT(1); _NOP() //設數據線位輸入
#define SDA_TO_OUT DDRC|=BIT(1); _NOP() //設數據線位輸出
#define SDA_IF_L (PINC&BIT(1))==0 //如果sda為低
#define SDA_IF_H (PINC&BIT(1))==BIT(1) //如果sda為高
//-------------------------------------------
#define DELAY_us tus(7) //avr單片機在晶振為8MHz時,延時5us, 可根據實際情況改變
#endif
//---------------------------------------------------------------------------
//------在此設定芯片型號------
#define e2prom 32 // <---在此設定芯片型號, 1代表24C01; 16代表24C16; 512代表24C512
#if e2prom==1
#define PAGE_SIZE 8
#define SIZE 0x007f
#elif e2prom==2
#define PAGE_SIZE 8
#define SIZE 0x00ff
#elif e2prom==4
#define PAGE_SIZE 16
#define SIZE 0x01ff
#elif e2prom==8
#define PAGE_SIZE 16
#define SIZE 0x03ff
#elif e2prom==16
#define PAGE_SIZE 16
#define SIZE 0x07ff
#elif e2prom==32
#define PAGE_SIZE 32
#define SIZE 0x0fff
#elif e2prom==64
#define PAGE_SIZE 32
#define SIZE 0x1fff
#elif e2prom==128
#define PAGE_SIZE 64
#define SIZE 0x3fff
#elif e2prom==256
#define PAGE_SIZE 64
#define SIZE 0x7fff
#elif e2prom==512
#define PAGE_SIZE 128
#define SIZE 0xffff
#endif
//--------------------------
//--------在此設定芯片地址-------
#define W_ADD_COM 0xa0 //寫字節命令及器件地址(根據地址實際情況改變), 1010 A2 A1 A0 0
#define R_ADD_COM 0xa1 //讀命令字節及器件地址(根據地址實際情況改變), 1010 A2 A1 A0 1
//-------------------------------
//-----在此改變預置錯誤號-----
#define I2C_ERR ERR_10 //寫字節命令及器件地址錯, 在此也就是讀寫器件錯!!
//---------------------------
//-----------4個I2總線公用函數, 可供其它I2總線器件的程序調用--------------
void i2cstart(void); //總線上起動開始條件
uchar i2cwt(uchar a); //把一個字節數據輸入器件
uchar i2crd(void); //i2c讀要調用的函數
void i2cstop(void); //總線上起動停止條件
//------------------------------------------------------------------------
uchar * wt24c_fc(uchar *p, uint ad, uchar n); //向24Cxx寫入數據wt24c_h()所要調用的函數
//向24Cxx寫入數據
//參數: *p_rsc要輸出數據的主機內存地址指針; ad_dst要寫入數據的i2c的地址(雙字節); num數據個數
//參數條件: ad_dst: ad_dst+(num-1)不能大于器件的最高地址; num必須>0;
void wt24c(uchar *p_rsc, uint ad_dst, uint num)
{ uint n;
n=ad_dst/PAGE_SIZE; //確定地址與塊地址的差
if(n) n=(ulong)PAGE_SIZE*(n+1)-ad_dst;
else n=PAGE_SIZE-ad_dst;
if(n>=num) //如果ad_dst所在的數據塊的末尾地址 >= ad_dst + num, 就直接寫入num個數據
{ wt24c_fc(p_rsc, ad_dst, num);
if(syserr!=0) return;
}
else //如果ad_dst所在的數據塊末尾地址 < ad_dst + num, 就先寫入ad_dst所在的數據塊末尾地址與 ad_dst 之差個數據
{ p_rsc=wt24c_fc(p_rsc, ad_dst, n);
if(syserr!=0) return;
num-=n; //更新剩下數據個數
ad_dst+=n; //更新剩下數據的起始地址
//把剩下數據寫入器件
while(num>=PAGE_SIZE) //先按PAGE_SIZE為長度一頁一頁的寫入
{ p_rsc=wt24c_fc(p_rsc, ad_dst, PAGE_SIZE);
if(syserr!=0) return;
num-=PAGE_SIZE; //更新剩余數據個數
ad_dst+=PAGE_SIZE; //更新剩下數據的起始地址
}
if(num) //把最后剩下的小于一個PAGE_SIZE長度的數據寫入器件
wt24c_fc(p_rsc, ad_dst, num);
}
}
//從24cxx讀出數據
//參數: *p_dst要讀入數據的主機內存地址指針; ad_rsc要輸出數據的i2c的地址(整形); num數據個數(整形)
//參數條件: ad_dst+(num-1)不能大于器件的最高地址; num必須>0;
void rd24c(uchar *p_dst, uint ad_rsc, uint num)
{ uchar t=0;
#if e2prom<32
t=ad_rsc>>8;
t<<=1;
#endif
i2cstart(); //發送起始信號
if(i2cwt(W_ADD_COM+t)) //發送寫字節命令及器件地址
{
#if e2prom>16
i2cwt(ad_rsc>>8); //ad_rsc的高位, 發送要讀出數據的地址
#endif
i2cwt(ad_rsc); //ad_rsc的低位
i2cstart(); //再發送起始信號
i2cwt(R_ADD_COM+t); //發送SLA_R, 讀命令字節及器件地址
for(;num>0;num--)
{ *p_dst=i2crd(); //從器件讀出一個字節
p_dst++;
}
}
else syserr=I2C_ERR; //寫字節命令及器件地址錯或對方無應答
i2cstop();
}
//向24Cxx寫入數據wt24c_h()所要調用的函數
//返回寫入n個字節后的主機內存指針
uchar * wt24c_fc(uchar *p, uint ad, uchar n)
{ uchar t=0;
#if e2prom<32
t=ad>>8;
t<<=1;
#endif
i2cstart(); //發送起始信號
if(i2cwt(W_ADD_COM+t)) //發送寫字節命令及器件地址
{
#if e2prom>16
i2cwt(ad>>8); //ad_dst的高位到器件
#endif
i2cwt(ad); //ad_dst的低位到器件
for(;n>0;n--) //發送要寫入的數據
{ i2cwt(*p);
p++;
}
}
else syserr=I2C_ERR; //寫字節命令及器件地址錯
i2cstop();
tms(6); //延時6ms
return(p);
}
//-------------------------------以下為其它I2總線器件可調用的函數--------------------------
//起始信號
void i2cstart(void)
{
SCL_L; DELAY_us;
SDA_H; DELAY_us;
SCL_H; DELAY_us;
SDA_L; DELAY_us;
SCL_L; DELAY_us;
}
//把一個字節數據輸入器件,并以收到應答信號為止
//寫入成功返回1,失敗返回0
uchar i2cwt(uchar a)
{ uchar i;
for(i=0;i<8;i++)
{ SCL_L; DELAY_us;
if((a<<i)&0x80) SDA_H;
else SDA_L;
DELAY_us;
SCL_H; DELAY_us;
}
SCL_L; DELAY_us;
SDA_H; DELAY_us;
SCL_H; DELAY_us;
SDA_TO_IN; //如果是avr單片機,就設SDA引腳位輸入狀態
if(SDA_IF_L) //測試有無應答
{ SDA_TO_OUT;
return(1); //有應答
}
else
{ SDA_TO_OUT;
return(0); //無應答
}
}
//i2c讀要調用的函數
//從器件讀出一個字節
uchar i2crd(void)
{ uchar i,temp;
for(i=0;i<8;i++)
{ SCL_L; DELAY_us;
SDA_H; DELAY_us; //置數據線接上內部上拉(數據輸入方式),此為必須
SCL_H; DELAY_us;
temp<<=1;
SDA_TO_IN; //如果是avr單片機,就設SDA引腳位輸入狀態
if(SDA_IF_H) temp+=1;
DELAY_us;
SDA_TO_OUT; //如果是avr單片機,就設SDA引腳位輸出狀態
}
SCL_L; DELAY_us; //主器件應答脈沖
SDA_L; DELAY_us;
SCL_H; DELAY_us;
return(temp);
}
//停止信號
void i2cstop(void)
{ SCL_L; DELAY_us;
SDA_L; DELAY_us;
SCL_H; DELAY_us;
SDA_H;
}
//--------------------------------------
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -