Merhabalar, doktora yeterlik sınavı dolayısıyla ara verdiğim blog yazılarıma, yeterlik aşamasını geçtiğimden dolayı devam ediyorum 😀 PIC16F84A ile ilgili, geriye kalan son bir iki konuyu da irdeleyeceğimiz bu yazıda, ana gündemimiz EEPROM olacak.
“EEPROM nedir?” sorusuna yanıt arayanlar için WIKIPEDIA sayfasında yeterli bilgi olduğunu belirtmek isterim. Kısaca özetlemek gerekirse EEPROM, elektriksel olarak yazılıp silinebilen, kalıcı bir bellek tipi; yani elektrik gitse de içerisinde kayıtlı olan veri kendiliğinden silinmiyor. Flash belleğe göre yazım ömrünün çok fazla olması, bu devre elemanını bu gün dahi popüler tutmaya yetiyor.
PIC16F84A içinde de 64 byte’lık bir EEPROM bulunuyor. 64 byte kadar küçük bir EEPROM olsa da, özellikle kalıcı konfigürasyonları saklama konusunda, bu modül hayat kurtarıyor. Bu durumda bize düşen de, PIC16FLIB adıyla geliştirdiğimiz alternatif PIC kütüphanesine bu modülü de eklemek olacak. Öyleyse hemen başlayalım!
İlk adım olarak, her zamanki gibi datasheet’i okuyup anlayarak, yazılımsal olarak modelleyeceğiz. Datasheet’te EEPROM modülü, sistemin blok diyagramında şöyle yer alıyor:
Buradan da görüldüğü gibi EEPROM modülümüz 64*8 bitlik veriyi saklayabiliyor. Şimdi de, EEPROM ile ilgili kütüklerin (register), hangi adreslerde olduğuna bakalım.
İlgili kütükleri fosforlu sarı ile işaretlediğimden adreslerini görebilirsiniz. Artık adreslerini ve yapılarını da bildiğimizden, bu kütükleri yazdığımız PIC kütüphanesine ekleyebiliriz. EEPROM modülünü de derlemeye dahil edip etmemeyi seçimli yapmak için işe pic16flib_conf.h dosyasına aşağıdaki işaretli satırı ekleyerek başlıyoruz.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
/* * File: pic16flib_conf.h * Author: ozenozkaya * * Created on 25 Eylül 2015 Cuma, 00:46 */ #ifndef PIC16FLIB_CONF_H #define PIC16FLIB_CONF_H #ifdef __cplusplus extern "C" { #endif #define MAX_INT_CALLBACK_NUM (1) //#define PIC16LIB_USE_RB0_INT //#define PIC16LIB_USE_PORTB_INT //#define PIC16LIB_USE_TIMER0_INT #define PIC16LIB_USE_EEPROM #ifdef __cplusplus } #endif #endif /* PIC16FLIB_CONF_H */ |
Şimdi pic16f84a_lib.h içerisindeki kütük tanımlamalarına geçelim. Aşağıdaki işaretli satırları pic16f84a_lib.h dosyasına ekliyoruz.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 |
/* * File: pic16f84a_lib.h * Author: ozenozkaya * * Created on 20 Temmuz 2015 Pazartesi, 00:05 */ #ifndef PIC16F84A_LIB_H #define PIC16F84A_LIB_H #ifdef __cplusplus extern "C" { #endif #include <stdint.h> #include "pic16flib_conf.h" #define PIC16LIB_ERROR_NONE (0) #define PIC16LIB_ERROR_CB_NULL (-1) #define PIC16LIB_ERROR_CB_ALREADY_REGISTERED (-2) #define PIC16LIB_ERROR_WRONG_EEPROM_ADDRESS (-3) #define F_OSC (1000000UL) #define _REG_TIMER0_ADDR (0x01) #define REG_TIMER0 (*( volatile uint8_t*)_REG_TIMER0_ADDR) #define _REG_PROGRAM_COUNTER_ADDR (0x02) #define REG_PROGRAM_COUNTER (*( volatile uint8_t*)_REG_PROGRAM_COUNTER_ADDR) #define _REG_STATUS_ADDR (0x03) #define REG_STATUS (*( volatile uint8_t*)_REG_STATUS_ADDR) #define _REG_PORTA_ADDR (0x05) #define REG_PORTA (*( volatile uint8_t*)_REG_PORTA_ADDR) #define _REG_PORTB_ADDR (0x06) #define REG_PORTB (*( volatile uint8_t*)_REG_PORTB_ADDR) #define PORT_PIN_LOW (0) #define PORT_PIN_HIGH (1) #define PORT_ALL_LOW (0) #define PORT_ALL_HIGH (0xFF) #define _REG_EEDATA_ADDR (0x08) #define REG_EEDATA (*( volatile uint8_t*)_REG_EEDATA_ADDR) #define _REG_EEADR_ADDR (0x09) #define REG_EEADR (*( volatile uint8_t*)_REG_EEADR_ADDR) #define _REG_TRISB_ADDR (0x86) #define REG_TRISB (*( volatile uint8_t*)_REG_TRISB_ADDR) #define _REG_TRISA_ADDR (0x85) #define REG_TRISA (*( volatile uint8_t*)_REG_TRISA_ADDR) #define TRIS_PIN_OUTPUT (0) #define TRIS_PIN_INPUT (1) #define TRIS_PORT_OUTPUT (0) #define TRIS_PORT_INPUT (0xFF) #define _REG_EECON1_ADDR (0x88) #define REG_EECON1 (*( volatile uint8_t*)_REG_EECON1_ADDR) #define _REG_EECON2_ADDR (0x89) #define REG_EECON2 (*( volatile uint8_t*)_REG_EECON2_ADDR) #define EECON2_PROTECTION_SEQ_1 (0x55) #define EECON2_PROTECTION_SEQ_2 (0xAA) #define _REG_INTCON_ADDR (0x0B) #define REG_INTCON (*( volatile uint8_t*)_REG_INTCON_ADDR) #define INT_ENABLE (1) #define INT_ENABLE_ALL (0xFF) #define INT_DISABLE (0) #define INT_DISABLE_ALL (0) #define INT_FLAG_CLEAR (0) #define _REG_OPTION_ADDR (0x81) #define REG_OPTION (*( volatile uint8_t*)_REG_OPTION_ADDR) #define INT_EDGE_FALLING (0) #define INT_EDGE_RISING (1) typedef struct { //one bit is stored in one BYTE uint8_t pin0:1; uint8_t pin1:1; uint8_t pin2:1; uint8_t pin3:1; uint8_t pin4:1; uint8_t pin5:1; uint8_t pin6:1; uint8_t pin7:1; }_tris_port_pin_t, *_tris_port_pin_ptr_t; typedef union { _tris_port_pin_t pins; uint8_t port; }tris_port_t,*tris_port_ptr_t; #define REG_TRISA_UNION (*(tris_port_ptr_t)_REG_TRISA_ADDR) #define REG_TRISB_UNION (*(tris_port_ptr_t)_REG_TRISB_ADDR) #define REG_PORTA_UNION (*(tris_port_ptr_t)_REG_PORTA_ADDR) #define REG_PORTB_UNION (*(tris_port_ptr_t)_REG_PORTB_ADDR) typedef struct { uint8_t RBIF:1; uint8_t INTF:1; uint8_t T0IF:1; uint8_t RBIE:1; uint8_t INTE:1; uint8_t T0IE:1; uint8_t EEIE:1; uint8_t GIE:1; }_intcon_reg_t,*_intcon_reg_ptr_t; typedef struct { uint8_t PS:3; uint8_t PSA:1; uint8_t T0SE:1; uint8_t T0CS:1; uint8_t INTEDG:1; uint8_t RBPU:1; }_option_reg_t,*_option_reg_ptr_t; #define T0CS_SOURCE_RA4_T0CKI_PIN (0x01) #define T0CS_SOURCE_INTERNAL_CLOCK (0x00) #define PSA_ASSIGN_TO_WATCHDOG (0x01) #define PSA_ASSIGN_TO_TIMER0 (0x00) #define PS_TMR0_RATE_DIVIDE_2 (0x00) #define PS_TMR0_RATE_DIVIDE_4 (0x01) #define PS_TMR0_RATE_DIVIDE_8 (0x02) #define PS_TMR0_RATE_DIVIDE_16 (0x03) #define PS_TMR0_RATE_DIVIDE_32 (0x04) #define PS_TMR0_RATE_DIVIDE_64 (0x05) #define PS_TMR0_RATE_DIVIDE_128 (0x06) #define PS_TMR0_RATE_DIVIDE_256 (0x07) #define REG_OPTION_UNION (*(option_reg_ptr_t)_REG_OPTION_ADDR) typedef union { _intcon_reg_t bits; uint8_t value; }intcon_reg_t, *intcon_reg_ptr_t; #define REG_INTCON_UNION (*(intcon_reg_ptr_t)_REG_INTCON_ADDR) typedef union { uint8_t value; uint8_t count; }timer0_reg_t, *timer0_reg_ptr_t; #define TIMER0_MAX_CNT (0xFF) #define TIMER0_ASSIGN_CNT(NEW_TMR0_CNT) (TIMER0_MAX_CNT - NEW_TMR0_CNT) #define REG_TIMER0_UNION (*(timer0_reg_ptr_t)_REG_TIMER0_ADDR) typedef struct { uint8_t RD:1; uint8_t WR:1; uint8_t WREN:1; uint8_t WRERR:1; uint8_t EEIF:1; uint8_t _RESERVED:3; }_eecon1_reg_t,*_eecon1_reg_ptr_t; #define EEPROM_MAX_ADDRESS (0x3F) #define RD_EEPROM_INIT_READ (0x01) #define RD_EEPROM_DEINIT_READ (0x00) #define WR_EEPROM_INIT_WRITE (0x01) #define WR_EEPROM_DEINIT_WRITE (0x00) #define EEPROM_SELECT_ADDRESS(EE_ADDR) do{REG_EEADR=EE_ADDR;}while(0) #define EEPROM_GET_DATA() (uint8_t)(REG_EEDATA) typedef union { _eecon1_reg_t bits; uint8_t value; }eecon1_reg_t, *eecon1_reg_ptr_t; #define REG_EECON1_UNION (*(eecon1_reg_ptr_t)_REG_EECON1_ADDR) #define WAIT_LOOP_FOREVER() while(1) #define DO_FOREVER() while(1) #ifdef PIC16LIB_USE_RB0_INT typedef void (*rb0_int_callback_t)(); int8_t register_rb0_int_callback(rb0_int_callback_t new_cb); int8_t unregister_rb0_int_callback(rb0_int_callback_t cb_to_unreg); #endif #ifdef PIC16LIB_USE_PORTB_INT typedef void (*portb_int_callback_t)(); int8_t register_portb_int_callback(portb_int_callback_t new_cb); int8_t unregister_portb_int_callback(portb_int_callback_t cb_to_unreg); #endif #ifdef PIC16LIB_USE_TIMER0_INT typedef void (*timer0_int_callback_t)(); int8_t register_timer0_int_callback(timer0_int_callback_t new_cb); int8_t unregister_timer0_int_callback(timer0_int_callback_t cb_to_unreg); #endif #ifdef PIC16LIB_USE_EEPROM int8_t eeprom_read_data(uint8_t ee_address, uint8_t *ee_read_data_ptr); int8_t eeprom_write_data(uint8_t ee_address, uint8_t ee_write_data_val); #endif #ifdef __cplusplus } #endif #endif /* PIC16F84A_LIB_H */ |
Register tanımlarını nasıl yaptığımızı daha önceki yazılarda çokça açıkladığımdan bu defa tekrara düşmemek adına açıklamayacağım. Her zamanki gibi, veri kağıdındaki bilgileri modelleyerek kütük tanımlarını yaptık.
Şimdi gelelim eeprom’dan veri okuma ve eeprom’a veri yazma fonksiyonlarına. Onları da aşağıda görebilirsiniz:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
int8_t eeprom_read_data(uint8_t ee_address, uint8_t *ee_read_data_ptr) { if(ee_address>EEPROM_MAX_ADDRESS) { return PIC16LIB_ERROR_WRONG_EEPROM_ADDRESS; } EEPROM_SELECT_ADDRESS(ee_address); REG_EECON1_UNION.bits.RD=1; *ee_read_data_ptr=REG_EEDATA; return PIC16LIB_ERROR_NONE; } int8_t eeprom_write_data(uint8_t ee_address, uint8_t ee_write_data_val) { if(ee_address>EEPROM_MAX_ADDRESS) { return PIC16LIB_ERROR_WRONG_EEPROM_ADDRESS; } EEPROM_SELECT_ADDRESS(ee_address); REG_EEDATA=ee_write_data_val; REG_EECON1_UNION.bits.WREN=1; REG_EECON2=EECON2_PROTECTION_SEQ_1; REG_EECON2=EECON2_PROTECTION_SEQ_2; REG_EECON1_UNION.bits.WR=1; REG_INTCON_UNION.bits.EEIE=1; while(REG_EECON1_UNION.bits.EEIF == 0) { asm ("nop"); } REG_INTCON_UNION.bits.EEIE=0; REG_EECON1_UNION.bits.EEIF=0; REG_EECON1_UNION.bits.WREN=0; } |
Her iki fonksiyon girişinde de, girilen adresin 63 değerinden büyük olup olmadığını kontrol ettik. Toplamda 64 byte’lık bir eeprom’umuz olduğundan, en yüksek adres 63 oluyor. Ardından okuma yapmak için, okuma yapacağımız adresi seçtik. Sonrasında RD bitini 1 yaparak okumayı başlattık ve okunan değeri REG_EEDATA kütüğünden okuduk.
Yazma kısmında ise işler biraz daha karışık şekilde çözülüyor. Yine adres seçimini yaptıktan sonra ilk iş olarak yazmak istediğimiz veriyi REG_EEDATA kütüğüne yazıyoruz. Ardından WREN bitini 1 yaparak yazma izni vermiş oluyoruz. Sonrasında, veri kağıdından okuduğumuza göre EECON2 kütüğüne sırasıyla 0x55 ve 0xAA yazmak gerekiyor. Bu, koruma amaçlı konmuş ve veri kağıdına üretici tarafından yazılmış bir ek sekans 🙂 Kodu yazan ne yaptığını biliyorsa, ancak o zaman yazabilsin demişler. Saygımız sonsuz 😉 Ardından WR bitini 1 yaparak yazım sürecini başlatıyoruz. Yazım hemen bitmiyor; bu durumda yazımın bittiğini anlayabilmek için tek çaremiz EEI (eeproma veri yazıldı) kesmesini kurarak, kesme bayrağı 1 olana kadar beklemek. Burada bekleme işini asm(“nop”); satırı ile yaptık. asm(KOMUT) fonksiyonu, XC8 derleycilerinde C kodunun içerisnde assembly komutları çağırmaya yarar. Biz de “nop” yani “bir şey yapmadan 1 saat darbesi bekle” komutunu çalıştırarak bekleme sağladık. Ardından kesme bayrağı 1 olup while döngüsünden çıktığımızda kesmeyi kapatıp, kesme bayrağını temizleyip, WREN kütüğünü sıfara çekerek çıkıp gidiyoruz 🙂 Verimiz yazıldı.
Yukarıdaki fonksiyonların eklendiği durumda pic16f84a_lib.c dosyamız şöyle oluyor:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 |
#include "pic16f84a_lib.h" #define BIT_TOGGLE(x) (x^=1) #ifndef NULL #define NULL ((void*)0) #endif #ifdef PIC16LIB_USE_RB0_INT rb0_int_callback_t rb0_int_callback_list[MAX_INT_CALLBACK_NUM]; #endif #ifdef PIC16LIB_USE_PORTB_INT portb_int_callback_t portb_int_callback_list[MAX_INT_CALLBACK_NUM]; #endif #ifdef PIC16LIB_USE_TIMER0_INT timer0_int_callback_t timer0_int_callback_list[MAX_INT_CALLBACK_NUM]; #endif #if defined(PIC16LIB_USE_RB0_INT) || defined(PIC16LIB_USE_PORTB_INT) || defined(PIC16LIB_USE_TIMER0_INT) static void interrupt global_isr_handler() { #ifdef PIC16LIB_USE_RB0_INT if(REG_INTCON_UNION.bits.INTF) { uint8_t cb_index=0; for(cb_index=0;cb_index<MAX_INT_CALLBACK_NUM; cb_index++) { if(NULL != rb0_int_callback_list[cb_index]) { rb0_int_callback_list[cb_index](); } } BIT_TOGGLE(REG_OPTION_UNION.bits.INTEDG); REG_INTCON_UNION.bits.INTF=INT_FLAG_CLEAR; } #endif #ifdef PIC16LIB_USE_PORTB_INT if(REG_INTCON_UNION.bits.RBIF) { uint8_t cb_index=0; for(cb_index=0;cb_index<MAX_INT_CALLBACK_NUM; cb_index++) { if(NULL != portb_int_callback_list[cb_index]) { portb_int_callback_list[cb_index](); } } BIT_TOGGLE(REG_OPTION_UNION.bits.INTEDG); REG_INTCON_UNION.bits.RBIF=INT_FLAG_CLEAR; } #endif #ifdef PIC16LIB_USE_TIMER0_INT if(REG_INTCON_UNION.bits.T0IF) { REG_INTCON_UNION.bits.T0IF=INT_FLAG_CLEAR; uint8_t cb_index=0; for(cb_index=0;cb_index<MAX_INT_CALLBACK_NUM; cb_index++) { if(NULL != timer0_int_callback_list[cb_index]) { timer0_int_callback_list[cb_index](); } } } #endif } #endif #ifdef PIC16LIB_USE_RB0_INT int8_t register_rb0_int_callback(rb0_int_callback_t new_cb) { if(NULL != new_cb) { uint8_t cb_index=0; for(cb_index=0;cb_index<MAX_INT_CALLBACK_NUM; cb_index++) { if(NULL == rb0_int_callback_list[cb_index]) { rb0_int_callback_list[cb_index]=new_cb; } } if(MAX_INT_CALLBACK_NUM == cb_index) { return PIC16LIB_ERROR_CB_ALREADY_REGISTERED; //All callbacks are already registered } } else { return PIC16LIB_ERROR_CB_NULL; // Callback is NULL } return 0; } int8_t unregister_rb0_int_callback(rb0_int_callback_t cb_to_unreg) { if(NULL != cb_to_unreg) { uint8_t cb_index=0; for(cb_index=0;cb_index<MAX_INT_CALLBACK_NUM; cb_index++) { if(cb_to_unreg == rb0_int_callback_list[cb_index]) { rb0_int_callback_list[cb_index]=NULL; } } } else { return PIC16LIB_ERROR_CB_NULL; // Callback is NULL } return PIC16LIB_ERROR_NONE; } #endif #ifdef PIC16LIB_USE_PORTB_INT int8_t register_portb_int_callback(portb_int_callback_t new_cb) { if(NULL != new_cb) { uint8_t cb_index=0; for(cb_index=0;cb_index<MAX_INT_CALLBACK_NUM; cb_index++) { if(NULL == portb_int_callback_list[cb_index]) { portb_int_callback_list[cb_index]=new_cb; } } if(MAX_INT_CALLBACK_NUM == cb_index) { return PIC16LIB_ERROR_CB_ALREADY_REGISTERED; //All callbacks are already registered } } else { return PIC16LIB_ERROR_CB_NULL; // Callback is NULL } return PIC16LIB_ERROR_NONE; } int8_t unregister_portb_int_callback(portb_int_callback_t cb_to_unreg) { if(NULL != cb_to_unreg) { uint8_t cb_index=0; for(cb_index=0;cb_index<MAX_INT_CALLBACK_NUM; cb_index++) { if(cb_to_unreg == portb_int_callback_list[cb_index]) { portb_int_callback_list[cb_index]=NULL; } } } else { return PIC16LIB_ERROR_CB_NULL; // Callback is NULL } return PIC16LIB_ERROR_NONE; } #endif #ifdef PIC16LIB_USE_TIMER0_INT int8_t register_timer0_int_callback(timer0_int_callback_t new_cb) { if(NULL != new_cb) { uint8_t cb_index=0; for(cb_index=0;cb_index<MAX_INT_CALLBACK_NUM; cb_index++) { if(NULL == timer0_int_callback_list[cb_index]) { timer0_int_callback_list[cb_index]=new_cb; } } if(MAX_INT_CALLBACK_NUM == cb_index) { return PIC16LIB_ERROR_CB_ALREADY_REGISTERED; //All callbacks are already registered } } else { return (int8_t)PIC16LIB_ERROR_CB_NULL; // Callback is NULL } return PIC16LIB_ERROR_NONE; } int8_t unregister_timer0_int_callback(timer0_int_callback_t cb_to_unreg) { if(NULL != cb_to_unreg) { uint8_t cb_index=0; for(cb_index=0;cb_index<MAX_INT_CALLBACK_NUM; cb_index++) { if(cb_to_unreg == timer0_int_callback_list[cb_index]) { timer0_int_callback_list[cb_index]=NULL; } } } else { return PIC16LIB_ERROR_CB_NULL; // Callback is NULL } return PIC16LIB_ERROR_NONE; } #endif #ifdef PIC16LIB_USE_EEPROM int8_t eeprom_read_data(uint8_t ee_address, uint8_t *ee_read_data_ptr) { if(ee_address>EEPROM_MAX_ADDRESS) { return PIC16LIB_ERROR_WRONG_EEPROM_ADDRESS; } EEPROM_SELECT_ADDRESS(ee_address); REG_EECON1_UNION.bits.RD=1; *ee_read_data_ptr=REG_EEDATA; return PIC16LIB_ERROR_NONE; } int8_t eeprom_write_data(uint8_t ee_address, uint8_t ee_write_data_val) { if(ee_address>EEPROM_MAX_ADDRESS) { return PIC16LIB_ERROR_WRONG_EEPROM_ADDRESS; } EEPROM_SELECT_ADDRESS(ee_address); REG_EEDATA=ee_write_data_val; REG_EECON1_UNION.bits.WREN=1; REG_EECON2=EECON2_PROTECTION_SEQ_1; REG_EECON2=EECON2_PROTECTION_SEQ_2; REG_EECON1_UNION.bits.WR=1; REG_INTCON_UNION.bits.EEIE=1; while(REG_EECON1_UNION.bits.EEIF == 0) { asm ("nop"); } REG_INTCON_UNION.bits.EEIE=0; REG_EECON1_UNION.bits.EEIF=0; REG_EECON1_UNION.bits.WREN=0; } #endif |
Artık kütüphanemiz hazır olduğuna göre, basit bir test fonksiyonu yazacağız. 0x01 adresli EEPROM bellek alanına 1 byte’lık ‘X’ karakterini yazan ve doğru yazıp yazmadığını kontrol eden bir kod, aşağıda yer almakta.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
/* * File: main.c * Author: ozenozkaya * */ #include "pic16f84a_lib.h" // CONFIG #pragma config FOSC = XT // Oscillator Selection bits (XT oscillator) #pragma config WDTE = ON // Watchdog Timer (WDT enabled) #pragma config PWRTE = ON // Power-up Timer Enable bit (Power-up Timer is enabled) #pragma config CP = OFF // Code Protection bit (Code protection disabled) #define EEPROM_TEST_ADDR (0x01) #define EEPROM_TEST_DATA ('X') void main() { uint8_t rd_data=0; REG_TRISB_UNION.port = TRIS_PORT_OUTPUT; REG_PORTB_UNION.port = PORT_ALL_LOW; eeprom_write_data(EEPROM_TEST_ADDR,EEPROM_TEST_DATA); eeprom_read_data(EEPROM_TEST_ADDR,&rd_data); if(EEPROM_TEST_DATA==rd_data) { REG_PORTB_UNION.port=0xAA; } while(1); } |
Bu kodumuz, yazım ve okuma işlemleri başarılı ise B portuna 0xAA yazıyor. Eğer hata olursa B portu ilk değeri olan 0x00 değerinde kalıyor. B portuna 0xAA=10101010 değerinin yazılması, sırasıyla pinlerin yüksekte ve alçakta olmasına sebep oluyor.
Kodda bir diğer önemli kısım ise #pragma ile başlayan konfigürasyon satırları. Buna göre osilatör olarak kristal osilatör seçmiş olduk. Ayrıca, mikrokontrolörün donup kaldığı durumlarda ona reset atacak olan watchdog timer modülünü aktive ettik. Yine güç dalgalanmalarında reset atmaya yarayan power on reset’i aktive ettik ve kod korumayı kapattık. Kod koruma açık olarak mikrokontrolöre yazılım atarsanız, o kod bir daha okunamayacak ve kolaylıkla değiştirilemeyecektir. Prototip aşamasında CP (code protection, kod koruma) seçeneğini OFF yapınız (varsayılan değer de budur).
Bu kodun çalıştığı duruma ilişkin Proteus ISIS simülasyon çıktısı ise aşağıda yer alıyor.
Gördüğünüz gibi, EEPROM sürücümüz de başarıyla çalışıyor 🙂
Projenin kaynak kodlarını BURADAN indirebilirsiniz.
Bu günlük de bu kadar. İleride yeni yazılarla devam edeceğiz.
Yazıları beğendiyseniz, faydalanabilecek tanıdıklarınızla paylaşmayı unutmayınız.
Önceki Sayfa Sonraki Sayfa