Sistem Programlama 9. Hafta Doküman 2

Zamanlanmış İşlem Yapma

Aşağıdaki iki işlem aynı anda yapılmak istenilmektedir.
• Seven segmente sayma işlemi yap (saniyede bir arttır)
• Ledi yakıp söndür (2.5 saniye yak, 2.5 saniye söndür)
Bu zaman ölçümüne göre yukarıdaki işlemlerin yapılması sağlanmaktadır.
İki işlem de zamanla tetiklenen bayrak değişken kullanılarak main fonksiyonu içerisinde yapılmaktadır.
         if (flag_ledi_ters_cevir) { // flag_ledi_ters_cevir != 0 ise islem yap
         flag_ledi_ters_cevir = 0; // islemi tekrar yapmamak icin sifirla
         GPIO_PORTF_DATA_R ^= 0b00100;
     }

    if (flag_sayi_arttir) {
        // 7-segmentte sayi gosterme islemi ...
    }
Bu bayrak değişken systick_handler fonksiyonu içerisinde değiştirilmektedir:
 #define SYSTICK_HZ 100

void systick_handler() {
    systick_count++; // kac tane systick kesmesi oldugunu say

    // 1 saniyede bir sayiyi arttirma flagini 1 yap
    // saydigimiz systick sayisi 100'e tam bolunuyorsa 1 saniye gecmistir
    if ((systick_count % (SYSTICK_HZ * 1)) == 0)
     flag_sayi_arttir = 1;

    // 5/2=2.5 saniyede bir ledi ters cevirme isleminin flagini 1 yap
    if (systick_count % (SYSTICK_HZ * 5/2) == 0)
     flag_ledi_ters_cevir = 1;
}
Yukarıdaki kodda zaman systick kesmesi sayılarak hesaplanmaktadır. Her 100 kesme olduğunda 1 saniye geçtiği anlaşılıp bayrak değişken 1 yapılmaktadır.
startup_gcc.c :
1) include kisimlarindan sonra asagidaki fonksiyon prototiplerini ekleyin
extern void systick_handler();
2) // The vector table yazan kisimdaki dizide aşağıdaki iki satırda:
IntDefaultHandler, // The SysTick handler
IntDefaultHandler yerine ilgili fonksiyonları yazin
systick_handler, // The SysTick handler
main.c :
#include <stdint.h>
#include <stdbool.h>

#include "inc/tm4c123gh6pm.h"
// stellaris icin: #include "inc/lm4f120h5qr.h"

#include "inc/hw_types.h"
#include "driverlib/sysctl.h" // SysCtl ile baslayan fonksiyonlarda gerekli

// 1 saniyedeki systick kesmesi sayisi, 1'den buyuk herhangi bir deger verebiliriz
// not: Bu sabit standart kutuphane ilgili degildir. Ismini ve degerini biz belirledik.
#define SYSTICK_HZ 100


static inline void disable_interrupts() {
    asm("CPSID I");
}

static inline void enable_interrupts() {
    asm("CPSIE I");
}

static inline void wait_for_interrupt() {
    asm("WFI");
}

void init_port_F() {
    volatile unsigned long tmp; // bu degisken gecikme yapmak icin gerekli
    SYSCTL_RCGCGPIO_R |= 0x00000020;  // 1) activate clock for Port F
    tmp = SYSCTL_RCGCGPIO_R;        // allow time for clock to start
    GPIO_PORTF_LOCK_R = 0x4C4F434B;   // 2) unlock GPIO Port F
    GPIO_PORTF_CR_R = 0x1F;         // allow changes to PF4-0
    // only PF0 needs to be unlocked, other bits can't be locked
    GPIO_PORTF_AMSEL_R = 0x00;      // 3) disable analog on PF
    GPIO_PORTF_PCTL_R = 0x00000000;   // 4) PCTL GPIO on PF4-0
    GPIO_PORTF_DIR_R = 0x0E;        // 5) PF4,PF0 in, PF3-1 out
    GPIO_PORTF_AFSEL_R = 0x00;      // 6) disable alt funct on PF7-0
    GPIO_PORTF_PUR_R = 0x11;        // enable pull-up on PF0 and PF4
    GPIO_PORTF_DEN_R = 0x1F;        // 7) enable digital I/O on PF4-0
}

void init_port_B() {
    volatile unsigned long delay;
    SYSCTL_RCGC2_R |= SYSCTL_RCGC2_GPIOB;
    delay = SYSCTL_RCGC2_R;
    GPIO_PORTB_DIR_R |= 0xFF;
    GPIO_PORTB_AFSEL_R &= ~0xFF;
    GPIO_PORTB_DEN_R |= 0xFF;
}

// 0'dan 9'a kadar olan sayilarin seven segment kodlari. bit sirasi: g f e d c b a
const uint8_t kodlar[] = {
    0b00111111,
    0b00000110,
    0b01011011,
    0b01001111,
    0b01100110,
    0b01101101,
    0b01111101,
    0b00000111,
    0b01111111,
    0b01101111
};

void SysTick_Init(unsigned long period) {
    NVIC_ST_CTRL_R = 0;         // disable SysTick during setup
    NVIC_ST_RELOAD_R = period - 1;      // reload value
    NVIC_ST_CURRENT_R = 0;      // any write to current clears it
    NVIC_SYS_PRI3_R = (NVIC_SYS_PRI3_R & 0x00FFFFFF) | 0x40000000; // priority 2
    NVIC_ST_CTRL_R = 0x07; // enable SysTick with core clock and interrupts
    // enable interrupts after all initialization is finished
}

// baslangictan itibaren olusan systick kesmesi sayisi
uint32_t systick_count = 0;
// 7-segmentte gosterilen sayi
volatile int sayi = 0;

volatile int flag_sayi_arttir = 0;
volatile int flag_ledi_ters_cevir = 0;

void systick_handler() {
    systick_count++; // kac tane systick kesmesi oldugunu say

    // 1 saniyede bir sayiyi arttirma flagini 1 yap
    // saydigimiz systick sayisi 100'e tam bolunuyorsa 1 saniye gecmistir
    if ((systick_count % (SYSTICK_HZ * 1)) == 0)
     flag_sayi_arttir = 1;

    // 5/2=2.5 saniyede bir ledi ters cevirme isleminin flagini 1 yap
    if (systick_count % (SYSTICK_HZ * 5/2) == 0)
     flag_ledi_ters_cevir = 1;
}

int main() {
    init_port_B();
    init_port_F();

    // 1 saniyede SYSTICK_HZ tane kesme uretecek sekilde ayarlar
    // not: kodun ust kisminda SYSTICK_HZ ifadesini define ile 100 olarak belirledik
    SysTick_Init(SysCtlClockGet() / SYSTICK_HZ);

    enable_interrupts();

    while (1) {
     if (flag_sayi_arttir) {
         flag_sayi_arttir = 0;
         sayi = (sayi + 1) % 10;
         GPIO_PORTB_DATA_R = kodlar[sayi];
     }

     if (flag_ledi_ters_cevir) {
         flag_ledi_ters_cevir = 0;
         GPIO_PORTF_DATA_R ^= 0b00100;
     }

     wait_for_interrupt(); // sonraki kesmeye kadar islemciyi uyku moduna alir
    }
}