No sexto artigo desta série, falaremos sobre o comparador analógico do CH552. Este é um periférico rápido que serve para comparar níveis analógicos entre dois sinais. Diferente do condicional IF(), ele é um periférico rápido. Lembrando que estamos falando do CH552, que é baseado no saudoso 8051.
O periférico comparador analógico não gera interrupção no CH552, ele apenas seta a flag “CMP0” para valor 1. Temos então o trabalho assíncrono de ler esta flag e tomar atitude de acordo com o que necessitamos.
De acordo com o datasheet do CH552, é possível escolher entre quatro (4) canais analógicos para ser a comparação positiva: AIN0.. AIN3. Já a comparação negativa pode ser escolhida entre dois (2) canais: AIN1 ou AIN3. O funcionamento do comparador baseia-se na seguinte lógica:
- Caso o pino comparador positivo tenha tensão menor que o pino comparador negativo, a flag “CMP0” fica em “0”,
- Caso o pino comparador positivo tenha tensão maior que o pino comparador negativo, a flag “CMP0” vai a “1”.
Nós criaremos um exemplo onde o pino positivo será AIN0 (P1.1) – um potenciômetro. Já o pino negativo será AIN1 (P1.4) – um divisor resistivo de 4,7k Ohm + 4,7k Ohm. Para indicar atuação do comparador nós faremos piscar o LED onboard da placa CH552, no pino P3.0.
Enquanto a tensão em um potenciômetro (pino P1.1) for menor que a tensão no divisor resistivo (P1.4), LED apagado. Quando a tensão do potenciômetro for maior que a do divisor resistivo, o LED começa a piscar a 3Hz.
O Hardware/montagem
Para esta montagem vamos usar o já tradicionar CH552 do Aliexpress, comprado (aqui) ou (aqui). Precisaremos também de um potenciômetro, pode ser qualquer tipo e modelo. O valor pode ser entre 1k Ohm e 100k Ohm. Usaremos também dois resistores de valor idêntico (iguais): entre 1k Ohm e 100k Ohm. Podem ser de qualquer potência e tamanho, o que for mais fácil para você manusear.
Como de costume aqui no blog, a montagem é simples e rápida. Veja nas imagens abaixo. Eu fiz a minha montagem em uma pequena protoboard 400 pontos, é mais que suficiente.


