Загрузка данных


//-----------------------------------------------------------------------------
// Includes
//-----------------------------------------------------------------------------
#include <SI_C8051F960_Register_Enums.h>

#define LED_DISPLAY_PORT  P3
#define DATABUS_PORT      P6

// Bool types in SFR memory space
sbit  D_FLIP_FLOP_CLK = P3^6;     // U4 clk input

// Global variables definitions
unsigned char DisplayPortValue = 0xFE; 
unsigned char current_digit = 0;       

// Tablica buforowa dla 5 pozycji wyświetlacza (na razie korzystamy tylko z 1 pozycji)
unsigned char led_display[5] = {0x00, 0x00, 0x00, 0x00, 0x00};

// Zmienne do obsługi klawiatury matrycowej (zgodnie z algorytmem z PDF)
unsigned char keyboard_counter = 0; // Wskazuje aktualnie skanowany wiersz (0 - 3)
unsigned char temp_val = 0xFF;      // Przechowuje odczyt z portu P4

// Tablica kodów 7-segmentowych odpowiadających układowi klawiatury na płycie EXTB-060/2
// Wiersz 0: 7, 8, 9, F
// Wiersz 1: 4, 5, 6, E
// Wiersz 2: 1, 2, 3, D
// Wiersz 3: 0, A, B, C
unsigned char code key_codes[4][4] = {
    {0x07, 0x7F, 0x6F, 0x71}, // Rząd 0 (P4.4 = 0)
    {0x66, 0x6D, 0x7D, 0x79}, // Rząd 1 (P4.5 = 0)
    {0x06, 0x5B, 0x4F, 0x5E}, // Rząd 2 (P4.6 = 0)
    {0x3F, 0x77, 0x7C, 0x39}  // Rząd 3 (P4.7 = 0)
};

//-----------------------------------------------------------------------------
// Initialization Routines
//-----------------------------------------------------------------------------
void SiLabs_Startup (void)
{
    SFRPAGE = LEGACY_PAGE;      
    PCA0MD &= ~0x40;            
    PCA0MD  = 0x00;             
    return;
}

void PORT_Init (void)
{
    SFRPAGE   = CONFIG_PAGE;    
    XBR2      = 0x40;           // Enable crossbar and weak pull-ups (ważne dla wejść P4.0-P4.3)
    // Port P4 nie wymaga specjalnej inicjalizacji w XBR, działa domyślnie
    return;
}

// Inicjalizacja Timer3 - Multipleksowanie LED (Zostaje jak w Lab 2)
void Timer3_Init(void)
{
    SFRPAGE   = LEGACY_PAGE;    
    TMR3CN    = 0x04;
    TMR3RLL   = 0x00;
    TMR3RLH   = 0xA0;
    EIE1     |= 0x80;           
    SFRPAGE   = CONFIG_PAGE;
    return;
}

// Inicjalizacja Timer0 - Skanowanie klawiatury (Zgodnie z instrukcją)
void Timer0_Init(void)
{
    SFRPAGE   = LEGACY_PAGE;
    TMOD     &= 0xF0;
    TMOD     |= 0x01;           // Timer0 w trybie 1 (16-bit)
    
    // Ustawienie wartości początkowej dla wygenerowania przerwania co ok. 5000 cykli
    TH0       = (char)((65535-5000)>>8);
    TL0       = (char)((65535-5000)>>0);
    
    TCON     |= 0x10;           // TR0 = 1 (Start licznika Timer0)
    IE       |= 0x02;           // Włączenie przerwań od Timer0 (ET0 = 1)
    
    SFRPAGE   = CONFIG_PAGE;
    return;
}

void LatchDataBusValue(unsigned char DataBusValue)
{
    unsigned char old_SFRPAGE = SFRPAGE;
    char  i = 0;
	
    SFRPAGE = CONFIG_PAGE;
    DATABUS_PORT = DataBusValue;

    D_FLIP_FLOP_CLK = 0;
    for (i = 0; i < 2; i++);
    D_FLIP_FLOP_CLK = 1;
  
    SFRPAGE = old_SFRPAGE;
    return;
}

//-----------------------------------------------------------------------------
// main() Routine
//-----------------------------------------------------------------------------
int main (void)
{
   PORT_Init();
   Timer3_Init();
   Timer0_Init(); // Dodano inicjalizację Timer0
   
   LED_DISPLAY_PORT = DisplayPortValue;
   
   // Początkowe ustawienie portu P4: Rząd 0 (P4.4) aktywny (0), reszta jedynki
   SFRPAGE = CONFIG_PAGE;
   P4 = ~(1 << 4) | 0x0F; 
   
   IE_EA = 1; // Enable Interrupts - Global Flag
   
   while (1) {} // Spin forever
}

