Ir ao conteúdo
  • Cadastre-se

Exibir valores de tensão em displays 7 segmentos


qwert

Posts recomendados

Olá pessoal,

estou com um pequeno problema aqui.

Preciso fazer um programa em C, para o PIC 16F877A que leia uma entrada analógica referente a tensão e exiba valores de 0 a 255 em um conjunto de displays de 7 segmentos.

como sou novo no assunto, estou buscando a ajuda de vocês.

iniciei da seguinte forma:

main

{

setut_adc_ports_a(ALL_ANALOG);

setup_adc(ADC_CLOCK_INTERNAL);

set_adc_channel(2);

valor = read_adc();

}

sei que a variável valor irá armazenar um byte referente ao valor no potenciômetro.

Qual lógica devo usar a partir daí?

Pensei num switch, mas seriam muitos valores pra comparar...

Link para o comentário
Compartilhar em outros sites

Depois daí, é necessário calcular o valor retornado, na unidade que você precisa.

Se for pra exibir tensão, crie uma variável float pra receber o valor.

Calcule a resolução do AD. Se for um AD de 8 bits (como você citou, já que a variável vai receber 1 byte ==> valor), então, cada bit do AD corresponde à uma tensão lida:

RES = VREF/RES_AD

Se VREF for 5V, então a resolução vai ser de: 5/256 = 19,5mV.

Cada bit do AD corresponde à 19,5mV, então, pra calcular a tensão lida, é só multiplicar o valor lido do AD por 19,5mV.

Esse valor é armazenado em uma variável FLOAT, e depois, convertido em uma string, separado e exibido número por número.

Pra converter um float pra string, seu compilador deveria possuir a função FTOA. Se ele não tiver essa função, você pode converter usando SPRINTF ou VPRINTF. Depende da sua necessidade.

Eu uso esse método, mas, a máquina que eu uso é muito rápida (AVR), logo, se seu MCU abrir o bico pra fazer cálculos de ponto flutuante, você precisa converter o valor lido através de cálculos com números inteiros. Dá mais trabalho.

[]'s

Link para o comentário
Compartilhar em outros sites

cara, fiz isso aqui...

mas ainda não entendi o lance dá transformação para string..

#include <16f877a.h>

#use delay(clock=4000000)

#fuses XT,NOWDT,NOPROTECT,PUT

main

{

float valor2;

byte valor;

while(TRUE)

{

setut_adc_ports_a(ALL_ANALOG);

setup_adc(ADC_CLOCK_INTERNAL);

set_adc_channel(2);

valor = read_adc();

valor2 = (valor*(5/256))

}

}

Nessa variável valor2 está armazenado a leitura - levando em consideração a referência - do adc não é verdade?

como eu faço para pra formar a string e enviá-las para os displays de 7 segmentos?

valeu men!

Link para o comentário
Compartilhar em outros sites

Exato. Está correto. A resolução do AD, depende do número de bits do AD, em função de VREF.

VREF marca o topo de leitura do AD. Se você tem um VREF de 2,5V, p. ex., e um AD de oito bits, quando o AD exibir 0xFF corresponde aos 2,5V na entrada.

Eu não programo PICs, logo, o código abaixo é genérico pra C. você precisa adaptar no seu compilador aí.

Protótipo de FTOA:

void ftoa(float n, unsigned char decimals, char *str) 



#include <16f877a.h>
#include <stdlib.h> // inclusão de FTOA
#include <string.h> // inclusão de STRLEN
#use delay(clock=4000000)
#fuses XT,NOWDT,NOPROTECT,PUT

main
{
float valor2;
byte valor;
char string [ 10 ];
unsigned char indice = 0;

while(TRUE)
{
setut_adc_ports_a(ALL_ANALOG);
setup_adc(ADC_CLOCK_INTERNAL);
set_adc_channel(2);
valor = read_adc();
valor2 = (valor*(5/256));
ftoa( valor2, 2, string ); // converte o float para string
for ( indice = 0; indice < strlen ( string ); indice++ )
{
lcd_imprime_char ( string [ indice ] ); // imprime a string no LCD, caractere por caractere
}
}
}
// USANDO FTOA



#include <16f877a.h>
#include <stdio.h> // inclusão de SPRINTF
#include <string.h> // inclusão de STRLEN
#use delay(clock=4000000)
#fuses XT,NOWDT,NOPROTECT,PUT

