Operácie

Zbernica i2c: EEPROM: Rozdiel medzi revíziami

Zo stránky SensorWiki

Balogh (diskusia | príspevky)
Balogh (diskusia | príspevky)
Riadok 45: Riadok 45:


[[Súbor:i2c_address.png|400px|center]]
[[Súbor:i2c_address.png|400px|center]]
== '''Software''' ==
Pri tvorbe programu pre modul budeme využívať už hotovú knižnicu <code>i2cmaster</code> dostupnú odtiaľto http://senzor.robotika.sk/mmp/src/i2c/
'''1. Inicializácia'''
Najprv je potrebné zbernicu inicializovať:
<source lang="c">
        i2c_init();                                      // initialize I2C library
</source>
'''
2. Čítanie z A/D prevodníka'''
Potom môžeme prečítať hodnotu na analógovom vstupe č. 3, na ktorom je pripojený trimer:
<div style='text-align: center;'>
[[File:MIPS_8591_ReadValue.png]]<br>
''Postupnosť pre čítanie hodnoty z obvodu 8591.''
</div>
<source lang="c">
/*    value = AnlogRead-From-PCF8591(channel);  */
        i2c_start( PCF8591_ADDR << 1 | I2C_WRITE);        // set device address and write mode
        i2c_write(channel);                              // which channel want to read
        i2c_stop();
        i2c_rep_start(PCF8591_ADDR << 1 | I2C_READ);      // repeated start for reading
        i2c_readAck();                                    // read dummy byte
value = i2c_readNak();                                    // read Analog value
        i2c_stop();
</source>
'''3. Zápis na analógový výstup'''
A napokon prečítanú hodnotu zapíšeme na analógový výstup, takže zmenu priamo uvidíme na pripojenej zelenej LED dióde.
<div style='text-align: center;'>
[[File:MIPS_8591_WriteValue.png]]<br>
''Postupnosť pre zápis hodnoty do obvodu 8591.''
</div>
<source lang="c">
/*    AnalogWrite-To-PCF8591(value);  */
        i2c_start((PCF8591_ADDR << 1 | I2C_WRITE));      // set device address and write mode
        i2c_write(CONTROL BYTE);                          // set analog output active
        i2c_write(value);                                // write the required Analog Output value (0-255)
        ...                                              // multiple write possible
        i2c_stop();                                      // set stop conditon = release bus                       
</source>
Program je samozrejme vhodné doplniť o zobrazovanie veličín buď na LCD displeji, alebo v termináli cez sériové rozhranie.
Pri vytváraní riadiaceho slova by vám mal napomôcť tento obrázok z datasheetu:
<div style='text-align: center;'>
[[File:MIPS_8591_Register.png|500px]]<br>
''Obsadenie riadiaceho registra obvodu 8591.''
</div>


=== 3. Zápis ===
=== 3. Zápis ===

Verzia z 18:54, 13. apríl 2023

Oboznámenie so zbernicou i2c

Úlohy:

  1. Pripojte k procesoru pamäť podľa schémy zapojenia
  2. Schému upravte tak, aby adresa zariadenia bola ?? - určí cvičiaci
  3. Zapíšte na prvé pamäťové miesto (adresa 0x00) znak 'A'
  4. Prečítajte, či je znak správne zapísaný
  5. Prečítajte obsah celej pamäte a vypíšte ho na terminál PC
  6. Zapíšte do pamäte 10 bytov nejakej informácie a zistite, ako dlho trvá zápis jedného byte, t.j. aká veľká musí byť prestávka medzi jednotlivými zápismi.


Literatúra


Datasheets



1. Schéma zapojenia


Správnosť zapojenia si môžete vyskúšať programom Médiá:i2c_scan.ino - nájde všetky obvody pripojené na zbernici.

2. Device address

Software

Pri tvorbe programu pre modul budeme využívať už hotovú knižnicu i2cmaster dostupnú odtiaľto http://senzor.robotika.sk/mmp/src/i2c/

1. Inicializácia

Najprv je potrebné zbernicu inicializovať:

         i2c_init();                                       // initialize I2C library

