LusoRobótica - Robótica em Português
Sistemas específicos => PIC => Tópico iniciado por: nunosilvarocha em 30 de Setembro de 2014, 11:14
-
Preciso mostrar as corres RGB e a mistura delas num ecrã por VGA.
A ideia é ligar a ficha VGA a um Pic 18f4550 e conseguir reproduzir as cores numa resolução 800x600.
Já procurei no google, existem projetos muito parecidos, mas não é bem o que quero.
Depois quero poder mudar a cor através do USART.
Seria bom conseguir ainda mostrar as cores RGB e a sua mistura numa imagem composta por listas/barras de cores.
Alguém já fez algo semelhante?
-
Com AVR's conheço alguns projectos desses, mas penso que nenhum é capaz de gerar VGA com uma resolução de 800x600, se é para meter um ecrã cheio de cores e pouco mais, para quê tanta resolução?
-
Com AVR's conheço alguns projectos desses, mas penso que nenhum é capaz de gerar VGA com uma resolução de 800x600, se é para meter um ecrã cheio de cores e pouco mais, para quê tanta resolução?
Também já vi alguns projetos com AVR, mas não estou muito à vontade com AVR
Que resolução aconselhas? Não conheces nenhum protejo do género com PIC?
-
Em PIC provavelmente terás de saltar para um dsPIC ou PIC24, um 18f é provavelmente demasiado lento.
-
Com AVR ou PIC é irrelevante, usas naturalmente o que te for mais familiar.
O que precisas de saber é como gerar os sinais VGA e depois implementar isso no microcontrolador:
http://lmgtfy.com/?q=generate+vga+signals (http://lmgtfy.com/?q=generate+vga+signals)
Mais fácil e educativo do que ires olhar para código já feito :)
-
Tipicamente é tudo em assembly, dado que tens de ser cycle accurate, a imprecisão de tempo de chamada a uma interrupção é fatal, nos AVR's dependendo de onde estás saltar para uma ISR demora 3 ou 4 ciclos, basta isso para te chatear a gerar VGA ou video composto.
É simplesmente uma questão de instruções por segundo, dado que o PIC corre no máximo a 48Mhz, e que internamente divide o clock por 4 devido á sua arquitectura, diria ser lento demais.
-
Com AVR ou PIC é irrelevante, usas naturalmente o que te for mais familiar.
O que precisas de saber é como gerar os sinais VGA e depois implementar isso no microcontrolador:
http://lmgtfy.com/?q=generate+vga+signals (http://lmgtfy.com/?q=generate+vga+signals)
Mais fácil e educativo do que ires olhar para código já feito :)
Esse link de 'ajuda' eu já utilizei.
Neste momento estou com dificuldades do vertical front porch, pois estão a aparecer umas falhas no lado esquerdo do ecrã e a cor não aparece totalmente perfeita.
Por isso estava a tentar encontrar algum exemplo para solucionar o meu problema.
-
Se é do lado esquerdo onde começa o varrimento, deves estar com jitter na geração do sync.
Como disse o senso, tens de ser preciso ao ciclo e só com assembly é que te safas.
Quanto às cores não estarem corretas, confirma se os níveis estão corretos nos sinais RGB.
-
Como é que estás a gerar a as cores, dac r-2r discreta?
Não esperes muito mais que 6-7 bits de resolução efectiva.
-
Eu ja fiz isso mas foi numa FPGA, numa cadeira de licenciatura, ha uns tres anos...
Pelo que me lembro, o varrimento VGA é a 25MHz, certo? Se fores para um PIC, utiliza um que vá até 64MHz. Tipicamente os das séries "K" podes utilizar um cristal de 16Mhz e depois fazes PPL para os 64MHz (18F46k22 por exemplo)
-
encontrei este projecto na net, pode ser que ajude para a geração dos sincronismos:
http://tinyvga.com/pic-vga (http://tinyvga.com/pic-vga)
-
Eu ja fiz isso mas foi numa FPGA, numa cadeira de licenciatura, ha uns tres anos...
Pelo que me lembro, o varrimento VGA é a 25MHz, certo? Se fores para um PIC, utiliza um que vá até 64MHz. Tipicamente os das séries "K" podes utilizar um cristal de 16Mhz e depois fazes PPL para os 64MHz (18F46k22 por exemplo)
25Mhz é o pixel clock (1/duração do pixel). Isso é um exagero se só quer gerar barras (que tem vários pixeis de largura). Se usar barras de 25 pixeis de largura , pode baixar o pixel clock para 1MHZ e ainda consegue desenhar 25 barras.
Tens exemplos de pessoal a gerar VGA com a velhinha PIC 16f84 a 4MHz (4 ciclos por instrução, 8 para jumps): http://tinyvga.com/pic-vga (http://tinyvga.com/pic-vga), mas quase não sobram instruções para pôr um led a piscar, pelo que algo mais recente com um clock maior não é má ideia ;)
-
E tens o outro extremo:
http://www.linusakesson.net/scene/craft/ (http://www.linusakesson.net/scene/craft/)
Avr a gerar som e video VGA, demoscene porn ;D
-
Muito doido... mas vindo da demoscene não é de admirar. Esses gajos são gurus da otimização.
Houve uma altura que seguia e as demos de 4k(bytes) eram alucinantes (https://www.youtube.com/watch?v=G1Q9LtnnE4w (https://www.youtube.com/watch?v=G1Q9LtnnE4w) , 3D todo feito em SW, as graficas 3D ainda estavam a começar) , e hoje fazem-se coisas doidas com 256bytes e tamanhos do género: https://www.youtube.com/watch?v=R35UuntQQF8 (https://www.youtube.com/watch?v=R35UuntQQF8)
http://www.theverge.com/2013/12/1/5162414/p01-demo-fits-minecraft-flyby-into-256-bytes-of-data (http://www.theverge.com/2013/12/1/5162414/p01-demo-fits-minecraft-flyby-into-256-bytes-of-data)
E há quem comece a olhar para os 16 bytes :o
http://countercomplex.blogspot.com/2011/06/16-byte-frontier-extreme-results-from.html?_sm_au_=i5FsvZLqLnS44SRs (http://countercomplex.blogspot.com/2011/06/16-byte-frontier-extreme-results-from.html?_sm_au_=i5FsvZLqLnS44SRs)
-
Conheço o projecto Uzebox à uns anos e o atmega644 funciona a 8bits com som e imagem, de vez em quando lá aparece um jogo novo.
Também existem uns vídeos pelo youtube com essa "consola"
http://belogic.com/uzebox/index.asp (http://belogic.com/uzebox/index.asp)
-
Encontrei um protejo com o Attiny que quase já soluciona o meu problema nesta fase inicial.
Agora estou com outro problema.
No MPlab com Hitech, quando executo algo do tipo:
if (a==1)
RD1=1;
else
RD2=1;
O que está a acontecer é que liga o bit 1 ou 2 e desliga o resto dos bits do PORTD.
O que está a acontecer? Como altero apenas um bit sem ter que me preocupar com os restantes?
-
Não tens de usar PORTD.lat ou algo do género?
-
No hitech não sei que nunca usei, mas no c18 ou xc8 é LATDbits.LATD1 =1.
Assim de repente, pesquisando no google, alguns exemplos têm como tu tens. se ninguém daqui te ajudar, mete o código todo que pode ser de outra coisa
-
Cá está o codigo.
O que está a acontecer é que na função 'main' quando entramos no ciclo 'if' ao fazer 'RA=0' desliga o 'PORTA' todo.
#include <htc.h>
__CONFIG(1, INTCLKO); // Configuração do oscilador como interno
//CPUDIV1-CPU sem divisão de frequência
__CONFIG(2, WDTDIS); //WatchDog desactivado
__CONFIG(3, MCLRDIS); //Pino de reset desactivado
__CONFIG(4, DEBUGEN&LVPDIS); //DEBUGEN-debug activado
//LVPDIS-Low-Voltage programming disabled
//(necessário para debugging)
void USARTInit();
void USARTescreverByte(char);
void USARTescreverString(const char *);
void USARTescreverLine(const char *);
void USARTescreverInt(int ,unsigned char);
unsigned char USARTlerByte();
void on_off();
void resolution();
void intervalo();
char data;
void main(void)
{
OSCCON = 0b11001111; //Configuração do oscilador
// 0,1 - Define como oscilador interno
// 2 - Define como oscilador interno estável
// 3 - Define como oscilador interno estável
// a funcionar como clock
// 4,5,6 - Define a frequencia do oscilador para 1MHz
// 7 - Abilita o modo IDLE
//Inicializa Porto A como saida de dados
TRISA=0;
PORTA=0b00000011;
//Inicializa Porto C como saida de dados
TRISC=0;
PORTC=0;
TRISB=0;
PORTB=0XFF;
unsigned s=1;
//Inicializar a USART
USARTInit();
USARTescreverLine("Escolha a resolucao");
resolution();
USARTescreverLine("Ligar o sistema");
on_off();
while(1)
{
data=USARTlerByte();
if (data=='0')
{
RA0=0;
intervalo ();
RA0=1;
}
if (data=='1')
{
RA1=0;
intervalo ();
RA1=1;
}
if (data=='9')
{
on_off();
}
}
}
void on_off()
{
unsigned int a=0;
while(!a)
{
USARTescreverLine("ON(1)|OFF(0)");
data=USARTlerByte();
if (data=='1')
{
RA2=1;
USARTescreverLine("Sistema_ON");
a=1;
}
else if (data=='0')
{
RA2=0;
USARTescreverLine("Sistema_OFF");
a=1;
}
}
}
void resolution()
{
unsigned int s=0;
while(!s)
{
data=USARTlerByte();
if (data=='1')
{
PORTB=0b00111111;
s=1;
}
if (data=='2')
{
PORTB=0b01011111;
s=1;
}
if (data=='3')
{
PORTB=0b01101111;
s=1;
}
if (data=='4')
{
PORTB=0b01110111;
s=1;
}
if (data=='5')
{
PORTB=0b01111011;
s=1;
}
if (data=='6')
{
PORTB=0b10111111;
s=1;
}
if (data=='7')
{
PORTB=0b11011111;
s=1;
}
if (data=='8')
{
PORTB=0b11111111;
s=1;
}
}
USARTescreverLine("Resolucao escolhida");
}
void intervalo ()
{
unsigned int i=0, a=0;
for(i=0; i<500; i++)
{
a++;
}
}
void USARTInit()
{
//Baud Rate = 9600 Bits por Second
//Gerador de taxa de transmissão SPBRG
SPBRG=25;
//TXSTA REG
TXEN=1;
BRGH=1;
//RCSTA
SPEN=1;
CREN=1; //Habilita Receiver (RX)
//BAUDCON
BRG16=1;
}
void USARTescreverByte(char ch)
{
//Espera até receber alguma coisa
while(!TXIF);
//Lê caracter
TXREG=ch;
}
void USARTescreverString(const char *str)
{
while((*str)!='\0')
{
//Espera até receber alguma coisa
while(!TXIF);
//Lê caracter
TXREG=(*str);
//incrementa para ler o proximo
str++;
}
}
void USARTescreverLine(const char *ln)
{
USARTescreverString(ln);
USARTescreverString("\r\n");
}
void USARTescreverInt(int val,unsigned char field_length)
{
if(val<0)
{
USARTescreverByte('-'); //Write '-' sign for negative numbers.
val=(val*(-1)); //Make it positive.
}
//Convert Number To String and pump over Tx Channel.
char str[5]={'0','0','0','0'};
int i=4,j=0;
while(val)
{
str[i]=val%10;
val=val/10;
i--;
}
if(field_length>5)
while(str[j]==0) j++;
else
j=5-field_length;
for(i=j;i<5;i++)
{
USARTescreverByte('0'+str[i]);
}
}
unsigned char USARTlerByte()
{
while(!RCIF); //Wait for a byte
return RCREG;
}
-
O que é o RA??
Tu estas a fazer operações de bits em binário tipo "PORTA=0b00000011;", podes usar a mesma filosofia para trocar um só bit de PORTA.
-
Cá está o codigo.
O que está a acontecer é que na função 'main' quando entramos no ciclo 'if' ao fazer 'RA=0' desliga o 'PORTA' todo.
#include <htc.h>
__CONFIG(1, INTCLKO); // Configuração do oscilador como interno
//CPUDIV1-CPU sem divisão de frequência
__CONFIG(2, WDTDIS); //WatchDog desactivado
__CONFIG(3, MCLRDIS); //Pino de reset desactivado
__CONFIG(4, DEBUGEN&LVPDIS); //DEBUGEN-debug activado
//LVPDIS-Low-Voltage programming disabled
//(necessário para debugging)
void USARTInit();
void USARTescreverByte(char);
void USARTescreverString(const char *);
void USARTescreverLine(const char *);
void USARTescreverInt(int ,unsigned char);
unsigned char USARTlerByte();
void on_off();
void resolution();
void intervalo();
char data;
void main(void)
{
OSCCON = 0b11001111; //Configuração do oscilador
// 0,1 - Define como oscilador interno
// 2 - Define como oscilador interno estável
// 3 - Define como oscilador interno estável
// a funcionar como clock
// 4,5,6 - Define a frequencia do oscilador para 1MHz
// 7 - Abilita o modo IDLE
//Inicializa Porto A como saida de dados
TRISA=0;
PORTA=0b00000011;
//Inicializa Porto C como saida de dados
TRISC=0;
PORTC=0;
TRISB=0;
PORTB=0XFF;
unsigned s=1;
//Inicializar a USART
USARTInit();
USARTescreverLine("Escolha a resolucao");
resolution();
USARTescreverLine("Ligar o sistema");
on_off();
while(1)
{
data=USARTlerByte();
if (data=='0')
{
RA0=0;
intervalo ();
RA0=1;
}
if (data=='1')
{
RA1=0;
intervalo ();
RA1=1;
}
if (data=='9')
{
on_off();
}
}
}
void on_off()
{
unsigned int a=0;
while(!a)
{
USARTescreverLine("ON(1)|OFF(0)");
data=USARTlerByte();
if (data=='1')
{
RA2=1;
USARTescreverLine("Sistema_ON");
a=1;
}
else if (data=='0')
{
RA2=0;
USARTescreverLine("Sistema_OFF");
a=1;
}
}
}
void resolution()
{
unsigned int s=0;
while(!s)
{
data=USARTlerByte();
if (data=='1')
{
PORTB=0b00111111;
s=1;
}
if (data=='2')
{
PORTB=0b01011111;
s=1;
}
if (data=='3')
{
PORTB=0b01101111;
s=1;
}
if (data=='4')
{
PORTB=0b01110111;
s=1;
}
if (data=='5')
{
PORTB=0b01111011;
s=1;
}
if (data=='6')
{
PORTB=0b10111111;
s=1;
}
if (data=='7')
{
PORTB=0b11011111;
s=1;
}
if (data=='8')
{
PORTB=0b11111111;
s=1;
}
}
USARTescreverLine("Resolucao escolhida");
}
void intervalo ()
{
unsigned int i=0, a=0;
for(i=0; i<500; i++)
{
a++;
}
}
void USARTInit()
{
//Baud Rate = 9600 Bits por Second
//Gerador de taxa de transmissão SPBRG
SPBRG=25;
//TXSTA REG
TXEN=1;
BRGH=1;
//RCSTA
SPEN=1;
CREN=1; //Habilita Receiver (RX)
//BAUDCON
BRG16=1;
}
void USARTescreverByte(char ch)
{
//Espera até receber alguma coisa
while(!TXIF);
//Lê caracter
TXREG=ch;
}
void USARTescreverString(const char *str)
{
while((*str)!='\0')
{
//Espera até receber alguma coisa
while(!TXIF);
//Lê caracter
TXREG=(*str);
//incrementa para ler o proximo
str++;
}
}
void USARTescreverLine(const char *ln)
{
USARTescreverString(ln);
USARTescreverString("\r\n");
}
void USARTescreverInt(int val,unsigned char field_length)
{
if(val<0)
{
USARTescreverByte('-'); //Write '-' sign for negative numbers.
val=(val*(-1)); //Make it positive.
}
//Convert Number To String and pump over Tx Channel.
char str[5]={'0','0','0','0'};
int i=4,j=0;
while(val)
{
str[i]=val%10;
val=val/10;
i--;
}
if(field_length>5)
while(str[j]==0) j++;
else
j=5-field_length;
for(i=j;i<5;i++)
{
USARTescreverByte('0'+str[i]);
}
}
unsigned char USARTlerByte()
{
while(!RCIF); //Wait for a byte
return RCREG;
}
Uma melhor modificacao de portas ao nivel do BIT, eh fazer da seguinte forma ::
RA0=0 -> LATA &= 0b11111110
RA0=1 -> LATA |= 0b00000001
ou se se quiser insistir em usar RA0=x, entao usar LATAbits.LATA0=x (confirmar no ficheiro de Inlcude como estao as definicoes...)
Ha outras maneiras de o fazer, claro.
-
As vezes a malta usa o PORTAbits.RA0 mas não é nada aconselhável; o registo PORTx é para ler o estado, não para escrever. A questão é que se mexermos no registo PORTx em vez do LATx tipicamente o estado altera, mas nalguns uC dá barraca. Fica a nota!
-
Problema resolvido.
LATx=1;
LATx=0;
Obrigado a todos.