A alimentação do experimento pode ser feita via cabo USB, via o conector USB C que fica na placa do CH552. Lembrando que a placa do CH552 até tem um pino que oferece 3,3V, porém todos os recursos da mesma são 5V. Isto inclui pinos digitais e entradas analógicas.
O firmware/código explicado
Nosso código usará o temporizador Timer0, assim como já fizemos neste artigo anterior. Configuraremos um “tick” ou interrupção de 10 milisegundos (10 ms), que governará tudo. Desde a leitura da flag do comparador até a piscada do LED.
Iniciamos o clock em 24MHz, que é justamente o valor do cristal oscilador soldado na placa do CH552. Inicializamos então o temporizador Timer0 com “0xB1E0”, que nos dá algo muito próximo de 10 milisegundos em 24MHz. Também dentro da inicialização do Timer0 nós damos o start em todas as interrupções, fazendo “EA= 1”.
void clock_init(void) {
SAFE_MOD = 0x55;
SAFE_MOD = 0xAA;
CLOCK_CFG |= bOSC_EN_INT;
// 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_init(void) {
// Force Timer0 to use Fsys/12
T2MOD &= ~bTMR_CLK; // disable fast clock mode
T2MOD &= ~bT0_CLK; // Timer0 = Fsys/12
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;
TF0 = 0;
ET0 = 1; // enable Timer0 interrupt
TR0 = 1; // start Timer0
EA = 1;
}
Faz-se então a inicialização do comparador, definindo quais pinos serão usados e como eles serão configurados.
void cmp_init(void) {
// Enable comparator power only (no ADC needed)
ADC_CFG = bCMP_EN;
// IN+ = AIN0 (P1.1): ADC_CHAN1=0, ADC_CHAN0=0
// IN- = AIN1 (P1.4): CMP_CHAN=0
// Both already 0 at reset, but be explicit:
ADC_CTRL = 0x00;
// P1.1 as high-impedance input (IN+)
P1_MOD_OC &= ~(1 << 1);
P1_DIR_PU &= ~(1 << 1);
// P1.4 as high-impedance input (IN-, reference divider)
P1_MOD_OC &= ~(1 << 4);
P1_DIR_PU &= ~(1 << 4);
}
Finalmente dentro do loop infinito “while(1) crio toda a lógica de piscar ou não o LED, conforme a tensão lida no comparador analógico:
while (1) {
EA = 0;
t = tick_10ms;
EA = 1;
if(t - comparatorTime > 10){
comparatorTime= t;
if (CMPO) { // CMP0 does not latch and does not generate interrupts, it is just a mirror of the analog comparator
if (!ledON) {
ledON = 1;
blink_base = t; // reset blink phase when comparator first triggers
}
} else {
ledON = 0;
P3 &= ~(1 << 0); // make sure LED goes off immediately when pot drops below reference
}
}
if (ledON) {
blink_led(t); // called every loop iteration while CMPO is high
}
}
Código completo do comparador analógico do CH552
Abaixo está o código completo do comparador analógico do CH552. Também disponível neste link do GitHub.
#include "inc\ch554.h"
#include <stdint.h>
volatile unsigned int tick_10ms = 0;
volatile unsigned int comparatorTime = 0;
volatile __bit ledON = 0;
unsigned int serialTime= 0;
unsigned int counter= 0;
unsigned int t;
static __bit wdt_started = 0;
static unsigned int blink_base = 0;
void timer0_ISR(void) __interrupt(1);
void blink_led(unsigned int t);
void clock_init(void);
void cmp_init(void);
void clock_init(void) {
SAFE_MOD = 0x55;
SAFE_MOD = 0xAA;
CLOCK_CFG |= bOSC_EN_INT;
// 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(1) __using(1){
TF0 = 0; // clear overflow flag (important for robustness)
TH0 = 0xB1;
TL0 = 0xE0;
tick_10ms++; // this is the 10ms tick for LED blinking
}
void timer0_init(void) {
// Force Timer0 to use Fsys/12
T2MOD &= ~bTMR_CLK; // disable fast clock mode
T2MOD &= ~bT0_CLK; // Timer0 = Fsys/12
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;
TF0 = 0;
ET0 = 1; // enable Timer0 interrupt
TR0 = 1; // start Timer0
EA = 1;
}
void cmp_init(void) {
// Enable comparator power only (no ADC needed)
ADC_CFG = bCMP_EN;
// IN+ = AIN0 (P1.1): ADC_CHAN1=0, ADC_CHAN0=0
// IN- = AIN1 (P1.4): CMP_CHAN=0
// Both already 0 at reset, but be explicit:
ADC_CTRL = 0x00;
// P1.1 as high-impedance input (IN+)
P1_MOD_OC &= ~(1 << 1);
P1_DIR_PU &= ~(1 << 1);
// P1.4 as high-impedance input (IN-, reference divider)
P1_MOD_OC &= ~(1 << 4);
P1_DIR_PU &= ~(1 << 4);
}
void blink_led(unsigned int t) {
unsigned int phase = t - blink_base;
if (phase < 15) {
P3 |= (1 << 0);
} else if (phase < 30) {
P3 &= ~(1 << 0);
} else {
blink_base = t;
}
}
void main(void) {
clock_init();
timer0_init();
cmp_init();
// Configure P3.0 (LED) as push-pull output
// P3.0 bit = 0x01
P3_MOD_OC &= ~(1 << 0); // push-pull
P3_DIR_PU |= (1 << 0); // enable strong output drive
P3 &= ~(1 << 0); // Make LED pin P3.0 "start" as OFF
while (1) {
EA = 0;
t = tick_10ms;
EA = 1;
if(t - comparatorTime > 10){
comparatorTime= t;
if (CMPO) { // CMP0 does not latch and does not generate interrupts, it is just a mirror of the analog comparator
if (!ledON) {
ledON = 1;
blink_base = t; // reset blink phase when comparator first triggers
}
} else {
ledON = 0;
P3 &= ~(1 << 0); // make sure LED goes off immediately when pot drops below reference
}
}
if (ledON) {
blink_led(t); // called every loop iteration while CMPO is high
}
}
}
Compilando e testando
Salve o arquivo acima como “analog-comparator.c”. Abra o terminal de comando do Windows “CMD” e entre na pasta onde está o seu arquivo “analog-comparator.c”. No meu caso fiz assim:
cd Documents\ch552
Agora vamos compilar e gravar o microcontrolador. Para isso eu criei (com ajuda da inteligência artificial) um arquivo em Python, disponível aqui, chamado “build_flash.py”. Ele precisa estar na mesma pasta onde está o arquivo fonte “analog-comparator.c”.
Digite o comando abaixo e pressione ENTER. Ainda não conecte a placa na porta USB do computador. Obs: o Python precisa estar instalado na sua máquina, e adicionado ao PATH.
python build_flash.py analog-comparator.c
Em poucos segundo a mensagem
Put the CH552 into BOOT mode (hold BOOT, plug USB, release).
Press ENTER when ready…
vai aparecer, neste momento pressione (e segure) o botão BOOT da sua placa CH552. Conecte a USB ao computador e só então solte o botão BOOT. Pressione ENTER. A gravação ocorreu com sucesso se a mensagem abaixo apareceu:
Build + Flash completed successfully!
Eu fiz um vídeo para ilustra o funcionamento deste código, está lá em cima no começo do artigo. Caso tenha dúvida pode comentar abaixo ou então lá no Youtube do FritzenLab. Nos vemos na próxima, até logo.




