Fala galera!
Pela foto acima dá para perceber que o problema com a área vazia foi resolvido, agora toda a área da tela é preenchida. Então a gente pode desenhar em qualquer canto (640 x 480 @ 60Hz). O problema era a função de interrução, os tempos de chamada e retorno eram altos demais no ATmega328 para o monitor, então substituí a função por um "if", checando o o valor no registrador do timer o tempo todo. Quando o timer chega a um determinado valor (31.3KHz), a condição do "if" é verdadeira e a linha é impressa. Assim o programa não desperdiça tempo chamando e retornando da função de interrupção.
Outro problema era que apenas monitores CRT entendiam o sinal. Esse problema foi resolvido ajustando o nível de tensão dos pinos RGB para o padrão de 0,7V, usando um resistor em série com um diodo, reduzindo de TTL (5V) para 0,7V, conforme imagem acima. Assim, todos os monitores estão entendendo o sinal (incluindo LCD e LED).
Com tudo resolvido, nós podemos gerar sinal VGA COLORIDO!!!
Agora vou tentar criar uma biblioteca inteligente o suficiente para desenhar figuras e letras, e talvez gerar mais cores.
Tudo usando apenas um Arduino UNO. :))
Aqui está o código que escrevi. Aproveitem! Estamos aqui para compartilhar.
https://github.com/LaboratorioDeGaragem/VGA-com-Arduino/blob/gh-pag...
Se você vai tentar usar esse código, é bom saber também:
E isso também:
Clique na imagem para ampliar
"VGA industry standard" 640x480 pixel mode
General characteristics
Clock frequency 25.175 MHz
Line frequency 31469 Hz
Field frequency 59.94 Hz
One line
8 pixels front porch
96 pixels horizontal sync
40 pixels back porch
8 pixels left border
640 pixels video
8 pixels right border
---
800 pixels total per line
One field
2 lines front porch
2 lines vertical sync
25 lines back porch
8 lines top border
480 lines video
8 lines bottom border
---
525 lines total per field
Atente-se em desligar seu sinal RGB sempre que for pulsar um de sincronia.
E fique esperto com o que o compilador faz. Muito tempo é desperdiçado em muitas situações, e os tempos não repetitivos são os mais perigosos.
Se o seu sinal não estiver em perfeita sincronia, o monitor vai rejeitar.
Use o osciloscópio para monitorar tudo!
Boa sorte e conte comigo se precisar de ajuda!
Abraço!!!
Atualização 05 novembro de 2014:
Atendendo a pedido, segue abaixo o código para gerar a imagem acima (precisa revisar, faz tempo que fiz). A matriz logoldg[25][40] é a representação da imagem pixel a pixel. Ela é obtida através do script em Python abaixo que lê a imagem BMP e transforma cada pixel nos valores para carregamento no registrador para gerar os bits RGB. A imagem tem 40x25 pixels e pode ser feita em qualquer software gráfico.
Imagem original BMP (a ser apresentada na tela):
Ela é pequena porque é o máximo que o ATmega328 consegue armazenar na flash.
#include <avr/pgmspace.h>
#define NOP asm("nop")
#define PRETO PORTB = B00000000; //0
#define AZUL PORTB = B00000001; //1
#define VERDE PORTB = B00000010; //2
#define CIANO PORTB = B00000011; //3
#define VERMELHO PORTB = B00000100; //4
#define MAGENTA PORTB = B00000101; //5
#define AMARELO PORTB = B00000110; //6
#define BRANCO PORTB = B00000111; //7
unsigned int contalinhas = 1;
void setup()
{
//Seta pinos 5, 6 e 7 como saidas
// 7 - HSYNC
// 6 - VSYNC
// 5 - RGB
DDRD |= B11100000;
DDRB |= B11100111;
PORTD |= B11000000;
//set timer
TCCR2A = 0x02; // WGM22=0 + WGM21=1 + WGM20=0 = Mode2 (CTC)
TCCR2B |= (1 CS20); //
TCCR2B |= (1 CS21); // Seta prescaler
TCCR2B &= ~(1 CS22); //
TCNT2 = 0; // limpa contador
//OCR2A = 0x03; // seta contador para comaracao
TIMSK2 &= ~(1OCIE2A); // seta interrupcao por comparacao
TIMSK2 |= (1TOIE2); // seta interrupcao por overflow
}
void loop()
{
PROGMEM byte logoldg[25][40] = { //A matriz da imagem contendo elementos hexadecimais no formato correto para o LCD
6,6,6,6,6,6,6,6,6,0,0,0,0,0,0,0,6,6,6,6,6,0,0,0,0,0,0,0,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,0,4,4,4,4,4,0,0,6,6,6,0,0,4,4,4,4,4,0,0,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,0,0,4,4,4,4,4,4,0,0,0,0,0,4,4,4,4,4,4,4,0,0,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,0,4,4,4,7,7,4,4,4,4,4,4,4,4,4,4,7,4,4,4,4,4,0,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,0,4,4,4,7,7,4,4,4,4,4,4,4,4,4,4,7,4,4,4,4,4,4,0,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,0,4,4,4,7,7,4,4,4,4,4,4,4,4,4,4,7,4,4,4,4,4,4,0,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,0,4,4,4,7,7,4,4,4,7,7,7,7,7,4,4,7,7,7,7,4,4,4,4,0,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,0,4,4,4,7,7,4,4,4,4,4,4,4,7,7,4,7,4,4,7,7,4,4,4,0,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,0,4,4,4,7,7,4,4,4,4,7,7,7,7,7,4,7,4,4,7,7,4,4,4,0,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,0,4,4,4,7,7,4,4,4,7,7,4,4,7,7,4,7,4,4,7,7,4,4,4,0,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,0,4,4,4,7,7,7,7,4,7,7,4,4,7,7,4,7,7,7,7,7,4,4,4,0,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,0,4,4,4,7,7,7,7,4,4,7,7,7,7,4,4,7,7,7,7,4,4,4,0,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,0,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,0,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,0,4,4,4,4,4,0,0,4,4,4,4,4,4,4,0,0,0,0,0,4,4,4,0,6,6,6,6,6,6,6,
1,1,1,1,1,1,1,1,0,4,4,4,4,4,4,0,0,4,4,4,4,4,4,4,0,0,0,0,0,4,4,4,0,1,1,1,1,1,1,1,
1,1,1,1,1,2,2,2,0,4,4,4,0,0,0,0,0,4,4,4,4,4,4,4,0,4,4,4,4,4,4,4,0,2,2,1,1,1,1,1,
1,1,1,1,2,2,2,2,0,4,4,4,0,0,0,0,0,4,0,0,0,0,4,4,0,4,4,4,4,4,4,4,0,2,2,2,2,1,1,1,
1,1,2,2,2,2,2,2,0,4,4,4,0,4,4,0,0,4,0,4,4,0,0,4,0,4,0,0,0,4,4,4,0,2,2,2,2,1,1,1,
1,1,2,2,2,2,2,2,0,4,4,4,0,4,4,0,0,4,0,0,0,0,0,4,0,4,4,4,0,4,4,4,0,2,2,2,2,2,1,1,
1,1,2,2,2,2,2,2,0,4,4,4,0,4,4,0,0,4,0,4,4,4,4,4,0,0,0,0,0,4,4,4,0,2,2,2,2,2,1,1,
1,1,2,2,2,2,2,2,0,4,4,4,0,0,0,0,0,4,0,0,0,0,0,4,0,0,0,0,0,4,4,4,0,2,2,2,2,2,1,1,
1,1,1,2,2,2,2,2,0,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,0,2,2,2,2,1,1,1,
1,1,1,1,1,2,2,2,2,0,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,0,2,2,2,2,1,1,1,1,
1,1,1,1,1,1,1,2,2,2,0,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,0,2,2,2,2,1,1,1,1,1,
1,1,1,1,1,1,1,1,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,1,1,1,1,1,1,1,
//1,1,1,1,1,1,1,1,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,1,1,1,1,1,1,1,
};
noInterrupts();
do{
PRETO;
if (TCNT2 > 0x0f){
delayMicroseconds(1);
NOP;NOP;NOP;NOP;
TCNT2 = 0x00;
//pequeno ajuste de tempo, pode ser necessario ou nao dependendo da placa
// #### HSYNC ###
PORTD &= ~(1 7);
if (++contalinhas >= 525){ //525 linhas
contalinhas = 1;
}
PORTD |= (1 7);
// ### VSYNC ###
if ((contalinhas == 1)||(contalinhas == 2)){ //492 e 493
PORTD &= ~(1 6);
} else {
PORTD |= (1 6);
//NOP;NOP;NOP;NOP;NOP;NOP;NOP;NOP;NOP;NOP;
//NOP;NOP;NOP;NOP;NOP;NOP;NOP;NOP;NOP;NOP;
//NOP;NOP;NOP;NOP;NOP;NOP;NOP;NOP;NOP;NOP;
//NOP;NOP;NOP;NOP;NOP;
int linhamatriz = 0;
linhamatriz = contalinhas / 16 - 1;
int j=0;
if ((contalinhas >= 16) && (contalinhas <= 415)){ // 2 e 482
PRETO;
//delayMicroseconds(1);NOP;NOP;NOP;NOP;NOP;NOP;NOP;NOP;NOP; //delay ate 25
//unsigned int i=contalinhas/9;
int j=0;
while(j<40){
PORTB = logoldg[linhamatriz][j];
j++;
}
NOP;NOP;
PRETO;
NOP;NOP;NOP;NOP;
}
}
}
}while(1);
}
Script em Python para gerar a matriz:
print "labdegaragem.com"
import Image
import ImageColor
image='paisagem.bmp' #Coloque aqui o nome do arquivo que deseja converter
texto='paisagem.txt' #Crie um arquivo texto em branco em um diretorio a sua escolha e coloque aqui o nome do arquivo texto para guardar a matriz da imagem em hexadecimal
f=open(texto,'w') #Ira abrir o arquivo texto
imopen=Image.open(image) #Abrira a imagem
x=y=0
h=0
while y<25: #Coloque aqui a altura da imagem. A imagem maxima tem 40x25 pixels
#print y
x=0
while x<40: # Coloque aqui o comprimento da imagem.
#print x
z=imopen.getpixel((x,y))
h=0
if z[0] > 200:
h = h+4
if z[1] > 200:
h = h+2
if z[2] > 200:
h = h+1
#print z[0],"-",z[1],"-",z[2],"=",h
f.write(str(h))
f.write(',')
x=x+1
y=y+1
f.write('\n')
f.close()
Comentar
Luís e galera,
Não deu para embedar a janela do Gist nem do Pastebin, o sistema aqui recusa e apaga a janela.
Mas de qualquer forma, troquei o código pelo link do Github. Assim, é só clicar para ver o código, agora sim, completinho.
Abraços!!
Marcelo, sugestão: disponibiliza aqui http://pastebin.com/ . Fica no formato, tudo bonitinho.
Luís,
Ainda bem que você postou esse erro. A rede social cortou os símbolos maior que/menor que do código que eu colei acima, provavelmente por entender que são tags html. Do jeito que está acima, não vai compilar mesmo!
Não sei como, mas vou corrigir isso e aviso aqui novamente. Se eu colar o texto como imagem não vai dar para a galera dar ctrl-c. Vou ver se a plataforma tem algum recurso para se postar códigos, ou coloco lá no Github, ou coisa do tipo.
Abraço!!
Belo trabalho, mais alguém não conseguiu compilar ?
Obtive os seguintes erros, acho que na hora de copiar pro site, alguma coisa foi removida:
sketch_mar29a.cpp:31:14: error: invalid suffix "TOIE2" on integer constant
sketch_mar29a.cpp: In function 'void setup()':
sketch_mar29a:22: error: expected `)' before numeric constant
sketch_mar29a:23: error: expected `)' before numeric constant
sketch_mar29a:24: error: expected `)' before numeric constant
sketch_mar29a.cpp: In function 'void loop()':
sketch_mar29a:47: error: expected `)' before numeric constant
sketch_mar29a:51: error: expected `)' before numeric constant
sketch_mar29a:54: error: expected `)' before numeric constant
sketch_mar29a:57: error: expected `)' before numeric constant
Valeu Luís!
Hoje vou começar a brincar com desenhos. Minha ideia é tentar definir uma matriz com o menor "pixel" que o Arduino consegue desenhar, o que depende da sua velocidade. Mas eu queria fazer isso lendo cada linha ou frame de alguma memória, para que o firmware possa desenhar qualquer coisa que seja enviada para ele, não apenas coisas pré-programadas.
Abraço!!
Edson,
Pode deixar, vou fazer uma placa para esse projeto e posto o esquemático aqui para a galera.
Quanto ao fluxograma, basta acompanhar o código acima, ele é bem simples. Basicamente gere um pulso de sincronia horizontal na frequência EXATA de 31,3KHz, de uma pausa e escreva a linha antes do próximo pulso acontecer. Conte as linhas e deixe o pulso vertical em baixa durante 1 ou duas linhas. O truque que nenhum site ensina é desligar o RGB quando der qualquer pulso de sincronia.
Depois posto o esquemático (vou fazer ainda).
Abraço!!
Olá Marcelo,
Parabéns pelo projeto !
Gostaria de lhe fazer um pedido, se possível fazer um fluxograma do programa, desta forma poderá ser portado para outras linguagens e outras plataformas, e também o esquema de ligação do microcontrolador ao monitor.
Abraço...
Edson.
Bem-vindo a
Laboratorio de Garagem (arduino, eletrônica, robotica, hacking)
© 2024 Criado por Marcelo Rodrigues. Ativado por
Você precisa ser um membro de Laboratorio de Garagem (arduino, eletrônica, robotica, hacking) para adicionar comentários!
Entrar em Laboratorio de Garagem (arduino, eletrônica, robotica, hacking)