/*-------------------------------------------------------- dice_mpx.c 3-fach Wuerfel mit gemultiplexten LEDs Compiler : SDCC 4.0.3 .. SDCC 4.4.4 MCU : PFS154 25.11.2024 R. Seelig -------------------------------------------------------- */ #include #include "pdk_init.h" #include "pfs1xx_gpio.h" volatile uint16_t millis; // Zaehlervariable fuer hochgezaehlte Millisekunden volatile uint16_t blink = 0; // Blinkfrequenzzaehler im Interruptvektor // Button #define button_init() PA5_input_init() #define is_button() (!(is_PA5())) // Bitmaps fuer Wuerfelaugen 1 2 3 4 5 6 aus const uint8_t dice_bmp[]= { 0x08, 0x01, 0x09, 0x03, 0x0b, 0x07, 0x00 }; uint8_t dices[3]; // Array das die anzuzeigenden Augen enthaelt /* -------------------------------------------------------- idelay verzoegert die weitere Programmausfuehrung um 1,024 * ms -------------------------------------------------------- */ void idelay(uint16_t ms) { millis= 0; while (millis < ms); } /* -------------------------------------------------------- int2dices dekodiert einen Integerzahlenwert 0..215 zu einem 3-stelligen Zahlenwert zur Basis 6 und weisst den Wert einem 3 Byte grossen Array zu, welches die Augenanzahl eines Wuerfels entspricht Uebergabe: val: zu dekodierender Zahlenwert *buf: Zeiger auf einen 3 Byte grossen Puffer -------------------------------------------------------- */ void int2dices(uint8_t val, uint8_t *buf) { volatile uint8_t i, dice, divi; __disgint(); divi= 36; for (i= 0; i< 3; i++) { dice= 0; while(val >= divi) { dice++; val -= divi; } *buf= dice; buf++; divi = divi / 6; } __engint(); } /* -------------------------------------------------------- interrupt der Interrupt-Handler. TM16 ruft den Interrupt mit ca. 1 kHz auf. Hier muss das Multiplexen der Anzeige, das Hochzaehlen von "millis" (fuer das idelay) und "blink" eingehaengt werden. -------------------------------------------------------- */ void interrupt(void) __interrupt(0) { static uint8_t mpx = 0; // Interruptquelle ist 16-Bit Timer if (INTRQ & INTRQ_T16) { millis++; blink++; PB = 0xf0; // alle MPX-Leitungen 1 = kein Digit angewaehlt switch (mpx) { case 0: { PB = 0xe0 | dice_bmp[dices[2]]; break; } case 1: { PB = 0xd0 | dice_bmp[dices[1]]; break; } case 2: { PB = 0xb0 | dice_bmp[dices[0]]; break; } default : break; } mpx++; mpx = mpx % 3; INTRQ &= ~INTRQ_T16; // Interruptanforderung quittieren } } /* -------------------------------------------------------- t16_init initialisiert den 16-Bit Timer mit Interruptaus- loesung. Das Modusregister T16M beinhaltet die Konfiguration des Timers hinsichtlich der Taktquelle, des Teilers und des Ausloesen eines Interrupts (siehe t16m_note.txt) -------------------------------------------------------- */ void t16_init(void) { // ( F_CPU / 16 / 512) = 8 MHz / 256 = 976Hz // Interruptausloesung alle 1.024ms T16M = (uint8_t)(T16M_CLK_IHRC | T16M_CLK_DIV16 | T16M_INTSRC_9BIT); T16C = 0; // Timerzaehlregister = 0; millis = 0; __engint(); // grundsaetzlich Interrupt zulassen INTEN |= INTEN_T16; // Timerinterrupt zulassen } /* -------------------------------------------------- main -------------------------------------------------- */ void main(void) { uint8_t wurf; PBC= 0xff; // alle Pins PortB als Ausgang (LED + MPX Anschluesse) button_init(); t16_init(); wurf= 0; // Wuerfel beim Start blinken lassen while(!(is_button()) ) { if (blink< 300) { dices[0]= 5; dices[1]= 5; dices[2]= 5; } else { dices[0]= 6; dices[1]= 6; dices[2]= 6; if (blink> 600) blink= 0; } wurf++; wurf= wurf % 216; } idelay(50); while(is_button()); idelay(50); int2dices(wurf, &dices[0]); while(1) { if (is_button()) { idelay(80); int2dices(wurf, &dices[0]); while(is_button()); idelay(80); } wurf++; wurf= wurf % 216; } }