/*
Monitor colorido mais simples do mundo
(use a roda do mouse para diminuir o zoom e ver o monitor inteiro)
*/
#define DATA PD4
#define LATCH PD7
#define CLOCK PB0
#define VERMELHO 1
#define VERDE 2
#define AZUL 3
#define AMARELO 4
#define CIANO 5
#define MAGENTA 6
#define BRANCO 7
const uint8_t linhas = 5; //quantidade de linhas
const uint8_t colunas = 32; //quantidade de colunas
const uint8_t quantidadeLEDs = linhas*colunas; // quantidade de LEDS
byte framebuffer[quantidadeLEDs]; // array de byte para funcionar como framebuffer para rasterização
byte memvideo[quantidadeLEDs]; // array de byte para funcionar como memória de vídeo
unsigned long counter = 0;
int dec = 31;
int dec2 = 31;
int passo = 1;
int main() {
// configurando as portas B e D setando pinos em OUTPUT
DDRB |= B00111111;
DDRD |= B11111100;
// limpando registrador TCCR1A
TCCR1A = 0;
// colocando o timer no modo CTC (Clear Timer on Compare-match)
TCCR1B &= ~(B00000001 << WGM13);
TCCR1B |= (B00000001 << WGM12);
// setando prescaler do timer para 64 (16 mHz / 64 = 250 kHz)
TCCR1B &= ~(B00000001 << CS12);
TCCR1B |= (B00000001 << CS11);
TCCR1B |= (B00000001 << CS10);
TCNT1 = 0;
OCR1A = 2500; // um centésimo de 250 mil para o Compare-match
TIMSK1 = (1 << OCIE1A);
asm( "sei \n"); // habilitando interrupções com inline assembly
PintaTela(VERMELHO);
while(true){ // substituto do loop() vazio
}
}
ISR(TIMER1_COMPA_vect){ // Rotina de Serviço de Interrupção (ISR) do Timer
counter++;
Condicionais();
Rasterizar();
}
void Condicionais(){
if(passo == 1){
PintaMemVideo(AZUL);
EscreveLetraMemoria('D', 1, AMARELO);
EscreveLetraMemoria('A', 7, AMARELO);
EscreveLetraMemoria('N', 13, AMARELO);
EscreveLetraMemoria('T', 19, AMARELO);
EscreveLetraMemoria('E', 25, AMARELO);
if(dec >=0){
if((counter % 15)==0){
CopiaFramebufferDaMemoria(dec);
dec = dec-1;
}
}else{
if( (counter % 600) == 0){
PintaTela(VERDE);
dec2= 31;
passo = 2;
}
}
}
if(passo == 2){
PintaMemVideo(BRANCO);
EscreveLetraMemoria('M', 2, VERMELHO);
EscreveLetraMemoria('E', 9, VERMELHO);
EscreveLetraMemoria('I', 13, VERMELHO);
EscreveLetraMemoria('R', 18, VERMELHO);
EscreveLetraMemoria('A', 24, VERMELHO);
if(dec2 >=0){
if((counter % 15)==0){
CopiaFramebufferDaMemoria(dec2);
dec2 = dec2-1;
}
}
}
}
void ApagaTudo(){
for (int i = quantidadeLEDs-1; i >= 0; i--) {
framebuffer[i] = 0;
}
}
void PintaTela(byte cor){
for (int i = quantidadeLEDs-1; i >= 0; i--) {
framebuffer[i] = cor;
}
}
void PintaMemVideo(byte cor){
for (int i = quantidadeLEDs-1; i >= 0; i--) {
memvideo[i] = cor;
}
}
void CopiaFramebufferDaMemoria(uint8_t colInicio){
int resto;
for (int i = quantidadeLEDs - 1; i >= 0; i--) {
resto = i % colunas;
if(resto >= colInicio){ framebuffer[i] = memvideo[i-colInicio]; }
}
}
void EscreveLetraMemoria(char letra, uint8_t pos, byte cor){
if(letra == 'A'){
for(int i = pos+1; i < pos+4; i++){
memvideo[i] = cor;
}
memvideo[pos+32] = cor;
memvideo[pos+36] = cor;
for(int i = pos+64; i < pos+69; i++){
memvideo[i] = cor;
}
memvideo[pos+96] = cor;
memvideo[pos+100] = cor;
memvideo[pos+128] = cor;
memvideo[pos+132] = cor;
}
if(letra == 'D'){
for(int i = pos; i < pos+4; i++){
memvideo[i] = cor;
}
memvideo[pos+33] = cor;
memvideo[pos+36] = cor;
memvideo[pos+65] = cor;
memvideo[pos+68] = cor;
memvideo[pos+97] = cor;
memvideo[pos+100] = cor;
for(int i = pos+128; i < pos+132; i++){
memvideo[i] = cor;
}
}
if(letra == 'E'){
for(int i = pos; i < pos+4; i++){
memvideo[i] = cor;
}
memvideo[pos+32] = cor;
for(int i = pos+64; i < pos+68; i++){
memvideo[i] = cor;
}
memvideo[pos+96] = cor;
for(int i = pos+128; i < pos+132; i++){
memvideo[i] = cor;
}
}
if(letra == 'I'){
memvideo[pos+2] = cor;
memvideo[pos+34] = cor;
memvideo[pos+66] = cor;
memvideo[pos+98] = cor;
memvideo[pos+130] = cor;
}
if(letra == 'M'){
for(int i = pos; i < pos+129; i = i+32){
memvideo[i] = cor;
}
for(int i = pos+4; i < pos+133; i = i+32){
memvideo[i] = cor;
}
memvideo[pos+33] = cor;
memvideo[pos+66] = cor;
memvideo[pos+35] = cor;
}
if(letra == 'N'){
for(int i = pos; i < pos+129; i = i+32){
memvideo[i] = cor;
}
for(int i = pos+4; i < pos+133; i = i+32){
memvideo[i] = cor;
}
memvideo[pos+33] = cor;
memvideo[pos+66] = cor;
memvideo[pos+99] = cor;
}
if(letra == 'P'){
memvideo[pos] = cor;
memvideo[pos+1] = cor;
memvideo[pos+2] = cor;
memvideo[pos+3] = cor;
memvideo[pos+36] = cor;
memvideo[pos+32] = cor;
memvideo[pos+64] = cor;
memvideo[pos+65] = cor;
memvideo[pos+66] = cor;
memvideo[pos+67] = cor;
memvideo[pos+96] = cor;
memvideo[pos+128] = cor;
}
if(letra == 'R'){
memvideo[pos] = cor;
memvideo[pos+1] = cor;
memvideo[pos+2] = cor;
memvideo[pos+3] = cor;
memvideo[pos+36] = cor;
memvideo[pos+32] = cor;
memvideo[pos+64] = cor;
memvideo[pos+65] = cor;
memvideo[pos+66] = cor;
memvideo[pos+67] = cor;
memvideo[pos+96] = cor;
memvideo[pos+98] = cor;
memvideo[pos+128] = cor;
memvideo[pos+131] = cor;
}
if(letra == 'T'){
memvideo[pos] = cor;
memvideo[pos+1] = cor;
memvideo[pos+2] = cor;
memvideo[pos+3] = cor;
memvideo[pos+4] = cor;
memvideo[pos+34] = cor;
memvideo[pos+66] = cor;
memvideo[pos+98] = cor;
memvideo[pos+130] = cor;
}
}
void Rasterizar(){
byte cor;
LatchLow();
for (int i = quantidadeLEDs-1; i >= 0; i--) {
cor = framebuffer[i];
switch(cor){
case 0:
EnviaApagado();
break;
case 1:
EnviaVermelho();
break;
case 2:
EnviaVerde();
break;
case 3:
EnviaAzul();
break;
case 4:
EnviaAmarelo();
break;
case 5:
EnviaCiano();
break;
case 6:
EnviaMagenta();
break;
case 7:
EnviaBranco();
break;
}
}
LatchHigh();
LatchLow();
}
void EnviaApagado(){
ClockLow();
DataLow();
ClockLow();
ClockHigh();
DataLow();
ClockLow();
ClockHigh();
DataLow();
ClockLow();
ClockHigh();
}
void EnviaVermelho(){
ClockLow();
DataLow(); // Azul = LOW
ClockLow();
ClockHigh();
DataLow(); // Verde = LOW
ClockLow();
ClockHigh();
DataHigh(); // Vermelho = HIGH
ClockLow();
ClockHigh();
}
void EnviaVerde(){
ClockLow();
DataLow();
ClockLow();
ClockHigh();
DataHigh();
ClockLow();
ClockHigh();
DataLow();
ClockLow();
ClockHigh();
}
void EnviaAzul(){
ClockLow();
DataHigh();
ClockLow();
ClockHigh();
DataLow();
ClockLow();
ClockHigh();
DataLow();
ClockLow();
ClockHigh();
}
void EnviaAmarelo(){
ClockLow();
DataLow();
ClockLow();
ClockHigh();
DataHigh();
ClockLow();
ClockHigh();
DataHigh();
ClockLow();
ClockHigh();
}
void EnviaCiano(){
ClockLow();
DataHigh();
ClockLow();
ClockHigh();
DataHigh();
ClockLow();
ClockHigh();
DataLow();
ClockLow();
ClockHigh();
}
void EnviaMagenta(){
ClockLow();
DataHigh();
ClockLow();
ClockHigh();
DataLow();
ClockLow();
ClockHigh();
DataHigh();
ClockLow();
ClockHigh();
}
void EnviaBranco(){
ClockLow();
DataHigh();
ClockLow();
ClockHigh();
DataHigh();
ClockLow();
ClockHigh();
DataHigh();
ClockLow();
ClockHigh();
}
void LatchLow(){
PORTD &= ~(B00000001 << LATCH); // colocando o LATCH em LOW direto no registrador PORTD
}
void LatchHigh(){
PORTD |= (B00000001 << LATCH); // colocando o LATCH em HIGH direto no registrador PORTD
}
void ClockLow(){
PORTB &= ~(B00000001 << CLOCK); // colocando o CLOCK em LOW direto no registrador PORTB
}
void ClockHigh(){
PORTB |= (B00000001 << CLOCK); // colocando o CLOCK em HIGH direto no registrador PORTB
}
void DataLow(){
PORTD &= ~(B00000001 << DATA); // colocando o DATA em LOW direto no registrador PORTD
}
void DataHigh(){
PORTD |= (B00000001 << DATA); // colocando o DATA em HIGH direto no registrador PORTD
}