// O monitor mais simples do mundo, by DANTE MEIRA
// (World's simplest monitor)
// Sem bibliotecas, sem "drivers", uma saída de "vídeo" feita bit a bit.
// Programado em C puro, sem as funções da biblioteca do Arduino como
// setup(), loop() e digitalWrite(). Timer e portas de saída configurados
// diretamente nos registradores do ATmega328. O "monitor" é controlado por
// sete registradores de deslocamento (shift registers), um para cada linha.
#define ACESO true
#define APAGADO false
#define NUM_REGISTRADORES_DE_DESLOCAMENTO 7 // se mudar o número de shift registers basta mudar aqui
const uint8_t quantidadeLEDs = NUM_REGISTRADORES_DE_DESLOCAMENTO * 8; // LEDS = registers vezes 8
bool framebuffer[quantidadeLEDs]; // array de boolean para funcionar como "memória de vídeo" (um framebuffer)
const int DATA_PIN = PD2; // conecta ao pino DS
const int CLOCK_PIN = PD3; // conecta ao pino SHCP
const int LATCH_PIN = PD4; // conecta ao pino STCP
unsigned long counter = 0;
int main() {
DDRD |= (B00000001 << DATA_PIN); // colocando DATA_PIN em modo OUTPUT direto no registrador DDRD
DDRD |= (B00000001 << CLOCK_PIN); // colocando CLOCK_PIN em modo OUTPUT direto no registrador DDRD
DDRD |= (B00000001 << LATCH_PIN); // colocando CLOCK_PIN em modo OUTPUT direto no registrador DDRD
TCCR1A = 0;
// colocando o timer no modo CTC (Clear Timer on Compare-match)
TCCR1B &= ~(1 << WGM13);
TCCR1B |= (B00000001 << WGM12);
// setando prescaler do timer para 64 (16 mHz / 64 = 250 kHz)
TCCR1B &= ~(1 << CS12);
TCCR1B |= (1 << CS11);
TCCR1B |= (1 << CS10);
TCNT1 = 0;
OCR1A = 2500; // um centésimo de 250 mil para o Compare-match
TIMSK1 = (1 << OCIE1A);
sei(); // habilita interrupções
while(true){ // substituto do loop() vazio
}
}
ISR(TIMER1_COMPA_vect){ // Rotina de Serviço de Interrupção (ISR) do Timer
counter++;
Condicionais();
Rasterizar();
}
void Rasterizar() {
PORTD &= ~(B00000001 << LATCH_PIN); // colocando o LATCH em LOW direto no registrador PORTD
for (int i = quantidadeLEDs - 1; i >= 0; i--) {
PORTD &= ~(B00000001 << CLOCK_PIN); // colocando o CLOCK em LOW direto no registrador PORTD
if(framebuffer[i]){ // se true (aceso)
PORTD |= (B00000001 << DATA_PIN); // colocando o DATA PIN em HIGH direto no registrador PORTD
}else{ // se false (apagado)
PORTD &= ~(B00000001 << DATA_PIN); // colocando o DATA PIN em LOW direto no registrador PORTD
}
PORTD |= (B00000001 << CLOCK_PIN); // colocando o CLOCK em HIGH direto no registrador PORTD
}
PORTD |= (B00000001 << LATCH_PIN); // colocando o LATCH em HIGH direto no registrador PORTD
}
void AcendeTudo(){
for (int i = quantidadeLEDs - 1; i >= 0; i--) {
framebuffer[i] = ACESO;
}
}
void ApagaTudo() {
for (int i = quantidadeLEDs - 1; i >= 0; i--) {
framebuffer[i] = APAGADO;
}
}
void mudaPixel(int index, int value) {
framebuffer[index] = value;
}
void Condicionais(){
if(counter == 50){
EscreveLetra('D');
}
if(counter == 80){
ApagaTudo() ;
}
if(counter == 110){
EscreveLetra('D');
}
if(counter == 140){
ApagaTudo() ;
}
if(counter == 170){
EscreveLetra('D');
}
if(counter == 270){
ApagaTudo() ;
}
if(counter == 350){
EscreveLetra('A');
}
if(counter == 380){
ApagaTudo() ;
}
if(counter == 410){
EscreveLetra('A');
}
if(counter == 440){
ApagaTudo() ;
}
if(counter == 470){
EscreveLetra('A');
}
if(counter == 570){
ApagaTudo() ;
}
if(counter == 640){
EscreveLetra('N');
}
if(counter == 670){
ApagaTudo() ;
}
if(counter == 700){
EscreveLetra('N');
}
if(counter == 730){
ApagaTudo() ;
}
if(counter == 760){
EscreveLetra('N');
}
if(counter == 860){
ApagaTudo() ;
}
if(counter == 930){
EscreveLetra('T');
}
if(counter == 960){
ApagaTudo() ;
}
if(counter == 990){
EscreveLetra('T');
}
if(counter == 1020){
ApagaTudo() ;
}
if(counter == 1050){
EscreveLetra('T');
}
if(counter == 1150){
ApagaTudo() ;
}
if(counter == 1220){
EscreveLetra('E');
}
if(counter == 1250){
ApagaTudo() ;
}
if(counter == 1280){
EscreveLetra('E');
}
if(counter == 1310){
ApagaTudo() ;
}
if(counter == 1340){
EscreveLetra('E');
}
if(counter == 1540){
ApagaTudo() ;
}
if(counter == 1600){
EscreveLetra('D');
}
if(counter == 1650){
ApagaTudo() ;
EscreveLetra('A');
}
if(counter == 1700){
ApagaTudo() ;
EscreveLetra('N');
}
if(counter == 1750){
ApagaTudo() ;
EscreveLetra('T');
}
if(counter == 1800){
ApagaTudo() ;
EscreveLetra('E');
}
if(counter == 1900){
ApagaTudo() ;
}
if(counter == 2000){
counter = 0;
}
}
void EscreveLetra(char letra){
if(letra == 'A'){
for(byte n = 10; n <= 13; n++){
mudaPixel(n, ACESO);
}
for(byte n = 26; n <= 29; n++){
mudaPixel(n, ACESO);
}
mudaPixel(17, ACESO);
mudaPixel(22, ACESO);
mudaPixel(25, ACESO);
mudaPixel(30, ACESO);
mudaPixel(33, ACESO);
mudaPixel(38, ACESO);
mudaPixel(41, ACESO);
mudaPixel(46, ACESO);
}
if(letra == 'D'){
for(byte n = 9; n <= 13; n++){
mudaPixel(n, ACESO);
}
mudaPixel(19, ACESO);
mudaPixel(22, ACESO);
mudaPixel(27, ACESO);
mudaPixel(30, ACESO);
mudaPixel(35, ACESO);
mudaPixel(38, ACESO);
for(byte n = 41; n <= 45; n++){
mudaPixel(n, ACESO);
}
}
if(letra == 'E'){
for(byte n = 9; n <= 13; n++){
mudaPixel(n, ACESO);
}
mudaPixel(17, ACESO);
for(byte n = 25; n <= 29; n++){
mudaPixel(n, ACESO);
}
mudaPixel(33, ACESO);
for(byte n = 41; n <= 45; n++){
mudaPixel(n, ACESO);
}
}
if(letra == 'N'){
mudaPixel(9, ACESO);
mudaPixel(14, ACESO);
mudaPixel(17, ACESO);
mudaPixel(18, ACESO);
mudaPixel(22, ACESO);
mudaPixel(25, ACESO);
mudaPixel(27, ACESO);
mudaPixel(30, ACESO);
mudaPixel(33, ACESO);
mudaPixel(36, ACESO);
mudaPixel(38, ACESO);
mudaPixel(41, ACESO);
mudaPixel(45, ACESO);
mudaPixel(46, ACESO);
}
if(letra == 'T'){
for(byte n = 10; n <= 14; n++){
mudaPixel(n, ACESO);
}
mudaPixel(20, ACESO);
mudaPixel(28, ACESO);
mudaPixel(36, ACESO);
mudaPixel(44, ACESO);
}
}