main
{
float valor2;
byte valor;
char string [ 10 ];
unsigned char indice = 0;

while(TRUE)
{
setut_adc_ports_a(ALL_ANALOG);
setup_adc(ADC_CLOCK_INTERNAL);
set_adc_channel(2);
valor = read_adc();
valor2 = (valor*(5/256));
sprintf ( string, "%f,2", valor2 ); // converte o float para string
for ( indice = 0; indice < strlen ( string ); indice++ )
{
lcd_imprime_char ( string [ indice ] ); // imprime a string no LCD, caractere por caractere
}
}
}
// USANDO SPRINTF

Não sei se a formatação de SPRINTF está correta, porque eu nem uso essa função, é só pra dar uma ideia. você precisa verificar no seu compilador qual a formatação correta. O formato é de um tipo FLOAT, com duas casas decimais, convertido para string.

É só uma ideia, porque existem outras formas de imprimir/converter um número sem precisar usar funções prontas, mas, como eu te disse, eu vou pelo método mais fácil! :D

Ops! Vendo agora é que o display é de 7 segmentos! eheheheehhehe

Nesse caso, o que eu faço é uma tabela com os segmentos correspondentes a cada dígito.

Vamos supor que seu display seja de catodo comum, ou seja, pra iluminar um segmento, você precisa escrever 1 nesse segmento.

você precisa criar uma tabela com cada dígito que você vai representar. Pro display de catodo comum, eu tenho essa tabela pronta:

char tabela_digitos [ ] = { 0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7C, 0x07, 0x7F, 0x67 };

São todos os dígitos iniciando de zero até nove.

O bit zero do Port corresponde ao segmento A. O bit 1 ao segmento B e assim sucessivamente até o bit 6 do Port. E o bit 7 está livre. Pode ser usado para representar o ponto decimal.

Usando a string convertida anteriormente, e supondo que seu display esteja no PORTA, você pode colocar a informação no Port desse jeito:

for (indice = 0; indice < strlen ( string ), indice++ )
{
PORTA = tabela_digitos [ string [ indice ] - 0x30 ];
}

Evidente que o programa só vai escrever um único dígito no display. E também não tem tratamento pra vírgula, que está lá na string.

Se você vai usar mais dígitos, aí a coisa complica. você precisa bolar um esquema para exibir em vários displays de 7 segmentos, e existem muitas técnicas para isso, inclusive varredura.

[]'s

Link para o comentário
Compartilhar em outros sites

  • 3 semanas depois...

Cara, obrigado pela ajuda.

aprendi muito...

quanto a divisão em string, acabei fazendo de outro jeito..

usei a função floor(), da biblioteca math.h...

ela faz uma aproximação para o valor piso...

ex:

floor(2.3) ou floor(2.9) retornam o valor inteiro 2.

o código ficou assim (lembrando que está sendo mostrado os valores de zero a 255 e não de 0 a 5 volts, que pode ser obtido com processo semelhante):

#include <16f877a.h>

#FUSES XT,NOWDT,NOPROTECT,NOPUT

#device adc=8

#use delay (clock=4000000)

#include <math.h>

void main()

{

byte const tabela[11]={

0b11111101, //0

0b01100001, //1

0b11011011, //2

0b11110011, //3

0b01100111, //4

0b10110111, //5

0b11111011, //6

0b11100001, //7

0b11111111, //8

0b11110111}; //9

float valor2;

int c,d,u;

int valor;

setup_adc_ports(ALL_ANALOG);

setup_adc(ADC_CLOCK_INTERNAL);

set_adc_channel(0);

while(TRUE)

{

valor = read_adc(); /*ler o valor do adc*/

valor2=(valor/100);

c=(int)floor(valor2); //extrai o primeiro piso para a casa das centenas

valor2=((valor/10) - (10*c));

d=(int)floor(valor2); /*extrai o segundo piso*/

valor2=((valor) - (100*c)- (10*d));

u=(int)floor(valor2); /*extrai o terceiro piso*/

output_bit(pin_c0,1);//\

output_d(tabela); // \_ Mostra unidade

delay_ms(1);

output_bit(pin_c0,0);///

output_bit(pin_c1,1);//\

output_d(tabela[d]); // \_ Mostra unidade

delay_ms(1);

output_bit(pin_c1,0);///

output_bit(pin_c2,1);//\

output_d(tabela[c]); // \_ Mostra unidade

delay_ms(1);

output_bit(pin_c2,0);///

}

}

Link para o comentário
Compartilhar em outros sites

beleza, qwert.

Nesse caso, você nem precisaria usar essa função FLOOR, uma vez que cálculos com inteiros, resultam em números inteiros (em C, claro).

