LCD 16x2 CGRAM

Software e Hardware para ATMEL

Moderadores: 51, guest2003, brasilma

LCD 16x2 CGRAM

Mensagempor Alirio926 » 10 Jan 2010 13:32

Boa Tarde.
Hoje consegui fazer meu LM35 + LCD16x2 funcionar, e agora vamos em frente.
Se possivel alguem poderia me explicar como gerar um Caracter no LCD tipo °C ou uma Barra de progresso?
Um routina simples com o intuito de aprendizado, um simples exemplo explicado. segue abaixo meu primeiro codigo totalmente em C, usava java ><.
Código: Selecionar todos
#include"lcd.c"
#include<avr/io.h>


#define F_CPU 11059200UL

void InitADC()
{
   ADMUX=(1<<REFS0);// Aref = AVcc;
   ADCSRA=(1<<ADEN)|(1<<ADPS2)|(1<<ADPS1);
   /* ADEN = 1 ADC ENABLE | 0 ADC DISABLE
    * ADSC = COLOCAMOS EM 1 P/ FAZER UMA CONVERSÃO
    * ADIF = 1 QUANDO A CONVERSÃO FOR CONCLUIDA
    * ADPS0/1/2 SÃO OS DIVISORES DE FRREQUENCIA*/
}
uint16_t ReadADC(uint8_t ch)
{
   //ADC channel 0-7
   ch = ch & 0b00000111;
   ADMUX |= ch;

   //Inicia uma simples conversão
   ADCSRA |= (1<<ADSC);

   //Espera até a conversão esta completa
   while(!(ADCSRA &(1<<ADIF)));

   //Limpa a ADIF
   ADCSRA |= (1<<ADIF);

   return(ADC);
}   
void Wait()
{
   uint8_t i;
   for(i=0; i<20; i++)
   _delay_loop_2(0);
}
void main()
{
   uint16_t adc_result;

   //Inicia o LCD
   InitLCD(LS_BLINK|LS_ULINE);
   LCDClear();

   //Inicia o ADC
   InitADC();

   //Imprime algo
   LCDWriteString("ADC Teste");
   LCDWriteStringXY(0,1,"Temp:");

   while(1)
   {
      //le uma entrada do canal 0 analogico
      adc_result = ReadADC(0);
      //imprime com 4 colunas.
      uint16_t temperatura = (5 * adc_result * 100) / 1024;
      LCDWriteIntXY(4,1,temperatura,2);
      LCDWriteString("C ");
      LCDWriteInt(adc_result,4);
      Wait();
   }
}


A variação da temperatura fica entre 31~34 (ADC 0063 - 0073) tem como diminuir essa variação? e por um 30.1 por exemplo.?

Fico Muito Grato pela antenção.
Alirio926
Bit
 
Mensagens: 23
Registrado em: 23 Dez 2009 21:02

Mensagempor Milhoci » 10 Jan 2010 14:58

Faça 8 aquisições e tira a média entre elas, fazendo isso você consegue um valor mais estável.



Milhocì
Milhoci
Byte
 
Mensagens: 148
Registrado em: 12 Out 2006 18:46

Mensagempor xultz » 10 Jan 2010 15:32

Há um bocado de tempo fiz um firmware que fazia isso, a única diferença é que era usando um LPC2105 ao invés de AVR, mas a idéia é a mesma.
Aqui vai a rotina de inicialização do LCD:

