PIC18F4520 EEPROM Sorunu

Başlatan PICaso, 11 Nisan 2019, 14:59:48

PICaso

Arkadaşlar merhaba,

PIC18f4520 ile MPLAB XC8 derleyicisi ile EEPROM uygulaması yapıyorum. data isminde integer bir değişkenim var. Enerji kesildiğin de son değerin hafızada kalmasını istiyorum. Yazdığım kod denemeleriyle başaramadım.Yazdığım kodu Pic datasheetinde ki assembly örneğinden faydalanarak yaptım. EEADR registerına ne yazacağımı bilemedim.

Yardımlarınız için şimdiden teşekkürler.
#pragma config CPD = ON  
 #pragma config WRTD = ON 
  void hafiza()
{
    EEADR =
    EEDATA = data;
            
    EECON1bits.EEPGD=0;
    EECON1bits.CFGS=0;
    EECON1bits.WREN=1;
    
    INTCONbits.GIE=0;
    EECON2 = 0x55;          // Part of required sequence for write to internal EEPROM
    EECON2 = 0xAA;          // Part of required sequence for write to internal EEPROM
    EECON1bits.WR = 1;  
    INTCONbits.GIE=1;
    
    
    EECON1bits.WREN=0;
  
}

mehmet

eeprom_write ve eeprom_read hazır fonksiyonlarını
neden kullanmıyorsunuz?
Olan olmuştur,
olacak olan da olmuştur.
Olacak bir şey yoktur.
---------------------------------------------
http://www.mehmetbilgi.net.tr

PICaso

Alıntı yapılan: mehmet - 11 Nisan 2019, 16:05:19eeprom_write ve eeprom_read hazır fonksiyonlarını
neden kullanmıyorsunuz?
Hazır fonksiyon bulamadım, sizin paylaşabileceğiniz varsa deneyebilirim.

PICaso

unsigned int data=0;

şeklindeki değişken EEPROM da kaydedildiğini düşünürsek program yeniden başlatıldığında data=0 ı görmezden gelip son değerinden mi devam eder.

Tagli

Hayır, bu mantığın yazılımsal olarak kurulması gerekir. Program başında EEPROM'daki değeri okumalı, bu değere göre bir karara varmalı ve eğer gerekiyorsa normal bir değişken olan data'yı buna göre güncellemelisin.

EEADR için adresler galiba 0'dan başlıyor. Datasheet'te çok net belirtilmemiş. İnternette biraz araştırınca, PIC16 ve PIC18 için bu işlemlerin farklı olabileceğini söylemişler.

Alternatif olarak, tanımlama sırasında bir değişkenin EEPROM'da saklandığı da belirtilebiliyor sanırım. Bu durumda normal bir değişken gibi kullanmak mümkün olabilir belki. Galiba bu durumda derleyici kendisi EEPROM'da bir adres buluyor otomatik olarak.
Gökçe Tağlıoğlu

PICaso

Alıntı yapılan: Tagli - 12 Nisan 2019, 11:59:45Hayır, bu mantığın yazılımsal olarak kurulması gerekir. Program başında EEPROM'daki değeri okumalı, bu değere göre bir karara varmalı ve eğer gerekiyorsa normal bir değişken olan data'yı buna göre güncellemelisin.

EEADR için adresler galiba 0'dan başlıyor. Datasheet'te çok net belirtilmemiş. İnternette biraz araştırınca, PIC16 ve PIC18 için bu işlemlerin farklı olabileceğini söylemişler.

Alternatif olarak, tanımlama sırasında bir değişkenin EEPROM'da saklandığı da belirtilebiliyor sanırım. Bu durumda normal bir değişken gibi kullanmak mümkün olabilir belki. Galiba bu durumda derleyici kendisi EEPROM'da bir adres buluyor otomatik olarak.

#define _XTAL_FREQ 20000000

#define RS RB2
#define EN RB3
#define D4 RB4
#define D5 RB5
#define D6 RB6
#define D7 RB7

#include <xc.h>
#include "lcd.h";

#include "stdio.h"


#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>

#pragma config OSC = HS        // Oscillator Selection bits HS
#pragma config FCMEN = OFF       // Fail-Safe Clock Monitor Enable bit (Fail-Safe Clock Monitor enabled)
#pragma config IESO = OFF        // Internal/External Oscillator Switchover bit (Oscillator Switchover mode enabled)

// CONFIG2L
#pragma config PWRT = OFF       // Power-up Timer Enable bit (PWRT disabled)
#pragma config BOREN = ON       // Brown-out Reset Enable bits (Brown-out Reset enabled and controlled by software (SBOREN is enabled))
#pragma config BORV = 3         // Brown Out Reset Voltage bits (Minimum setting)

// CONFIG2H
#pragma config WDT = OFF        // Watchdog Timer Enable bit (WDT disabled (control is placed on the SWDTEN bit))
#pragma config WDTPS = 32768    // Watchdog Timer Postscale Select bits (1:32768)

