XC8 Dersleri 1 – I/O

47528Bu yazıda XC8 ile registerların nasıl kullanıldığını ve PIC de I/O (Input/Output) işlemlerinin nasıl yapıldığını anlatmaya çalışacağım. Oldukça basit olan Microchip mimarisi sayesinde bu işlmeleri yapmanın kolay olması yanı sıra yazılımları taşınabilirliği ve başla MCU’lara uyarlanabilmesi oldukça güzel. Sürekli gelişen bir alanda çalıştığımız için yazılan kodların taşınabilir, düzenlenebilir, anlaşılabilir olması bir MCU programcısı için çok önemlidir.

Önceki yazıda sizden istediğim programları kurduysanız bir proje oluşturarak başlayalım.








Son adımdaki işlemin aynısını “Header Files” içinde yapın. Yani elimizde bir kaynak ve bir başlık dosyası olsun. Daha öncede söylediğim gibi PIC16F1827 ile çalışacağız bu yüzden ilgili datasheet’i mutlaka kaydedin ara ara bakacağız. Datasheet

Projeleri Proteus programında simüle edeceğiz fakat isterseniz canlı olarak da deneyebilirsiniz.


Pin özelliklerinin bulunduğu resimde görüldüğü gibi tek besleme yapılıyor. VDD(+) VSS(-)

Tabi Reset pini olan MCLR yi 10K direnç ile VDD ye bağlamayı unutmuyoruz. Bu uygulamada A0 pinin yakıp söndüreceğimiz bir uygulama yapalım.

Öncelikle PIC’in hız ve sigorta ayarlarını yapmalıyız.

Sigorta ayarlarını yapmak için MPLABX çok güzel bir tool yapmış.Window>PIC Memory Views>Configuration Bits e tıklıyoruz. Burada sigorta ayarlarını sonra “Genarate Source Code to Output” butonuna basıyoruz ve bize bu ayarların kodunu veriyor. Unutmadan bu PIC in kendi içindeki 8MHz osilatörü kullanacağız ve PLL yi aktif ederek(4x) 32MHz elde edeceğiz.

Yapmanız gereken adımları şöyle sıraladım.


Butona bastıkdan sonra bize bir kod çıktısı veriyor onu header dosyamıza ekliyoruz.Main header dosyası son hali şu şekilde oluyor;

/* 
 * File:   main.h
 * Author: EKREM
 *
 * Created on 13 Eylül 2015 Pazar, 19:01
 */
#ifndef MAIN_H
#define	MAIN_H
 
#ifdef	__cplusplus
extern "C" {
#endif
 
// PIC16F1827 Configuration Bit Settings
// 'C' source line config statements
#include <xc.h>
 
// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.
 
// CONFIG1
#pragma config FOSC = INTOSC    // Oscillator Selection (INTOSC oscillator: I/O function on CLKIN pin)
#pragma config WDTE = OFF       // Watchdog Timer Enable (WDT disabled)
#pragma config PWRTE = OFF      // Power-up Timer Enable (PWRT disabled)
#pragma config MCLRE = ON       // MCLR Pin Function Select (MCLR/VPP pin function is MCLR)
#pragma config CP = OFF         // Flash Program Memory Code Protection (Program memory code protection is disabled)
#pragma config CPD = OFF        // Data Memory Code Protection (Data memory code protection is disabled)
#pragma config BOREN = OFF      // Brown-out Reset Enable (Brown-out Reset disabled)
#pragma config CLKOUTEN = OFF   // Clock Out Enable (CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin)
#pragma config IESO = OFF       // Internal/External Switchover (Internal/External Switchover mode is disabled)
#pragma config FCMEN = OFF      // Fail-Safe Clock Monitor Enable (Fail-Safe Clock Monitor is disabled)
 
// CONFIG2
#pragma config WRT = OFF        // Flash Memory Self-Write Protection (Write protection off)
#pragma config PLLEN = ON       // PLL Enable (4x PLL enabled)
#pragma config STVREN = OFF     // Stack Overflow/Underflow Reset Enable (Stack Overflow or Underflow will not cause a Reset)
#pragma config BORV = LO        // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (Vbor), low trip point selected.)
#pragma config LVP = OFF        // Low-Voltage Programming Enable (High-voltage on MCLR/VPP must be used for programming)
 
#define _XTAL_FREQ 32000000L
#ifdef	__cplusplus
}
#endif
 
#endif	/* MAIN_H */

NOT : Bu çıktı bize _XTAL_FREQ değerini vermiyor bu yüzden biz kullanacağımız MHz bu şekilde mutlaka tanımlamalıyız.Bu tanımlamayı ayarların sonuna ekleyebilirsiniz.

Ayarları yaptık dan sonra main.c dosyasını açıp artık örneğe başlayalım.Tabi ilk yapmamız gereken standart main fonksiyonumuz oluşturmak.Sonsuz döngü kullanacağımız için return değerine gerek yok void yapabiliriz.

#include "main.h"
 
void main(void) {
    for(;;) { // Sonsuz döngü = while(1)
 
    }
}

Hız için ne demiştik ? Dahili 8MHz VE PLL ile 32MHz elde edeceğiz.Bu ayarlar OSCCON adlı register dan yapılıyor.Şimdi datasheet sayfa 65 den bu işlemleri nasıl yapacağımıza bakalım.OSCCON registerinin 7 biti SPLLEN yani PLL.Aktif etmek için bu biti 1 yapmamız gerekiyor.XC Compilerda registerlara şu şekilde erişit değer verebilirsiniz.