//-----------------------------------------------------------------------------
// Interrupt Service Routines
//-----------------------------------------------------------------------------

// ISR dla Timer3: Obsługuje TYLKO wyświetlanie (Multipleksowanie)
SI_INTERRUPT(TIMER3_ISR, TIMER3_IRQn)
{
    unsigned char old_SFRPAGE = SFRPAGE;
    SFRPAGE = LEGACY_PAGE;
    TMR3CN &= 0x7F;                        

    SFRPAGE = CONFIG_PAGE;                 
    
    LED_DISPLAY_PORT = 0xFF;
    LatchDataBusValue(0x00);
    LED_DISPLAY_PORT = DisplayPortValue;
    
    // Zawsze pobiera dane z tablicy led_display
    LatchDataBusValue(led_display[current_digit]);

    DisplayPortValue = (DisplayPortValue << 1) | (DisplayPortValue >> 7);
    current_digit++;
    
    if (current_digit >= 5) {
        current_digit = 0;
        DisplayPortValue = 0xFE; 
    }

    SFRPAGE = old_SFRPAGE;                 
    return;
}

// ISR dla Timer0: Obsługuje TYLKO skanowanie klawiatury
SI_INTERRUPT(TIMER0_ISR, TIMER0_IRQn)
{
    char old_SFRPAGE = SFRPAGE;
    unsigned char col_val;
    unsigned char col_index;
    
    SFRPAGE = LEGACY_PAGE;
    // Przeładowanie wartości licznika Timer0 (wymagane w trybie 1)
    TH0 = (char)((65535-5000)>>8);
    TL0 = (char)((65535-5000)>>0);

    SFRPAGE = CONFIG_PAGE; // P4 najlepiej odczytywać/zapisywać na stronie CONFIG_PAGE
    
    // Algorytm zgodny ze schematem blokowym z PDF (Rys. 8)
    
    // Krok a: przypisz wartość portu P4 do zmiennej temp_val
    temp_val = P4;
    
    // Krok b: iloczyn logiczny z 0x0F (izolacja linii wejściowych kolumn)
    col_val = temp_val & 0x0F;
    
    // Krok c: sprawdź, czy wciśnięto klawisz (czy jest jakieś '0' na młodszych bitach)
    if (col_val != 0x0F) 
    {
        // KLAWISZ WCIŚNIĘTY
        
        // Dekodowanie kolumny na indeks (0-3)
        if      (col_val == 0x0E) col_index = 0; // 1110 -> Kolumna 0
        else if (col_val == 0x0D) col_index = 1; // 1101 -> Kolumna 1
        else if (col_val == 0x0B) col_index = 2; // 1011 -> Kolumna 2
        else if (col_val == 0x07) col_index = 3; // 0111 -> Kolumna 3
        else col_index = 0; // Zabezpieczenie na wypadek wciśnięcia wielu na raz
        
        // Prześlij kod klawisza do tablicy wyświetlacza LED (pozycja 0)
        led_display[0] = key_codes[keyboard_counter][col_index];
        
        // Zgodnie z algorytmem: NIE modyfikujemy keyboard_counter, 
        // wychodzimy z procedury (aby ciągle wyświetlać znak trzymanego klawisza)
    } 
    else 
    {
        // KLAWISZ NIE JEST WCIŚNIĘTY W TYM WIERSZU
        
        // Czyszczenie wyświetlacza, jeśli przycisk został puszczony
        led_display[0] = 0x00; 
        
        // Przejście do następnego wiersza
        keyboard_counter++;
        if (keyboard_counter >= 4) {
            keyboard_counter = 0; // Zabezpieczenie przed wyjściem poza zakres
        }
        
        // Ustawienie '0' na odpowiedniej linii wyboru (P4.4 - P4.7)
        // Bitowe przesunięcie: 1 << (0+4) = 00010000. Negacja (~) daje 11101111. 
        // OR z 0x0F zapewnia, że linie odczytu (młodsze bity) pozostają jako '1' (w trybie wejściowym)
        P4 = ~(1 << (keyboard_counter + 4)) | 0x0F;
        
        temp_val = 0xFF;
    }
    
    SFRPAGE = old_SFRPAGE; // Restore SFR
    return;
}