// CONFIG3H
#pragma config CCP2MX = PORTC   // CCP2 MUX bit (CCP2 input/output is multiplexed with RC1)
#pragma config PBADEN = OFF     // PORTB A/D Enable bit (PORTB<4:0> pins are configured as digital I/O on Reset)
#pragma config LPT1OSC = OFF    // Low-Power Timer1 Oscillator Enable bit (Timer1 configured for higher power operation)
#pragma config MCLRE = ON       // MCLR Pin Enable bit (MCLR pin enabled; RE3 input pin disabled)

// CONFIG4L
#pragma config STVREN = ON      // Stack Full/Underflow Reset Enable bit (Stack full/underflow will cause Reset)
#pragma config LVP = OFF        // Single-Supply ICSP Enable bit (Single-Supply ICSP disabled)
#pragma config XINST = OFF      // Extended Instruction Set Enable bit (Instruction set extension and Indexed Addressing mode disabled (Legacy mode))

// CONFIG5L
#pragma config CP0 = OFF        // Code Protection bit (Block 0 (000800-001FFFh) not code-protected)
#pragma config CP1 = OFF        // Code Protection bit (Block 1 (002000-003FFFh) not code-protected)
#pragma config CP2 = OFF        // Code Protection bit (Block 2 (004000-005FFFh) not code-protected)
#pragma config CP3 = OFF        // Code Protection bit (Block 3 (006000-007FFFh) not code-protected)

// CONFIG5H
#pragma config CPB = OFF        // Boot Block Code Protection bit (Boot block (000000-0007FFh) not code-protected)
#pragma config CPD = OFF      // Data EEPROM Code Protection bit (Data EEPROM not code-protected)

// CONFIG6L
#pragma config WRT0 = OFF       // Write Protection bit (Block 0 (000800-001FFFh) not write-protected)
#pragma config WRT1 = OFF       // Write Protection bit (Block 1 (002000-003FFFh) not write-protected)
#pragma config WRT2 = OFF       // Write Protection bit (Block 2 (004000-005FFFh) not write-protected)
#pragma config WRT3 = OFF       // Write Protection bit (Block 3 (006000-007FFFh) not write-protected)

// CONFIG6H
#pragma config WRTC = OFF       // Configuration Register Write Protection bit (Configuration registers (300000-3000FFh) not write-protected)
#pragma config WRTB = OFF       // Boot Block Write Protection bit (Boot block (000000-0007FFh) not write-protected)
#pragma config WRTD = OFF       // Data EEPROM Write Protection bit (Data EEPROM not write-protected)

// CONFIG7L
#pragma config EBTR0 = OFF      // Table Read Protection bit (Block 0 (000800-001FFFh) not protected from table reads executed in other blocks)
#pragma config EBTR1 = OFF      // Table Read Protection bit (Block 1 (002000-003FFFh) not protected from table reads executed in other blocks)
#pragma config EBTR2 = OFF      // Table Read Protection bit (Block 2 (004000-005FFFh) not protected from table reads executed in other blocks)
#pragma config EBTR3 = OFF      // Table Read Protection bit (Block 3 (006000-007FFFh) not protected from table reads executed in other blocks)

// CONFIG7H
#pragma config EBTRB = OFF      // Boot Block Table Read Protection bit (Boot block (000000-0007FFh) not protected from table reads executed in other blocks)


uint8_t data = 0;


uint8_t Eeprom_read(uint8_t addr){
    EEADR = addr;
    EECON1bits.EEPGD = 0;
    EECON1bits.CFGS = 0;
    EECON1bits.RD = 1;
    while(EECON1bits.RD);
    return EEDATA;
}

void Eeprom_write(uint8_t addr,uint8_t data){
    EEADR = addr;
    EEDATA = data;
    EECON1bits.EEPGD = 0;
    EECON1bits.CFGS = 0;
    EECON1bits.WREN = 1;
    INTCONbits.GIEH = 0; 
    
    EECON2 = 0x55;
    EECON2 = 0xAA;
    
    EECON1bits.WR = 1;
    while(EECON1bits.WR);
    EECON1bits.WREN = 0;
    INTCONbits.GIEH = 1;
        
}

void interrupt high_isr(void);
void interrupt low_priority low_isr(void);


int main()
{
  char s[16];
  
  TRISB = 0x00;
  TRISD = 0x01; //RD0 as Input PIN
  
  Lcd_Init();

  while(1)
   { 
     
       if(RD0 == 0) //If Switch Pressed 
    {
       if(RD0 == 0) //If Switch Pressed
      {
        data=data++;
       __delay_ms(100); 
      }
    }
    

      
    sprintf(s, "Zaman = %d s", data);
    Lcd_Set_Cursor(1,1);
    Lcd_Write_String(s);
      __delay_ms(50); 
   
  
      
  }
  return 0;
}


void interrupt high_isr(void){
    INTCONbits.GIEH = 0;
    
     
    
    INTCONbits.GIEH = 1;
}

void interrupt low_priority low_isr(void){
    INTCONbits.GIEH = 0;
    
    INTCONbits.GIEH = 1;
}

