Jogo de Adivinhação com LCD1602 e Matriz de Teclas - Projeto 8051

Jogo Interativo de Adivinhação de Números

Este projeto apresenta um jogo de adivinhação de números implementado utilizando o microcontrolador STC89C52RC, um display LCD1602 e uma matriz de teclas 4x4. O objetivo é implementar um sistema completo de interação com o usuário, incluindo geração de números aleatórios, leitura de entrada via matriz de teclas e exibição de informações em tempo real.

Componentes e Especificações

O projeto utiliza os seguintes recursos de hardware:

  • Microcontrolador: STC89C52RC
  • Frequência de operação: 12T a 11.0592MHz
  • Display: LCD1602 (16 colunas x 2 linhas)
  • Interface de entrada: Matriz de teclas 4x4

Descrição do Jogo

O jogadordefine uma faixa de números (entre 1 e 9999) e o sistema gera um número aleatório dentro dessa faixa. O jogador tenta adivinhar o número, e o sistema fornece dicas indicando se o número inserido é maior ou menor que o valor secreto. O jogo continua até que o jogador acerte o número, mostrando a quantidade de tentativas realizadas.

Análise de Funcionamento

1. Entrada de Dados e Limpeza

Para capturar números digitados pelo usuário, o sistema utiliza operações de deslocamento decimal e adição progressiva. Cada novo dígito é integrado ao valor total através da fórmula: valor = valor × 10 + dígito, permitindo a construção de números de até quatro dígitos.

2. Geração de Números Aleatórios

O sistema gera números aleatórios dentro da faixa definida pelo usuário (1 a 9999). Para melhorar a aleatoriedade, são utilizados múltiplos componentes do temporizador como semente, incluindo valores dos registradores TH0 e TL0 em combinação com operações matemáticas. Embora ainda seja um gerador pseudoaleatório, esta abordagem produz resultados suficientemente imprevisíveis para o propósito do jogo.

3. Limitações de Faixa

Devido às dimensões do display LCD1602, a faixa de números foi limitada a 1-9999 (máximo de 4 dígitos). Ao definir os limites, o sistema verifica se a diferença entre máximo e mínimo é de pelo menos 2 unidades, garantindo uma faixa válida para o jogo.

4. Detecção de Teclas

A matriz de teclas é explorada através de varredura行列 (linha-coluna). O temporizador 0 é configurado para verificar o estado das teclas a cada 20ms, evitando bloqueios na execução do programa principal.

Implementação dos Módulos

1. Biblioteca LCD1602

O módulo de controle do display LCD1602 oferece funções para escrita de comandos, dados, posicionamento do cursor e exibição de diferentse formatos numéricos.

Arquivo de cabeçalho (lcd1602.h):

#ifndef LCD1602_H
#define LCD1602_H

void LCD_Inicializar(void);
void LCD_EscreverComando(unsigned char cmd);
void LCD_EscreverDado(unsigned char dado);
void LCD_PosicionarCursor(unsigned char linha, unsigned char coluna);
void LCD_ExibirCaractere(unsigned char linha, unsigned char coluna, char caractere);
void LCD_ExibirTexto(unsigned char linha, unsigned char coluna, char *texto);
void LCD_ExibirNumero(unsigned char linha, unsigned char coluna, unsigned int valor, unsigned char digitos);
void LCD_ExibirNumeroSigned(unsigned char linha, unsigned char coluna, int valor, unsigned char digitos);
void LCD_ExibirHex(unsigned char linha, unsigned char coluna, unsigned int valor, unsigned char digitos);
void LCD_ExibirBinario(unsigned char linha, unsigned char coluna, unsigned int valor, unsigned char digitos);
void LCD_Limpar(void);
void LCD_ControlarCursor(unsigned char estado);
void LCD_ExibirTexto16(unsigned char linha, unsigned char coluna, char *texto);

#endif

Arquivo de implementação (lcd1602.c):

#include <REGX52.H>

