Avançar para o conteúdo

Piscar LED com CH552 (8051) #2

Hoje vou te mostar como piscar LED com CH552 (8051), usando apenas programação bare metal e arquivos de configuração “ch554.c/.h. Este é o segundo artigo da série que vai te ensina a programar o microcontrolador Ch552 do zero, acompanhe.

Lembrando que para comprar esta plaquinha você pode usar meus links do Aliexpress, (aqui) ou (aqui). Esta placa é barata pois é baseada na saudosa e poderosa família 8051. As vantagens da versão Ch552 (na minha opinião) são possuir bootloader USB, comparador analógico e entradas touch capacitivas.

Detalhe: quer comprar o osciloscópio do vídeo? Comprei no Aliexpress.

O que eu vou precisar?

Clique no link no primeiro parágrafo para ler (primeiro artigo e vídeo) sobre a configuração inicial do seu computador e placa. Fora isso para este experimento você vai apenas precisar da placa Ch552. Se quiser pode usar um LED externo (3mm ou 5mm qualquer cor) com um resistor série entre 220 Ohm e 1k5 Ohm.

Também é necessário:

  • Compilador SDCC e software gravador Chprog, configurados no primeiro artigo da série,
  • Um editor de texto, eu uso o Visual Studio code,
  • Script em Python para compilação/linkagem/gravação, obtido neste link. Python instalado na sua máquina.

Após criar o código nos próximos passos, você vai precisar abrir a linha de comando do Windows, digitando “cmd” ao apertar para abrir o menu do Windows. Por lá no cmd você vai fazer todo o resto.

Explicando o código

Diferente de como se ensina Arduino, eu não vou te ensinar a usar funções como delay() para piscar um LED. Eu vou te monstar como usar um temporizador interno do Ch552, no caso o Timer0. Assim implementaremos um código não bloqueante, que pode executar muitas outras coisas “em série” sem ficar parado enquanto o LED pisca.

Detalhe importante: no ano (Abril/2026) e era em que estamos, eu fiz uso pesado de inteligência artificiar para aprender a programar o Ch552. Tudo que absorvi veio do ChatGPT, Claude.ai, Microsoft Copilot e Google Gemini.

O código completo está abaixo e também neste link, sob o nome “blink-basic-timer.c”. O que precisamos fazer é configurar o clock para 24MHz (que é o valor do cristal oscilador montado na placa). Depois configuramos o temporizador Timer0 para gerar uma interrupção a cada 10ms (dez milisegundos).

#include "inc\ch554.h"
//#include <stdint.h>

volatile unsigned int tick_10ms = 0;
unsigned char led_state = 0;
unsigned int counter= 0;

void timer0_ISR(void) __interrupt(1) __using(1);
void blink_led(void);
void clock_init(void);

void clock_init(void) {
    SAFE_MOD = 0x55;
    SAFE_MOD = 0xAA;
    // Set Fsys = 24 MHz (Fpll/4, bits[2:0] = 110 = 0x06)
    CLOCK_CFG = (CLOCK_CFG & ~MASK_SYS_CK_SEL) | 0x06;
    
    SAFE_MOD = 0x00;
}

void timer0_ISR(void) __interrupt(INT_NO_TMR0) {
    TF0 = 0;  // clear overflow flag (important for robustness)
    // This are the TH0 and TL0 values to 10ms interrupts, based on a 24Mhz clock
    TH0 = 0xB1;
    TL0 = 0xE0;
    
    if(tick_10ms >= 30) {
        tick_10ms = 0;
    } else{
        tick_10ms++;
    }
    
}

void timer0_init(void) {
    TMOD &= ~0x03;  // clear Timer0 mode bits
    TMOD |=  0x01;  // Timer0 mode 1: 16-bit

    // 10ms @ 24MHz: tick = 24M/12 = 2MHz = 0.5us
    // 10ms / 0.5us = 20000 ticks; 65536-20000 = 45536 = 0xB1E0
    TH0 = 0xB1;
    TL0 = 0xE0;

    ET0 = 1;   // enable Timer0 interrupt
    TR0 = 1;   // start Timer0
    EA = 1;   // enable interrupts
}

void blink_led(void) {
    if(tick_10ms % 50 < 25){
        P3 |= (1 << 0);  // LED ON
    } else {
        P3 &= ~(1 << 0); // LED OFF
    }
}

void main(void) {
    clock_init();
    timer0_init();

    // Disable watchdog (important on CH55x)
    SAFE_MOD = 0x55;
    SAFE_MOD = 0xAA;
    GLOBAL_CFG &= ~bWDOG_EN;   // turn off watchdog
    SAFE_MOD = 0x00;

    // Configure P3.0 as push-pull output
    // P3.0 bit = 0x01
    P3_MOD_OC &= ~0x01;   // not open-drain
    P3_DIR_PU |= 0x01;    // output, with pull-up

    while (1) {
        blink_led();        
    }
}