Hocam örneklerden incelediğim kadarıyla kodu en son bu hale getirebildim. Yüksek öncelikle interrupt rutinin de data değişkeniyle ilgili kaydetmeler yapılmasını düşünüyorum. Sizce de doğru mudur? Ne gibi değişiklikler yapabilirim?

Tagli

Ben olsam mevcut EEPROM yazma kodunu kesme içinde çağırmazdım. Yazma kodu bir miktar bekleme yapar. Kesme içinde bekleme yapmak iyi değildir. Genelde kesme içinde bir bayrak kaldırıp, ana kodda bu bayrağa bakarak kayıt işlemi yapmak daha uygun olur.

Bu arada, kesme kodlarının içinde global kesme bitlerini aç-kapa yapmana gerek yok. O işi donanım yapar zaten. Senin yapman gereken şey işini bitirince ilgili kesme bayraklarını sıfırlamak. Bazı kesme bayrakları elle 0 yapılamaz, gerekli şartlar sağlandığında kendiliğinden 0 olurlar.
Gökçe Tağlıoğlu

PICaso

Alıntı yapılan: Tagli - 18 Nisan 2019, 17:49:52Ben olsam mevcut EEPROM yazma kodunu kesme içinde çağırmazdım. Yazma kodu bir miktar bekleme yapar. Kesme içinde bekleme yapmak iyi değildir. Genelde kesme içinde bir bayrak kaldırıp, ana kodda bu bayrağa bakarak kayıt işlemi yapmak daha uygun olur.

Bu arada, kesme kodlarının içinde global kesme bitlerini aç-kapa yapmana gerek yok. O işi donanım yapar zaten. Senin yapman gereken şey işini bitirince ilgili kesme bayraklarını sıfırlamak. Bazı kesme bayrakları elle 0 yapılamaz, gerekli şartlar sağlandığında kendiliğinden 0 olurlar.

Hocam yardımların için teşekkür ederim. Son düzenlemeler ile birlikte program çalıştı fakat kafama takılan 2 tane sorum var. 1-Program ilk çalıştığın da data=0 değerin de olması gerekirken data=255 değerini gösteriyor.Ben buton ile değeri arttırdığımda 8 bit olduğu için değer 0 oluyor. 2-Eeprom_write(0x00,data); bu kodu while döngüsünde kullanmam döngü bu satıra geldiğinde data değeri değişmese dahi tekrar tekrar yazma işlemi yapar mı? Eeprom un 100.000 kere yazma silme yapabildiğini biliyorum. Her while döngüsünde bu değerden azalma meydana gelir mi?
Yeni Kod
uint8_t data = 0;

uint8_t Eeprom_read(uint8_t addr){
    EEADR = addr;
    EECON1bits.EEPGD = 0;
    EECON1bits.CFGS = 0;
    EECON1bits.RD = 1;
    while(EECON1bits.RD);
    return EEDATA;
}

void Eeprom_write(uint8_t addr,uint8_t data){
    EEADR = addr;
    EEDATA = data;
    EECON1bits.EEPGD = 0;
    EECON1bits.CFGS = 0;
    EECON1bits.WREN = 1;
    INTCONbits.GIEH = 0; 
    
    EECON2 = 0x55;
    EECON2 = 0xAA;
    
    EECON1bits.WR = 1;
    while(EECON1bits.WR);
    EECON1bits.WREN = 0;
    INTCONbits.GIEH = 1;      
}

int main()
{
  char s[16];
  TRISB = 0x00; //LCD BAGLANTILARI
  TRISD = 0x01; //RD0 as Input PIN
  
  Lcd_Init();
  
  data = 0;
  data = Eeprom_read(0x00);
    __delay_ms(50);
  
  while(1)
  { 
    
    if(RD0 == 0) //If Switch Pressed 
    {
      if(RD0 == 0) //If Switch Pressed
      {
        data=data++;
      __delay_ms(100); 
      }
    }
  
    sprintf(s, "Zaman = %d s", data);
    Lcd_Set_Cursor(1,1);
    Lcd_Write_String(s);
      __delay_ms(50); 
  
  Eeprom_write(0x00,data);
  __delay_ms(50);  
  }
  return 0;
}

Tagli

1) EEPROM içinde data = 255 olarak kalmışsa, açılışta data = 255 olması normal, çünkü zaten programın başında EEPROM verisi okunarak data'ya aktarılmış. EEPROM silindiğinde içindeki değerler 0 mı yoksa 255 mi oluyor onu bilmiyorum. 255 olması tüm bitlerin 1 olması anlamına gelir ki bunu şaşırtıcı bulmam.

2) Bu şekilde bir kullanım EEPROM ömründen yer, çünkü veri aynı olsa bile işlemci körlemesine yazma işlemi yapar. Fonksiyonu biraz değiştirip, önce EEPROM'u okuyabilir ve ancak değer farklı ise yazma işlemi yapacak şekle getirebilirsin. Bu performansı pek etkilemez çünkü okuma işlemi yazmanın aksine çok hızlı gerçekleşir. AVR'lerin kütüphanesinde böyle bir yöntem izlenmiş.
Gökçe Tağlıoğlu