























-
- #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); } |