-
- #define I2C_SCL GPIO_Pin_6
- #define I2C_SDA GPIO_Pin_7
- #define GPIO_I2C GPIOB
- #define I2C_SCL_H GPIO_SetBits(GPIO_I2C, I2C_SCL) //把PB6置高
- #define I2C_SCL_L GPIO_ResetBits(GPIO_I2C, I2C_SCL) //把PB6置低
- #define I2C_SDA_H GPIO_ResetBits(GPIO_I2C, I2C_SDA) //把PB7置高
- #define I2C_SCL_L GPIO_ResetBits(GPIO_I2C, I2C_SDA) //把PB7置低
轉自:IIC時序詳解——http://blog.csdn.net/drivermonkey/article/details/7695547
AT24C02是由ATMEL公司提供的,IIC總線串行EEPROM(electronic eraser programmer read only memory),其容量為2kbit(256B),工作電壓在2.7v"5.5v之間,生產工藝是CMOS。 
一般數字芯片都在左下角和右上角為GND,VCC。容量的計算方法:AT24Cxx :01"1024
容量 = xx * 1kbit。
寫入過程:
AT24C系列EEPROM芯片的固定部分為1010,A2,A1,A0引腳接高低電平后得到確定的3位編碼,形成7位編碼即為該器件的地址碼。
單片機進行寫操作時,首先發送該器件的7位地址碼和寫方向位”0”(共8位,即一個字節),發送完后釋放SDA線並在SCL線上產生第9個時鍾信號。被選中的存儲器器件在確認是自己的地址后,在SDA線上產生一個應答信號作為響應,單片機收到應答后就可以傳送數據了。傳送數據時,單片機首先發送一個字節的被寫入存儲器的首地址,收到存儲器器件的應答后,單片機就逐個發送數據字節,但每發送一個字節后都要等待應答。AT24C系列片內地址在接收到每一個數據字節地址后自動加1,在芯片的“一次裝載字節數”限度內,只需輸入首地址。裝載字節數超過芯片的“一次裝載字節數”時,數據地址將“上卷”,前面的數據將被覆蓋。 ![]()
字節寫: 
頁寫: 
讀入過程:
單片機先發送該器件的7位地址碼和寫方向位“0”(“偽寫”),發送完后釋放SDA線並在SCL線上產生第9個時鍾信號。被選中的存儲器器件在確認是自己的地址后,在SDA線上產生一個應答信號作為回應。
然后,再發一個字節的要讀出器件的存儲區的首地址,收到應答后,單片機要重復一次起始信號並發出器件地址和讀方向位(“1”),收到器件應答后就可以讀出數據字節,每讀出一個字節,單片機都要回復應答信號。當最后一個字節數據讀完后,單片機應返回以“非應答”(高電平),並發出終止信號以結束讀出操作。 ![]()
當前地址讀: 
隨機讀: 
有序讀: 
IIC總線模擬時序圖: 
IIC總線應答時序圖: 
設備地址: 
寫周期: 
兩次寫之間要有一個10ms的twR間隔
轉自:http://bbs.21ic.com/icview-236765-1-1.html
| 終於弄出來了,用IO口模擬的,但是最后一位不知道為什么總是為0呢
|
轉自:AVR模擬IIC總線-https://download.csdn.net/download/iamfengpeng/1913080
#include <iom128.h>
#include <stdio.h>
#include "iic.h"
#define uchar unsigned char
#define uint unsigned int
/********************************************************************
此程序是I2C操作平台(主方式的軟件平台)的底層的C子程序,如發送數據
及接收數據,應答位發送,並提供了幾個直接面對器件的操作函數,它很方便的
與用戶程序連接並擴展.....
注意:函數是采用軟件延時的方法產生SCL脈沖,固對高晶振頻率要作
一定的修改....(本例是1us機器周期,即晶振頻率要小於12MHZ)
********************************************************************/
#define uchar unsigned char /*宏定義*/
#define uint unsigned int
#define _Nop() asm("nop") /*定義空指令*/
/* 常,變量定義區 */
/*端口位定義*/
#define SDA PORTA_Bit1 /*模擬I2C數據傳送位*/
#define SCL PORTA_Bit0 /*模擬I2C時鍾控制位*/
#define SDA_pin DDRA_Bit1 /*SDA輸入輸出*/
#define SCL_pin DDRA_Bit0
#define SDA_in PINA_Bit1
#define iic_delay() delay_us(1) // 根據系統時鍾進行調整
uchar TAB_T[]={ 0x31,0x06,0x10,//秒,分,時
0x13,0x01,0x07,0x08};//日,星期,月,年.
void delay_us( uchar us )
{
uchar dly;
while ( us -- )
{
for(dly=0;dly<8;dly++);
}
}
/*狀態標志*/
uchar ack; /*應答標志位*/
/*******************************************************************
起動總線函數
函數原型: void Start_I2c();
功能: 啟動I2C總線,即發送I2C起始條件.
********************************************************************/
void Start()
{
SCL_pin=0;
SDA_pin=0;
SDA=1; /*發送起始條件的數據信號*/
_Nop();
SCL=1;
iic_delay();/*起始條件建立時間大於4.7us,延時*/
SDA_pin=1;
SDA=0; /*發送起始信號*/
iic_delay();/* 起始條件鎖定時間大於4μs*/
SCL=0; /*鉗住I2C總線,准備發送或接收數據 */
SCL_pin=1;
iic_delay();
}
/*******************************************************************
結束總線函數
函數原型: void Stop_I2c();
功能: 結束I2C總線,即發送I2C結束條件.
********************************************************************/
void Stop()
{
SDA=0; /*發送結束條件的數據信號*/
SDA_pin=1;
iic_delay(); /*發送結束條件的時鍾信號*/
SCL_pin=0;
SCL=1;
iic_delay(); /*結束條件建立時間大於4μs*/
SDA_pin=0;
SDA=1; /*發送I2C總線結束信號*/
iic_delay();
}
/*******************************************************************
字節數據傳送函數
函數原型: void SendByte(uchar c);
功能: 將數據c發送出去,可以是地址,也可以是數據,發完后等待應答,並對
此狀態位進行操作.(不應答或非應答都使ack=0 假)
發送數據正常,ack=1; ack=0表示被控器無應答或損壞。
********************************************************************/
void WriteByte(uchar c)
{
uchar BitCnt;
for(BitCnt=0;BitCnt<8;BitCnt++) /*要傳送的數據長度為8位*/
{
if((c<<BitCnt)&0x80)
{
SDA_pin=0;
SDA=1; /*判斷發送位*/
}
else
{
SDA=0;
SDA_pin=1;
}
_Nop();
SCL_pin=0;
SCL=1; /*置時鍾線為高,通知被控器開始接收數據位*/
iic_delay(); /*保證時鍾高電平周期大於4μs*/
SCL=0;
SCL_pin=1;
}
iic_delay() ;
SDA_pin=0;
SDA=1; /*8位發送完后釋放數據線,准備接收應答位*/
iic_delay() ;
SCL_pin=0;
SCL=1;
iic_delay();
if(SDA_in==1)
ack=0;
else
ack=1; /*判斷是否接收到應答信號*/
SCL=0;
SCL_pin=1;
iic_delay() ;
}
/*******************************************************************
字節數據傳送函數
函數原型: uchar RcvByte();
功能: 用來接收從器件傳來的數據,並判斷總線錯誤(不發應答信號),
發完后請用應答函數。
********************************************************************/
uchar ReadByte()
{
uchar retc;
uchar BitCnt;
retc=0;
SDA_pin=0;
SDA=1; /*置數據線為輸入方式*/
for(BitCnt=0;BitCnt<8;BitCnt++)
{
SCL=0; /*置時鍾線為低,准備接收數據位*/
SCL_pin=1;
iic_delay(); /*時鍾低電平周期大於4.7μs*/
SCL_pin=0;
SCL=1; /*置時鍾線為高使數據線上數據有效*/
iic_delay();
retc=retc<<1;
if(SDA_in==1)retc=retc+1; /*讀數據位,接收的數據位放入retc中 */
iic_delay();
}
SCL=0;
SCL_pin=1;
iic_delay();
return(retc);
}
/********************************************************************
應答子函數
原型: void Ack_I2c(bit a);
功能:主控器進行應答信號,(可以是應答或非應答信號)
********************************************************************/
void Ack_I2c(uchar a)
{
if(a==0)
{
SDA_pin=1;
SDA=0; /*在此發出應答或非應答信號 */
}
else
{
SDA_pin=0;
SDA=1;
}
iic_delay();
SCL_pin=0;
SCL=1;
iic_delay(); /*時鍾低電平周期大於4μs*/
iic_delay();
SCL=0; /*清時鍾線,鉗住I2C總線以便繼續接收*/
SCL_pin=1;
iic_delay();
}
void Write8563(uchar ucAddr,uchar ucData)
{
Start();
WriteByte(0xa2);
WriteByte(ucAddr);
WriteByte(ucData);
Stop();
}
uchar Read8563(uchar ucAddr)
{
uchar ucData;
Start();
WriteByte(0xa2); //寫器件地址
WriteByte(ucAddr); //寫字節地址
Start();
WriteByte(0xa3); //寫器件地址,最低為1表示讀
ucData=ReadByte(); //寫字節地址
Stop();
return ucData; //讀數據
}
void Init8563(void)
{
uchar i,ucAddr=0x02;
Write8563(0x0d,0x80);
i = Read8563(0x0D);
Write8563(0x00,0x00);
Write8563(0x01,0x11);
i = Read8563(0x00);
i = Read8563(0x01);
for(i=0;i<7;i++)
{
Write8563(ucAddr,TAB_T[i]);
ucAddr++;
}
}
void GetTime(void)
{
uchar i,ucData1,ucData2,ucAddr=0x02;
uchar *pTime=TAB_T;
for(i=0;i<7;i++)
{
pTime[i]=Read8563(ucAddr);
ucAddr++;
}
pTime[0]&=0x7f; //屏蔽無效位
pTime[1]&=0x7f;
pTime[2]&=0x3f;
pTime[3]&=0x3f;
pTime[4]&=0x07;
pTime[5]&=0x1f;
// for(i=0;i<7;i++)
//
// {
//
// ucData1=pTime[i]/16; //BCD碼轉十六進制
//
// ucData2=pTime[i]%16;
//
// pTime[i]=ucData1*10+ucData2;
//
// }
}
/* 完畢 */
轉自:http://bbs.21ic.com/icview-236765-1-1.html
| 終於弄出來了,用IO口模擬的,但是最后一位不知道為什么總是為0呢 #include<avr/io.h> #define uint unsigned int #define uchar unsigned char #define BIT(x) (1<<x) //PORTA0=SCL //PORTA1=SDA void delay1(uint n) { uint i,j; for(i=0;i<n;i++) for(j=0;j<367;j++); } void delay() { asm("NOP"); asm("NOP");asm("NOP"); } void start() //開始信號 { PORTA|=BIT(1); delay(); PORTA|=BIT(0); delay(); asm("NOP");asm("NOP"); PORTA&=~BIT(1); delay(); asm("NOP");asm("NOP"); PORTA&=~BIT(0); delay(); } void stop() //停止 { PORTA&=~BIT(1); delay(); PORTA|=BIT(0); delay();asm("NOP");asm("NOP");asm("NOP");asm("NOP"); PORTA|=BIT(1); delay();asm("NOP");asm("NOP");asm("NOP");asm("NOP"); } void respons() //應答 { //uchar i; PORTA&=~BIT(1); delay(); PORTA|=BIT(0); delay();asm("NOP");asm("NOP");asm("NOP");asm("NOP"); PORTA&=~BIT(0); delay(); } /* void respons_send() //應答 { uchar i; PORTA|=BIT(0); delay(); while(((PORA&BIT(1))==1)&&(i<250))i++; PORTA&=~BIT(0); delay(); } */ void init() { PORTA|=BIT(1); delay(); PORTA|=BIT(0); delay(); } void write_byte(uchar date) { uchar i,temp; for(i=0;i<8;i++) //要傳送的數據長度為8位 { if((date<<i)&0x80) PORTA|=BIT(1); //判斷發送位 else PORTA&=~BIT(1); delay(); PORTA|=BIT(0); //置時鍾線為高,通知被控器開始接收數據位 delay(); delay(); //在此期間取走數據 PORTA&=~BIT(0); delay(); delay(); } PORTA&=~BIT(0); delay(); PORTA|=BIT(1); delay(); } uchar read_byte() { uchar i,k,temp=0; PORTA&=~BIT(0); delay(); PORTA|=BIT(1); //釋放數據線SDA delay(); for(i=0;i<8;i++) { PORTA|=BIT(0); delay(); DDRA&=~BIT(1); PORTA|=BIT(1); delay(); temp=(PINA&0x02); k=((k<<1)|temp); // DDRA|=BIT(1); PORTA&=~BIT(0); delay(); } DDRA|=BIT(1); delay(); return k; } void write_add(uchar address,uchar date) { start(); write_byte(0x56); respons(); write_byte(address); respons(); write_byte(date); respons(); stop(); } uchar read_add(uchar address) { uchar date; start(); write_byte(0x57); respons(); write_byte(address); respons(); date=read_byte(); stop(); return date; } main() { DDRA=0xff; DDRB=0xFF; init(); write_add(0x03,0x3f); delay(); write_add(0x00,0x41); delay(1); write_add(0x08,0xab); delay1(10); PORTB=read_add(0x08); delay(); // PORTB=0XFF; delay(); while(1); } |