P. ex., se você dividir 10 por 3 (10/3) o resultado SEMPRE vai ser 3. Não tem fração.

O que determina o cálculo é o TIPO DO DADO envolvido.

Eu uso esse algoritmo aqui, pra separar dígitos de um número hexadecimal. Não sei se é o mais eficiente, mas, é rápido e funciona! :D


{
char centena, dezena, unidade;

unsigned char numero = 0xFF;

centena = numero / 100;

dezena = ( numero - ( centena * 100 ) ) / 10;

unidade = numero - ( ( centena * 100 ) + ( dezena * 10 ) );

}
void desmembrar_numero ( void )

Depois de separados, é só indexar a tabela como eu te falei lá em cima.

Experimenta aí e vê se te serve!

[]'s

Link para o comentário
Compartilhar em outros sites

Salve amigo Mauricio, gostei dessa sua rotina de ajuste decimal, realmente um tanto mais simples e adaptavel ao assembly!

em todo o caso eu uso essa aqui:


void ajuste_decimal (void)
{
char dez,uni,cent ;
i = valor_AD;
for(i = valor_AD ; i >= 0 ; i --) //refaz esse laço até que todos os digitos estejam //separados
{
uni ++ ; //incrementa unidade
if (uni == 9) //unidade maior que 9?
{
uni = 0; zera unidade
dez ++; incrementa a dezena
if (dez == 9) ; a mesa coisa aqui so que com a dezena
{
dez = 0;
cent ++;
}
}
}
}

abs.

Link para o comentário
Compartilhar em outros sites

  • 3 anos depois...

Pessoal estou com problema para exibir valores em um display, por enquanto montei um programa só para fazer um contador com um timer de 0 a 99, mas o problema é que quando a unidade chega a nove eu mando zerar a unidade e somar 1 na dezena, mas ele n faz isso, ele continua a somar a unidade sem zerar e n soma na dezena. alguem sabe o que pode ser, segue codigo abaixo



char dez=0,uni=0,cent=0;

#int_TIMER0
void TIMER0_isr(void)
{
contador++;
output_toggle(PIN_E0);
if(contador==19)
{
contador=0;
dez++;

if(dez==9)
{
dez=0;
cent++;

if(cent==9 && dez==9 && uni==9)
{
uni=0;
dez=0;
cent=0;
}
}

}
}

void main()
{

setup_adc_ports(AN0_TO_AN2|VSS_VDD);
setup_adc(ADC_OFF);
setup_psp(PSP_DISABLED);
setup_spi(SPI_SS_DISABLED);
setup_wdt(WDT_OFF);
setup_timer_0(RTCC_INTERNAL);
setup_timer_1(T1_DISABLED);
setup_timer_2(T2_DISABLED,0,1);
setup_comparator(NC_NC_NC_NC);
setup_vref(FALSE);
enable_interrupts(INT_TIMER0);
enable_interrupts(GLOBAL);

while(true)
{

switch(dez)
{
case 0: dez=0x40;break;
case 1: dez=0x41;break;
case 2: dez=0x42;break;
case 3: dez=0x43;break;
case 4: dez=0x44;break;
case 5: dez=0x45;break;
case 6: dez=0x46;break;
case 7: dez=0x47;break;
case 8: dez=0x48;break;
case 9: dez=0x49;break;
}
output_d(dez);
delay_us(10);

switch(cent)
{
case 0: cent=0b00100000;break;
case 1: cent=0b00100001;break;
case 2: cent=0b00100010;break;
case 3: cent=0b00100011;break;
case 4: cent=0b00100100;break;
case 5: cent=0x25;break;
case 6: cent=0x26;break;
case 7: cent=0x27;break;
case 8: cent=0x28;break;
case 9: cent=0x29;break;
}

output_d(cent);
delay_us(10);

}
}

Link para o comentário
Compartilhar em outros sites

Arquivado

Este tópico foi arquivado e está fechado para novas respostas.

Sobre o Clube do Hardware

No ar desde 1996, o Clube do Hardware é uma das maiores, mais antigas e mais respeitadas comunidades sobre tecnologia do Brasil. Leia mais

Direitos autorais

Não permitimos a cópia ou reprodução do conteúdo do nosso site, fórum, newsletters e redes sociais, mesmo citando-se a fonte. Leia mais

×
×
  • Criar novo...

 

GRÁTIS: ebook Redes Wi-Fi – 2ª Edição

EBOOK GRÁTIS!

CLIQUE AQUI E BAIXE AGORA MESMO!