Código: Selecionar todos
void lcd_init(void)
{
   int x, y;                  // Variavel usada no contador
   unsigned char bits = 0x10;      // Variavel que contem os bits que gerarao os caracteres na CGRAM
   
   espera(0x001E8480);      // Espero 40ms
   lcd_write(0, 0x30);
   
   espera(0x000320C8);      // Espero 4.1ms
   lcd_write(0, 0x30);
   
   espera(0x00001388);      // Espero 100us
   lcd_write(0, 0x30);
   
   lcd_busywait();
   
   lcd_write(0, 0x38);      // Configuro para N=1 (duas linhas), F=0 (5x8 dots)
   lcd_busywait();
   
   lcd_write(0, 0x08);      // Display off, cursor off, blink off
   lcd_busywait();
   
   lcd_write(0, 0x01);      // Limpa o display e move o cursor para a primeira posição
   lcd_busywait();
   
   lcd_write(0, 0x06);      // Seta incremento e shift
   lcd_busywait();

   // Final da inicializacao do display
   
   // Vou configurar os primeiros 5 caracteres da CGRAM para barras verticais, para
   // poder usar em progress bar
   // O primeiro caracter é feito de bits 0001.0000, o segundo de 0001.1000 ate 0001.1111
   
   lcd_write(0, 0x40);      // Configuro para iniciar gravacao na CGRAM
   lcd_busywait();
   
   // Vou fazer dois loops, sendo o externo para selecionar os 5 caracteres, o interno as 8 posicoes
   // de memoria de cada caracter
   
   for(x=0; x!=5; x++)
   {
      for(y=0; y!=8; y++)
      {
         lcd_write(1, bits);
         lcd_busywait();
      }
   bits = bits >> 1;
   bits = bits + 0x10;

   }
   
   // Vou escrever no sexto byte os bits para formar o simbolo de graus a ser usado na medicao de temperatura
   // Resultado:
   // .....OO.
   // ....O..O
   // ....O..O
   // .....OO.
   // ........
   // ........
   // ........
   // ........   
   lcd_write(1, 0x06);
   lcd_busywait();
   
   lcd_write(1, 0x09);
   lcd_busywait();
   
   lcd_write(1, 0x09);
   lcd_busywait();
   
   lcd_write(1, 0x06);
   lcd_busywait();
   
   lcd_write(1, 0x00);
   lcd_busywait();
   
   lcd_write(1, 0x00);
   lcd_busywait();
   
   lcd_write(1, 0x00);
   lcd_busywait();
   
   lcd_write(1, 0x00);
   lcd_busywait();   
   
   lcd_write(0, 0x0C);      // Ligo display, sem cursor e sem blinking
   lcd_busywait();

}


As rotinas usadas acima, a rotina espera() ficava travada alguns ciclos, para gerar um delay preciso.
A rotina lcd_write tinha o seguinte protótipo:
static void lcd_write(unsigned char comando, unsigned char valor)
No caso comando era um flag, se fosse 0 era um comando, se fosse 1 era um caracter (basicamente este flag colocava o pino RS em nivel alto ou baixo). valor era o valor escrito nos pinos D0 a D7 do display (eu estava usando o display com 8 bits porque tinha GPIO sobrando).
O comando lcd_busywait() trava esperando um flag de not_busy do display (eu usei o pino de RW no display porque tinha GPIO sobrando, e o tratamento do display fica bem mais espertinho).

A primeira parte da rotina faz o reset do display, conforme o datasheet dele manda fazer, sem tirar nem por.

Logo após a incialização, tem dois loops aninhados. O que este loop faz é criar 5 caracteres na CGRAM. Estes caracteres são símbolos para fazer um bargraph.
Cada caracter do display pode ter resolução de 5x8 pixels. Se pensar em linha e colunas, o primeiro caracter é (. é pixel apagado, 0 é pixel aceso):
Código: Selecionar todos
0....
0....
0....
0....
0....
0....
0....
0....

Se observar que a variável bits é inicializada com 0x10, isso em binário corresponde a 0001.0000 (o ponto eu coloco só pra separar os nibbles, meu costume, mas é um byte inteiro). Para o display, na CGRAM os três bits mais significativos não servem para nada. Dessa forma, escrevendo 0x10 nos primeiros 8 bytes da CGRAM gera um caracter que é uma linha vertical na coluna mais da esquerda.
Na segunda iteração do loop externo, o valor 0x10 é rotacionado uma vez prá direita, resultando em 0x08, ou 0000.1000 e depois é somado com 0x10, que resulta em 0001.1000. Escrevendo mais 8 vezes no display, gera um caracter assim:
Código: Selecionar todos
00...
00...
00...
00...
00...
00...
00...
00...

