STC8G1K08A : Démo UART hello world minuscule de 349 octets

Voir aussi :

Dans notre article précédent STC8G1K08A minimal UART hello world demo, nous avons montré comment utiliser FwLib_STC8 pour écrire une application UART hello world simple pour le STC8G1K08A qui fait juste un peu plus de 2,2 Ko.

Bien que cet exemple soit très simple, il souffre d’un problème majeur lié aux fonctionnalités de SDCC : Actuellement, SDCC ne prend pas en charge l’élimination des fonctions inutilisées de la sortie liée. Cela signifie que si vous utilisez n’importe quelle fonction de la bibliothèque UART, vous finissez par lier toute la bibliothèque, ce qui ajoute beaucoup de surcharge de taille de code.

Pour corriger cela, nous pouvons inliner et quelque peu optimiser le code.

main.c
#include "fw_uart.h"

/* Garder le débit baud à un seul endroit pour que la formule de rechargement du Timer1 reste évidente. */
#define UART1_BAUD_RATE 115200UL

/* Reproduire le calcul SYSCLK de la bibliothèque sans appeler de code d'exécution. */
#define UART1_SYSCLK_HZ (__CONF_FOSC / ((__CONF_CLKDIV == 0) ? 1UL : (unsigned long)__CONF_CLKDIV))

/* Le mode 1 d'UART1 utilise le débordement du Timer1 divisé par quatre comme horloge de débit baud. */
#define UART1_TIMER1_RELOAD (65536UL - (UART1_SYSCLK_HZ / (4UL * UART1_BAUD_RATE)))

/* Garder tout le message dans une seule zone mémoire pour que la bibliothèque puisse le diffuser. */
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)
{
    /*
     * Ouvrir la banque SFR étendue pour pouvoir écrire CLKDIV avant de démarrer UART1.
     * B7 = 1 : activer l'accès à la région SFR étendue.
     * B6..B0 = 0 : laisser les autres contrôles de commutation de banque et de routage de périphériques inchangés.
     */
    P_SW2 = 0x80;

    /* Appliquer le diviseur d'horloge configuré avec une écriture directe sur tout le registre. */
    CLKDIV = __CONF_CLKDIV;

    /*
     * Revenir à la banque SFR normale maintenant que le diviseur d'horloge est programmé.
     * B7 = 0 : désactiver à nouveau l'accès SFR étendu.
     * B6..B0 = 0 : garder les contrôles restants de P_SW2 inactifs dans cette démo minimale.
     */
    P_SW2 = 0x00;

    /*
     * Sélectionner la bande de l'oscillateur RC interne haute vitesse pour laquelle les valeurs de calibration ont été réglées.
     * 0x03 conserve uniquement IRCBAND[1:0], qui sont les bits de sélection de bande.
     * Tous les bits supérieurs de la valeur de configuration sont ignorés pour ne toucher que le champ de bande documenté.
     */
    IRCBAND = (__CONF_IRCBAND & 0x03);

    /* Charger l'octet de calibration de tension correspondant à cette bande RC. */
    VRTRIM = __CONF_VRTRIM;

    /* Charger l'octet de calibration fine du RC haute vitesse. */
    IRTRIM = __CONF_IRTRIM;

    /*
     * Charger le champ de calibration du RC basse vitesse même si cette démo fonctionne avec l'horloge interne rapide.
     * 0x03 conserve uniquement LIRTRIM[1:0], qui sont les bits valides de calibration basse vitesse.
     * Tous les bits supérieurs sont forcés à zéro pour ne pas écrire de valeurs indéfinies dans ce registre.
     */
    LIRTRIM = (__CONF_LIRTRIM & 0x03);

    /*
     * Mettre UART1 en mode asynchrone 8 bits standard et permettre au récepteur de fonctionner.
     * 0x50 = 0101 0000b.
     * SM0 = 0, SM1 = 1 : sélectionner le mode UART 1, le UART 8 bits habituel avec débit baud variable.
     * SM2 = 0 : désactiver le filtrage d'adresse multiprocesseur, donc chaque octet reçu est accepté.
     * REN = 1 : activer le récepteur UART.
     * TB8 = 0, RB8 = 0 : l'état du neuvième bit en émission/réception commence effacé car le mode 1 ne l'utilise pas.
     * TI = 0, RI = 0 : effacer les deux indicateurs d'état d'émission et de réception avant le premier caractère.
     */
    SCON = 0x50;

    /*
     * Configurer Timer1 comme générateur de débit baud dont UART1 va compter les débordements.
     * 0x40 = 0100 0000b.
     * B6 = 1 : faire fonctionner Timer1 en mode 1T pour qu'il s'incrémente à chaque cycle d'horloge système au lieu de tous les 12 cycles.
     * B0 = 0 : garder la source de débit baud d'UART1 sur Timer1 plutôt que de la basculer sur Timer2.
     * B5..B1 = 0 : laisser les fonctionnalités AUXR non liées désactivées dans cette démo.
     */
    AUXR = 0x40;

    /*
     * Mettre Timer1 dans le mode de rechargement attendu par le chemin de code UART de FwLib.
     * 0x00 = 0000 0000b.
     * GATE1 = 0 : Timer1 démarre et s'arrête uniquement depuis TR1, pas depuis la broche externe INT1.
     * C/T1 = 0 : Timer1 compte les cycles d'horloge, pas les événements externes.
     * M1_1 = 0, M0_1 = 0 : sélectionner le mode Timer1 que cette bibliothèque STC8 utilise pour la génération de débit baud UART.
     * La moitié Timer0 de TMOD est également effacée car cette démo n'utilise pas Timer0.
     */
    TMOD = 0x00;

    /* Charger l'octet haut de la valeur de rechargement du Timer1 calculée à la compilation. */
    TH1 = (unsigned char)(UART1_TIMER1_RELOAD >> 8);

    /* Charger l'octet bas pour que le tout premier débordement utilise déjà le bon débit baud. */
    TL1 = (unsigned char)(UART1_TIMER1_RELOAD & 0xFF);

    /* Démarrer Timer1 pour qu'UART1 puisse dériver son minutage de bit. */
    TR1 = 1;
}

void main(void)
{
    /* Une variable de boucle unsigned initialisée à zéro donne un délai compact sur toute la plage. */
    unsigned int settle = 0;

    UART1_Init();
    
    /* Confier tout le tampon de message terminé par NUL à l'assistant local d'émission de chaîne. */
    while (1)
    {
        UART1_SendString(uart_message);
        delay_ms(1000);
    }
}

Comment flasher

Consultez notre article How to flash STC8G1K08A using stcgal

Comment vérifier la sortie série

Vérifiez la sortie avec

monitor.sh
picocom -b 115200 /dev/ttyUSB0

Utilisation de la mémoire

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:Data, 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   
==========================================================

avec SDCC 4.2.0 #13081 - 349 octets de flash est une vaste amélioration par rapport aux 2,2 Ko de l’exemple précédent.

Notez que vous pouvez choisir individuellement de simplement copier des fonctions FwLib dans votre projet (les termes de la licence Apache permissive de FwLib_STC8 le permettent, mais vous devrez peut-être conserver la mention de copyright), ou les « inliner » complètement pour compresser encore plus le code. Dans notre code ci-dessus, nous avons choisi de faire un mélange des deux.


Check out similar posts by category: STC8, Embedded, C/C++