/* Configuração de pinos */
sbit LCD_RS = P2^6;
sbit LCD_RW = P2^5;
sbit LCD_EN = P2^7;
#define LCD_PORTA_DADOS P0

/* Função de atraso - aproximadamente 50μs */
void Atraso50us(void)
{
    unsigned char contador;
    contador = 20;
    while(--contador);
}

/* Função de atraso - aproximadamente 2ms */
void Atraso2ms(void)
{
    unsigned char i, j;
    i = 4;
    j = 146;
    do {
        while(--j);
    } while(--i);
}

/* Escreve comando no LCD */
void LCD_EscreverComando(unsigned char cmd)
{
    LCD_RS = 0;
    LCD_RW = 0;
    LCD_PORTA_DADOS = cmd;
    LCD_EN = 1;
    Atraso50us();
    LCD_EN = 0;
    Atraso50us();
}

/* Escreve dado no LCD */
void LCD_EscreverDado(unsigned char dado)
{
    LCD_RS = 1;
    LCD_RW = 0;
    LCD_PORTA_DADOS = dado;
    LCD_EN = 1;
    Atraso50us();
    LCD_EN = 0;
    Atraso50us();
}

/* Posiciona o cursor */
void LCD_PosicionarCursor(unsigned char linha, unsigned char coluna)
{
    if(linha == 1) {
        LCD_EscreverComando(0x80 | (coluna - 1));
    } else if(linha == 2) {
        LCD_EscreverComando(0x80 | (coluna - 1 + 0x40));
    }
}

/* Inicializa o LCD */
void LCD_Inicializar(void)
{
    LCD_EscreverComando(0x38);
    LCD_EscreverComando(0x0C);
    LCD_EscreverComando(0x06);
    LCD_EscreverComando(0x01);
    Atraso2ms();
}

/* Exibe caractere na posição especificada */
void LCD_ExibirCaractere(unsigned char linha, unsigned char coluna, char caractere)
{
    LCD_PosicionarCursor(linha, coluna);
    LCD_EscreverDado(caractere);
}

/* Exibe string a partir da posição especificada */
void LCD_ExibirTexto(unsigned char linha, unsigned char coluna, char *texto)
{
    unsigned char indice;
    LCD_PosicionarCursor(linha, coluna);
    for(indice = 0; texto[indice] != '\0'; indice++) {
        LCD_EscreverDado(texto[indice]);
    }
}

/* Calcula potência de X elevado a Y */
unsigned int Potencia(unsigned int X, unsigned char Y)
{
    unsigned char i;
    unsigned int resultado = 1;
    for(i = 0; i < Y; i++) {
        resultado *= X;
    }
    return resultado;
}

/* Exibe número sem sinal */
void LCD_ExibirNumero(unsigned char linha, unsigned char coluna, unsigned int valor, unsigned char digitos)
{
    unsigned char i;
    LCD_PosicionarCursor(linha, coluna);
    for(i = digitos; i > 0; i--) {
        LCD_EscreverDado(valor / Potencia(10, i-1) % 10 + '0');
    }
}

/* Exibe número com sinal */
void LCD_ExibirNumeroSigned(unsigned char linha, unsigned char coluna, int valor, unsigned char digitos)
{
    unsigned char i;
    unsigned int valorAbs;
    LCD_PosicionarCursor(linha, coluna);
    if(valor >= 0) {
        LCD_EscreverDado('+');
        valorAbs = valor;
    } else {
        LCD_EscreverDado('-');
        valorAbs = -valor;
    }
    for(i = digitos; i > 0; i--) {
        LCD_EscreverDado(valorAbs / Potencia(10, i-1) % 10 + '0');
    }
}