Este tempo de interrupção é arbitrário, eu que decidi fazer assim. Poderia tranquilamente ser 10 us (dez microsegundos) ou 100 ms (cem milisegundos), bastando somente “contar” com a variável “tick_10ms” até atingir o tempo de piscada do LED desejado.

A “mágica” do piscar do LED está na parte do código mostrada abaixo, que liga o LED durante os primeiros 250 ms e desliga-o nos próximos 250 ms, fechando um período de 500 ms. Ou seja, piscaremos o LED a f = 1/T :: f= 1/0,5 :: f= 2 Hz.

void blink_led(void) {
    if(tick_10ms % 50 < 25){
        P3 |= (1 << 0);  // LED ON
    } else {
        P3 &= ~(1 << 0); // LED OFF
    }
}

A função blink_led() acima é a única coisa chamada no while(1), loop principal do programa. Portanto é a única coisa executada no momento dentro do Ch552.

As principais funções e o que elas fazem

Começaremos por configuar o clock do microcontrolador. Para setar nosso clock em 24MHz precisamos usar o código abaixo. 24MHz pois é o cristal que vem montado na placa que compramos.

void clock_init(void) {
    SAFE_MOD = 0x55;
    SAFE_MOD = 0xAA;
    // Set Fsys = 24 MHz (Fpll/4, bits[2:0] = 110 = 0x06)
    CLOCK_CFG = (CLOCK_CFG & ~MASK_SYS_CK_SEL) | 0x06;
    
    SAFE_MOD = 0x00;
}

Os valores de SAFE_MOD chamados em série são uma sequência necessária para alterar partes sensíveis do microcontrolador. O próximo passo é configurar o temporizador Timer0 que vamos usar para controlar a piscada do LED.

void timer0_init(void) {
    TMOD &= ~0x03;  // clear Timer0 mode bits
    TMOD |=  0x01;  // Timer0 mode 1: 16-bit

    // 10ms @ 24MHz: tick = 24M/12 = 2MHz = 0.5us
    // 10ms / 0.5us = 20000 ticks; 65536-20000 = 45536 = 0xB1E0
    TH0 = 0xB1;
    TL0 = 0xE0;

    ET0 = 1;   // enable Timer0 interrupt
    TR0 = 1;   // start Timer0
    EA = 1;   // enable interrupts
}

Com TMOD definimos que usaremos 16bit; TH0 e TL0 definem o prescaler de contagem, ou seja, até quanto tempo demora para o temporizador “estourar”. Como eu quis fazer um estouro a cada 10 ms (dez milisegundos), cofigurei assim:

    // 10ms @ 24MHz: tick = 24M/12 = 2MHz = 0.5us
    // 10ms / 0.5us = 20000 ticks; 65536-20000 = 45536 = 0xB1E0

Depois usamos ET0 para habilitar o timer, TR0 para inicia-lo e EA para habilitar as interrupções. A cada 10 ms o programa entra na interrupção de timer, que executa o código abaixo:

void timer0_ISR(void) __interrupt(INT_NO_TMR0) {
    TF0 = 0;  // clear overflow flag (important for robustness)
    // This are the TH0 and TL0 values to 10ms interrupts, based on a 24Mhz clock
    TH0 = 0xB1;
    TL0 = 0xE0;
    
    if(tick_10ms >= 50) {
        tick_10ms = 0;
    } else{
        tick_10ms++;
    }
    
}

Inicialmente limpamos a flag de overflow, que é responsável por entrar na interrupção, fazendo TF0= 0. Então realimentamos o tempo de interrupção para o próximo ciclo, com TH0 e TL0. E finalmente fazemos nossa “mágica”, que incrementa tick_10ms a cada 10 ms ou zera a mesma variável se chegamos em 500 ms (50 * 10 ms).

Então finalmente executamos nosso loop infinito wlhile(1), apenas chamando blink_led(). Isso é tudo que precisamos para fazer piscar LED com Ch552.

while (1) {
        blink_led();        
    }

O Hardware

Conforme comentado, pode-se usar o próprio LED onboard da placa Ch552 da WeAct neste experimento. Porém se você quiser, pode adicionar um LED + resistor (entre 220 Ohm e 1k5 Ohm) ao pino P3.0, conforme imagem abaixo.

Piscar LED com Ch552
Piscar LED com Ch552

O resultado final

Fiz um vídeo mostrando todo o processo de compilação, linkagem, gravação e teste do microcontrolador CH552. Assista no início do artigo e comente logo abaixo ou lá no Youtube mesmo, caso tenha dúvidas.

A imagem abaixo mostra que no pino P3.0 onde está o LED, a frequência é de quase 2Hz (1.95Hz). Ciclo ativo é de quase 50% (50,97%) e a tensão é de 5,12V, condizente com os 5V da saída do micrcocontrolador Ch552.

LED piscando a 2Hz
LED piscando a 2Hz

Lembrando que se quiser comprar a plaquinha Ch552, você pode usar meus links do Aliexpress (aqui) ou (aqui).

Deixe um comentário

O seu endereço de email não será publicado. Campos obrigatórios marcados com *