Ou seja, um caracter onde as duas colunas mais da esquerda estão acesas.
O loop faz isso mais três vezes, gerando caracteres com três, quatro e cinco colunas acesas.
Com estes caracteres, eu consegui fazer um bargrapha que crescia da esquerda para a direita. Supondo que quizesse fazer o bargrapha crescer de 0 até 15, seria assim:
1. apaga o display (isso representa zero)
2. escreve o caracter 0 (na tabela do display, os primeiros 8 caracteres são da CGRAM), isso coloca 1 barra no display
3. escreve o caracter 1, isso coloca duas barras no display
4. escreve o caracter 2
5. escreve o caracter 3
6. escreve o caracter 4
7. não faz nada. Isso porque não é possível ter 6 barras horizontais na tela. Eu optei assim, o bargraph não daria saltos nas colunas vazias
8. mudar o cursor para segunda posição do display, escreve o caracter 1
9. escreve o caracter 2
e assim por diante.

Na rotina, após a criação das barras do bargraph, eu crio o caracter do símbolo °. Essa parte não tem mistério.

Bom, é isso, se alguma parte não ficou clara, é só perguntar que eu tento ajudar.

Abraço
98% das vezes estou certo, e não estou nem aí pros outros 3%.
Avatar do usuário
xultz
Dword
 
Mensagens: 3001
Registrado em: 13 Out 2006 18:41
Localização: Curitiba

Mensagempor Alirio926 » 10 Jan 2010 15:51

.... Preciso abilitar o pino r/w o lcd pra ecrever? esse codigo escreve direto no display ou só na cgram, caso seja na cgram como usar o caracter gravado nele?
Alirio926
Bit
 
Mensagens: 23
Registrado em: 23 Dez 2009 21:02

Mensagempor xultz » 10 Jan 2010 19:30

O pino R/W pode ser mantido em nível fixo (se não me falha a memória em nível baixo), isso deixa ele no modo escrita o tempo todo. No modo leitura, você pode ler o conteúdo da CGRAM e o flag de busy, na prática a única utilidade é ler o flag de busy. Se você deixar ele no modo de escrita o tempo todo, não pode ler este flag, então precisa dar delays a cada comando efetuado no display, e com alguma folga para não correr o risco de sobrepor comandos no display. Na prática, quase todas as aplicações fazem isso, eu usei o pino de R/W porque tinha GPIO sobrando.

A CGRAM faz parte do display, então perguntar se o código escreve direto no display ou na CGRAM não faz sentido.

Para usar qualquer dos oito caracteres da CGRAM (no meu código, só gerei 6 caracteres, os outros dois não usei) basta escrever no display o caracter de valor 0 a 7. O resto da tabela de caracteres segue mais ou menos a tabela ASCII (voc~e pode ver uma no site http://asciitable.com/). Por exemplo, se você quiser escrever um "A" no display, escreve o valor 0x41 com o pino RS em nível alto, porque 0x41 na tabela do display corresponde a "A". Com a minha rotina de incialização, se escrever o valor 0x05 no display com o pino RS em nível alto, vai aparecer o símbolo "°" porque eu desenhei-o na sexta posição da CGRAM, e assim por diante. Dessa forma, dizemos que a CGRAM está mapeada na tabela de caracteres nas 8 primeiras posições. Note que na tabela ASCII estas posições se referem a caracteres de controle, alguns usados em comunicações seriais, outros para marcar arquivos, e que não fazem nenhum sentido num display, então espertamente mapearam a CGRAM no lugar destes caracteres.
98% das vezes estou certo, e não estou nem aí pros outros 3%.
Avatar do usuário
xultz
Dword
 
Mensagens: 3001
Registrado em: 13 Out 2006 18:41
Localização: Curitiba

Mensagempor Alirio926 » 10 Jan 2010 22:20

Obrigado, agora ficou muito claro.
Alirio926
Bit
 
Mensagens: 23
Registrado em: 23 Dez 2009 21:02


Voltar para AVR

Quem está online

Usuários navegando neste fórum: Bing [Bot] e 1 visitante

x