/* Exibe número em hexadecimal */
void LCD_ExibirHex(unsigned char linha, unsigned char coluna, unsigned int valor, unsigned char digitos)
{
    unsigned char i, digito;
    LCD_PosicionarCursor(linha, coluna);
    for(i = digitos; i > 0; i--) {
        digito = valor / Potencia(16, i-1) % 16;
        if(digito < 10) {
            LCD_EscreverDado(digito + '0');
        } else {
            LCD_EscreverDado(digito - 10 + 'A');
        }
    }
}

/* Exibe número em binário */
void LCD_ExibirBinario(unsigned char linha, unsigned char coluna, unsigned int valor, unsigned char digitos)
{
    unsigned char i;
    LCD_PosicionarCursor(linha, coluna);
    for(i = digitos; i > 0; i--) {
        LCD_EscreverDado(valor / Potencia(2, i-1) % 2 + '0');
    }
}

/* Limpa o display */
void LCD_Limpar(void)
{
    LCD_EscreverComando(0x01);
    Atraso2ms();
}

/* Controla visibilidade do cursor */
void LCD_ControlarCursor(unsigned char estado)
{
    if(estado) {
        LCD_EscreverComando(0x0E);
    } else {
        LCD_EscreverComando(0x0C);
    }
}

2. Módulo de Matriz de Teclas

A biblioteca de varredura da matriz de teclas oferece detecção de pressão, liberação e pressão contínua.

Arquivo de cabeçalho (matriz_telas.h):

#ifndef MATRIZ_TECLAS_H
#define MATRIZ_TECLAS_H

unsigned char Matriz_Teclas_Ler(void);
void Matriz_Teclas_Atualizar(void);

#endif

Arquivo de implementação (matriz_teclas.c):

#include <REGX52.H>

#define PORTA_MATRIZ P1

unsigned char CodigoTecla;

/* Obtém código da tecla pressionada */
unsigned char Matriz_Teclas_Ler(void)
{
    unsigned char temp = CodigoTecla;
    CodigoTecla = 0;
    return temp;
}

/* Captura estado atual das teclas */
unsigned char Tecla_EstadoAtual(void)
{
    unsigned char valor = 0;
    unsigned char i = 0;
    
    PORTA_MATRIZ = 0x0F;
    i = 2;
    while(i--);
    
    if(PORTA_MATRIZ != 0x0F) {
        PORTA_MATRIZ = 0x0F;
        i = 2;
        while(i--);
        switch(PORTA_MATRIZ) {
            case 0x07: valor = 1; break;
            case 0x0B: valor = 2; break;
            case 0x0D: valor = 3; break;
            case 0x0E: valor = 4; break;
            default: break;
        }
        
        PORTA_MATRIZ = 0xF0;
        i = 2;
        while(i--);
        switch(PORTA_MATRIZ) {
            case 0x70: valor = valor; break;
            case 0xB0: valor = valor + 4; break;
            case 0xD0: valor = valor + 8; break;
            case 0xE0: valor = valor + 12; break;
            default: break;
        }
    } else {
        valor = 0;
    }
    return valor;
}

