I2C softwaremässig umsetzen



  • hallo zusammen

    ich bin gerade an einer ausbildung als elektroniker und arbeite an einem kleineren projekt.

    in diesem projekt soll ich mit dem PIC16F876A mit einem temperatursensor (LM75) kommunizieren um dessen werte auszulesen. das ganze soll über I2C funktionieren, jedoch muss ich nun das ganze I2C softwaremässig umsetzen da ich die I2C hardware schon für was anderes brauche.

    leider weiss ich nicht was ich alles definieren muss damit ich schlussendlich die c-befehle für I2C gebrauchen kann und es funktioniert. achja, wir arbeiten mit dem Ccs-Compiler in MPLap.

    ich hoffe da kann mir jemand ein wenig weiterhelfen



  • Elektroniker schrieb:

    jedoch muss ich nun das ganze I2C softwaremässig umsetzen da ich die I2C hardware schon für was anderes brauche.

    Warum kannst du nicht beide Slaves am I2C-Master betreiben? Oder ist der I2C-Controller mit einer anderen Hardware-Resource verkuddelt die du brauchst?



  • Ist jetzt aus meiner M16C- Adaption geklaut, funktioniert aber einwandfrei. Man muß nur wissen, daß ich Pins verwendet habe, die kein aktives Hi treiben (Pullup), kann man aber durch Anpassen leicht ändern.
    Natürlich ist da nix mit Multimasterbetrieb usw. ist jetzt nur der absolute Grundstock für i2c.
    Wieso sind die Pins für i2c eigentlich anderweitig belegt, man kann ja von einer Slaveklasse meist acht oder mehr Bausteine ranhängen und die Hardwareimplementationen können sogar meist Multimasterbetrieb.
    Naja, wahtsoever, vielleicht hilft's Dir:

    #define	sda_value			p7_0
    #define	sda					pd7_0
    #define sck					p7_1
    #define sck_dir				pd7_1
    
    void wait(void)
    {
    	char i;
    	for ( i=0; i<=8; i++ )
    	{
    	}
    }
    
    char I2C_stac()		// generate start condition
    {
    //	sck_dir = 0;		// SCL High
    	sda = 0;		// SDA release
    	sck = 1;
    	wait();
    	if (sda_value) // beide High
    	{
    		sda = 1;
    		sda_value = 0;	// force SDA low
    		wait();
    
    //		sck_dir = 1;
    		sck = 0;	// force SCL low
    		wait();
    		return 255;
    	}
    	else return 0;
    }
    
    char I2C_stoc()		// generate stop condition
    {
    	char	merk;
    	sda = 1;			// Force Low
    	wait();
    	sck = 1;		// SCL High
    	wait();
    	sda = 0;		// SDA release
    	wait();
    //	sck_dir = 0;
    	if (sda_value) //  High
    		merk = 255;
    	else 
    		merk = 0;
    	sda_value = 0;		// SDA low
    
    }
    
    char GetAck(char ack)
    {
    	char merk;
    	sda = 0;		// SDA release
    	sck = 1;	// SCL hi
    	wait();
    	merk = (char) sda_value;
    	if (merk)
    	{
    		merk = 255;
    	}
    	sck = 0;
    	// while (sda_value == 0);
    	sda_value = 0;
    	if (ack)
    	{
    		merk = !merk;
    	}
    	return merk;
    }
    
    void PutAck(char ack)
    {
    	if (ack)
    	{
    		sda = 1;
    		sda_value = 0;
    	}
    	else
    		sda = 0;		// SDA release
    	sck = 1;	// SCL hi
    	wait();
    	sck = 0;
    }
    
    char I2C_out(char value, char ack)
    {
    	char i;
    	for (i=0; i<=7 ;i++ )
    	{
    		if (value & 128)
    			sda = 0;		// SDA release
    		else
    			{
    				sda_value = 0;
    				sda = 1;
    			}
    		sck = 1;	// SCL hi
    		value <<=1;
    		wait();
    		sck = 0;	// SCL lo
    	}
    	return GetAck(ack);
    }
    
    char I2C_in(char *value, char ack)
    {
    char i;
    	sda = 0;
    	for (i=0; i<=7 ;i++ )
    	{
    		sck = 1;	// SCL hi
    		wait();
    		*value <<=1;	// make place for bit
    		if (sda_value) 
    			*value |= 1;
    		sda_value = 0;
    		sck = 0;	// SCL lo
    	}
    
    	PutAck(ack);
    	return 255;
    }
    
    char I2C_adress_device(char dev_adress, char mode, char attempts)
    {
    	char out;
    		out = (char)((char)((char)( dev_adress & 7)  << 1)| 0xa0);	// ((dev_adress & 7) <<1) | 0xa0;
    		if (mode) out |= 0x01; 
    												// write, ACK expected
    	do
    	{
    	    if (I2C_stac())	// send start condition
    			if (I2C_out(out,255)) 
    				return 255; 
    			else 
    				I2C_stoc();
    	} while (--attempts);
    	return 0;
    }
    


  • pointercrash() schrieb:

    Man muß nur wissen, daß ich Pins verwendet habe, die kein aktives Hi treiben (Pullup), kann man aber durch Anpassen leicht ändern.

    das mit den pull-ups ist doch das einzig richtige. ansonsten kann's kurzschlüsse geben, wenn der master aktive einsen ausgibt (und ein slave z.b. clock-stretching macht).
    🙂



  • ~fricky schrieb:

    und ein slave z.b. clock-stretching macht.
    🙂

    Clock-stretching? 😮

    Was perverses ist das denn? 🕶



  • vielen dank für die auskunft! der code funktioniert nun mit eurer hilfe schon mal ohne fehlermeldungen, jetzt muss ich das nur noch testen und wenns funzt ists perfekt 😃

    also die beiden pins SLC und SDA sind bereits durch dot-matrix-driver belegt und darum musste ich den temperatursensor auf zwei andere pins legen.



  • Javaner schrieb:

    Clock-stretching?
    Was perverses ist das denn?

    das ist iic-flusskontrolle. damit können slaves den master ausbremsen, wenn sie 'ne verschnaufpause brauchen.
    🙂


Anmelden zum Antworten