STC8G1K08A winziges 349-Byte-UART-Hello-World-Demo

Siehe auch:

In unserem vorherigen Beitrag STC8G1K08A minimales UART-Hello-World-Demo haben wir gezeigt, wie man FwLib_STC8 verwendet, um eine einfache UART-Hello-World-Anwendung für den STC8G1K08A zu schreiben, die nur etwas über 2,2 KB groß ist.

Während dieses Beispiel sehr einfach ist, leidet es unter einem großen Problem im Zusammenhang mit dem SDCC-Funktionsumfang: Zum jetzigen Zeitpunkt unterstützt SDCC nicht das Entfernen ungenutzter Funktionen aus der gelinkten Ausgabe. Das bedeutet, dass wenn du irgendeine Funktion aus der UART-Bibliothek verwendest, du die gesamte Bibliothek linkst, was viel Code-Größen-Overhead hinzufügt.

Um dies zu beheben, können wir den Code inlinen und etwas optimieren.

main.c
#include "fw_uart.h"

/* Baudrate an einer Stelle halten, damit die Timer1-Reload-Formel offensichtlich bleibt. */
#define UART1_BAUD_RATE 115200UL

/* Die SYSCLK-Berechnung der Bibliothek reproduzieren, ohne Laufzeitcode aufzurufen. */
#define UART1_SYSCLK_HZ (__CONF_FOSC / ((__CONF_CLKDIV == 0) ? 1UL : (unsigned long)__CONF_CLKDIV))

/* UART1-Modus 1 verwendet Timer1-Überlauf geteilt durch vier als Baudraten-Takt. */
#define UART1_TIMER1_RELOAD (65536UL - (UART1_SYSCLK_HZ / (4UL * UART1_BAUD_RATE)))

/* Die gesamte Nachricht in einem Speicherbereich halten, damit die Bibliothek sie streamen kann. */
static unsigned char uart_message[] = "Hello, world from UART1!\r\n";

static void UART1_SendString(unsigned char *str)
{
    while (*str)
    {
        SBUF = *str++;
        TI = 0;
        while (!TI)
        {
        }
    }
}

#define TICKS_MS (__CONF_FOSC / ((__CONF_CLKDIV == 0) ? 1UL : (unsigned long)__CONF_CLKDIV) / 9000UL)

static void delay_ms(unsigned int ms)
{
    unsigned int i;

    do
    {
        i = TICKS_MS;
        while (--i)
        {
        }
    } while (--ms);
}

static void UART1_Init(void)
{
    /*
     * Erweiterte SFR-Bank öffnen, damit CLKDIV geschrieben werden kann, bevor UART1 hochgefahren wird.
     * B7 = 1: Zugriff auf die erweiterte SFR-Region aktivieren.
     * B6..B0 = 0: die anderen Bank-Schalt- und Peripherie-Routing-Steuerungen unverändert lassen.
     */
    P_SW2 = 0x80;

    /* Den konfigurierten Teiler mit einem direkten Register-Schreibzugriff anwenden. */
    CLKDIV = __CONF_CLKDIV;

    /*
     * Zur normalen SFR-Bank zurückkehren, da der Teiler jetzt programmiert ist.
     * B7 = 0: erweiterten SFR-Zugriff wieder deaktivieren.
     * B6..B0 = 0: die verbleibenden P_SW2-Steuerungen in diesem minimalen Demo inaktiv lassen.
     */
    P_SW2 = 0x00;

    /*
     * Das Hochgeschwindigkeits-RC-Oszillator-Band auswählen, für das die Trim-Werte abgeglichen wurden.
     * 0x03 behält nur IRCBAND[1:0], die Band-Auswahl-Bits.
     * Obere Bits im Konfigurationswert werden verworfen, sodass nur das dokumentierte Band-Feld berührt wird.
     */
    IRCBAND = (__CONF_IRCBAND & 0x03);

    /* Den passenden Spannungs-Trim-Byte für dieses RC-Band laden. */
    VRTRIM = __CONF_VRTRIM;

    /* Den Fein-Trim-Byte des Hochgeschwindigkeits-RC laden. */
    IRTRIM = __CONF_IRTRIM;

    /*
     * Das Niedergeschwindigkeits-RC-Trim-Feld laden, obwohl dieses Demo mit dem schnellen internen Takt läuft.
     * 0x03 behält nur LIRTRIM[1:0], die gültigen Niedergeschwindigkeits-Trim-Bits.
     * Obere Bits werden niedrig erzwungen, damit keine undefinierten Werte in dieses Register geschrieben werden.
     */
    LIRTRIM = (__CONF_LIRTRIM & 0x03);

    /*
     * UART1 in den Standard-8-Bit-Asynchronmodus versetzen und den Empfänger aktivieren.
     * 0x50 = 0101 0000b.
     * SM0 = 0, SM1 = 1: UART-Modus 1 auswählen, das übliche 8-Bit-UART mit variabler Baudrate.
     * SM2 = 0: Multiprozessor-Adressfilterung deaktivieren, sodass jedes empfangene Byte akzeptiert wird.
     * REN = 1: UART-Empfänger aktivieren.
     * TB8 = 0, RB8 = 0: Neun-Bit-Sende-/Empfangsstatus beginnt gelöscht, da Modus 1 ihn nicht verwendet.
     * TI = 0, RI = 0: beide Sende- und Empfangsstatus-Flags vor dem ersten Zeichen löschen.
     */
    SCON = 0x50;

    /*
     * Timer1 als Baudraten-Generator konfigurieren, von dem UART1 zählt.
     * 0x40 = 0100 0000b.
     * B6 = 1: Timer1 im 1T-Modus betreiben, sodass er jeden Systemtakt inkrementiert statt alle 12 Takte.
     * B0 = 0: UART1s Baudquelle auf Timer1 belassen statt auf Timer2 umzuschalten.
     * B5..B1 = 0: die nicht relevanten AUXR-Funktionen in diesem Demo deaktiviert lassen.
     */
    AUXR = 0x40;

    /*
     * Timer1 in den Reload-Modus versetzen, den der FwLib-UART-Codepfad erwartet.
     * 0x00 = 0000 0000b.
     * GATE1 = 0: Timer1 startet und stoppt nur über TR1, nicht über den externen INT1-Pin.
     * C/T1 = 0: Timer1 zählt Takt-Impulse, nicht externe Ereignisse.
     * M1_1 = 0, M0_1 = 0: den Timer1-Modus auswählen, den diese STC8-Bibliothek für UART-Baudgenerierung verwendet.
     * Die Timer0-Hälfte von TMOD wird ebenfalls gelöscht, da dieses Demo Timer0 nicht verwendet.
     */
    TMOD = 0x00;

    /* Das obere Byte des Kompilierzeit-Timer1-Reload-Werts laden. */
    TH1 = (unsigned char)(UART1_TIMER1_RELOAD >> 8);

    /* Das untere Byte laden, sodass der allererste Überlauf bereits die richtige Baudrate verwendet. */
    TL1 = (unsigned char)(UART1_TIMER1_RELOAD & 0xFF);

    /* Timer1 starten, damit UART1 sein Bit-Timing ableiten kann. */
    TR1 = 1;
}