/* Função de tratamento chamada por interrupção */
void Matriz_Teclas_Atualizar(void)
{
    static unsigned char EstadoAtual, EstadoAnterior;
    static unsigned int ContadorPressao;
    
    EstadoAnterior = EstadoAtual;
    EstadoAtual = Tecla_EstadoAtual();
    
    /* Detecção de pressão */
    if(EstadoAnterior == 0) {
        switch(EstadoAtual) {
            case 1: CodigoTecla = 1; break;
            case 2: CodigoTecla = 2; break;
            case 3: CodigoTecla = 3; break;
            case 4: CodigoTecla = 4; break;
            case 5: CodigoTecla = 5; break;
            case 6: CodigoTecla = 6; break;
            case 7: CodigoTecla = 7; break;
            case 8: CodigoTecla = 8; break;
            case 9: CodigoTecla = 9; break;
            case 10: CodigoTecla = 10; break;
            case 11: CodigoTecla = 11; break;
            case 12: CodigoTecla = 12; break;
            case 13: CodigoTecla = 13; break;
            case 14: CodigoTecla = 14; break;
            case 15: CodigoTecla = 15; break;
            case 16: CodigoTecla = 16; break;
            default: break;
        }
    }
    
    /* Detecção de pressão contínua (longa) */
    if(EstadoAnterior && EstadoAtual) {
        ContadorPressao++;
        
        if(ContadorPressao % 50 == 0) {
            if(EstadoAnterior == 1 && EstadoAtual == 1) CodigoTecla = 17;
            else if(EstadoAnterior == 2 && EstadoAtual == 2) CodigoTecla = 18;
            else if(EstadoAnterior == 3 && EstadoAtual == 3) CodigoTecla = 19;
            else if(EstadoAnterior == 4 && EstadoAtual == 4) CodigoTecla = 20;
            else if(EstadoAnterior == 5 && EstadoAtual == 5) CodigoTecla = 21;
            else if(EstadoAnterior == 6 && EstadoAtual == 6) CodigoTecla = 22;
            else if(EstadoAnterior == 7 && EstadoAtual == 7) CodigoTecla = 23;
            else if(EstadoAnterior == 8 && EstadoAtual == 8) CodigoTecla = 24;
            else if(EstadoAnterior == 9 && EstadoAtual == 9) CodigoTecla = 25;
            else if(EstadoAnterior == 10 && EstadoAtual == 10) CodigoTecla = 26;
            else if(EstadoAnterior == 11 && EstadoAtual == 11) CodigoTecla = 27;
            else if(EstadoAnterior == 12 && EstadoAtual == 12) CodigoTecla = 28;
            else if(EstadoAnterior == 13 && EstadoAtual == 13) CodigoTecla = 29;
            else if(EstadoAnterior == 14 && EstadoAtual == 14) CodigoTecla = 30;
            else if(EstadoAnterior == 15 && EstadoAtual == 15) CodigoTecla = 31;
            else if(EstadoAnterior == 16 && EstadoAtual == 16) CodigoTecla = 32;
        }
    } else {
        ContadorPressao = 0;
    }
    
    /* Detecção de liberação */
    if(EstadoAtual == 0) {
        switch(EstadoAnterior) {
            case 1: CodigoTecla = 33; break;
            case 2: CodigoTecla = 34; break;
            case 3: CodigoTecla = 35; break;
            case 4: CodigoTecla = 36; break;
            case 5: CodigoTecla = 37; break;
            case 6: CodigoTecla = 38; break;
            case 7: CodigoTecla = 39; break;
            case 8: CodigoTecla = 40; break;
            case 9: CodigoTecla = 41; break;
            case 10: CodigoTecla = 42; break;
            case 11: CodigoTecla = 43; break;
            case 12: CodigoTecla = 44; break;
            case 13: CodigoTecla = 45; break;
            case 14: CodigoTecla = 46; break;
            case 15: CodigoTecla = 47; break;
            case 16: CodigoTecla = 48; break;
            default: break;
        }
    }
}

3. Módulo de Temporizador

Configuração do temporizador 0 para geração de interrupções periódicas.

Arquivo de cabeçalho (temporizador0.h):

#ifndef TEMPORIZADOR0_H
#define TEMPORIZADOR0_H

void Temporizador0_Iniciar(void);

#endif

Arquivo de implementação (temporizador0.c):

#include <REGX52.H>

/* Inicializa temporizador 0 para interrupção a cada 10ms */
void Temporizador0_Iniciar(void)
{
    TMOD &= 0xF0;
    TMOD |= 0x01;
    TL0 = 0x00;
    TH0 = 0xDC;
    TF0 = 0;
    TR0 = 1;
    ET0 = 1;
    EA = 1;
    PT0 = 0;
}

4. Programa Principal

O código principal implementa a lógica completa do jogo, incluindo controle de estados, entrada do usuário e feedback visual.

#include <REGX52.H>
#include "lcd1602.h"
#include "matriz_telas.h"
#include "temporizador0.h"
#include <STDLIB.H>

