Veja também:
- Quer apenas um demo simples sem a otimização de tamanho? Confira STC8G1K08A demo mínimo de UART hello world
Em nosso post anterior STC8G1K08A demo mínimo de UART hello world mostramos como usar a FwLib_STC8 para escrever uma aplicação UART hello world simples para o STC8G1K08A com pouco mais de 2.2 KB de tamanho.
Embora esse exemplo seja muito simples, ele sofre de um grande problema relacionado ao conjunto de recursos do SDCC: No momento, o SDCC não suporta a remoção de funções não utilizadas da saída do linker. Isso significa que se você usar qualquer função da biblioteca UART, acaba linkando a biblioteca inteira, o que adiciona muita sobrecarga de tamanho de código.
Para corrigir isso, podemos inlinar e otimizar um pouco o código.
#include "fw_uart.h"
/* Mantenha o baud rate em um lugar só para que a fórmula de reload do Timer1 permaneça óbvia. */
#define UART1_BAUD_RATE 115200UL
/* Reproduza o cálculo de SYSCLK da biblioteca sem chamar nenhum código de runtime. */
#define UART1_SYSCLK_HZ (__CONF_FOSC / ((__CONF_CLKDIV == 0) ? 1UL : (unsigned long)__CONF_CLKDIV))
/* O modo 1 da UART1 usa o overflow do Timer1 dividido por quatro como clock de baud rate. */
#define UART1_TIMER1_RELOAD (65536UL - (UART1_SYSCLK_HZ / (4UL * UART1_BAUD_RATE)))
/* Mantenha a mensagem inteira em uma área de memória para que a biblioteca possa transmiti-la. */
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)
{
/*
* Abra o banco SFR estendido para podermos escrever CLKDIV antes de iniciar a UART1.
* B7 = 1: habilita o acesso à região SFR estendida.
* B6..B0 = 0: deixa os demais controles de troca de banco e roteamento de periféricos inalterados.
*/
P_SW2 = 0x80;
/* Aplique o divisor de clock configurado com uma escrita direta no registrador inteiro. */
CLKDIV = __CONF_CLKDIV;
/*
* Retorne ao banco SFR normal agora que o divisor de clock está programado.
* B7 = 0: desabilita o acesso SFR estendido novamente.
* B6..B0 = 0: mantém os controles restantes do P_SW2 inativos neste demo mínimo.
*/
P_SW2 = 0x00;
/*
* Selecione a banda do oscilador RC interno de alta velocidade para a qual os valores de trim foram calibrados.
* 0x03 mantém apenas IRCBAND[1:0], que são os bits de seleção de banda.
* Quaisquer bits superiores no valor de configuração são descartados para tocarmos apenas o campo de banda documentado.
*/
IRCBAND = (__CONF_IRCBAND & 0x03);
/* Carregue o byte de trim de tensão correspondente para aquela banda do RC. */
VRTRIM = __CONF_VRTRIM;
/* Carregue o byte de trim fino do RC de alta velocidade. */
IRTRIM = __CONF_IRTRIM;
/*
* Carregue o campo de trim do RC de baixa velocidade mesmo este demo rodando a partir do clock interno rápido.
* 0x03 mantém apenas LIRTRIM[1:0], que são os bits válidos de trim de baixa velocidade.
* Quaisquer bits superiores são forçados em nível baixo para não escrevermos valores indefinidos naquele registrador.
*/
LIRTRIM = (__CONF_LIRTRIM & 0x03);
/*
* Coloque a UART1 no modo assíncrono padrão de 8 bits e permita que o receptor funcione.
* 0x50 = 0101 0000b.
* SM0 = 0, SM1 = 1: seleciona o modo 1 da UART, a UART usual de 8 bits com baud rate variável.
* SM2 = 0: desabilita a filtragem de endereço multiprocessador, de modo que cada byte recebido é aceito.
* REN = 1: habilita o receptor da UART.
* TB8 = 0, RB8 = 0: o estado do nono bit de transmissão/recepção começa zerado porque o modo 1 não o utiliza.
* TI = 0, RI = 0: limpa ambos os flags de status de transmissão e recepção antes do primeiro caractere.
*/
SCON = 0x50;
/*
* Configure o Timer1 como o gerador de baud rate a partir do qual a UART1 contará.
* 0x40 = 0100 0000b.
* B6 = 1: roda o Timer1 no modo 1T para que ele incremente a cada clock do sistema em vez de a cada 12 clocks.
* B0 = 0: mantém a fonte de baud da UART1 no Timer1 em vez de trocá-la para o Timer2.
* B5..B1 = 0: deixa os recursos não relacionados do AUXR desabilitados neste demo.
*/
AUXR = 0x40;
/*
* Coloque o Timer1 no modo de reload esperado pelo caminho de código UART da FwLib.
* 0x00 = 0000 0000b.
* GATE1 = 0: o Timer1 inicia e para apenas a partir de TR1, não a partir do pino INT1 externo.
* C/T1 = 0: o Timer1 conta ticks de clock, não eventos externos.
* M1_1 = 0, M0_1 = 0: seleciona o modo do Timer1 que esta biblioteca STC8 usa para a geração de baud da UART.
* A metade Timer0 do TMOD também é limpa porque este demo não usa o Timer0.
*/
TMOD = 0x00;
/* Carregue o byte alto do valor de reload do Timer1 em tempo de compilação. */
TH1 = (unsigned char)(UART1_TIMER1_RELOAD >> 8);
/* Carregue o byte baixo para que o primeiro overflow já use o baud rate correto. */
TL1 = (unsigned char)(UART1_TIMER1_RELOAD & 0xFF);
/* Inicie o Timer1 para que a UART1 possa derivar seu timing de bit. */
TR1 = 1;
}
void main(void)
{
/* Uma variável de loop unsigned inicializada em zero fornece um delay compacto de faixa completa. */
unsigned int settle = 0;
UART1_Init();
/* Entregue todo o buffer de mensagem terminado em NUL ao helper local de transmissão de string. */
while (1)
{
UART1_SendString(uart_message);
delay_ms(1000);
}
}Como gravar
Veja nosso post Como gravar o STC8G1K08A usando stcgal
Como verificar a saída serial
Verifique a saída usando
picocom -b 115200 /dev/ttyUSB0Uso de memória
===== 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
==========================================================com SDCC 4.2.0 #13081 - 349 bytes de flash é uma grande melhoria em relação aos 2.2 KB do exemplo anterior.
Note que você pode optar individualmente por apenas copiar funções da FwLib para o seu projeto (os termos liberais da licença Apache da FwLib_STC8 permitem isso, mas pode ser necessário manter a declaração de copyright), ou “inliná-las” todas juntas para comprimir o código ainda mais. Em nosso código acima, escolhemos fazer uma mistura de ambos.