void main(void)
{
    /* Eine mit Null initialisierte unsigned-Schleifenvariable ergibt eine kompakte Vollbereich-Verzögerung. */
    unsigned int settle = 0;

    UART1_Init();
    
    /* Den gesamten NUL-terminierten Nachrichtenpuffer an die lokale String-Sendehilfe übergeben. */
    while (1)
    {
        UART1_SendString(uart_message);
        delay_ms(1000);
    }
}

Wie man flasht

Siehe unseren Beitrag Wie man STC8G1K08A mit stcgal flasht

Wie man die serielle Ausgabe überprüft

Überprüfe die Ausgabe mit

monitor.sh
picocom -b 115200 /dev/ttyUSB0

Speichernutzung

memory_usage.txt
===== Memory usage summary for uart_minimal_size_demo =====
Internal RAM layout:
      0 1 2 3 4 5 6 7 8 9 A B C D E F
0x00:|0|0|0|0|0|0|0|0|S|S|S|S|S|S|S|S|
0x10:|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|
0x20:|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|
0x30:|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|
0x40:|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|
0x50:|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|
0x60:|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|
0x70:|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|
0x80:|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|
0x90:|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|
0xa0:|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|
0xb0:|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|
0xc0:|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|
0xd0:|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|
0xe0:|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|
0xf0:|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|
0-3:Reg Banks, T:Bit regs, a-z:Datum, B:Bits, Q:Overlay, I:iData, S:Stack, A:Absolute

Stack starts at: 0x08 (sp set to 0x07) with 248 bytes available.
No spare internal RAM space left.

Other memory:
   Name             Start    End      Size     Max     
   ---------------- -------- -------- -------- --------
   PAGED EXT. RAM                         0      256   
   EXTERNAL RAM     0x0001   0x0020      32     1024   
   ROM/EPROM/FLASH  0x0000   0x015c     349     8192   
==========================================================

mit SDCC 4.2.0 #13081 - 349 Bytes Flash sind eine enorme Verbesserung gegenüber den 2,2 KB des vorherigen Beispiels.

Beachte, dass du individuell wählen kannst, ob du nur FwLib-Funktionen in dein Projekt kopierst (die liberalen Apache-Lizenzbedingungen von FwLib_STC8 erlauben dies, aber du möglicherweise musst die Urheberrechtserklärung beibehalten), oder sie insgesamt “inlinen”, um den Code noch mehr zu komprimieren. In unserem obigen Code haben wir uns für eine Mischung aus beidem entschieden.


Ähnliche Beiträge nach Kategorie: STC8 Embedded C/C++