2. Čítanie z A/D prevodníka

Potom môžeme prečítať hodnotu na analógovom vstupe č. 3, na ktorom je pripojený trimer:


Postupnosť pre čítanie hodnoty z obvodu 8591.

/*    value = AnlogRead-From-PCF8591(channel);   */	

         i2c_start( PCF8591_ADDR << 1 | I2C_WRITE);        // set device address and write mode
         i2c_write(channel);                               // which channel want to read
         i2c_stop();
         i2c_rep_start(PCF8591_ADDR << 1 | I2C_READ);      // repeated start for reading
         i2c_readAck();                                    // read dummy byte
 value = i2c_readNak();                                    // read Analog value
         i2c_stop();


3. Zápis na analógový výstup

A napokon prečítanú hodnotu zapíšeme na analógový výstup, takže zmenu priamo uvidíme na pripojenej zelenej LED dióde.


Postupnosť pre zápis hodnoty do obvodu 8591.

 /*    AnalogWrite-To-PCF8591(value);   */	
	
         i2c_start((PCF8591_ADDR << 1 | I2C_WRITE));       // set device address and write mode
         i2c_write(CONTROL BYTE);                          // set analog output active 
         i2c_write(value);                                 // write the required Analog Output value (0-255)
         ...                                               // multiple write possible
         i2c_stop();                                       // set stop conditon = release bus

Program je samozrejme vhodné doplniť o zobrazovanie veličín buď na LCD displeji, alebo v termináli cez sériové rozhranie.

Pri vytváraní riadiaceho slova by vám mal napomôcť tento obrázok z datasheetu:


Obsadenie riadiaceho registra obvodu 8591.


3. Zápis

4. Čítanie





#include <avr/interrupt.h>  
#include <stdlib.h>
#include <avr/io.h>
#include <util/delay.h>
#include <util/twi.h>
#include <stdio.h>

//#include "lcd.h"
#include "Uart_ch.h"

unsigned char RD_EEprom(unsigned char adr_RAM);
void WR_EEprom(unsigned char adr_IC,unsigned char adr_pocitadlo);
void obsluha_Stav_Aut_I2C(void);



#define ADR_IC_WR		0xA0   	// EEPROM Adresa IC+WR
#define ADR_IC_RD		0xA1   	// EEPROM Adresa IC+RD



volatile  unsigned char	buffer_I2C[10];	// buffer pre obsluhu I2C
	




FILE mystdout_Uart = FDEV_SETUP_STREAM(sendchar, NULL, _FDEV_SETUP_WRITE);


void WR_EEprom(unsigned char adr_IC,unsigned char adr_pocitadlo)
{ 	// nastavenie globalnych premennych

	buffer_I2C[0]=adr_IC;	// Adr obvodu + wr
	buffer_I2C[1]=adr_pocitadlo;	    // Nastavenie Adresneho citaca 24LC04 , Adresa (z ktorej citam)/(do ktorej zapisujem)
//	buffer_I2C[1]=<obsah>;			// zapisovane data, byte,-ty
	
	TWCR = _BV(TWINT) | _BV(TWSTA) | _BV(TWEN); // send start condition 
	// a odovzdanie riadenia "preruseniu od I2C"
	obsluha_Stav_Aut_I2C();

}



unsigned char RD_EEprom(unsigned char adr_RAM)
{ 	
	// nastavenie globalnych premennych

	buffer_I2C[0]=ADR_IC_RD;	// Adr obvodu + rd
	buffer_I2C[1]=adr_RAM;		    // Sem vrati obsah z nastavenej adresy 24LC04

	TWCR = _BV(TWINT) | _BV(TWSTA) | _BV(TWEN); // send start condition 
	// a odovzdanie riadenia "preruseniu od I2C"
	obsluha_Stav_Aut_I2C();
	return(buffer_I2C[1]);
	
}

// tato funkcia vyuziva globalne premenne 
// buffer_I2C[x]
// Wr_data - tato premenna nadobuda vyznam az pri komunikacii s konkretnou premennou
//           vid. "instrukcny subor" I2C periferie

