logo elektroda
logo elektroda
X
logo elektroda
REKLAMA
REKLAMA
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

Atmega16 bledny odczyt z EEPROMU

w.adamczak 26 Mar 2009 09:02 1627 10
REKLAMA
  • #1 6334002
    w.adamczak
    Poziom 10  
    Witam!
    Próbuję poradzić sobie z zapisem i odczytem zmiennej z EEPROM'u.
    Gdy po zapisaniu do pamięci zmiennej resetuję procka przy użyciu programatora to jest ona prawidłowo odczytywana. Gdy natomiast odłączę zasilanie to niestety procek odczytuje mi inną wartość. Ta źle odczytana wartość równa jest '1' czyli takiej wartości jaką wpisuję do EEpromu w przerwaniu po załadowaniu nowego programu.

    Będę wdzięczny za pomoc
    schemat polaczen:
    Atmega16 bledny odczyt z EEPROMU

    Kod:
    
    #include <avr/io.h>
    #include <avr/interrupt.h> 
    //#include<avr/signal.h>
    #include <avr/eeprom.h>
    #include "font.h"
    
    
    // definicje UART
    #define F_CPU 7372800// Clock Speed
    #define BAUD 19200
    #define MYUBRR ((F_CPU/(16*BAUD))-1)
    
    // port szyny danych
    #define LCD_DATA_PORT 	PORTA
    #define LCD_DATA_PIN 	PINA
    #define LCD_DATA_DDR 	DDRA
    // port sygnałów sterujących
    #define LCD_CTRL_PORT 	PORTC
    #define LCD_CTRL_PIN 	PINC
    #define LCD_CTRL_DDR 	DDRC
    // sygnały sterujące
    #define LCD_CS1P 	(PINC, 4)	
    #define LCD_CS2P 	(PINC, 3)	
    #define LCD_EN 		(PINC, 2)		
    #define LCD_RW 		(PINC, 1)		
    #define LCD_RS 		(PINC, 0)
    // inne sygnaly od LCD
    //#define DISPLAY_STATUS_BUSY (PINA, 7)		
    
    // instrukcje sterownika KS0108
    #define DISPLAY_SET_Y       0x40
    #define DISPLAY_SET_X       0xB8
    #define DISPLAY_START_LINE  0xC0
    #define DISPLAY_ON_CMD		0x3E
    #define ON					0x01
    #define OFF					0x00
    #define DISPLAY_STATUS_BUSY	0x80
    
    
    // makroinstrukcje ustawienia stanu na linii CS1
    #define SET_CS1() 	(LCD_CTRL_PORT |= (1 << LCD_CS1P))
    #define CLR_CS1() 	(LCD_CTRL_PORT &= ~(1 << LCD_CS1P))
    // makroinstrukcje ustawienia stanu na linii CS2
    #define SET_CS2() 	(LCD_CTRL_PORT |= (1 << LCD_CS2P))
    #define CLR_CS2() 	(LCD_CTRL_PORT &= ~(1 << LCD_CS2P))
    // makroinstrukcje ustawienia stanu na linii EN
    #define SET_EN() 	(LCD_CTRL_PORT |= (1 << LCD_EN))
    #define CLR_EN() 	(LCD_CTRL_PORT &= ~(1 << LCD_EN))
    // makroinstrukcje ustawienia stanu na linii RW
    #define SET_RW() 	(LCD_CTRL_PORT |= (1 << LCD_RW))
    #define CLR_RW() 	(LCD_CTRL_PORT &= ~(1 << LCD_RW))
    // makroinstrukcje ustawienia stanu na linii RS
    #define SET_RS() 	(LCD_CTRL_PORT |= (1 << LCD_RS))
    #define CLR_RS() 	(LCD_CTRL_PORT &= ~(1 << LCD_RS))
    // makroinstrukcje ustawiajace odpowiednią kombinację sygnałów CS1 i CS2
    #define LCD_CS0() 	CLR_CS1();SET_CS2();
    #define LCD_CS1() 	SET_CS1();CLR_CS2();
    #define LCD_NOCS() 	SET_CS1();SET_CS2();
    
    //inne
    #define tau 	6
    
    //definicje zmiennych
    unsigned char ii=0, n=1, m=0, ii_old = 0, p=0, stan_BTM=0; 
    char ii_current=0;
    long int i=0;
    int x=0, k=0, ll=0;
    unsigned char znak1 [20], znaczek=0, zmiana=0;
    unsigned char znak [30], znak2 [20], znak3;
    unsigned char znak4 [30], znak_old [30], znak5 [10], znak6 [30];
    char volatile liczba=0;
    unsigned char j=0;
    
    
    unsigned char wartosc=0, wartosc1=8, wartosc_old=8;
    unsigned char flaga=0, flaga1=0, flaga2=0, flaga_BTM=0,flaga_BTM_1=0, flaga_BTM2=0, flaga_RS=0;
    unsigned char flaga_AT=0, flaga_AT_old=0, flaga_obsluga=0, flaga_BTM_stan=0;
    unsigned char urzadzenia_polaczone=0;
    
    unsigned char gg=0, gg1=0, gg11=0x30; //zmienne ktore uzywalem do zapisu do eepromu
    
    
    /**************************************************************/
    void wait1(void) {	  for(i=0;  i<500;  i++) asm("nop");}
    void wait2(void) {    for(i=0;  i<1000; i++) asm("nop");}
    void wait3(void) {    for(i=0;  i<8000; i++) asm("nop");}
    void wait4(void) {    for(i=0;  i<80000; i++) asm("nop");}
    
    /****************************************************************/
    
    void USART_Init( unsigned int baud )
    {
       /* Set baud rate */
       UBRRH = (F_CPU/(BAUD*16L)-1) >> 8; //(unsigned char)(baud>>8);
       UBRRL = (unsigned char)(F_CPU/(BAUD*16L)-1); //(unsigned char)baud;
       /* Enable receiver and transmitter */
       UCSRB = (1<<RXCIE)|(1<<TXEN)|(1<<RXEN);//|(1<<TXCIE);
          /* Set frame format: 8data, 1stop bit */
       UCSRC = (1<<URSEL)|(3<<UCSZ0);//|(1<<USBS)
    }
    
    /**************************************************************/
    
    void USART_Transmit( unsigned char data )
    {
       /* Wait for empty transmit buffer */
       while ( !( UCSRA & _BV(UDRE)) )
       ;
       
       /* Put data into buffer, sends the data */
       UDR = data;
    }
    
    /**************************************************************/
    
    unsigned char USART_Receive( void )
    {
       /* Wait for data to be received */
       while ( !(UCSRA & (1<<RXC)) )
       ;
       /* Get and return received data from buffer */
       return UDR;
    }
    
    /**************************************************************/
    
    void USART_write_text(char *s)
    {
       while(*s)                               // do napotkania 0
            {
            //tu by sie cos przydalo atoi np
            USART_Transmit(*s);                   // zapisz znak wskazywany przez s na LCD
            s++;                               // zwiększ s (przygotuj nastepny znak)
            }
    } 
    
    /**************************************************************/
    
    int wyszukaj_liczbe(unsigned char *tablica2)	// funkcja służąca do wyszukiwania ustawien parametrow transmisji
    						// zwraca wartosc odpowiadajaca ustawieniom transmisji
    {	
    	unsigned char l;
    	for (l=0; l<5; l++)
    	{
    		//if((u>0)&&(tablica2[l-1]==tablica1[u-1])&&(tablica2[l]!=tablica1[u])) 	{u=0;}
    		if(tablica2[l]==0x30 ) 		{return 0;}
    		if(tablica2[l]==0x31 ) 		{return 1;}
    		if(tablica2[l]==0x32 ) 		{return 2;}
    		if(tablica2[l]==0x33 ) 		{return 3;}
    		if(tablica2[l]==0x34 ) 		{return 4;}
    		if(tablica2[l]==0x35 ) 		{return 5;}
    		if(tablica2[l]==0x36 ) 		{return 6;}
    		if(tablica2[l]==0x37 ) 		{return 7;}
    
    	}
    	return 8;
    }
    
    /**************************************************************/
    void wyswietl(unsigned char wyswietl_ustawienia)	//funkcja wyswietla ustawienia transmisji szeregowej
    {
    	if(wyswietl_ustawienia!=wartosc1) 
    	{
    		switch (wyswietl_ustawienia)
      		{
    			case 0:	
    					lcdWriteSpeed("4800 bps"); 
    					lcdWriteStopBits("stop"); 
    					lcdWriteParity("parity");
    					eeprom_write_byte((char*)0x0001,0x30);
    					while(eeprom_is_ready()==0);
    					break;
    
    			case 1:		
    					lcdWriteSpeed("9600 bps"); 
    					lcdWriteStopBits("stop"); 
    					lcdWriteParity("parity");
    					eeprom_write_byte((char*)0x0001,0x31);
    					while(eeprom_is_ready()==0);
    					break;
    
    			case 2:	
    					lcdWriteSpeed("19200 bps");
    					lcdWriteStopBits("stop"); 
    					lcdWriteParity("parity");
    					eeprom_write_byte((char*)0x0001,0x32);
    					while(eeprom_is_ready()==0);
    					break;
    
    			case 3:	
    					lcdWriteSpeed("38400 bps");
    					lcdWriteStopBits("stop"); 
    					lcdWriteParity("parity");
    					lcdLocate(8,7);
    					eeprom_write_byte((char*)0x0001,0x33);
    					while(eeprom_is_ready()==0);
    					break;
    
    			case 4:	
    					lcdWriteSpeed("57600 bps");
    					lcdWriteStopBits("stop"); 
    					lcdWriteParity("parity");;
    					break;
    
    			case 5:	
    					lcdWriteSpeed("115200 bps");
    					lcdWriteStopBits("stop"); 
    					lcdWriteParity("parity");
    					break;
    
    			case 6:	
    					lcdWriteSpeed("230400 bps");
    					lcdWriteStopBits("stop"); 
    					lcdWriteParity("parity");
    					break;
    
    			case 7:	
    					lcdWriteSpeed("460800 bps");
    					lcdWriteStopBits("stop"); 
    					lcdWriteParity("parity");
    					break;
      		}
      }
      wartosc1=wyswietl_ustawienia;
    }
    
    /************************PRZERWANIA****************************/
    
    
    SIGNAL(SIG_INTERRUPT0) // przerwanie zewnetrzne INT0
    {
    	eeprom_write_byte((char*)0x0001, 0x31);	//pierwszy zapis do eepromu po zaladowaniu programu
    }
    
    /**************************************************************/
    SIGNAL(SIG_INTERRUPT1) // przerwanie zewnetrzne INT0
    {
    
    }
    
    /**************************************************************/
    SIGNAL(SIG_UART_RECV)		//przerwanie od UART'a
    {
    	//znaczek=UDR;
    
    	znak[ii]=UDR;
    	ii++;
    	if(ii>29) ii=0;
    } 
    
    /**************************************************************/
    int main(void)
    {
    
    DDRD=0x02;					//0 to wejscie
    						//1 to wyjscie
    
    
    GICR=(1<<INT0)|(1<<INT1);			//zezwolenie na przerwanie zewnetrzne INT0
    MCUCR=(1<<ISC01)|(1<<ISC11); 			//wjescie INT0 reaguje na zbocze opadajace
    
    
    TCNT0=tau;
    TCCR0=2;				//preskaler XTAL/8
    
    USART_Init(BAUD);
    sei(); 
    
    lcdInit();
    lcdOn();
    lcdCls();
    
    gg = eeprom_read_byte((char*)0x0001);		//odczyt z eepromu
    while(eeprom_is_ready()==0);
    
    wyswietl(gg-0x30);
    
       while(1)
       {
    	lcdLocate(0,7);
    	lcdWriteChar(gg);			//wyswietla na graicznym odczytana wartosc z eepromu
    	lcdWriteConnection("CONNECTED");
    	wyswietl(wyszukaj_liczbe(znak));	//wyswietla parametry transmisji
    
       }
    }
    
    
  • REKLAMA
  • #2 6334838
    kaktus_c++
    Poziom 18  
    proponuję zastosować zarówno przed każdym zapisem i odczytem jak i po zapisie/odczycie eepromu makro eeprom_busy_wait() które jest tym samym co while(eeprom_is_ready()==0)
  • REKLAMA
  • #3 6335089
    w.adamczak
    Poziom 10  
    niestety nic nie pomogło:/
  • #4 6335528
    Dr_DEAD
    Poziom 28  
    w.adamczak napisał:
    Ta źle odczytana wartość równa jest '1' czyli takiej wartości jaką wpisuję do EEpromu w przerwaniu po załadowaniu nowego programu.

    Czyli podczas wyłączania lub startu wywołuje ci się przerwanie i zapisuje EEPROMA. A bez obsługi tego przerwania wszytko jest oki??
  • #5 6335736
    w.adamczak
    Poziom 10  
    właśnie też nie. Tzn gdy zrobie inaczej, najpierw coś zapiszę a później odczytam to jest ok.
    Czyli jak zrobie tak:
    
    int main(void)
    {
    
    DDRD=0x02;               //0 to wejscie
                      //1 to wyjscie
    
    
    GICR=(1<<INT0)|(1<<INT1);         //zezwolenie na przerwanie zewnetrzne INT0
    MCUCR=(1<<ISC01)|(1<<ISC11);          //wjescie INT0 reaguje na zbocze opadajace
    
    
    TCNT0=tau;
    TCCR0=2;            //preskaler XTAL/8
    
    USART_Init(BAUD);
    sei();
    
    lcdInit();
    lcdOn();
    lcdCls();
    
    eeprom_write_byte((char*)0x0001, 0x31);   //pierwszy zapis do eepromu po zaladowaniu programu 
    while(eeprom_is_ready()==0);
    gg = eeprom_read_byte((char*)0x0001);      //odczyt z eepromu
    while(eeprom_is_ready()==0);
    
    wyswietl(gg-0x30);
    
       while(1)
       {
       lcdLocate(0,7);
       lcdWriteChar(gg);         //wyswietla na graicznym odczytana wartosc z eepromu
       lcdWriteConnection("CONNECTED");
       wyswietl(wyszukaj_liczbe(znak));   //wyswietla parametry transmisji
    
       }
    } 
    


    No ale przecież nie o to tutaj chodzi
  • #6 6336235
    kaktus_c++
    Poziom 18  
    weź napisz jak to ma wg Ciebie działać - to przerwanie INT0 w jakich okolicznościach jest wywoływane?. Bo wg schematu nie jest podłączony ten pin chyba do niczego.
  • REKLAMA
  • #7 6337308
    w.adamczak
    Poziom 10  
    w zasadzie to przerwanie nie jest mi potrzebne. Ale uzylem go tylko po to zeby zapisac jakas wartosc do epromu i odczytac ja po ponownym wlaczeniu zasilania. Teraz zmienilem Avr studio na nowsza wersje i wychodzi na to ze przy starcie wywoluje mi sie przerwanie. Skrocilem do min program do testow i wyglada to nastepujaco:
    
    #include <avr/io.h>
    #include <avr/interrupt.h> 
    //#include<avr/signal.h>
    #include <avr/eeprom.h>
    #include "font.h"
    
    // funkcji do obslugi wyswieltacza nie wklejam!!!!
    
    //definicje zmiennych
    unsigned char lcd_x, lcd_y, wartosc=0;
    unsigned char gg=0, gg1=8, gg11=0x30; //zmienne ktore uzywalem do zapisu do eepromu
    SIGNAL(SIG_INTERRUPT0) // przerwanie zewnetrzne INT0
    {
    //	while(eeprom_is_ready()==0);
    	eeprom_busy_wait();
    	eeprom_write_byte((unsigned char*)0x0001, 0x39);
    	eeprom_busy_wait();
    //	while(eeprom_is_ready()==0);
    //	eeprom_write_byte(201, wartosc+0x32);
    }
    
    int main(void)
    {
    
    DDRD=0x00;				//0 to wejscie
    //PORTD=0xFF;						//1 to wyjscie
    
    GICR=(1<<INT0);//|(1<<INT1);			//zezwolenie na przerwanie zewnetrzne INT0
    MCUCR=(1<<ISC01)|(1<<ISC11); 			//wjescie INT0 reaguje na zbocze opadajace
    SREG|=(1<<SREG_I); 		// globalne zezwolenie na przerwania
    //sei(); 
    
    lcdInit();
    lcdOn();
    lcdCls();
    
    
    lcdWriteString("w1");
    gg = eeprom_read_byte((unsigned char*)0x0001);
    
       while(1)
       {
       	lcdLocate(0,1);
    	lcdWriteString("while");
    	if(bit_is_clear(PIND, 6)) 
    	{
    		eeprom_write_byte((unsigned char*)0x0001, 0x35);
    		eeprom_busy_wait();
    		lcdWriteString("pin");
    	}
    	if(bit_is_clear(PIND, 5)) 
    	{
    		eeprom_write_byte((unsigned char*)0x0001, 0x33);
    		eeprom_busy_wait();
    		lcdWriteString("pin");
    	}
      	if(gg!=gg1) 
    	lcdWriteChar(gg);
    	gg1=gg;
    
       }
    }
    


    Po zaladowaniu programu wysiwetlaja mi sie jakies smieci. za pomoca przycisku zapisuje nowa wartosc do pamieci. Po ponownym wlaczeniu procka zamiast wyswietlac mi sie 3 lub 5 dostaje 9 czyli wartosc z przerwania.
  • REKLAMA
  • #8 6337497
    Dr_DEAD
    Poziom 28  
    Skoro wywołuje ci się przerwanie przy starcie to nic dziwnego że masz 9 wpisane. A kasujesz w ogóle fagi przerwań przed włączeniem globalnego zezwolenia i po konfiguracji przerwań???
  • #9 6337534
    kaktus_c++
    Poziom 18  
    może ja czegoś nie rozumiem ale pomysła z przerwaniem jest dla mnie bez sensu. Jeśli pin nie jest podłączony do niczego to teoretycznie przerwanie nie powinno się wywoływać wcale. Ale są różne zakłócenia i może Ci się ono w takim przypadku wywoływać w różnych momentach, z kąd wiesz kiedy się ono wywoła?

    ten fragment uruchomienia przerwania i obsługi przerwania proponuję wywalić i zmodyfikować resztę jak poniżej:

    
    lcdWriteString("w1");
    eeprom_busy_wait();
    gg = eeprom_read_byte((unsigned char*)0x0001); 
    eeprom_busy_wait();
    if (gg!=0x35 || gg!=0x31)
    {
    gg=0x39;
    eeprom_busy_wait();
    eeprom_write_byte((unsigned char*)0x0001, 0x39);
    eeprom_busy_wait();
    }
       while(1)
       {
          lcdLocate(0,1);
       lcdWriteString("while");
       if(bit_is_clear(PIND, 6))
       {
    eeprom_busy_wait();      
    eeprom_write_byte((unsigned char*)0x0001, 0x35);
          eeprom_busy_wait();
          lcdWriteString("pin");
       }
       if(bit_is_clear(PIND, 5))
       {
    eeprom_busy_wait();      
    eeprom_write_byte((unsigned char*)0x0001, 0x33);
          eeprom_busy_wait();
          lcdWriteString("pin");
       }
         if(gg!=gg1)
       lcdWriteChar(gg);
       gg1=gg;
    
       }
    }
    
  • #10 6337536
    Dr_DEAD
    Poziom 28  
    Dobra praktyka nakazuje aby po grzebaniu w konfiguracji któregoś z peryferii które obsługuje przerwania, kasować na końcu flagi, tak samo dobra praktyka nakazuje kasować flagi przerwań gdy włączamy zezwolenie na nie czy to globalne czy lokalne (dla danego zasobu).
  • #11 6366567
    Greyangel
    Poziom 14  
    Jak pisze Pan Witkowski, początkowa komórka pamięci EEPROM czyli ta o adresie h00 może zmieniać swoją wartość na skutek spadku napięcia zasilania i nie jest to zawarte w żadnych papierach. Dobra praktyka nakazuje żeby umieszczać pod tym adresem bajt z którego nie będzie się korzystać. Czy Zaobserwowałeś objawy na tym jednym bajcie czy pod wszystkimi adresami ?
REKLAMA