OSCCONbits.SPLLEN  = 0b1;//Binary olarak 1 verdik 0 vermek için 0b0 olur.

PLL den sonra 4 bitlik olan IRCf bitlerine bakıyoruz.Şöyle bir açıklama mevcut: “1110 = 8 MHz or 32 MHz”

OSCCONbits.IRCF     = 0b1110;

Bu kısmı da hallettiğimize göre 2 bitlik alana sahip olan SCS bitlerini de açıklamadaki ayara göre 0b10 değerini yükleyebiliriz.

OSCCONbits.SCS      = 0b10;

Clock ayarlarını yaptığımıza göre MCU çalışmaya hazır basit bir IO işlemi ile led yakıp söndürelim. Bildiğimiz üzere bir pinde oldukça fazla özellik mevcut bunlardan kullanmadıklarımızı kapatmamız gerekiyor.Bu pinlerde Analog özellikleri kapatıp pinleri dijital olarak ayalamamızı sağlayan ANSELx Register’ı bulunuyor.PIC16F1827 de 2 port bulunuyor bunlar A ve B bu portların hepsini dijital olarak ayarlayalım.

ANSELA = 0x00; // A portu komple dijital
ANSELB = 0x00; // B portu komple dijital

Pinler dijital oldu.Şimdi bu pinleri Giriş mi (Input-1) Çıkış mı(Output-0) olacağını belirleyelim.Basit bir LED uygulaması için Çıkış yapmalıyız.Giriş-Çıkış işlemleri TRISx Register’ı ile yapılıyor.Biz 2 portu da çıkış olarak tanımlayalım.

TRISA = 0x00; //A portu komple çıkış
TRISB = 0x00; //B portu komple çıkış

Son olarak portlara bir başlangıç değeri atayalım.Bunun sebebi pinler standart olarak kapalı olmaya bilir yani MCU içindeki ortam şartlarından dolayı rastgele değer alabilir.Portlara değer vermek için PORTx Register’ının kullanıyoruz.Başlangıçta hepsini sıfırlayalım.

PORTA = 0x00; //A portu komple lojik 0 (GND, 0, OFF)
PORTB = 0x00; //B portu komple lojik 0 (GND, 0, OFF)

Portlarıda ayarladığımıza göre LED işlemine gelebiliriz(Sonunda geldik 🙂 ) LED adından bir makro tanımlayalım ve A portunun 0.bitini LED makrosuna atayalım.

#define LED (PORTAbits.RA0)

Bu LED değişkenimizi sonsuz döngü içinde terleyelim.Sürekli kendi durumunun tersini alsın.Bunun için “tilda” sembolünü kullandım.Sinüs dalgasına benziyor.(~)

for(;;) { // Sonsuz döngü = while(1)
   LED = ~LED;
}

LED’i sürekli tersliyoruz ama biraz bekleme yapmamız gerekmiyor mu ? Başka bir konu olan Delay fonksiyonunu oluşturmalıyız.LED her durumunu değiştirdiğinde 500 milisaniye bekleme yapalım.Bunun için __delay_ms(x) fonksiyonunu kullanabiliriz ama x değer fazla oldukça Compiler hata verebilir bu iş için basit bir fonksiyon oluşturdum.

void Delay_ms(unsigned int miliSecond) {
    while(--miliSecond)
        __delay_ms(1);
}

Artık sonsuz döngüyü şu şekilde düzenleyebiliriz.

for(;;) { // Sonsuz döngü = while(1)
        LED = ~LED;
        Delay_ms(500);
}

Kodun son halini şurada paylaşayım.Ben Clock ve GPIO kısmını fonksiyon olarak yaptım.Düzenli durması açısından böyle kullanmak da fayda var.

#include "main.h"
 
#define LED (PORTAbits.RA0)
 
void Clock_Init(void);
void GPIO_Init(void);
void Delay_ms(unsigned int miliSecond);
 
void main(void) {
 
    Clock_Init();
    GPIO_Init();
 
    for(;;) { // Sonsuz döngü = while(1)
        LED = ~LED;
        Delay_ms(500);
    }
}
 
void Clock_Init(void) {
 
    OSCCONbits.SPLLEN   = 0b1;
    OSCCONbits.IRCF     = 0b1110;
    OSCCONbits.SCS      = 0b10;
}
 
void GPIO_Init(void) {
 
    ANSELA = 0x00; // A portu komple dijital
    ANSELB = 0x00; // B portu komple dijital
 
    TRISA = 0x00; //A portu komple çıkış
    TRISB = 0x00; //B portu komple çıkış
 
    PORTA = 0x00; //A portu komple lojik 0 (GND, 0, OFF)
    PORTB = 0x00; //B portu komple lojik 0 (GND, 0, OFF)
}
 
void Delay_ms(unsigned int miliSecond) {
    while(--miliSecond) //milisecond 0 olana kadar azaltır.
        __delay_ms(1);//milisecond kadar 1 ms bekleriz
}

Yarım saniye aralıklar ile yana LED için devreyi şu şekilde yapabilirsiniz.


Sanırım şimdilik bu kadar. Bir sonra ki yazıda buton kullanımı yapabiliriz. Yazıda herhangi bir hata görürseniz mutlaka bildirin.

Esen Kalın !

 

You may also like...

Bir yanıt yazın