Hi, This programing is to Start I2c Communication with the basic start up code followed by sending a 8 bit address together with a write bit. Next, it will send a string a serial port to show a string "nack" only if the SDA is not pulled low, which means not acknowledged.
Chip used: Dallas DS89C450 11.0592Mhz Accelerometer: SEN 10955 2.25 Mhz
Problem faced: SDA could not be pulled low. Nack received.
Question: May i know is there any faults in this program?
#include <DS89C4XX.h> //DS89C450 Microcontroller #include <intrins.h> //_nop_() function sbit SDA=P1^0; sbit SCL=P1^1; //--------------------------Transmit---------------------------------- void Uart_Tx2(unsigned char c) { while (TI_0==0); TI_0=0; SBUF0=c; } // ----------------------Transmit string ------------------------------------------------------ void sendstring (char *String) { int i=0; //set counter to 0 while(String[i]) { Uart_Tx2(String[i++]); } } //-------------------------------Delay ----------------------------------------- void I2CBitDly() // wait approximately 4.7uS { // tune to xtal. This works at 11.0592MHz unsigned int time_end = 9; unsigned int index; for (index = 0; index < time_end; index++); return; } //-------------------------------------------Start-------------------------- void I2CSendStart(void) { SDA = 1; I2CBitDly(); SCL = 1; I2CBitDly(); SDA = 0; I2CBitDly(); SCL = 0; I2CBitDly(); } //-------------------------------------------STOP----------------------------- void I2CSendStop(void) { SDA = 0; I2CBitDly(); SCL = 1; I2CBitDly(); SDA = 1; I2CBitDly(); } //-----------------------------------------SEND data--------------------------- void I2CSendByte(unsigned char bt) { register unsigned char i; for (i=0; i<8; i++) { if ((bt<<i)&0x80) SDA = 1; // Send each bit else SDA = 0; SCL = 1; I2CBitDly(); SCL = 0; I2CBitDly(); } SDA = 1; // make P1.0 an input. I2CBitDly(); SCL = 1; // 9th clock high. I2CBitDly(); if (SDA == 1) // { sendstring("nack"); // SDA is not pulled low. nack is sent. } SCL = 0; I2CBitDly(); //SDA = 1; // end transmission SCL = 1; } //---------------MAIN--------------------------------- void main () { SCON1 = 0x52; SCON0 = 0x52; TMOD = 0x20; TCON = 0x69; TH1 = 0xFD; //Buad Rate: 9600 bps I2CSendStart(); I2CSendByte(0x38); while(1) { }; }
You are testing SDA after you set SCL high. This can't work. If the SDA would change while SCL is high 'other' I2C devices would see a 'start' or 'stop' condition on the bus. After you set SCL high then set SCL low again and then test the SDA state. Please read the I2C specification carefully. Read what happens on rising and falling edge of the SCL signal.
Hi! I finally manage to receive an acknowledge, the problem was the wrong slave address used. However, Now, i could not Read from the I2C bus. I keep receiving 0x01 as the final result.
Question: Is my Transmitting to serial port or receiving from I2C function at fault?
#include <DS89C4XX.h> //DS89C450 Microcontroller #include <intrins.h> //_nop_() function #include <stdio.h> //sprintf() function sbit SDA=P1^0; sbit SCL=P1^1; //--------------------------Transmit---------------------------------- void Uart_Tx1(unsigned char c) { while (TI_0==0); TI_0=0; SBUF0=c; } //--------------------------Transmit---------------------------------- void Uart_Tx2(unsigned char c) { while (TI_0==0); TI_0=0; SBUF0=c; } // ----------------------Transmit string ------------------------------------------------------ void sendstring (char *String) { int i=0; //set counter to 0 while(String[i]) { Uart_Tx2(String[i++]); } } //-----------------------------Delay-------------------------------------------- void Delay(int count) { int i,j; for (i=0;i<count;i++){ for (j=0;j<1200;j++); } } //-------------------------------Delay ----------------------------------------- void I2CBitDly() // wait approximately 4.7uS { // tune to xtal. This works at 11.0592MHz unsigned int time_end = 10; unsigned int index; for (index = 0; index < time_end; index++); return; } //-------------------------------------------Start-------------------------- void I2CSendStart(void) { SDA = 1; I2CBitDly(); SCL = 1; I2CBitDly(); SDA = 0; I2CBitDly(); SCL = 0; I2CBitDly(); } //-------------------------------------------STOP----------------------------- void I2CSendStop(void) { SDA = 0; I2CBitDly(); SCL = 1; I2CBitDly(); SDA = 1; I2CBitDly(); } //-----------------------------------------SEND data--------------------------- void I2CSendByte(unsigned char bt) { register unsigned char i; for (i=0; i<8; i++) { if ((bt<<i)&0x80) SDA = 1; // Send each bit else SDA = 0; SCL = 1; I2CBitDly(); SCL = 0; I2CBitDly(); } SDA = 1; // make P1.0 an input. I2CBitDly(); SCL = 1; // 9th clock high. I2CBitDly(); if (SDA == 0) // { //sendstring(" ack "); // SDA is not pulled low. nack is sent. } SCL = 0; I2CBitDly(); SDA = 1; // end transmission SCL = 1; } //----------------READ DATA -------------------------------------------------------------------------------- unsigned char I2CGetByte() { unsigned char retc; unsigned char BitCnt; retc=0; I2CBitDly(); SCL=0; I2CBitDly(); SDA=1; // set as input pin. for(BitCnt=0;BitCnt<8;BitCnt++) { I2CBitDly(); SCL=1; retc=retc<<1; // shift by 1 for each bit. I2CBitDly(); if(SDA==1)retc=retc+1; I2CBitDly(); SCL=0; } I2CBitDly(); return(retc); } //-------------------Standby--------------------------- void standby_mode () { I2CSendStart(); I2CSendByte(0x3A); I2CSendByte(0x0B); //address I2CSendByte(0x00); // standby mode I2CSendStop(); } //-------------------Active mode----------------------- void active_mode () { I2CSendStart(); I2CSendByte(0x3A); I2CSendByte(0x0B); I2CSendByte(0x01); // active mode I2CSendStop(); } //---------------------8g mode ----------------------- void g_mode () { I2CSendStart(); I2CSendByte(0x3A); I2CSendByte(0x0E); I2CSendByte(0x02); // set to 8g. I2CSendStop(); } //-------------------Register Active mode ---------------- void AReg1 () { I2CSendStart(); I2CSendByte(0x3A); I2CSendByte(0x2A); I2CSendByte(0x01); // active mode I2CSendStop(); } //----------------------------------Transmit CHAR---------------------- void Char_Int(unsigned char c) { unsigned char s[4]; int i; c=c&0xff; sprintf(s,"%03d ",(int)c); for (i=0;i<4;i++) Uart_Tx1(s[i]); } //---------------MAIN--------------------------------- void main () { unsigned char value; SCON1 = 0x52; SCON0 = 0x52; TMOD = 0x20; TCON = 0x69; TH1 = 0xFD; //Buad Rate: 9600 bps Delay(200); SDA = 0; //set to output pin SCL = 0; //set to output pin Delay(200); standby_mode (); // set to standby to do config g_mode (); // set to 8g range AReg1 (); // set REG 1 active for reading active_mode (); // set back to active mode while (1) { I2CSendStart(); I2CSendByte(0x3A); I2CSendByte(0x01); I2CSendStart(); I2CSendByte(0x3B); value = I2CGetByte(); Char_Int(value); I2CSendStop(); Delay(1000); } }
these days, why not choose one of the plethora of chips with hardware I²C?. Soft I²C is a HUGE "performance killer"
Erik
A large percentage of embedded devices will probably see no performance loss from sw-implemented I2C. Lots of equipment needs an area for storage of some configuration. So it's enough to read out the configuration on boot, and to rewrite one or more configuration entries when the user enters the menu system to reconfigure the device.
It's only data loggers or similar devices that is constantly reading/writing data that have to consider the percentage of time the device is locked up doing I2C communication.
But the big question here is that since sw-implemented I2C is so very portable (it's just how to read and write the pins and how to create the delay that depends on the processor), there are lots of well-working code out there. So why get stuck with broken code, unless it is a school assignment to implement the algorithm?