{"id":470,"date":"2015-10-01T21:57:17","date_gmt":"2015-10-01T18:57:17","guid":{"rendered":"http:\/\/ozenozkaya.com\/blog\/?p=470"},"modified":"2016-01-10T00:03:36","modified_gmt":"2016-01-09T22:03:36","slug":"pic-programlama-8-zamanlayicilar-timers","status":"publish","type":"post","link":"http:\/\/ozenozkaya.com\/blog\/?p=470","title":{"rendered":"PIC Programlama \u2013 8 \u2013 Zamanlay\u0131c\u0131lar (Timers)"},"content":{"rendered":"<p>Merhabalar, ge\u00e7en yaz\u0131m\u0131zda kesmeler \u00fczerine olduk\u00e7a marjinal baz\u0131 \u00e7al\u0131\u015fmalar yapm\u0131\u015ft\u0131k. \u015eu ana kadar PIC mikrokontrol\u00f6r\u00fcn\u00a0giri\u015f \u00e7\u0131k\u0131\u015f \u00fcnitelerini, kesmeleri de i\u00e7erecek \u015fekilde evire \u00e7evire kullanabilecek bilgi birikimini\u00a0edindik. Tabi bu bahsetti\u011fimiz konu, i\u015fin bahanesiydi. As\u0131l amac\u0131m\u0131z, t\u00fcm mikrokontrol\u00f6rlerde kullanabilece\u011fimiz bir modelleme ve geli\u015ftirme altyap\u0131s\u0131n\u0131 tahsis etmekti. Buna istinaden yapt\u0131\u011f\u0131m\u0131z en orijinal i\u015f, Microchip firmas\u0131n\u0131n sundu\u011fu k\u00fct\u00fcphanelerden performans, estetik, yaz\u0131l\u0131m kalitesi, ta\u015f\u0131nabilirlik ve geli\u015ftirilebilirlik bak\u0131m\u0131ndan \u00e7ok daha iyi bir k\u00fct\u00fcphane olu\u015fturmak oldu. Mikrokontrol\u00f6r&#8217;\u00fcn veri ka\u011f\u0131d\u0131n\u0131 nas\u0131l modelleyece\u011fimizi g\u00f6rd\u00fc\u011f\u00fcm\u00fczden ayn\u0131 i\u015flemleri herhangi bir ba\u015fka platform i\u00e7in yapmak sorun olmayacakt\u0131r.<\/p>\n<p>D\u0131\u015f d\u00fcnyaya mikrokontrol\u00f6r\u00fcn I\/O pinleri \u00fczerinden m\u00fcdahale edebildi\u011fimizden bir sonraki ad\u0131ma ge\u00e7menin s\u0131ras\u0131 geldi. Bir sonraki ad\u0131m \u015f\u00fcphesiz ki periyodik i\u015flerle nas\u0131l ba\u015fa \u00e7\u0131kabilece\u011fimizi bulmak\u00a0olacak. G\u00fcncel durumda yazd\u0131\u011f\u0131m\u0131z kodlar \u00f6m\u00fcrleri boyunca ayn\u0131 i\u015fi aral\u0131ks\u0131z olarak yapt\u0131lar. Oysa ger\u00e7ek hayattaki pek \u00e7ok uygulamada ger\u00e7ekle\u015fmesi gereken zamanda ve periyodik ger\u00e7ekle\u015ftirilmesi gereken olaylar g\u00f6r\u00fcr\u00fcz. Periyodik yap\u0131lan i\u015flerden ilk akla gelen \u00f6rneklemedir. Nyquist amcam\u0131z\u0131n da y\u0131llar \u00f6nce ortaya koydu\u011fu gibi, bir i\u015fareti do\u011fru zamanlama ile \u00f6rneklemezsek o i\u015faretin ta\u015f\u0131d\u0131\u011f\u0131 bilgiyi kaybetmi\u015f olabiliyoruz. \u00a0Biraz daha net \u015fekilde a\u00e7\u0131klamak gerekirse:<\/p>\n<div class=\"su-box su-box-style-soft\" id=\"\" style=\"border-color:#74ad73;border-radius:3px;\"><div class=\"su-box-title\" style=\"background-color:#a7e0a6;color:#FFFFFF;border-top-left-radius:1px;border-top-right-radius:1px\">Sosyal Mesaj<\/div><div class=\"su-box-content su-u-clearfix su-u-trim\" style=\"border-bottom-left-radius:1px;border-bottom-right-radius:1px\">Nyquist \u00f6rnekleme frekans\u0131, bir i\u015faretin\u00a0\u00f6rneklenmesi s\u00fcrecinde tan\u0131mlanan bir alt limittir ve bu limit i\u015faretin i\u00e7erdi\u011fi maksimum frekans bile\u015feninin iki kat\u0131d\u0131r. E\u011fer i\u015faret maksimum frekans bile\u015feninin iki kat\u0131ndan \u00a0&#8211; ki bu frekans Nyquist frekans\u0131 oluyor &#8211; daha az bir frekansla \u00f6rneklenirse o i\u015faret, \u00f6l\u00e7\u00fcmlerden d\u00fczg\u00fcnce tekrar \u00fcretilemez \u00e7\u00fcnk\u00fc \u00f6rnekleme esnas\u0131nda bilgi kayb\u0131 ya\u015fanm\u0131\u015f olur.<\/div><\/div>\n<p>Sonu\u00e7 olarak, mikrokontrol\u00f6rde zaman\u0131 \u00f6l\u00e7menin bir yolunun olmas\u0131 gerekiyor. \u0130\u015fte bu noktada devreye Timer (Zamanlay\u0131c\u0131) mod\u00fclleri giriyor. Ancak zamanlay\u0131c\u0131lara ge\u00e7meden \u00f6nce, zamanlama sorununa sundu\u011fumuz en basit \u00e7\u00f6z\u00fcm\u00fc hat\u0131rlayal\u0131m. <a href=\"http:\/\/ozenozkaya.com\/blog\/?p=414\" target=\"_blank\">BURADAK\u0130<\/a> yaz\u0131m\u0131zda, DummyDelayMs fonksiyonun kurnazca tan\u0131mlayarak milisaniye mertebesinde bir zamanlama sa\u011flam\u0131\u015ft\u0131k. Hemen implementasyonu hat\u0131rlayal\u0131m.<\/p>\n<pre class=\"lang:c decode:true\" title=\"DummyDelayMs\">static void DummyDelayMs(unsigned int delay_ms)\r\n{\r\n    unsigned long cnt=0;\r\n    unsigned long delay_limit_ms= delay_ms*(F_OSC\/120000);\r\n    for(cnt=0;cnt&lt;delay_limit_ms;cnt++);\r\n}<\/pre>\n<p>G\u00f6rd\u00fc\u011f\u00fcn\u00fcz gibi bu kodda, mikrokontrol\u00f6re bo\u015f bele\u015f say\u0131 sayd\u0131r\u0131p, ge\u00e7en zamandan faydaland\u0131k. Tersten giderek, 1ms beklemek i\u00e7in gerekli olan sayma say\u0131s\u0131n\u0131 hesaplay\u0131p, mikrokontrol\u00f6r\u00fcn o kadar bo\u015f bele\u015f (dummy) i\u015flem yapmas\u0131n\u0131 sa\u011flad\u0131k. Bu da adeta bir ara\u00e7ta vitesi bo\u015fa at\u0131p gaza sonuna kadar basmaya benziyor. Bir yere gitmiyoruz ama cay\u0131r cay\u0131r benzin yak\u0131yoruz \ud83d\ude42 \u0130\u015fte bunu yapmamak i\u00e7in Timer mod\u00fcl\u00fc var.<\/p>\n<p>Bizim bu zamana kadar \u00e7al\u0131\u015ft\u0131\u011f\u0131m\u0131z PIC16F84A&#8217;da ne yaz\u0131k ki tek bir zamanlay\u0131c\u0131 mod\u00fcl\u00fc var. Ancak di\u011fer modellerde daha fazla say\u0131da zamanlay\u0131c\u0131 mod\u00fcl\u00fc mevcut. Unutmamak gerekir ki zamanlay\u0131c\u0131lar g\u00f6m\u00fcl\u00fc sistemlerde &#8220;elzem&#8221; oldu\u011fundan, hemen her mikrokontrol\u00f6rde zamanlay\u0131c\u0131 bulunur. \u015eimdi hemen bir tablo ile hangi PIC&#8217;te hangi zamanlay\u0131c\u0131 var g\u00f6relim.<\/p>\n<table width=\"863\">\n<tbody>\n<tr>\n<td width=\"144\"><b>Zamanlay\u0131c\u0131<\/b><\/td>\n<td width=\"219\"><b>PIC16F8X<\/b><\/td>\n<td width=\"258\"><b>PIC16F62X<\/b><\/td>\n<td width=\"242\"><b>PIC16F877<\/b><\/td>\n<\/tr>\n<tr>\n<td width=\"144\">Timer0<\/td>\n<td width=\"219\">+<\/td>\n<td width=\"258\">+<\/td>\n<td width=\"242\">+<\/td>\n<\/tr>\n<tr>\n<td width=\"144\">Timer1<\/td>\n<td width=\"219\">&#8211;<\/td>\n<td width=\"258\">+<\/td>\n<td width=\"242\">+<\/td>\n<\/tr>\n<tr>\n<td width=\"144\">Timer2<\/td>\n<td width=\"219\">&#8211;<\/td>\n<td width=\"258\">+<\/td>\n<td width=\"242\">+<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Bu arada hemen araya s\u0131k\u0131\u015ft\u0131ray\u0131m; zamanlay\u0131c\u0131lar\u0131 da bitirince art\u0131k daha geli\u015fmi\u015f PIC modelleri \u00fczerinden devam etmemizde bir sak\u0131nca kalmayacak. O nedenle yava\u015ftan di\u011ferlerine de\u00a0ge\u00e7ebiliriz. \u015eimdi Timer0&#8217;\u0131n hakk\u0131ndan gelelim \ud83d\ude09<\/p>\n<p><strong>TIMER 0<\/strong><\/p>\n<p>Timer0 karde\u015fimiz, 8-bit&#8217;lik bir zamanlay\u0131c\u0131\/say\u0131c\u0131 olarak tasarlanm\u0131\u015f olup, do\u011fal olarak 0&#8217;dan 255&#8217;e kadar sayabilmektedir. Yine bu efendi karde\u015fimizin sayac\u0131n\u0131 okumak da sayac\u0131na yazmak da m\u00fcmk\u00fcnd\u00fcr; bu da bize zamanlay\u0131 istedi\u011fimiz de\u011ferden ba\u015flatma ve g\u00fcncel de\u011feri okuma imkanlar\u0131 sunar.<\/p>\n<p>Zamanlay\u0131c\u0131, esas\u0131nda; herhangi bir saat i\u015faretini (clock pulse) al\u0131p o i\u015fareti \u00e7e\u015fitli \u00f6n i\u015flemlerle \u00f6rnekleyerek sayan bir devreciktir. Buna istinaden s\u00f6z konusu saat i\u015fareti d\u0131\u015far\u0131daki bir osilat\u00f6rden (Ring osilat\u00f6r) ya da i\u00e7 osilat\u00f6rden (RC osilat\u00f6r) al\u0131nabilmektedir.<\/p>\n<p>Bu zamanlay\u0131c\u0131lar 255&#8217;e kadar sayabildi\u011finden 255&#8217;ten sonraki say\u0131mda ta\u015fma olur yani de\u011fer tekrar 0&#8217;a d\u00f6ner. Bu anda kesme kurmak m\u00fcmk\u00fcnd\u00fcr. Bu da zamanlay\u0131c\u0131 kesmesi olarak adland\u0131r\u0131lmaktad\u0131r.<\/p>\n<p>Timer0 ile alakas\u0131 olan k\u00fct\u00fckler, mikrodoentleyicinin veri ka\u011f\u0131d\u0131nda a\u00e7\u0131k\u00e7a belirtilmi\u015ftir. Buna g\u00f6re OPTION_REG, INTCON_REG, TMR0_REG, TMR0_REG ve inanmazs\u0131n\u0131z TRISA\/PORTA k\u00fct\u00fckleri Timer0 ile ilintili imi\u015f. Bunlar\u0131n her birini didik didik ederek zamanlay\u0131c\u0131lar\u0131n suyunu \u00e7\u0131karaca\u011f\u0131z. Tabi ki yapaca\u011f\u0131m\u0131z ilk i\u015f, hen\u00fcz modellemedi\u011fimiz k\u00fct\u00fckleri modelleyerek k\u00fct\u00fcphanemize eklemek olacak.<\/p>\n<p>T\u00fcm bunlara ek olarak, k\u00fct\u00fcphanemizi yine ad\u0131m ad\u0131m optimize etmeye devam edece\u011fiz. Burada yine tasar\u0131m trade-off&#8221;lar\u0131n\u0131 tart\u0131\u015faca\u011f\u0131z ve yeni eksikleri hep birlikte tespit edece\u011fiz \ud83d\ude42 \u00d6yleyse i\u015fe koyulal\u0131m ve TIMER0 ile ilk periyodik fonksiyonumuza hayat verelim!<\/p>\n<p>Malumunuz her yaz\u0131da yeni kesme de\u011ferlendirme rutinleri, yeni veri yap\u0131lar\u0131 ekliyoruz. Bunlar\u0131 her uygulamada kullanmayaca\u011f\u0131m\u0131zdan, bu uygulamalarda biraz bellek israf\u0131 yapm\u0131\u015f oluyorduk. \u015eimdi onlar\u0131 bir config dosyas\u0131 \u00fczerinden se\u00e7imli hale getirmenin tam s\u0131ras\u0131. Yeni config dosyam\u0131z &#8220;pic16lib_conf.h&#8221; a\u015fa\u011f\u0131daki gibi.<\/p>\n<pre class=\"lang:c decode:true\" title=\"pic16flib_config.h\">\/* \r\n * File:   pic16flib_conf.h\r\n * Author: ozenozkaya\r\n *\r\n * Created on 25 Eyl\u00fcl 2015 Cuma, 00:46\r\n *\/\r\n\r\n#ifndef PIC16FLIB_CONF_H\r\n#define    PIC16FLIB_CONF_H\r\n\r\n#ifdef __cplusplus\r\nextern \"C\" {\r\n#endif\r\n\r\n#define MAX_INT_CALLBACK_NUM (1)\r\n\r\n\/\/#define PIC16LIB_USE_RB0_INT\r\n\/\/#define PIC16LIB_USE_PORTB_INT\r\n#define PIC16LIB_USE_TIMER0_INT\r\n\r\n#ifdef __cplusplus\r\n}\r\n#endif\r\n\r\n#endif \/* PIC16FLIB_CONF_H *\/\r\n<\/pre>\n<p>G\u00f6rm\u00fc\u015f oldu\u011funuz PIC16FLIB_USE* etiketlerinden ikisi commentlenmi\u015f. E\u011fer uygulaman\u0131zda RB0\/PORTB kesmesini kullanacaksan\u0131z bunlar\u0131 da a\u00e7abilirsiniz. Biz bu uygulamam\u0131zda yaln\u0131zca TIMER0 kesmelerini kullanaca\u011f\u0131m\u0131zdan se\u00e7imi o \u015fekilde yapt\u0131k.<\/p>\n<p>Hemen g\u00fcncelledi\u011fimiz k\u00fct\u00fcphane dosyalar\u0131m\u0131z\u0131 g\u00f6relim.<\/p>\n<pre class=\"lang:c decode:true\" title=\"pic16f84a_lib.h\">\/* \r\n * File:   pic16f84a_lib.h\r\n * Author: ozenozkaya\r\n *\r\n * Created on 20 Temmuz 2015 Pazartesi, 00:05\r\n *\/\r\n\r\n#ifndef PIC16F84A_LIB_H\r\n#define    PIC16F84A_LIB_H\r\n\r\n#ifdef __cplusplus\r\nextern \"C\" {\r\n#endif\r\n \r\n#include &lt;stdint.h&gt;\r\n#include \"pic16flib_conf.h\"\r\n    \r\n#define PIC16LIB_ERROR_NONE     (0)\r\n#define PIC16LIB_ERROR_CB_NULL  (-1)\r\n#define PIC16LIB_ERROR_CB_ALREADY_REGISTERED (-2)\r\n\r\n#define F_OSC (1000000UL)\r\n    \r\n#define REG_TIMER0_ADDR (0x01)\r\n#define REG_TIMER0 (*( volatile unsigned char*)REG_TIMER0_ADDR)\r\n    \r\n#define REG_TRISB_ADDR (0x86)\r\n#define REG_TRISB (*( volatile unsigned char*)REG_TRISB_ADDR)\r\n \r\n#define REG_TRISA_ADDR (0x85)\r\n#define REG_TRISA (*( volatile unsigned char*)REG_TRISA_ADDR)\r\n    \r\n#define TRIS_PIN_OUTPUT (0)\r\n#define TRIS_PIN_INPUT  (1)\r\n#define TRIS_PORT_OUTPUT (0)\r\n#define TRIS_PORT_INPUT  (0xFF)\r\n\r\n#define REG_PORTB_ADDR (0x06)\r\n#define REG_PORTB (*( volatile unsigned char*)REG_PORTB_ADDR)\r\n    \r\n#define REG_PORTA_ADDR (0x05)\r\n#define REG_PORTA (*( volatile unsigned char*)REG_PORTA_ADDR)\r\n\r\n#define PORT_PIN_LOW  (0)\r\n#define PORT_PIN_HIGH (1)\r\n#define PORT_ALL_LOW  (0)\r\n#define PORT_ALL_HIGH (0xFF)\r\n\r\n#define REG_INTCON_ADDR (0x0B)\r\n#define REG_INTCON (*( volatile unsigned char*)REG_INTCON_ADDR)\r\n#define INT_ENABLE (1)\r\n#define INT_ENABLE_ALL (0xFF)\r\n#define INT_DISABLE (0)\r\n#define INT_DISABLE_ALL (0)\r\n#define INT_FLAG_CLEAR (0)\r\n\r\n#define REG_OPTION_ADDR (0x81)\r\n#define REG_OPTION (*( volatile unsigned char*)REG_OPTION_ADDR)\r\n#define INT_EDGE_FALLING (0)\r\n#define INT_EDGE_RISING  (1)\r\n    \r\n\r\n\r\ntypedef struct \r\n{\r\n    \/\/one bit is stored in one BYTE\r\n    uint8_t pin0:1;\r\n    uint8_t pin1:1;\r\n    uint8_t pin2:1;\r\n    uint8_t pin3:1;\r\n    uint8_t pin4:1;\r\n    uint8_t pin5:1;\r\n    uint8_t pin6:1;\r\n    uint8_t pin7:1;\r\n}_tris_port_pin_t, *_tris_port_pin_ptr_t;\r\n\r\ntypedef struct\r\n{\r\n    uint8_t RBIF:1;\r\n    uint8_t INTF:1;\r\n    uint8_t T0IF:1;\r\n    uint8_t RBIE:1;\r\n    uint8_t INTE:1;\r\n    uint8_t T0IE:1;\r\n    uint8_t EEIE:1;\r\n    uint8_t GIE:1;\r\n}_intcon_reg_t,*_intcon_reg_ptr_t;\r\n\r\ntypedef struct\r\n{\r\n    uint8_t PS:3;\r\n    uint8_t PSA:1;\r\n    uint8_t T0SE:1;\r\n    uint8_t T0CS:1;\r\n    uint8_t INTEDG:1;\r\n    uint8_t RBPU:1;\r\n}_option_reg_t,*_option_reg_ptr_t;\r\n\r\ntypedef union\r\n{\r\n    _tris_port_pin_t pins;\r\n    uint8_t port;\r\n}tris_port_t,*tris_port_ptr_t;\r\n#define REG_TRISA_UNION (*(tris_port_ptr_t)REG_TRISA_ADDR) \r\n#define REG_TRISB_UNION (*(tris_port_ptr_t)REG_TRISB_ADDR) \r\n#define REG_PORTA_UNION (*(tris_port_ptr_t)REG_PORTA_ADDR) \r\n#define REG_PORTB_UNION (*(tris_port_ptr_t)REG_PORTB_ADDR) \r\n\r\ntypedef union\r\n{\r\n  _option_reg_t bits;\r\n  uint8_t value;  \r\n}option_reg_t, *option_reg_ptr_t;\r\n#define T0CS_SOURCE_RA4_T0CKI_PIN (0x01)\r\n#define T0CS_SOURCE_INTERNAL_CLOCK (0x00)\r\n\r\n#define PSA_ASSIGN_TO_WATCHDOG  (0x01)\r\n#define PSA_ASSIGN_TO_TIMER0    (0x00)\r\n\r\n#define PS_TMR0_RATE_DIVIDE_2   (0x00)\r\n#define PS_TMR0_RATE_DIVIDE_4   (0x01)\r\n#define PS_TMR0_RATE_DIVIDE_8   (0x02)\r\n#define PS_TMR0_RATE_DIVIDE_16   (0x03)\r\n#define PS_TMR0_RATE_DIVIDE_32   (0x04)\r\n#define PS_TMR0_RATE_DIVIDE_64   (0x05)\r\n#define PS_TMR0_RATE_DIVIDE_128   (0x06)\r\n#define PS_TMR0_RATE_DIVIDE_256   (0x07)\r\n\r\n#define REG_OPTION_UNION (*(option_reg_ptr_t)REG_OPTION_ADDR) \r\n\r\ntypedef union\r\n{\r\n  _intcon_reg_t bits;\r\n  uint8_t value;  \r\n}intcon_reg_t, *intcon_reg_ptr_t;\r\n#define REG_INTCON_UNION   (*(intcon_reg_ptr_t)REG_INTCON_ADDR)\r\n\r\ntypedef union\r\n{\r\n    uint8_t value;\r\n    uint8_t count;\r\n}timer0_reg_t, *timer0_reg_ptr_t;\r\n#define TIMER0_MAX_CNT (0xFF)\r\n#define TIMER0_ASSIGN_CNT(NEW_TMR0_CNT)    (TIMER0_MAX_CNT-NEW_TMR0_CNT)\r\n#define REG_TIMER0_UNION   (*(timer0_reg_ptr_t)REG_TIMER0_ADDR)\r\n\r\n#define WAIT_LOOP_FOREVER()  while(1)\r\n\r\n#ifdef PIC16LIB_USE_RB0_INT\r\ntypedef void (*rb0_int_callback_t)();\r\nint8_t register_rb0_int_callback(rb0_int_callback_t new_cb);\r\nint8_t unregister_rb0_int_callback(rb0_int_callback_t cb_to_unreg);\r\n#endif\r\n\r\n#ifdef PIC16LIB_USE_PORTB_INT\r\ntypedef void (*portb_int_callback_t)();\r\nint8_t register_portb_int_callback(portb_int_callback_t new_cb);\r\nint8_t unregister_portb_int_callback(portb_int_callback_t cb_to_unreg);\r\n#endif\r\n\r\n#ifdef PIC16LIB_USE_TIMER0_INT\r\ntypedef void (*timer0_int_callback_t)();\r\nint8_t register_timer0_int_callback(timer0_int_callback_t new_cb);\r\nint8_t unregister_timer0_int_callback(timer0_int_callback_t cb_to_unreg);\r\n#endif\r\n\r\n#ifdef __cplusplus\r\n}\r\n#endif\r\n\r\n#endif \/* PIC16F84A_LIB_H *\/\r\n<\/pre>\n<p>Timer0 adres ve k\u00fct\u00fck tan\u0131mlamalar\u0131n\u0131n yap\u0131lm\u0131\u015f oldu\u011funa dikkatinizi \u00e7ekerim \ud83d\ude42 Ayn\u0131 zamanda, config dosyas\u0131nda kulland\u0131\u011f\u0131m\u0131z etiketler de, kullan\u0131lmayan kesmelerin fonksiyon prototiplerini derleme zaman\u0131nda kapatmak i\u00e7in yerli yerinde. \u00d6yleyse hemen .c dosyam\u0131z\u0131 g\u00f6relim.<\/p>\n<pre class=\"lang:c decode:true\">#include \"pic16f84a_lib.h\"\r\n\r\n#define BIT_TOGGLE(x) (x^=1)\r\n\r\n#ifndef NULL\r\n#define NULL ((void*)0)\r\n#endif\r\n\r\n#ifdef PIC16LIB_USE_RB0_INT\r\nrb0_int_callback_t rb0_int_callback_list[MAX_INT_CALLBACK_NUM];\r\n#endif\r\n\r\n#ifdef PIC16LIB_USE_PORTB_INT\r\nportb_int_callback_t portb_int_callback_list[MAX_INT_CALLBACK_NUM];\r\n#endif\r\n\r\n#ifdef PIC16LIB_USE_TIMER0_INT\r\ntimer0_int_callback_t timer0_int_callback_list[MAX_INT_CALLBACK_NUM];\r\n#endif\r\n\r\n\r\n#if defined(PIC16LIB_USE_RB0_INT) || defined(PIC16LIB_USE_PORTB_INT) || defined(PIC16LIB_USE_TIMER0_INT)\r\nstatic void interrupt global_isr_handler()\r\n{\r\n#ifdef PIC16LIB_USE_RB0_INT\r\n    if(REG_INTCON_UNION.bits.INTF)\r\n    {\r\n        uint8_t cb_index=0;\r\n        for(cb_index=0;cb_index&lt;MAX_INT_CALLBACK_NUM; cb_index++)\r\n        {\r\n            if(NULL != rb0_int_callback_list[cb_index])\r\n            {\r\n                rb0_int_callback_list[cb_index]();\r\n            }\r\n        }\r\n        BIT_TOGGLE(REG_OPTION_UNION.bits.INTEDG);\r\n        REG_INTCON_UNION.bits.INTF=INT_FLAG_CLEAR;\r\n    }\r\n#endif\r\n#ifdef PIC16LIB_USE_PORTB_INT\r\n    if(REG_INTCON_UNION.bits.RBIF)\r\n    {\r\n        uint8_t cb_index=0;\r\n        for(cb_index=0;cb_index&lt;MAX_INT_CALLBACK_NUM; cb_index++)\r\n        {\r\n            if(NULL != portb_int_callback_list[cb_index])\r\n            {\r\n                portb_int_callback_list[cb_index]();\r\n            }\r\n        }\r\n        BIT_TOGGLE(REG_OPTION_UNION.bits.INTEDG);\r\n        REG_INTCON_UNION.bits.RBIF=INT_FLAG_CLEAR;\r\n    }\r\n#endif\r\n#ifdef PIC16LIB_USE_TIMER0_INT\r\n    if(REG_INTCON_UNION.bits.T0IF)\r\n    {\r\n        REG_INTCON_UNION.bits.T0IF=INT_FLAG_CLEAR;\r\n        uint8_t cb_index=0;\r\n        for(cb_index=0;cb_index&lt;MAX_INT_CALLBACK_NUM; cb_index++)\r\n        {\r\n            if(NULL != timer0_int_callback_list[cb_index])\r\n            {\r\n                timer0_int_callback_list[cb_index]();\r\n            }\r\n        }\r\n    }\r\n#endif\r\n}\r\n#endif\r\n\r\n#ifdef PIC16LIB_USE_RB0_INT\r\nint8_t register_rb0_int_callback(rb0_int_callback_t new_cb)\r\n{\r\n    if(NULL != new_cb)\r\n    {\r\n        uint8_t cb_index=0;\r\n        for(cb_index=0;cb_index&lt;MAX_INT_CALLBACK_NUM; cb_index++)\r\n        {\r\n            if(NULL == rb0_int_callback_list[cb_index])\r\n            {\r\n                rb0_int_callback_list[cb_index]=new_cb;\r\n            }\r\n        }\r\n        if(MAX_INT_CALLBACK_NUM == cb_index)\r\n        {\r\n            return PIC16LIB_ERROR_CB_ALREADY_REGISTERED; \/\/All callbacks are already registered\r\n        }\r\n    }\r\n    else\r\n    {\r\n        return PIC16LIB_ERROR_CB_NULL; \/\/ Callback is NULL\r\n    }\r\n    return 0;\r\n}\r\n\r\nint8_t unregister_rb0_int_callback(rb0_int_callback_t cb_to_unreg)\r\n{\r\n    if(NULL != cb_to_unreg)\r\n    {\r\n        uint8_t cb_index=0;\r\n        for(cb_index=0;cb_index&lt;MAX_INT_CALLBACK_NUM; cb_index++)\r\n        {\r\n            if(cb_to_unreg == rb0_int_callback_list[cb_index])\r\n            {\r\n                rb0_int_callback_list[cb_index]=NULL;\r\n            }\r\n        }\r\n    }\r\n    else\r\n    {\r\n        return PIC16LIB_ERROR_CB_NULL; \/\/ Callback is NULL\r\n    }\r\n    return PIC16LIB_ERROR_NONE;\r\n}\r\n#endif\r\n#ifdef PIC16LIB_USE_PORTB_INT\r\nint8_t register_portb_int_callback(portb_int_callback_t new_cb)\r\n{\r\n    if(NULL != new_cb)\r\n    {\r\n        uint8_t cb_index=0;\r\n        for(cb_index=0;cb_index&lt;MAX_INT_CALLBACK_NUM; cb_index++)\r\n        {\r\n            if(NULL == portb_int_callback_list[cb_index])\r\n            {\r\n                portb_int_callback_list[cb_index]=new_cb;\r\n            }\r\n        }\r\n        if(MAX_INT_CALLBACK_NUM == cb_index)\r\n        {\r\n            return PIC16LIB_ERROR_CB_ALREADY_REGISTERED; \/\/All callbacks are already registered\r\n        }\r\n    }\r\n    else\r\n    {\r\n        return PIC16LIB_ERROR_CB_NULL; \/\/ Callback is NULL\r\n    }\r\n    return PIC16LIB_ERROR_NONE;\r\n}\r\n \r\n \r\n \r\nint8_t unregister_portb_int_callback(portb_int_callback_t cb_to_unreg)\r\n{\r\n    if(NULL != cb_to_unreg)\r\n    {\r\n        uint8_t cb_index=0;\r\n        for(cb_index=0;cb_index&lt;MAX_INT_CALLBACK_NUM; cb_index++)\r\n        {\r\n            if(cb_to_unreg == portb_int_callback_list[cb_index])\r\n            {\r\n                portb_int_callback_list[cb_index]=NULL;\r\n            }\r\n        }\r\n    }\r\n    else\r\n    {\r\n        return PIC16LIB_ERROR_CB_NULL; \/\/ Callback is NULL\r\n    }\r\n    return PIC16LIB_ERROR_NONE;\r\n}\r\n#endif\r\n#ifdef PIC16LIB_USE_TIMER0_INT\r\nint8_t register_timer0_int_callback(timer0_int_callback_t new_cb)\r\n{\r\n    if(NULL != new_cb)\r\n    {\r\n        uint8_t cb_index=0;\r\n        for(cb_index=0;cb_index&lt;MAX_INT_CALLBACK_NUM; cb_index++)\r\n        {\r\n            if(NULL == timer0_int_callback_list[cb_index])\r\n            {\r\n                timer0_int_callback_list[cb_index]=new_cb;\r\n            }\r\n        }\r\n        if(MAX_INT_CALLBACK_NUM == cb_index)\r\n        {\r\n            return PIC16LIB_ERROR_CB_ALREADY_REGISTERED; \/\/All callbacks are already registered\r\n        }\r\n    }\r\n    else\r\n    {\r\n        return PIC16LIB_ERROR_CB_NULL; \/\/ Callback is NULL\r\n    }\r\n    return PIC16LIB_ERROR_NONE;\r\n}\r\n \r\n \r\n \r\nint8_t unregister_timer0_int_callback(timer0_int_callback_t cb_to_unreg)\r\n{\r\n    if(NULL != cb_to_unreg)\r\n    {\r\n        uint8_t cb_index=0;\r\n        for(cb_index=0;cb_index&lt;MAX_INT_CALLBACK_NUM; cb_index++)\r\n        {\r\n            if(cb_to_unreg == timer0_int_callback_list[cb_index])\r\n            {\r\n                timer0_int_callback_list[cb_index]=NULL;\r\n            }\r\n        }\r\n    }\r\n    else\r\n    {\r\n        return PIC16LIB_ERROR_CB_NULL; \/\/ Callback is NULL\r\n    }\r\n    return PIC16LIB_ERROR_NONE;\r\n}\r\n#endif<\/pre>\n<p>G\u00f6r\u00fcld\u00fc\u011f\u00fc \u00fczere, al\u0131\u015f\u0131lageldik \u015fekilde timer0 kesme rutinlerini de ekledik. Ek olarak yine config etiketlerimiz de fonksiyonlar\u0131 \u00e7evrelemi\u015f durumda \ud83d\ude42 Art\u0131k k\u00fct\u00fcphanemizi kullanan kimselere \u00e7ok daha geni\u015f optimizasyon imkan\u0131 sunuyoruz! Her durumda yine Microchip liblerinden \u00e7ok daha y\u00fcksek performansl\u0131 bir konumda k\u00fct\u00fcphanemiz \ud83d\ude42 0 byte kullanarak t\u00fcm register eri\u015fimlerini yapmak m\u00fcmk\u00fcn.\u00a0Konfor arayan yaz\u0131l\u0131mc\u0131lar i\u00e7in de, k\u00fct\u00fck eri\u015fimlerini \u00e7ok kolayla\u015ft\u0131ran veri yap\u0131lar\u0131n\u0131 implement ettik. \u0130steyen istedi\u011fi y\u00f6nde optimizasyon yapabiliyor. Bu da k\u00fct\u00fcphanemizin esnekli\u011fini ciddi oranda art\u0131rm\u0131\u015f durumda. \u015eimdi uygulama koduna ge\u00e7elim.<\/p>\n<pre class=\"lang:c decode:true\" title=\"main.c\">\/* \r\n * File:   main.c\r\n * Author: ozenozkaya\r\n *\r\n * Created on 24 September 2015 \r\n *\/\r\n\r\n#include \"pic16f84a_lib.h\"\r\n\r\n\/*FOSC is 4Mhz. Prescaler input it 1Mhz.\r\n Because prescaler is 8, prescaler output f=125kHz.\r\n So,the prescaler output period is 8uS.\r\n Hence, we need 125 timer pulses to reach 1mS.\r\n 8uS*125 = 1mS*\/\r\n#define TIMER0_VAL_FOR_1MS  (125)\r\n\r\nstatic void milisecond_event_callback()\r\n{\r\n    REG_PORTB_UNION.port^=0xFF;\r\n    REG_TIMER0_UNION.count = TIMER0_ASSIGN_CNT(TIMER0_VAL_FOR_1MS);\r\n}\r\n\r\nvoid main() {\r\n    REG_TRISB_UNION.port = TRIS_PORT_OUTPUT;\r\n    REG_PORTB_UNION.port = PORT_ALL_LOW;\r\n\r\n    REG_OPTION_UNION.bits.T0CS = T0CS_SOURCE_INTERNAL_CLOCK;\r\n    REG_OPTION_UNION.bits.PSA = PSA_ASSIGN_TO_TIMER0;\r\n    REG_OPTION_UNION.bits.PS = PS_TMR0_RATE_DIVIDE_8; \/\/8uS\r\n    \r\n    \/*! 125*8uS = 1000uS = 1mS*\/\r\n    REG_TIMER0_UNION.count = TIMER0_ASSIGN_CNT(TIMER0_VAL_FOR_1MS); \r\n    REG_INTCON_UNION.value = INT_DISABLE_ALL;\r\n    REG_INTCON_UNION.bits.GIE = INT_ENABLE;\r\n    REG_INTCON_UNION.bits.T0IE = INT_ENABLE;\r\n    \r\n    register_timer0_int_callback(milisecond_event_callback);\r\n    WAIT_LOOP_FOREVER();\r\n}\r\n<\/pre>\n<p>Bu yaz\u0131l\u0131mda, B portlar\u0131n\u0131 1 milisaniyede bir eviren bir yaz\u0131l\u0131m olu\u015fturduk. Peki ama bunu nas\u0131l yapt\u0131k? Hemen hesap kitaba de\u011finelim. PIC mikrokontrol\u00f6r\u00fcm\u00fcze d\u0131\u015far\u0131dan bir kristal osilat\u00f6r ba\u011fl\u0131 ve frekans\u0131 4MHz.<\/p>\n<div class=\"su-box su-box-style-soft\" id=\"\" style=\"border-color:#74ad73;border-radius:3px;\"><div class=\"su-box-title\" style=\"background-color:#a7e0a6;color:#FFFFFF;border-top-left-radius:1px;border-top-right-radius:1px\">Aman Diyelim<\/div><div class=\"su-box-content su-u-clearfix su-u-trim\" style=\"border-bottom-left-radius:1px;border-bottom-right-radius:1px\"> Proteus sim\u00fclasyonu yapmadan \u00f6nce, PIC mikrokontrol\u00f6re \u00e7ift t\u0131klay\u0131p FOSC de\u011ferini 4Mhz yaparsak, buradaki hesaplarla uyumlu \u00e7\u0131kt\u0131lar alabiliriz. Aksi durumda varsay\u0131lan de\u011fer olan 1Mhz ge\u00e7erli olacakt\u0131r ve bu durumda istenen \u00e7\u0131kt\u0131lar elde edilemeyecektir. <\/div><\/div>\n<p>PIC16F84A&#8217;da timer mod\u00fcl\u00fcne gelen saat i\u015fareti 4&#8217;e b\u00f6l\u00fcnerek gelir (datasheet&#8217;te yazmakta). Dolay\u0131s\u0131yla mod\u00fcl\u00fcn giri\u015fi 1MHz yani saniyede 1 milyon saat darbesi geliyor. Timer mod\u00fcl\u00fcn\u00fcn giri\u015f k\u0131sm\u0131nda bir frekans \u00f6l\u00e7eklendirici\u00a0(prescaler) bulunmakta.\u00a0Biz \u00f6l\u00e7eklendirme oran\u0131n\u0131 8&#8217;e b\u00f6lecek \u015fekilde se\u00e7tik. Bunu, a\u015fa\u011f\u0131daki sat\u0131r ile yapt\u0131k.<\/p>\n<pre class=\"lang:c decode:true\">REG_OPTION_UNION.bits.PS = PS_TMR0_RATE_DIVIDE_8; \/\/8uS<\/pre>\n<p>Buna g\u00f6re, 1MHz&#8217;lik\u00a0i\u015faret frekans\u0131n\u0131 8&#8217;e b\u00f6ld\u00fck ve prescaler \u00e7\u0131k\u0131\u015f\u0131ndaki frekans 125Khz oldu. Bu da 8 micro saniyede bir saat darbesi demek. E\u011fer bu saat darbelerinden 125 tane say\u0131l\u0131nca kesme olacak \u015fekilde bir konfigurasyon yaparsak, 8*125 us = 1ms&#8217;lik bir kesme rutini elde etmi\u015f olaca\u011f\u0131z. \u00a0Bu sebeple a\u015fa\u011f\u0131daki tan\u0131mla 125 de\u011feri tan\u0131mland\u0131.<\/p>\n<pre class=\"lang:c decode:true\">\/*FOSC is 4Mhz. Prescaler input it 1Mhz.\r\n Because prescaler is 8, prescaler output f=125kHz.\r\n So,the prescaler output period is 8uS.\r\n Hence, we need 125 timer pulses to reach 1mS.\r\n 8uS*125 = 1mS*\/\r\n#define TIMER0_VAL_FOR_1MS  (125)<\/pre>\n<p>Bu de\u011fer ise timer0 k\u00fct\u00fc\u011f\u00fcne a\u015fa\u011f\u0131daki \u015fekilde atand\u0131.<\/p>\n<pre class=\"lang:default decode:true\">\/*! 125*8uS = 1000uS = 1mS*\/\r\n    REG_TIMER0_UNION.count = TIMER0_ASSIGN_CNT(TIMER0_VAL_FOR_1MS);<\/pre>\n<p>Burada ibretlik bir macromuz var. Bu macro TIMER0_ASSIGN_CNT. Peki neden buna ihtiya\u00e7 duyduk? Malumunuz bizim timer0 mod\u00fcl\u00fc yukar\u0131 do\u011fru say\u0131yor ve 255(0xFF)&#8217;de ta\u015f\u0131yor. Ta\u015fmadan \u00f6nce 125 tur\u00a0sayabilmesi i\u00e7in asl\u0131nda 255-125 =130 de\u011ferinden ba\u015flamal\u0131 Timer0. Bu durumda timer 130&#8217;dan ba\u015flat\u0131lacak ve tam 125 tur sonra (1ms yap\u0131yor) kesme gelmi\u015f olacak. \u0130\u015fte bu \u00e7\u0131karma hesab\u0131n\u0131 yapan macromuz\u00a0TIMER0_ASSIGN_CNT. K\u00fct\u00fcphanemizdeki tan\u0131m\u0131 da a\u015fa\u011f\u0131daki gibi idi.<\/p>\n<pre class=\"lang:c decode:true \">#define TIMER0_MAX_CNT (0xFF)\r\n#define TIMER0_ASSIGN_CNT(NEW_TMR0_CNT)    (TIMER0_MAX_CNT-NEW_TMR0_CNT)<\/pre>\n<p>Bu sayede 1ms&#8217;lik zamanlama sa\u011flam\u0131\u015f oluyor. Ancak s\u00fcrekli olarak 1ms&#8217;lik zamanlamay\u0131 sa\u011flamak i\u00e7in TIMER0 ta\u015ft\u0131\u011f\u0131nda, yani kesme olu\u015ftu\u011funda Timer0&#8217;\u0131 tekrar 130 de\u011ferinden ba\u015flatmak gerekiyor. Bunun i\u00e7in, milisaniye callback fonskiyonumuzda a\u015fa\u011f\u0131daki gibi bir tekar y\u00fckleme yapt\u0131k.<\/p>\n<pre class=\"lang:c decode:true \">static void milisecond_event_callback()\r\n{\r\n    REG_PORTB_UNION.port^=0xFF;\r\n    REG_TIMER0_UNION.count = TIMER0_ASSIGN_CNT(TIMER0_VAL_FOR_1MS);\r\n}\r\n<\/pre>\n<p>Bu sayede her \u015fey \u00e7al\u0131\u015f\u0131r durumda ve enerji efektif \u015fekilde periyodik i\u015flerimizi yapabilir hale geldik \ud83d\ude42 Hemen proteus isis \u00fczerindeki sim\u00fclasyon \u00e7\u0131kt\u0131m\u0131z\u0131 da ekleyelim.<\/p>\n<p><a href=\"https:\/\/i0.wp.com\/ozenozkaya.com\/blog\/wp-content\/uploads\/pic_timer0_0.png\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-475\" src=\"https:\/\/i0.wp.com\/ozenozkaya.com\/blog\/wp-content\/uploads\/pic_timer0_0.png?resize=640%2C342\" alt=\"pic_timer0_0\" width=\"640\" height=\"342\" \/><\/a><\/p>\n<p>&nbsp;<\/p>\n<p>Osiloskoptaki zaman \u00f6l\u00e7\u00fcm\u00fcn\u00fcn 1.06 mS olu\u015funa dikkat ediniz. 1ms g\u00fczel de, bu 0.06 mS nereden geldi? Buradan da \u00e7ok g\u00fczel ibretlere de\u011finece\u011fiz dostlar, ancak bu sorunun yan\u0131t\u0131 ve dahas\u0131n\u0131 bir sonraki yaz\u0131ya b\u0131rak\u0131yoruz \ud83d\ude42<\/p>\n<p>Zamanlay\u0131c\u0131lar konusunda ne kadar \u00e7ok tekrar yaparsan\u0131z, farkl\u0131 uygulamalar yazarsan\u0131z o kadar iyi olur. \u00d6rne\u011fin kara\u015fim\u015fek uygulamas\u0131n\u0131 zamanlay\u0131c\u0131 kullanarak yazmakta faydalar var.<\/p>\n<p>\u015eimdi devam!<\/p>\n<p>Yaz\u0131lar\u0131 be\u011fendiyseniz, faydalanabilecek tan\u0131d\u0131klar\u0131n\u0131zla payla\u015fmay\u0131 unutmay\u0131n\u0131z.<\/p>\n<a href=\"http:\/\/ozenozkaya.com\/blog\/?p=457\" class=\"su-button su-button-style-3d\" style=\"color:#FFFFFF;background-color:#2D89EF;border-color:#246ec0;border-radius:5px\" target=\"_self\"><span style=\"color:#FFFFFF;padding:6px 16px;font-size:13px;line-height:20px;border-color:#6cadf4;border-radius:5px;text-shadow:none\"><i class=\"sui sui-arrow-circle-o-left\" style=\"font-size:13px;color:#FFFFFF\"><\/i> \u00d6nceki Sayfa<\/span><\/a> \u00a0<a href=\"http:\/\/ozenozkaya.com\/blog\/?p=523\" class=\"su-button su-button-style-3d\" style=\"color:#FFFFFF;background-color:#2D89EF;border-color:#246ec0;border-radius:5px\" target=\"_self\"><span style=\"color:#FFFFFF;padding:6px 16px;font-size:13px;line-height:20px;border-color:#6cadf4;border-radius:5px;text-shadow:none\"><i class=\"sui sui-arrow-circle-right\" style=\"font-size:13px;color:#FFFFFF\"><\/i> Sonraki Sayfa<\/span><\/a>\n","protected":false},"excerpt":{"rendered":"<p>Merhabalar, ge\u00e7en yaz\u0131m\u0131zda kesmeler \u00fczerine olduk\u00e7a marjinal baz\u0131 \u00e7al\u0131\u015fmalar yapm\u0131\u015ft\u0131k. \u015eu ana kadar PIC mikrokontrol\u00f6r\u00fcn\u00a0giri\u015f \u00e7\u0131k\u0131\u015f \u00fcnitelerini, kesmeleri de i\u00e7erecek \u015fekilde evire \u00e7evire kullanabilecek bilgi birikimini\u00a0edindik. Tabi bu bahsetti\u011fimiz konu, i\u015fin bahanesiydi. As\u0131l amac\u0131m\u0131z, t\u00fcm mikrokontrol\u00f6rlerde kullanabilece\u011fimiz bir modelleme ve geli\u015ftirme altyap\u0131s\u0131n\u0131 tahsis etmekti. Buna istinaden yapt\u0131\u011f\u0131m\u0131z en orijinal i\u015f, Microchip firmas\u0131n\u0131n sundu\u011fu k\u00fct\u00fcphanelerden performans, <a class=\"read-more\" href=\"http:\/\/ozenozkaya.com\/blog\/?p=470\">Read more<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_tr_post_content":"Merhabalar, ge\u00e7en yaz\u0131m\u0131zda kesmeler \u00fczerine olduk\u00e7a marjinal baz\u0131 \u00e7al\u0131\u015fmalar yapm\u0131\u015ft\u0131k. \u015eu ana kadar PIC mikrokontrol\u00f6r\u00fcn\u00a0giri\u015f \u00e7\u0131k\u0131\u015f \u00fcnitelerini, kesmeleri de i\u00e7erecek \u015fekilde evire \u00e7evire kullanabilecek bilgi birikimini\u00a0edindik. Tabi bu bahsetti\u011fimiz konu, i\u015fin bahanesiydi. As\u0131l amac\u0131m\u0131z, t\u00fcm mikrokontrol\u00f6rlerde kullanabilece\u011fimiz bir modelleme ve geli\u015ftirme altyap\u0131s\u0131n\u0131 tahsis etmekti. Buna istinaden yapt\u0131\u011f\u0131m\u0131z en orijinal i\u015f, Microchip firmas\u0131n\u0131n sundu\u011fu k\u00fct\u00fcphanelerden performans, estetik, yaz\u0131l\u0131m kalitesi, ta\u015f\u0131nabilirlik ve geli\u015ftirilebilirlik bak\u0131m\u0131ndan \u00e7ok daha iyi bir k\u00fct\u00fcphane olu\u015fturmak oldu. Mikrokontrol\u00f6r'\u00fcn veri ka\u011f\u0131d\u0131n\u0131 nas\u0131l modelleyece\u011fimizi g\u00f6rd\u00fc\u011f\u00fcm\u00fczden ayn\u0131 i\u015flemleri herhangi bir ba\u015fka platform i\u00e7in yapmak sorun olmayacakt\u0131r.\r\n\r\nD\u0131\u015f d\u00fcnyaya mikrokontrol\u00f6r\u00fcn I\/O pinleri \u00fczerinden m\u00fcdahale edebildi\u011fimizden bir sonraki ad\u0131ma ge\u00e7menin s\u0131ras\u0131 geldi. Bir sonraki ad\u0131m \u015f\u00fcphesiz ki periyodik i\u015flerle nas\u0131l ba\u015fa \u00e7\u0131kabilece\u011fimizi bulmak\u00a0olacak. G\u00fcncel durumda yazd\u0131\u011f\u0131m\u0131z kodlar \u00f6m\u00fcrleri boyunca ayn\u0131 i\u015fi aral\u0131ks\u0131z olarak yapt\u0131lar. Oysa ger\u00e7ek hayattaki pek \u00e7ok uygulamada ger\u00e7ekle\u015fmesi gereken zamanda ve periyodik ger\u00e7ekle\u015ftirilmesi gereken olaylar g\u00f6r\u00fcr\u00fcz. Periyodik yap\u0131lan i\u015flerden ilk akla gelen \u00f6rneklemedir. Nyquist amcam\u0131z\u0131n da y\u0131llar \u00f6nce ortaya koydu\u011fu gibi, bir i\u015fareti do\u011fru zamanlama ile \u00f6rneklemezsek o i\u015faretin ta\u015f\u0131d\u0131\u011f\u0131 bilgiyi kaybetmi\u015f olabiliyoruz. \u00a0Biraz daha net \u015fekilde a\u00e7\u0131klamak gerekirse:\r\n\r\n[su_box title=\"Sosyal Mesaj\" style=\"soft\" box_color=\"#a7e0a6\"]Nyquist \u00f6rnekleme frekans\u0131, bir i\u015faretin\u00a0\u00f6rneklenmesi s\u00fcrecinde tan\u0131mlanan bir alt limittir ve bu limit i\u015faretin i\u00e7erdi\u011fi maksimum frekans bile\u015feninin iki kat\u0131d\u0131r. E\u011fer i\u015faret maksimum frekans bile\u015feninin iki kat\u0131ndan \u00a0- ki bu frekans Nyquist frekans\u0131 oluyor - daha az bir frekansla \u00f6rneklenirse o i\u015faret, \u00f6l\u00e7\u00fcmlerden d\u00fczg\u00fcnce tekrar \u00fcretilemez \u00e7\u00fcnk\u00fc \u00f6rnekleme esnas\u0131nda bilgi kayb\u0131 ya\u015fanm\u0131\u015f olur.[\/su_box]\r\n\r\nSonu\u00e7 olarak, mikrokontrol\u00f6rde zaman\u0131 \u00f6l\u00e7menin bir yolunun olmas\u0131 gerekiyor. \u0130\u015fte bu noktada devreye Timer (Zamanlay\u0131c\u0131) mod\u00fclleri giriyor. Ancak zamanlay\u0131c\u0131lara ge\u00e7meden \u00f6nce, zamanlama sorununa sundu\u011fumuz en basit \u00e7\u00f6z\u00fcm\u00fc hat\u0131rlayal\u0131m. <a href=\"http:\/\/ozenozkaya.com\/blog\/?p=414\" target=\"_blank\">BURADAK\u0130<\/a> yaz\u0131m\u0131zda, DummyDelayMs fonksiyonun kurnazca tan\u0131mlayarak milisaniye mertebesinde bir zamanlama sa\u011flam\u0131\u015ft\u0131k. Hemen implementasyonu hat\u0131rlayal\u0131m.\r\n<pre class=\"lang:c decode:true\" title=\"DummyDelayMs\">static void DummyDelayMs(unsigned int delay_ms)\r\n{\r\n    unsigned long cnt=0;\r\n    unsigned long delay_limit_ms= delay_ms*(F_OSC\/120000);\r\n    for(cnt=0;cnt&lt;delay_limit_ms;cnt++);\r\n}<\/pre>\r\nG\u00f6rd\u00fc\u011f\u00fcn\u00fcz gibi bu kodda, mikrokontrol\u00f6re bo\u015f bele\u015f say\u0131 sayd\u0131r\u0131p, ge\u00e7en zamandan faydaland\u0131k. Tersten giderek, 1ms beklemek i\u00e7in gerekli olan sayma say\u0131s\u0131n\u0131 hesaplay\u0131p, mikrokontrol\u00f6r\u00fcn o kadar bo\u015f bele\u015f (dummy) i\u015flem yapmas\u0131n\u0131 sa\u011flad\u0131k. Bu da adeta bir ara\u00e7ta vitesi bo\u015fa at\u0131p gaza sonuna kadar basmaya benziyor. Bir yere gitmiyoruz ama cay\u0131r cay\u0131r benzin yak\u0131yoruz :) \u0130\u015fte bunu yapmamak i\u00e7in Timer mod\u00fcl\u00fc var.\r\n\r\nBizim bu zamana kadar \u00e7al\u0131\u015ft\u0131\u011f\u0131m\u0131z PIC16F84A'da ne yaz\u0131k ki tek bir zamanlay\u0131c\u0131 mod\u00fcl\u00fc var. Ancak di\u011fer modellerde daha fazla say\u0131da zamanlay\u0131c\u0131 mod\u00fcl\u00fc mevcut. Unutmamak gerekir ki zamanlay\u0131c\u0131lar g\u00f6m\u00fcl\u00fc sistemlerde \"elzem\" oldu\u011fundan, hemen her mikrokontrol\u00f6rde zamanlay\u0131c\u0131 bulunur. \u015eimdi hemen bir tablo ile hangi PIC'te hangi zamanlay\u0131c\u0131 var g\u00f6relim.\r\n<table width=\"863\">\r\n<tbody>\r\n<tr>\r\n<td width=\"144\"><b>Zamanlay\u0131c\u0131<\/b><\/td>\r\n<td width=\"219\"><b>PIC16F8X<\/b><\/td>\r\n<td width=\"258\"><b>PIC16F62X<\/b><\/td>\r\n<td width=\"242\"><b>PIC16F877<\/b><\/td>\r\n<\/tr>\r\n<tr>\r\n<td width=\"144\">Timer0<\/td>\r\n<td width=\"219\">+<\/td>\r\n<td width=\"258\">+<\/td>\r\n<td width=\"242\">+<\/td>\r\n<\/tr>\r\n<tr>\r\n<td width=\"144\">Timer1<\/td>\r\n<td width=\"219\">-<\/td>\r\n<td width=\"258\">+<\/td>\r\n<td width=\"242\">+<\/td>\r\n<\/tr>\r\n<tr>\r\n<td width=\"144\">Timer2<\/td>\r\n<td width=\"219\">-<\/td>\r\n<td width=\"258\">+<\/td>\r\n<td width=\"242\">+<\/td>\r\n<\/tr>\r\n<\/tbody>\r\n<\/table>\r\nBu arada hemen araya s\u0131k\u0131\u015ft\u0131ray\u0131m; zamanlay\u0131c\u0131lar\u0131 da bitirince art\u0131k daha geli\u015fmi\u015f PIC modelleri \u00fczerinden devam etmemizde bir sak\u0131nca kalmayacak. O nedenle yava\u015ftan di\u011ferlerine de\u00a0ge\u00e7ebiliriz. \u015eimdi Timer0'\u0131n hakk\u0131ndan gelelim ;)\r\n\r\n<strong>TIMER 0<\/strong>\r\n\r\nTimer0 karde\u015fimiz, 8-bit'lik bir zamanlay\u0131c\u0131\/say\u0131c\u0131 olarak tasarlanm\u0131\u015f olup, do\u011fal olarak 0'dan 255'e kadar sayabilmektedir. Yine bu efendi karde\u015fimizin sayac\u0131n\u0131 okumak da sayac\u0131na yazmak da m\u00fcmk\u00fcnd\u00fcr; bu da bize zamanlay\u0131 istedi\u011fimiz de\u011ferden ba\u015flatma ve g\u00fcncel de\u011feri okuma imkanlar\u0131 sunar.\r\n\r\nZamanlay\u0131c\u0131, esas\u0131nda; herhangi bir saat i\u015faretini (clock pulse) al\u0131p o i\u015fareti \u00e7e\u015fitli \u00f6n i\u015flemlerle \u00f6rnekleyerek sayan bir devreciktir. Buna istinaden s\u00f6z konusu saat i\u015fareti d\u0131\u015far\u0131daki bir osilat\u00f6rden (Ring osilat\u00f6r) ya da i\u00e7 osilat\u00f6rden (RC osilat\u00f6r) al\u0131nabilmektedir.\r\n\r\nBu zamanlay\u0131c\u0131lar 255'e kadar sayabildi\u011finden 255'ten sonraki say\u0131mda ta\u015fma olur yani de\u011fer tekrar 0'a d\u00f6ner. Bu anda kesme kurmak m\u00fcmk\u00fcnd\u00fcr. Bu da zamanlay\u0131c\u0131 kesmesi olarak adland\u0131r\u0131lmaktad\u0131r.\r\n\r\nTimer0 ile alakas\u0131 olan k\u00fct\u00fckler, mikrodoentleyicinin veri ka\u011f\u0131d\u0131nda a\u00e7\u0131k\u00e7a belirtilmi\u015ftir. Buna g\u00f6re OPTION_REG, INTCON_REG, TMR0_REG, TMR0_REG ve inanmazs\u0131n\u0131z TRISA\/PORTA k\u00fct\u00fckleri Timer0 ile ilintili imi\u015f. Bunlar\u0131n her birini didik didik ederek zamanlay\u0131c\u0131lar\u0131n suyunu \u00e7\u0131karaca\u011f\u0131z. Tabi ki yapaca\u011f\u0131m\u0131z ilk i\u015f, hen\u00fcz modellemedi\u011fimiz k\u00fct\u00fckleri modelleyerek k\u00fct\u00fcphanemize eklemek olacak.\r\n\r\nT\u00fcm bunlara ek olarak, k\u00fct\u00fcphanemizi yine ad\u0131m ad\u0131m optimize etmeye devam edece\u011fiz. Burada yine tasar\u0131m trade-off''lar\u0131n\u0131 tart\u0131\u015faca\u011f\u0131z ve yeni eksikleri hep birlikte tespit edece\u011fiz :) \u00d6yleyse i\u015fe koyulal\u0131m ve TIMER0 ile ilk periyodik fonksiyonumuza hayat verelim!\r\n\r\nMalumunuz her yaz\u0131da yeni kesme de\u011ferlendirme rutinleri, yeni veri yap\u0131lar\u0131 ekliyoruz. Bunlar\u0131 her uygulamada kullanmayaca\u011f\u0131m\u0131zdan, bu uygulamalarda biraz bellek israf\u0131 yapm\u0131\u015f oluyorduk. \u015eimdi onlar\u0131 bir config dosyas\u0131 \u00fczerinden se\u00e7imli hale getirmenin tam s\u0131ras\u0131. Yeni config dosyam\u0131z \"pic16lib_conf.h\" a\u015fa\u011f\u0131daki gibi.\r\n<pre class=\"lang:c decode:true\" title=\"pic16flib_config.h\">\/* \r\n * File:   pic16flib_conf.h\r\n * Author: ozenozkaya\r\n *\r\n * Created on 25 Eyl\u00fcl 2015 Cuma, 00:46\r\n *\/\r\n\r\n#ifndef PIC16FLIB_CONF_H\r\n#define    PIC16FLIB_CONF_H\r\n\r\n#ifdef __cplusplus\r\nextern \"C\" {\r\n#endif\r\n\r\n#define MAX_INT_CALLBACK_NUM (1)\r\n\r\n\/\/#define PIC16LIB_USE_RB0_INT\r\n\/\/#define PIC16LIB_USE_PORTB_INT\r\n#define PIC16LIB_USE_TIMER0_INT\r\n\r\n#ifdef __cplusplus\r\n}\r\n#endif\r\n\r\n#endif \/* PIC16FLIB_CONF_H *\/\r\n<\/pre>\r\nG\u00f6rm\u00fc\u015f oldu\u011funuz PIC16FLIB_USE* etiketlerinden ikisi commentlenmi\u015f. E\u011fer uygulaman\u0131zda RB0\/PORTB kesmesini kullanacaksan\u0131z bunlar\u0131 da a\u00e7abilirsiniz. Biz bu uygulamam\u0131zda yaln\u0131zca TIMER0 kesmelerini kullanaca\u011f\u0131m\u0131zdan se\u00e7imi o \u015fekilde yapt\u0131k.\r\n\r\nHemen g\u00fcncelledi\u011fimiz k\u00fct\u00fcphane dosyalar\u0131m\u0131z\u0131 g\u00f6relim.\r\n<pre class=\"lang:c decode:true\" title=\"pic16f84a_lib.h\">\/* \r\n * File:   pic16f84a_lib.h\r\n * Author: ozenozkaya\r\n *\r\n * Created on 20 Temmuz 2015 Pazartesi, 00:05\r\n *\/\r\n\r\n#ifndef PIC16F84A_LIB_H\r\n#define    PIC16F84A_LIB_H\r\n\r\n#ifdef __cplusplus\r\nextern \"C\" {\r\n#endif\r\n \r\n#include &lt;stdint.h&gt;\r\n#include \"pic16flib_conf.h\"\r\n    \r\n#define PIC16LIB_ERROR_NONE     (0)\r\n#define PIC16LIB_ERROR_CB_NULL  (-1)\r\n#define PIC16LIB_ERROR_CB_ALREADY_REGISTERED (-2)\r\n\r\n#define F_OSC (1000000UL)\r\n    \r\n#define REG_TIMER0_ADDR (0x01)\r\n#define REG_TIMER0 (*( volatile unsigned char*)REG_TIMER0_ADDR)\r\n    \r\n#define REG_TRISB_ADDR (0x86)\r\n#define REG_TRISB (*( volatile unsigned char*)REG_TRISB_ADDR)\r\n \r\n#define REG_TRISA_ADDR (0x85)\r\n#define REG_TRISA (*( volatile unsigned char*)REG_TRISA_ADDR)\r\n    \r\n#define TRIS_PIN_OUTPUT (0)\r\n#define TRIS_PIN_INPUT  (1)\r\n#define TRIS_PORT_OUTPUT (0)\r\n#define TRIS_PORT_INPUT  (0xFF)\r\n\r\n#define REG_PORTB_ADDR (0x06)\r\n#define REG_PORTB (*( volatile unsigned char*)REG_PORTB_ADDR)\r\n    \r\n#define REG_PORTA_ADDR (0x05)\r\n#define REG_PORTA (*( volatile unsigned char*)REG_PORTA_ADDR)\r\n\r\n#define PORT_PIN_LOW  (0)\r\n#define PORT_PIN_HIGH (1)\r\n#define PORT_ALL_LOW  (0)\r\n#define PORT_ALL_HIGH (0xFF)\r\n\r\n#define REG_INTCON_ADDR (0x0B)\r\n#define REG_INTCON (*( volatile unsigned char*)REG_INTCON_ADDR)\r\n#define INT_ENABLE (1)\r\n#define INT_ENABLE_ALL (0xFF)\r\n#define INT_DISABLE (0)\r\n#define INT_DISABLE_ALL (0)\r\n#define INT_FLAG_CLEAR (0)\r\n\r\n#define REG_OPTION_ADDR (0x81)\r\n#define REG_OPTION (*( volatile unsigned char*)REG_OPTION_ADDR)\r\n#define INT_EDGE_FALLING (0)\r\n#define INT_EDGE_RISING  (1)\r\n    \r\n\r\n\r\ntypedef struct \r\n{\r\n    \/\/one bit is stored in one BYTE\r\n    uint8_t pin0:1;\r\n    uint8_t pin1:1;\r\n    uint8_t pin2:1;\r\n    uint8_t pin3:1;\r\n    uint8_t pin4:1;\r\n    uint8_t pin5:1;\r\n    uint8_t pin6:1;\r\n    uint8_t pin7:1;\r\n}_tris_port_pin_t, *_tris_port_pin_ptr_t;\r\n\r\ntypedef struct\r\n{\r\n    uint8_t RBIF:1;\r\n    uint8_t INTF:1;\r\n    uint8_t T0IF:1;\r\n    uint8_t RBIE:1;\r\n    uint8_t INTE:1;\r\n    uint8_t T0IE:1;\r\n    uint8_t EEIE:1;\r\n    uint8_t GIE:1;\r\n}_intcon_reg_t,*_intcon_reg_ptr_t;\r\n\r\ntypedef struct\r\n{\r\n    uint8_t PS:3;\r\n    uint8_t PSA:1;\r\n    uint8_t T0SE:1;\r\n    uint8_t T0CS:1;\r\n    uint8_t INTEDG:1;\r\n    uint8_t RBPU:1;\r\n}_option_reg_t,*_option_reg_ptr_t;\r\n\r\ntypedef union\r\n{\r\n    _tris_port_pin_t pins;\r\n    uint8_t port;\r\n}tris_port_t,*tris_port_ptr_t;\r\n#define REG_TRISA_UNION (*(tris_port_ptr_t)REG_TRISA_ADDR) \r\n#define REG_TRISB_UNION (*(tris_port_ptr_t)REG_TRISB_ADDR) \r\n#define REG_PORTA_UNION (*(tris_port_ptr_t)REG_PORTA_ADDR) \r\n#define REG_PORTB_UNION (*(tris_port_ptr_t)REG_PORTB_ADDR) \r\n\r\ntypedef union\r\n{\r\n  _option_reg_t bits;\r\n  uint8_t value;  \r\n}option_reg_t, *option_reg_ptr_t;\r\n#define T0CS_SOURCE_RA4_T0CKI_PIN (0x01)\r\n#define T0CS_SOURCE_INTERNAL_CLOCK (0x00)\r\n\r\n#define PSA_ASSIGN_TO_WATCHDOG  (0x01)\r\n#define PSA_ASSIGN_TO_TIMER0    (0x00)\r\n\r\n#define PS_TMR0_RATE_DIVIDE_2   (0x00)\r\n#define PS_TMR0_RATE_DIVIDE_4   (0x01)\r\n#define PS_TMR0_RATE_DIVIDE_8   (0x02)\r\n#define PS_TMR0_RATE_DIVIDE_16   (0x03)\r\n#define PS_TMR0_RATE_DIVIDE_32   (0x04)\r\n#define PS_TMR0_RATE_DIVIDE_64   (0x05)\r\n#define PS_TMR0_RATE_DIVIDE_128   (0x06)\r\n#define PS_TMR0_RATE_DIVIDE_256   (0x07)\r\n\r\n#define REG_OPTION_UNION (*(option_reg_ptr_t)REG_OPTION_ADDR) \r\n\r\ntypedef union\r\n{\r\n  _intcon_reg_t bits;\r\n  uint8_t value;  \r\n}intcon_reg_t, *intcon_reg_ptr_t;\r\n#define REG_INTCON_UNION   (*(intcon_reg_ptr_t)REG_INTCON_ADDR)\r\n\r\ntypedef union\r\n{\r\n    uint8_t value;\r\n    uint8_t count;\r\n}timer0_reg_t, *timer0_reg_ptr_t;\r\n#define TIMER0_MAX_CNT (0xFF)\r\n#define TIMER0_ASSIGN_CNT(NEW_TMR0_CNT)    (TIMER0_MAX_CNT-NEW_TMR0_CNT)\r\n#define REG_TIMER0_UNION   (*(timer0_reg_ptr_t)REG_TIMER0_ADDR)\r\n\r\n#define WAIT_LOOP_FOREVER()  while(1)\r\n\r\n#ifdef PIC16LIB_USE_RB0_INT\r\ntypedef void (*rb0_int_callback_t)();\r\nint8_t register_rb0_int_callback(rb0_int_callback_t new_cb);\r\nint8_t unregister_rb0_int_callback(rb0_int_callback_t cb_to_unreg);\r\n#endif\r\n\r\n#ifdef PIC16LIB_USE_PORTB_INT\r\ntypedef void (*portb_int_callback_t)();\r\nint8_t register_portb_int_callback(portb_int_callback_t new_cb);\r\nint8_t unregister_portb_int_callback(portb_int_callback_t cb_to_unreg);\r\n#endif\r\n\r\n#ifdef PIC16LIB_USE_TIMER0_INT\r\ntypedef void (*timer0_int_callback_t)();\r\nint8_t register_timer0_int_callback(timer0_int_callback_t new_cb);\r\nint8_t unregister_timer0_int_callback(timer0_int_callback_t cb_to_unreg);\r\n#endif\r\n\r\n#ifdef __cplusplus\r\n}\r\n#endif\r\n\r\n#endif \/* PIC16F84A_LIB_H *\/\r\n<\/pre>\r\nTimer0 adres ve k\u00fct\u00fck tan\u0131mlamalar\u0131n\u0131n yap\u0131lm\u0131\u015f oldu\u011funa dikkatinizi \u00e7ekerim :) Ayn\u0131 zamanda, config dosyas\u0131nda kulland\u0131\u011f\u0131m\u0131z etiketler de, kullan\u0131lmayan kesmelerin fonksiyon prototiplerini derleme zaman\u0131nda kapatmak i\u00e7in yerli yerinde. \u00d6yleyse hemen .c dosyam\u0131z\u0131 g\u00f6relim.\r\n<pre class=\"lang:c decode:true\">#include \"pic16f84a_lib.h\"\r\n\r\n#define BIT_TOGGLE(x) (x^=1)\r\n\r\n#ifndef NULL\r\n#define NULL ((void*)0)\r\n#endif\r\n\r\n#ifdef PIC16LIB_USE_RB0_INT\r\nrb0_int_callback_t rb0_int_callback_list[MAX_INT_CALLBACK_NUM];\r\n#endif\r\n\r\n#ifdef PIC16LIB_USE_PORTB_INT\r\nportb_int_callback_t portb_int_callback_list[MAX_INT_CALLBACK_NUM];\r\n#endif\r\n\r\n#ifdef PIC16LIB_USE_TIMER0_INT\r\ntimer0_int_callback_t timer0_int_callback_list[MAX_INT_CALLBACK_NUM];\r\n#endif\r\n\r\n\r\n#if defined(PIC16LIB_USE_RB0_INT) || defined(PIC16LIB_USE_PORTB_INT) || defined(PIC16LIB_USE_TIMER0_INT)\r\nstatic void interrupt global_isr_handler()\r\n{\r\n#ifdef PIC16LIB_USE_RB0_INT\r\n    if(REG_INTCON_UNION.bits.INTF)\r\n    {\r\n        uint8_t cb_index=0;\r\n        for(cb_index=0;cb_index&lt;MAX_INT_CALLBACK_NUM; cb_index++)\r\n        {\r\n            if(NULL != rb0_int_callback_list[cb_index])\r\n            {\r\n                rb0_int_callback_list[cb_index]();\r\n            }\r\n        }\r\n        BIT_TOGGLE(REG_OPTION_UNION.bits.INTEDG);\r\n        REG_INTCON_UNION.bits.INTF=INT_FLAG_CLEAR;\r\n    }\r\n#endif\r\n#ifdef PIC16LIB_USE_PORTB_INT\r\n    if(REG_INTCON_UNION.bits.RBIF)\r\n    {\r\n        uint8_t cb_index=0;\r\n        for(cb_index=0;cb_index&lt;MAX_INT_CALLBACK_NUM; cb_index++)\r\n        {\r\n            if(NULL != portb_int_callback_list[cb_index])\r\n            {\r\n                portb_int_callback_list[cb_index]();\r\n            }\r\n        }\r\n        BIT_TOGGLE(REG_OPTION_UNION.bits.INTEDG);\r\n        REG_INTCON_UNION.bits.RBIF=INT_FLAG_CLEAR;\r\n    }\r\n#endif\r\n#ifdef PIC16LIB_USE_TIMER0_INT\r\n    if(REG_INTCON_UNION.bits.T0IF)\r\n    {\r\n        REG_INTCON_UNION.bits.T0IF=INT_FLAG_CLEAR;\r\n        uint8_t cb_index=0;\r\n        for(cb_index=0;cb_index&lt;MAX_INT_CALLBACK_NUM; cb_index++)\r\n        {\r\n            if(NULL != timer0_int_callback_list[cb_index])\r\n            {\r\n                timer0_int_callback_list[cb_index]();\r\n            }\r\n        }\r\n    }\r\n#endif\r\n}\r\n#endif\r\n\r\n#ifdef PIC16LIB_USE_RB0_INT\r\nint8_t register_rb0_int_callback(rb0_int_callback_t new_cb)\r\n{\r\n    if(NULL != new_cb)\r\n    {\r\n        uint8_t cb_index=0;\r\n        for(cb_index=0;cb_index&lt;MAX_INT_CALLBACK_NUM; cb_index++)\r\n        {\r\n            if(NULL == rb0_int_callback_list[cb_index])\r\n            {\r\n                rb0_int_callback_list[cb_index]=new_cb;\r\n            }\r\n        }\r\n        if(MAX_INT_CALLBACK_NUM == cb_index)\r\n        {\r\n            return PIC16LIB_ERROR_CB_ALREADY_REGISTERED; \/\/All callbacks are already registered\r\n        }\r\n    }\r\n    else\r\n    {\r\n        return PIC16LIB_ERROR_CB_NULL; \/\/ Callback is NULL\r\n    }\r\n    return 0;\r\n}\r\n\r\nint8_t unregister_rb0_int_callback(rb0_int_callback_t cb_to_unreg)\r\n{\r\n    if(NULL != cb_to_unreg)\r\n    {\r\n        uint8_t cb_index=0;\r\n        for(cb_index=0;cb_index&lt;MAX_INT_CALLBACK_NUM; cb_index++)\r\n        {\r\n            if(cb_to_unreg == rb0_int_callback_list[cb_index])\r\n            {\r\n                rb0_int_callback_list[cb_index]=NULL;\r\n            }\r\n        }\r\n    }\r\n    else\r\n    {\r\n        return PIC16LIB_ERROR_CB_NULL; \/\/ Callback is NULL\r\n    }\r\n    return PIC16LIB_ERROR_NONE;\r\n}\r\n#endif\r\n#ifdef PIC16LIB_USE_PORTB_INT\r\nint8_t register_portb_int_callback(portb_int_callback_t new_cb)\r\n{\r\n    if(NULL != new_cb)\r\n    {\r\n        uint8_t cb_index=0;\r\n        for(cb_index=0;cb_index&lt;MAX_INT_CALLBACK_NUM; cb_index++)\r\n        {\r\n            if(NULL == portb_int_callback_list[cb_index])\r\n            {\r\n                portb_int_callback_list[cb_index]=new_cb;\r\n            }\r\n        }\r\n        if(MAX_INT_CALLBACK_NUM == cb_index)\r\n        {\r\n            return PIC16LIB_ERROR_CB_ALREADY_REGISTERED; \/\/All callbacks are already registered\r\n        }\r\n    }\r\n    else\r\n    {\r\n        return PIC16LIB_ERROR_CB_NULL; \/\/ Callback is NULL\r\n    }\r\n    return PIC16LIB_ERROR_NONE;\r\n}\r\n \r\n \r\n \r\nint8_t unregister_portb_int_callback(portb_int_callback_t cb_to_unreg)\r\n{\r\n    if(NULL != cb_to_unreg)\r\n    {\r\n        uint8_t cb_index=0;\r\n        for(cb_index=0;cb_index&lt;MAX_INT_CALLBACK_NUM; cb_index++)\r\n        {\r\n            if(cb_to_unreg == portb_int_callback_list[cb_index])\r\n            {\r\n                portb_int_callback_list[cb_index]=NULL;\r\n            }\r\n        }\r\n    }\r\n    else\r\n    {\r\n        return PIC16LIB_ERROR_CB_NULL; \/\/ Callback is NULL\r\n    }\r\n    return PIC16LIB_ERROR_NONE;\r\n}\r\n#endif\r\n#ifdef PIC16LIB_USE_TIMER0_INT\r\nint8_t register_timer0_int_callback(timer0_int_callback_t new_cb)\r\n{\r\n    if(NULL != new_cb)\r\n    {\r\n        uint8_t cb_index=0;\r\n        for(cb_index=0;cb_index&lt;MAX_INT_CALLBACK_NUM; cb_index++)\r\n        {\r\n            if(NULL == timer0_int_callback_list[cb_index])\r\n            {\r\n                timer0_int_callback_list[cb_index]=new_cb;\r\n            }\r\n        }\r\n        if(MAX_INT_CALLBACK_NUM == cb_index)\r\n        {\r\n            return PIC16LIB_ERROR_CB_ALREADY_REGISTERED; \/\/All callbacks are already registered\r\n        }\r\n    }\r\n    else\r\n    {\r\n        return PIC16LIB_ERROR_CB_NULL; \/\/ Callback is NULL\r\n    }\r\n    return PIC16LIB_ERROR_NONE;\r\n}\r\n \r\n \r\n \r\nint8_t unregister_timer0_int_callback(timer0_int_callback_t cb_to_unreg)\r\n{\r\n    if(NULL != cb_to_unreg)\r\n    {\r\n        uint8_t cb_index=0;\r\n        for(cb_index=0;cb_index&lt;MAX_INT_CALLBACK_NUM; cb_index++)\r\n        {\r\n            if(cb_to_unreg == timer0_int_callback_list[cb_index])\r\n            {\r\n                timer0_int_callback_list[cb_index]=NULL;\r\n            }\r\n        }\r\n    }\r\n    else\r\n    {\r\n        return PIC16LIB_ERROR_CB_NULL; \/\/ Callback is NULL\r\n    }\r\n    return PIC16LIB_ERROR_NONE;\r\n}\r\n#endif<\/pre>\r\nG\u00f6r\u00fcld\u00fc\u011f\u00fc \u00fczere, al\u0131\u015f\u0131lageldik \u015fekilde timer0 kesme rutinlerini de ekledik. Ek olarak yine config etiketlerimiz de fonksiyonlar\u0131 \u00e7evrelemi\u015f durumda :) Art\u0131k k\u00fct\u00fcphanemizi kullanan kimselere \u00e7ok daha geni\u015f optimizasyon imkan\u0131 sunuyoruz! Her durumda yine Microchip liblerinden \u00e7ok daha y\u00fcksek performansl\u0131 bir konumda k\u00fct\u00fcphanemiz :) 0 byte kullanarak t\u00fcm register eri\u015fimlerini yapmak m\u00fcmk\u00fcn.\u00a0Konfor arayan yaz\u0131l\u0131mc\u0131lar i\u00e7in de, k\u00fct\u00fck eri\u015fimlerini \u00e7ok kolayla\u015ft\u0131ran veri yap\u0131lar\u0131n\u0131 implement ettik. \u0130steyen istedi\u011fi y\u00f6nde optimizasyon yapabiliyor. Bu da k\u00fct\u00fcphanemizin esnekli\u011fini ciddi oranda art\u0131rm\u0131\u015f durumda. \u015eimdi uygulama koduna ge\u00e7elim.\r\n<pre class=\"lang:c decode:true\" title=\"main.c\">\/* \r\n * File:   main.c\r\n * Author: ozenozkaya\r\n *\r\n * Created on 24 September 2015 \r\n *\/\r\n\r\n#include \"pic16f84a_lib.h\"\r\n\r\n\/*FOSC is 4Mhz. Prescaler input it 1Mhz.\r\n Because prescaler is 8, prescaler output f=125kHz.\r\n So,the prescaler output period is 8uS.\r\n Hence, we need 125 timer pulses to reach 1mS.\r\n 8uS*125 = 1mS*\/\r\n#define TIMER0_VAL_FOR_1MS  (125)\r\n\r\nstatic void milisecond_event_callback()\r\n{\r\n    REG_PORTB_UNION.port^=0xFF;\r\n    REG_TIMER0_UNION.count = TIMER0_ASSIGN_CNT(TIMER0_VAL_FOR_1MS);\r\n}\r\n\r\nvoid main() {\r\n    REG_TRISB_UNION.port = TRIS_PORT_OUTPUT;\r\n    REG_PORTB_UNION.port = PORT_ALL_LOW;\r\n\r\n    REG_OPTION_UNION.bits.T0CS = T0CS_SOURCE_INTERNAL_CLOCK;\r\n    REG_OPTION_UNION.bits.PSA = PSA_ASSIGN_TO_TIMER0;\r\n    REG_OPTION_UNION.bits.PS = PS_TMR0_RATE_DIVIDE_8; \/\/8uS\r\n    \r\n    \/*! 125*8uS = 1000uS = 1mS*\/\r\n    REG_TIMER0_UNION.count = TIMER0_ASSIGN_CNT(TIMER0_VAL_FOR_1MS); \r\n    REG_INTCON_UNION.value = INT_DISABLE_ALL;\r\n    REG_INTCON_UNION.bits.GIE = INT_ENABLE;\r\n    REG_INTCON_UNION.bits.T0IE = INT_ENABLE;\r\n    \r\n    register_timer0_int_callback(milisecond_event_callback);\r\n    WAIT_LOOP_FOREVER();\r\n}\r\n<\/pre>\r\nBu yaz\u0131l\u0131mda, B portlar\u0131n\u0131 1 milisaniyede bir eviren bir yaz\u0131l\u0131m olu\u015fturduk. Peki ama bunu nas\u0131l yapt\u0131k? Hemen hesap kitaba de\u011finelim. PIC mikrokontrol\u00f6r\u00fcm\u00fcze d\u0131\u015far\u0131dan bir kristal osilat\u00f6r ba\u011fl\u0131 ve frekans\u0131 4MHz.\r\n\r\n[su_box title=\"Aman\u00a0Diyelim\" style=\"soft\" box_color=\"#a7e0a6\"] Proteus sim\u00fclasyonu yapmadan \u00f6nce, PIC mikrokontrol\u00f6re \u00e7ift t\u0131klay\u0131p FOSC de\u011ferini 4Mhz yaparsak, buradaki hesaplarla uyumlu \u00e7\u0131kt\u0131lar alabiliriz. Aksi durumda varsay\u0131lan de\u011fer olan 1Mhz ge\u00e7erli olacakt\u0131r ve bu durumda istenen \u00e7\u0131kt\u0131lar elde edilemeyecektir. [\/su_box]\r\n\r\nPIC16F84A'da timer mod\u00fcl\u00fcne gelen saat i\u015fareti 4'e b\u00f6l\u00fcnerek gelir (datasheet'te yazmakta). Dolay\u0131s\u0131yla mod\u00fcl\u00fcn giri\u015fi 1MHz yani saniyede 1 milyon saat darbesi geliyor. Timer mod\u00fcl\u00fcn\u00fcn giri\u015f k\u0131sm\u0131nda bir frekans \u00f6l\u00e7eklendirici\u00a0(prescaler) bulunmakta.\u00a0Biz \u00f6l\u00e7eklendirme oran\u0131n\u0131 8'e b\u00f6lecek \u015fekilde se\u00e7tik. Bunu, a\u015fa\u011f\u0131daki sat\u0131r ile yapt\u0131k.\r\n<pre class=\"lang:c decode:true\">REG_OPTION_UNION.bits.PS = PS_TMR0_RATE_DIVIDE_8; \/\/8uS<\/pre>\r\nBuna g\u00f6re, 1MHz'lik\u00a0i\u015faret frekans\u0131n\u0131 8'e b\u00f6ld\u00fck ve prescaler \u00e7\u0131k\u0131\u015f\u0131ndaki frekans 125Khz oldu. Bu da 8 micro saniyede bir saat darbesi demek. E\u011fer bu saat darbelerinden 125 tane say\u0131l\u0131nca kesme olacak \u015fekilde bir konfigurasyon yaparsak, 8*125 us = 1ms'lik bir kesme rutini elde etmi\u015f olaca\u011f\u0131z. \u00a0Bu sebeple a\u015fa\u011f\u0131daki tan\u0131mla 125 de\u011feri tan\u0131mland\u0131.\r\n<pre class=\"lang:c decode:true\">\/*FOSC is 4Mhz. Prescaler input it 1Mhz.\r\n Because prescaler is 8, prescaler output f=125kHz.\r\n So,the prescaler output period is 8uS.\r\n Hence, we need 125 timer pulses to reach 1mS.\r\n 8uS*125 = 1mS*\/\r\n#define TIMER0_VAL_FOR_1MS  (125)<\/pre>\r\nBu de\u011fer ise timer0 k\u00fct\u00fc\u011f\u00fcne a\u015fa\u011f\u0131daki \u015fekilde atand\u0131.\r\n<pre class=\"lang:default decode:true\">\/*! 125*8uS = 1000uS = 1mS*\/\r\n    REG_TIMER0_UNION.count = TIMER0_ASSIGN_CNT(TIMER0_VAL_FOR_1MS);<\/pre>\r\nBurada ibretlik bir macromuz var. Bu macro TIMER0_ASSIGN_CNT. Peki neden buna ihtiya\u00e7 duyduk? Malumunuz bizim timer0 mod\u00fcl\u00fc yukar\u0131 do\u011fru say\u0131yor ve 255(0xFF)'de ta\u015f\u0131yor. Ta\u015fmadan \u00f6nce 125 tur\u00a0sayabilmesi i\u00e7in asl\u0131nda 255-125 =130 de\u011ferinden ba\u015flamal\u0131 Timer0. Bu durumda timer 130'dan ba\u015flat\u0131lacak ve tam 125 tur sonra (1ms yap\u0131yor) kesme gelmi\u015f olacak. \u0130\u015fte bu \u00e7\u0131karma hesab\u0131n\u0131 yapan macromuz\u00a0TIMER0_ASSIGN_CNT. K\u00fct\u00fcphanemizdeki tan\u0131m\u0131 da a\u015fa\u011f\u0131daki gibi idi.\r\n<pre class=\"lang:c decode:true \">#define TIMER0_MAX_CNT (0xFF)\r\n#define TIMER0_ASSIGN_CNT(NEW_TMR0_CNT)    (TIMER0_MAX_CNT-NEW_TMR0_CNT)<\/pre>\r\nBu sayede 1ms'lik zamanlama sa\u011flam\u0131\u015f oluyor. Ancak s\u00fcrekli olarak 1ms'lik zamanlamay\u0131 sa\u011flamak i\u00e7in TIMER0 ta\u015ft\u0131\u011f\u0131nda, yani kesme olu\u015ftu\u011funda Timer0'\u0131 tekrar 130 de\u011ferinden ba\u015flatmak gerekiyor. Bunun i\u00e7in, milisaniye callback fonskiyonumuzda a\u015fa\u011f\u0131daki gibi bir tekar y\u00fckleme yapt\u0131k.\r\n<pre class=\"lang:c decode:true \">static void milisecond_event_callback()\r\n{\r\n    REG_PORTB_UNION.port^=0xFF;\r\n    REG_TIMER0_UNION.count = TIMER0_ASSIGN_CNT(TIMER0_VAL_FOR_1MS);\r\n}\r\n<\/pre>\r\nBu sayede her \u015fey \u00e7al\u0131\u015f\u0131r durumda ve enerji efektif \u015fekilde periyodik i\u015flerimizi yapabilir hale geldik :) Hemen proteus isis \u00fczerindeki sim\u00fclasyon \u00e7\u0131kt\u0131m\u0131z\u0131 da ekleyelim.\r\n\r\n<a href=\"http:\/\/ozenozkaya.com\/blog\/wp-content\/uploads\/pic_timer0_0.png\"><img class=\"alignnone size-full wp-image-475\" src=\"http:\/\/ozenozkaya.com\/blog\/wp-content\/uploads\/pic_timer0_0.png\" alt=\"pic_timer0_0\" width=\"798\" height=\"426\" \/><\/a>\r\n\r\n&nbsp;\r\n\r\nOsiloskoptaki zaman \u00f6l\u00e7\u00fcm\u00fcn\u00fcn 1.06 mS olu\u015funa dikkat ediniz. 1ms g\u00fczel de, bu 0.06 mS nereden geldi? Buradan da \u00e7ok g\u00fczel ibretlere de\u011finece\u011fiz dostlar, ancak bu sorunun yan\u0131t\u0131 ve dahas\u0131n\u0131 bir sonraki yaz\u0131ya b\u0131rak\u0131yoruz :)\r\n\r\nZamanlay\u0131c\u0131lar konusunda ne kadar \u00e7ok tekrar yaparsan\u0131z, farkl\u0131 uygulamalar yazarsan\u0131z o kadar iyi olur. \u00d6rne\u011fin kara\u015fim\u015fek uygulamas\u0131n\u0131 zamanlay\u0131c\u0131 kullanarak yazmakta faydalar var.\r\n\r\n\u015eimdi devam!\r\n\r\nYaz\u0131lar\u0131 be\u011fendiyseniz, faydalanabilecek tan\u0131d\u0131klar\u0131n\u0131zla payla\u015fmay\u0131 unutmay\u0131n\u0131z.\r\n\r\n[su_button url=\"http:\/\/ozenozkaya.com\/blog\/?p=457\" style=\"3d\"\u00a0icon=\"icon: arrow-circle-o-left\"]\u00d6nceki Sayfa[\/su_button] \u00a0[su_button url=\"http:\/\/ozenozkaya.com\/blog\/?p=523\" style=\"3d\" icon=\"icon: arrow-circle-right\"]Sonraki Sayfa[\/su_button]","_tr_post_name":"pic-programlama-8-zamanlayicilar-timers","_tr_post_excerpt":"","_tr_post_title":"PIC Programlama \u2013 8 \u2013 Zamanlay\u0131c\u0131lar (Timers)","_en_post_content":"","_en_post_name":"","_en_post_excerpt":"","_en_post_title":"","edit_language":"tr","jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"enabled":false},"version":2}},"categories":[2,3],"tags":[],"class_list":["post-470","post","type-post","status-publish","format-standard","hentry","category-elektronik","category-gomulu-sistemler"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/p5gWM6-7A","jetpack-related-posts":[],"_links":{"self":[{"href":"http:\/\/ozenozkaya.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/470","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/ozenozkaya.com\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/ozenozkaya.com\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/ozenozkaya.com\/blog\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/ozenozkaya.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=470"}],"version-history":[{"count":3,"href":"http:\/\/ozenozkaya.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/470\/revisions"}],"predecessor-version":[{"id":528,"href":"http:\/\/ozenozkaya.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/470\/revisions\/528"}],"wp:attachment":[{"href":"http:\/\/ozenozkaya.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=470"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/ozenozkaya.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=470"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/ozenozkaya.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=470"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}