unsigned char TeclaRecebida;
unsigned char EstadoJogo;
unsigned char ExecucaoUnica = 1;
unsigned char DigitosEntrada;
unsigned char UltimosDigitos;
bit FlagConfirmacao;
unsigned char DigitoAtual;
bit FlagConfigMin;
bit FlagConfigMax;
unsigned int ValorMinimo;
unsigned int ValorMaximo;
unsigned char DigitosMin;
unsigned char DigitosMax;
bit FlagVerificacao;
bit FlagReentrada;
unsigned int NumeroJogador;
unsigned char DigitosJogador;
unsigned int NumeroSorteado;
unsigned char DigitosSorteado;
unsigned int Tentativas;
unsigned char DigitosTentativas;

/* Função de atraso em milissegundos */
void Atraso(unsigned int ms)
{
    unsigned char i, j;
    while(ms--) {
        i = 2;
        j = 199;
        do {
            while(--j);
        } while(--i);
    }
}

/* Função principal */
void main()
{
    Temporizador0_Iniciar();
    LCD_Inicializar();
    
    while(1) {
        TeclaRecebida = Matriz_Teclas_Ler();
        
        if(TeclaRecebida) {
            if(EstadoJogo == 0) {
                if(TeclaRecebida >= 33 && TeclaRecebida <= 48) {
                    EstadoJogo = 1;
                    ExecucaoUnica = 1;
                }
            } else if(EstadoJogo == 1) {
                if(TeclaRecebida >= 33 && TeclaRecebida <= 42) {
                    if(DigitosEntrada < 4) {
                        if(DigitosEntrada != 0 || TeclaRecebida != 42) {
                            DigitoAtual = (TeclaRecebida - 32) % 10;
                            DigitosEntrada++;
                        }
                    }
                }
                if(TeclaRecebida == 27) {
                    ExecucaoUnica = 1;
                }
                if(TeclaRecebida == 43) {
                    FlagReentrada = 1;
                }
                if(TeclaRecebida == 44) {
                    if(DigitosEntrada) FlagConfirmacao = 1;
                }
            } else if(EstadoJogo == 2) {
                if(TeclaRecebida >= 33 && TeclaRecebida <= 42) {
                    if(DigitosEntrada < 4) {
                        if(DigitosEntrada != 0 || TeclaRecebida != 42) {
                            DigitoAtual = (TeclaRecebida - 32) % 10;
                            DigitosEntrada++;
                        }
                    }
                }
                if(TeclaRecebida == 27) {
                    EstadoJogo = 1;
                    ExecucaoUnica = 1;
                }
                if(TeclaRecebida == 43) {
                    FlagReentrada = 1;
                }
                if(TeclaRecebida == 44) {
                    if(DigitosEntrada) FlagConfirmacao = 1;
                }
            } else if(EstadoJogo == 3) {
                if(TeclaRecebida == 43) {
                    EstadoJogo = 1;
                    ExecucaoUnica = 1;
                }
            }
        }
        
        /* Estado 0: Tela inicial */
        if(EstadoJogo == 0) {
            if(ExecucaoUnica) {
                ExecucaoUnica = 0;
                LCD_Limpar();
                LCD_ExibirTexto(1, 3, "Guess Number");
            }
        }
        
        /* Estado 1: Configuração de faixa */
        else if(EstadoJogo == 1) {
            if(ExecucaoUnica) {
                ExecucaoUnica = 0;
                UltimosDigitos = 0;
                DigitosEntrada = 0;
                FlagConfirmacao = 0;
                FlagVerificacao = 0;
                FlagReentrada = 0;
                FlagConfigMin = 1;
                FlagConfigMax = 0;
                ValorMinimo = 0;
                ValorMaximo = 0;
                DigitosMin = 0;
                DigitosMax = 0;
                Tentativas = 0;
                LCD_Limpar();
                LCD_ExibirTexto(1, 1, "Set Range");
                LCD_ExibirTexto(2, 1, "Min:");
                LCD_ExibirTexto(2, 9, "Max:");
                LCD_PosicionarCursor(2, 5);
                LCD_ControlarCursor(1);
            }
            
            if(UltimosDigitos != DigitosEntrada) {
                UltimosDigitos = DigitosEntrada;
                if(FlagConfigMax) {
                    LCD_ExibirNumero(2, 12 + DigitosEntrada, DigitoAtual, 1);
                    ValorMaximo *= 10;
                    ValorMaximo += DigitoAtual;
                    DigitosMax++;
                }
                if(FlagConfigMin) {
                    LCD_ExibirNumero(2, 4 + DigitosEntrada, DigitoAtual, 1);
                    ValorMinimo *= 10;
                    ValorMinimo += DigitoAtual;
                    DigitosMin++;
                }
            }
            
            if(FlagConfirmacao || DigitosEntrada == 4) {
                if(FlagConfigMax) {
                    FlagConfigMax = 0;
                    FlagConfirmacao = 0;
                    UltimosDigitos = 0;
                    DigitosEntrada = 0;
                    FlagVerificacao = 1;
                }
                if(FlagConfigMin) {
                    FlagConfigMin = 0;
                    FlagConfirmacao = 0;
                    UltimosDigitos = 0;
                    DigitosEntrada = 0;
                    LCD_PosicionarCursor(2, 13);
                    FlagConfigMax = 1;
                }
            }
            
            if(FlagVerificacao) {
                FlagVerificacao = 0;
                if(ValorMinimo + 1 < ValorMaximo) {
                    EstadoJogo = 2;
                    ExecucaoUnica = 1;
                } else {
                    ExecucaoUnica = 1;
                    LCD_ExibirTexto(1, 14, "ERR");
                    Atraso(1000);
                }
            }
            
            if(FlagReentrada) {
                FlagReentrada = 0;
                if(FlagConfigMin) {
                    UltimosDigitos = 0;
                    DigitosEntrada = 0;
                    ValorMinimo = 0;
                    DigitosMin = 0;
                    LCD_ExibirTexto(2, 5, "    ");
                    LCD_PosicionarCursor(2, 5);
                }
                if(FlagConfigMax) {
                    UltimosDigitos = 0;
                    DigitosEntrada = 0;
                    ValorMaximo = 0;
                    DigitosMax = 0;
                    LCD_ExibirTexto(2, 13, "    ");
                    LCD_PosicionarCursor(2, 13);
                }
            }
        }
        
        /* Estado 2: Jogo em andamento */
        else if(EstadoJogo == 2) {
            if(ExecucaoUnica) {
                ExecucaoUnica = 0;
                UltimosDigitos = 0;
                DigitosEntrada = 0;
                FlagConfirmacao = 0;
                srand(TL0);
                NumeroSorteado = ((rand() + TH0 * TL0 + TL0 / TH0) * (TH0 - TL0) % (ValorMaximo - ValorMinimo - 1) + ValorMinimo + 1);
                LCD_Limpar();
                LCD_ExibirTexto(1, 1, "Range:");
                LCD_ExibirNumero(1, 8, ValorMinimo, DigitosMin);
                LCD_ExibirCaractere(1, 8 + DigitosMin, '~');
                LCD_ExibirNumero(1, 9 + DigitosMin, ValorMaximo, DigitosMax);
                LCD_PosicionarCursor(2, 1);
            }
            
            if(UltimosDigitos != DigitosEntrada) {
                UltimosDigitos = DigitosEntrada;
                LCD_ExibirNumero(2, DigitosEntrada, DigitoAtual, 1);
                NumeroJogador *= 10;
                NumeroJogador += DigitoAtual;
                DigitosJogador++;
            }
            
            if(FlagConfirmacao || DigitosEntrada == 4) {
                FlagConfirmacao = 0;
                UltimosDigitos = 0;
                DigitosEntrada = 0;
                Tentativas++;
                
                if(NumeroJogador == NumeroSorteado) {
                    EstadoJogo = 3;
                    ExecucaoUnica = 1;
                } else if(NumeroJogador < NumeroSorteado && NumeroJogador > ValorMinimo) {
                    ValorMinimo = NumeroJogador;
                    DigitosMin = DigitosJogador;
                } else if(NumeroJogador > NumeroSorteado && NumeroJogador < ValorMaximo) {
                    ValorMaximo = NumeroJogador;
                    DigitosMax = DigitosJogador;
                } else {
                    Tentativas--;
                    LCD_ExibirTexto(2, 14, "ERR");
                    Atraso(1000);
                    LCD_ExibirTexto(2, 14, "   ");
                }
                
                NumeroJogador = 0;
                DigitosJogador = 0;
                
                LCD_ExibirTexto(1, 8, "         ");
                LCD_ExibirNumero(1, 8, ValorMinimo, DigitosMin);
                LCD_ExibirCaractere(1, 8 + DigitosMin, '~');
                LCD_ExibirNumero(1, 9 + DigitosMin, ValorMaximo, DigitosMax);
                LCD_PosicionarCursor(2, 1);
                
                UltimosDigitos = 0;
                DigitosEntrada = 0;
                LCD_ExibirTexto(2, 1, "    ");
                LCD_PosicionarCursor(2, 1);
            }
            
            if(FlagReentrada) {
                FlagReentrada = 0;
                UltimosDigitos = 0;
                DigitosEntrada = 0;
                NumeroJogador = 0;
                DigitosJogador = 0;
                LCD_ExibirTexto(2, 1, "    ");
                LCD_PosicionarCursor(2, 1);
            }
        }
        
        /* Estado 3: Vitória */
        else if(EstadoJogo == 3) {
            if(ExecucaoUnica) {
                ExecucaoUnica = 0;
                LCD_Limpar();
                LCD_ExibirTexto(1, 1, "Yes!");
                LCD_ExibirTexto(1, 6, "Number:");
                if(NumeroSorteado / 1000) DigitosSorteado = 4;
                else if(NumeroSorteado / 100) DigitosSorteado = 3;
                else if(NumeroSorteado / 10) DigitosSorteado = 2;
                else DigitosSorteado = 1;
                LCD_ExibirNumero(1, 13, NumeroSorteado, DigitosSorteado);
                LCD_ExibirTexto(2, 1, "Times:");
                if(Tentativas / 1000) DigitosTentativas = 4;
                else if(Tentativas / 100) DigitosTentativas = 3;
                else if(Tentativas / 10) DigitosTentativas = 2;
                else DigitosTentativas = 1;
                LCD_ExibirNumero(2, 7, Tentativas, DigitosTentativas);
                LCD_ControlarCursor(0);
            }
        }
    }
}

/* Rotina de interrupção do temporizador 0 */
void Temporizador0_Tratamento() interrupt 1
{
    static unsigned char ContadorT0;
    TL0 = 0x00;
    TH0 = 0xDC;
    ContadorT0++;
    if(ContadorT0 >= 2) {
        ContadorT0 = 0;
        Matriz_Teclas_Atualizar();
    }
}

Controles do Jogo

S1-S9 Dígitos 1-9
S10 Dígito 0
S11 Limpar/Retornar
S12 Confirmar

Observações Finais

A implementação atual utiliza uma abordagem pseudoaleatória baseada em registradores do temporizador. Para aplicações que exigem maior aleatoriedade, considere a adição de fontes de entropia externas ou algoritmos de randomização mais sofisticados. O sistema de detecção de teclas implementa múltiplos estados (pressão, liberação, pressão contínua), proporcionando uma experiência de usuário rica e responsiva.

Tags: 8051 STC89C52RC LCD1602 matriz-teclas Microcontrolador

Publicado em 7-16 09:49