// implementovany instrukcny subor pre seriovu EEPROM max 256 byte
// S|adr_IO+wr|<AC>|P                -- nastavenie adresneho citaca pamate EEPROM
// {nie je implementova} S|adr_IO+wr|<AC>|data|P           -- zapisanie dat na nastavenu adresu pamate EEPROM
// S|adr_IO+rd|data|P                -- precitanie jedneho bytu z aktualne nastavenej adresy pamate EEPROM
//                                      obsah adresneho citaca sa inkrementne 

void obsluha_Stav_Aut_I2C(void)
{ unsigned char pom_St_Aut=0;
	
	
nav:while ((TWCR & _BV(TWINT)) == 0);  /* wait for transmission */

    {   pom_St_Aut=TWSR & 0xf8;		// precitaj stav 
	    printf(" %02x",pom_St_Aut); 
	 	switch(pom_St_Aut)		
	 	{ case TW_START:// = 0x08 // odvysielany start
		  case TW_REP_START:// = 0x10 // odvysielany repeated start
		                 	TWDR = buffer_I2C[0];// Adr+wr/rd, adresa IO
	  						TWCR = _BV(TWINT) | _BV(TWEN); /* clear interrupt to start transmission */
		  break;
		  
		  case TW_MT_SLA_ACK:	//        0x18   Data byte has been tramsmitted and ACK received
		                 	TWDR = buffer_I2C[1]; // tu konkretne, nastavenie Adreseho citaca pamate.
	  						TWCR = _BV(TWINT) | _BV(TWEN); /* clear interrupt to start transmission */
		  break;

		  case TW_MT_DATA_ACK:	//        0x28   Data byte has been tramsmitted and ACK received
		   					TWCR = _BV(TWINT) | _BV(TWSTO) | _BV(TWEN); /* send stop condition */
							return; //  tento riadok v preruseni vypadne
		  break;

		  case TW_MR_SLA_ACK:	//   0x40  // Data byte has been tramsmitted and NACK received
		   					TWCR = _BV(TWINT) | _BV(TWEN) ; // clear interrupt to start transmission 							
		  break;

		  case TW_MR_DATA_NACK:	// 0x58  // Data byte has been tramsmitted and ACK received
		  				    buffer_I2C[1]= TWDR;	    // Vycitaj jeden byte z  24LC04.  Adresny citac sa posunie
				      		TWCR = _BV(TWINT) | _BV(TWSTO) | _BV(TWEN); // send stop condition 
							return; // tento riadok v preruseni vypadne
		  break;		 

		  default:
		  					TWCR = _BV(TWINT) | _BV(TWSTO) | _BV(TWEN); /* send stop condition */
							return; // tento riadok v preruseni vypadne
		  break;
	 	}
	}
	goto nav; // toto v preruseni vypadne
}




int main(void)
{ 	unsigned char znak;

unsigned int i=0;
unsigned char poc_adresa_EEPROM=0;
	


	inituart();								// inicializacia UARTU                       // inicializacia v 4-bitovom rezime
   	                   

//  sei();                    // Enable ALL interrupts                      

// ini I2C
{  
   
   TWCR =  _BV(TWEN); /* send start condition */
   TWBR = 72; // fi2c= fosc/(16 +2(preddelic=00=> 1)(<TWBR>)) = 100kHz
   TWSR=1;
}


// TODO: to USART 
/* ************************************************************	*/

stdout = &mystdout_Uart;


printf("Nastavenie adresy EEPROM = %02x \n\r",poc_adresa_EEPROM);
WR_EEprom(ADR_IC_WR,poc_adresa_EEPROM);


printf("\n\r\rVypis EEPROM: \n\r");

	// vypisme prvych 10 znakov
    while (i<10) //256)// kapacita pamate 256 znakov, bytov, 
	{ 
		znak = RD_EEprom(ADR_IC_RD); // obsah adresneho citaca EEPROM sa automaticky inkrementuje
		if(znak==0xff)i=256; // vymazane pametove miesto
		{
			printf("   %02d %02x %c\r",i++,znak,znak);
		}
        
	}
	
 for(;;);  // a cakam napr. na  "RESET"
 
}