Загрузка данных
//-----------------------------------------------------------------------------
// 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;
}