Ir ao conteúdo
  • Cadastre-se

Multiplexar display de 7 segmentos em C


valecovo

Posts recomendados

Olá
Estou aqui mais uma vez para pedir a vossa ajuda.

Estou a tentar fazer um voltímetro com PIC, mas não sei como separar os números para os apresentar num display de 7 segmentos. Com um disply LCD já consegui fazer.

 

Por exemplo se a conversão ADC der 13,675 ou der 15,78954, como fazer para separar a parte inteira da decimal e como reduzir a parte decimal a apenas uma casa?????

Estou a usar linguagem C e o compilador PCW - CCS 4.114.

Se alguém me puder ajudar, agradeço desde já.

Link para o comentário
Compartilhar em outros sites

Boa noite.

você poderia postar o circuito. Para eu saber qual PIC  você esta usando e quais I/Os para ligar e multiplexar os displays...

Eu costumo usar o 4511 para facilitar minha vida na decodificação dos displays e economizar as I/Os

 

você pode separar os numeros por dividir eles... gasta muito processador (tempo) para executar, existe outras maneiras para fazer isso mas essa funciona e é muito simples fazer.

 

Se alguem souber uma mais simples... tipo funções próprias para isso.... por favor me fale, quero saber tb :)

 

 

Ex (em Mikroc):

 

floar valor=142.6233;

int  valor_int;

unsigned short decimo, unidade, dezena, centena;

 

valor_int= (int) valor *10; // transformo o numero em inteiro conservo uma casa decimal. Valor_int= 1426

 

decimo= valor_int%10; //divide por 10 e atribui o resto para a variavel. decimo=6

 

valor_int=valor_int/10; //valor int vai ser 142

unidade=valor_int%10;  //unidade vai ser 2

 

valor_int=valor_int/10; //valor_int vai ser 14

dezena= valor_int%10;  //valor_int será 4

centena=valor_int/10; //valor_int será 1

 

Pronto você ja separou todos os numeros... 

agora você pode colocar nos displays

 

Quando uso 4 displays e o 4511, deixo os 4 bits baixo da porta para o numero e os 4 bits altos da mesma porta multiplexar os displays

ai fica fácil... 

 

PORTB=decimo+16; //usando o bit 4 p/ setar o transistor do display do decimo e coloca o numero da variavel decimo nele. no caso do ex. acima nº 6 

  Delay_us(200); //para dar tempo de vê alguma coisa

  PORTB=unidade+32; //usando o bit 5 da porta B p/ setar o transistor do display da unidade. 
  Delay_us(200);
  PORTB=dezena+64;//usando o bit 6 p/ setar o transistor do display da dezena
  Delay_us(200);
  PORTB=centena+128;//usando o bit 7 p/ setar o transistor do display da centena
  Delay_us(200);
 
 PORTB=0x00;//apaga os displays para executar o programa senao o display da centena vai ficar mais aceso do que os outro e se você travar o programa, o display pode queimar visto será ligado direto no vcc sem resistores. você pode colocar a interrupção de Timmer para nao precisar fazer os Delays_us(xxx); e o clear na porta. O programa fica melhor mas é um pouco mais complicado.
 
Espero ter ajudado. 
Link para o comentário
Compartilhar em outros sites

Obrigado pela ajuda. Vou tentar fazer em C.

Então é assim.

Vou contar a história toda para que melhor possam perceber a minha intenção.

Há dias construi uma fonte variável de 2 a 30 voltes. Para “complicar” a situação, resolvi instalar um voltímetro. Então procurei na NET e encontrei um voltímetro com o PIC 16F676. Fui testar no Proteus e não funcionou. Não sei se é só no Proteus se na realidade também não funciona. Como não funcionou na simulação fiquei com medo de montar e depois não funcionar. 

Foi assim que resolvi fazer a minha programação e como estava a tratar do PIC 16F676, que já comprei, resolvi fazer a programação para este PIC. No entanto parece-me que este PIC é muito fraquinho (poucas capacidades).

Aqui fica o programa feito para LCD. Na simulação funciona bem, porque não é necessário separar os números. Agora eu estava a pensar montar o voltímetro com display de 7 segmentos (que tenho vários), para evitar comprar um LCD. E o problema é que com display de 7 segmentos vou ter que separar os números. Porém, só vou ter necessidade de apresentar 3 dígitos (unidade, dezena e uma casa decimal). Se fosse um número inteiro não tinha problemas, mas a virgula está a atrapalhar-me.

#include <16F676.h>#device ADC=10#FUSES NOWDT                    //No Watch Dog Timer#FUSES XT                       //Crystal osc <= 4mhz for PCM/PCH , 3mhz to 10 mhz for PCD#FUSES PUT                      //Power Up Timer#FUSES NOMCLR                   //Master Clear pin used for I/O#FUSES NOBROWNOUT               //No brownout reset#FUSES NOPROTECT                //Code not protected from reading#FUSES NOCPD                    //No EE protection#use delay(clock=1000000)#include <PIC16F676_Voltimetro_LCD_4Vias_02.h>#include <LCD.c>// CONSTANTES INTERNAS // Estas são as definições dos pinos que o LCD utiliza.// Definem quais pinos do PIC controlarão os pinos do LCD#define lcd_enable pin_c1     // pino enable do LCD#define lcd_rs pin_c0         // pino rs (register select)do LCD                              // (0) para comandos (1) para dados#define lcd_dc4 pin_c2        // pino de dados d4 do LCD#define lcd_dc5 pin_c3        // pino de dados d5 do LCD#define lcd_dc6 pin_c4        // pino de dados d6 do LCD#define lcd_dc7 pin_c5        // pino de dados d7 do LCD// DEFINIÇÃO E INICIALIZAÇÃO DOS PORTS #byte porta = 0x05#byte portc = 0x07// ENVIO DE NIBBLE PARA O LCD //Esta rotina lê o "Nibble" inferior de uma variável e envia para o LCD.//1byte = 8 bits = 2 Nibbles. Serão enviados para os pinos db4, db5, db6, db7 do LCDvoid envia_nibble_lcd(int dado){   //Carrega as vias de dados (pinos) do LCD de acordo com o nibble lido   output_bit(lcd_dc4, bit_test(dado,0));  //Carrega DB4 do LCD com o bit DADO<0>   output_bit(lcd_dc5, bit_test(dado,1));  //Carrega DB5 do LCD com o bit DADO<1>   output_bit(lcd_dc6, bit_test(dado,2));  //Carrega DB6 do LCD com o bit DADO<2>   output_bit(lcd_dc7, bit_test(dado,3));  //Carrega DB7 do LCD com o bit DADO<3>                                           //Gera um pulso de enable   output_high(lcd_enable);                // ENABLE = 1 delay_us(1);   delay_us(1);                            // Recomendado para estabilizar o LCD   output_low(lcd_enable);                 // ENABLE = 0   return;                                 // Retorna ao ponto de chamada}// ENVIO DE BYTE PARA O LCD // Esta rotina irá enviar um dado ou um comando para o LCD conforme abaixo:// ENDEREÇO = 0 -> a variável DADO será uma instrução// ENDEREÇO = 1 -> a variável DADO será um caracterevoid envia_byte_lcd(boolean endereco, int dado){   output_bit(lcd_rs,endereco);   // Seta o bit RS para instrução ou caractere   delay_us(100);                 // Aguarda 100 us para estabilizar o pino do LCD   output_low(lcd_enable);        // Desativa a linha ENABLE   envia_nibble_lcd(dado>>4);     // Envia a parte ALTA do dado/comando   envia_nibble_lcd(dado & 0x0f); // Limpa a parte ALTA e envia a parte BAIXA do                                  //dado/comando   delay_us(40);                  // Aguarda 40us para estabilizar o LCD   return;                        // Retorna ao ponto de chamada da função}/* * * * ** * * * * * * * * * * * * * * ** * * * * * * ** * ** ENVIO DE CARACTER PARA O LCD ** * * * * * * * * * * * * *  * * * * * * * * * * * * * * * */// Esta rotina serve apenas como uma forma mais fácil de escrever um caractere no display.void escreve_lcd(char c)      // envia caractere para o display{   envia_byte_lcd(1,c);}/* * * * * * * * * * * * * * * * * * * * * * * ** * * * * * * ** * ** FUNÇÃO PARA LIMPAR O LCD ** * * * * * * * * * * * * ** * * * * * * * * * ** * * * * * * ** * */// Como esta operação pode ser muito utilizada, transformando-a em função// faz com que o código compilado seja menor.void limpa_lcd(){   envia_byte_lcd(0,0x01);   // Envia instrução para limpar o LCD      // 0 - envio de instrução. 0X01 - mostrar tabela   delay_ms(2);              // Aguarda 2ms para estabilizar o LCD   return;                   // Retorna ao ponto de chamada da função}/* * * * * * * * * * * * * * * * * * * * * * * * * * * * ** INICIALIZA O LCD ** * * * * * * * * * * * * * * * * * * * * * * * * * * * */void inicializa_lcd(){   output_low(lcd_dc4);    // Garante que o pino DB4 estão em 0 (low)   output_low(lcd_dc5);    // Garante que o pino DB5 estão em 0 (low)   output_low(lcd_dc6);    // Garante que o pino DB6 estão em 0 (low)   output_low(lcd_dc7);    // Garante que o pino DB7 estão em 0 (low)   output_low(lcd_rs);     // Garante que o pino RS estão em 0 (low)   output_low(lcd_enable); // Garante que o pino ENABLE estão em 0 (low)   delay_ms(15);           // Aguarda 15ms para estabilizar o LCD   envia_nibble_lcd(0x02); // CURSOR HOME - Envia comando para zerar o                   //contador de caracteres e retornar à posição inicial (0x80)   delay_ms(1);            // Aguarda 1ms para estabilizar o LCD   //envia_byte_lcd(0,0x20); // FUNCTION SET - Configura o LCD para                            //4 bits, 1 linha, fonte 5X7.   envia_byte_lcd(0,0x28); // FUNCTION SET - Configura o LCD para                            //4 bits, 2 linhas, fonte 5X7.                                                   // 0 - envio de instrução 0x20 - mostrar tabela   envia_byte_lcd(0,0x0C); // DISPLAY CONTROL - Display ligado, sem cursor                           // 0 - envio de instrução 0x0C - mostrar tabela   limpa_lcd();            // Limpa o LCD   envia_byte_lcd(0,0x06); // ENTRY MODE SET - A cada caracter, incrementa uma posição                           // 0 - envio de instrução 0x06 - mostrar tabela   return;                 // Retorna ao ponto de chamada da função}// Serve para se definir em que posição do LCD deseja-se// iniciar a escrita. Para isto basta chamar a Função "caracter_Inicio()" // indicando a linha e a coluna onde o cursor será posicionado antes de se // mandar escrevervoid caracter_inicio(int linha, int coluna)  //define a posicão de inicio da frase{   int16 posicao=0;   if(linha == 1)   {      posicao=0x80;   //Se setado linha 1, end incial 0x80   }   if(linha == 2)   {      posicao=0xC0;  //Se setado linha 2, end incial 0xc0   }   posicao=posicao+coluna;   //soma ao end inicial, o numero da coluna   posicao--;                 //subtrai 1 para corrigir posição   envia_byte_lcd(0,posicao);   return;}void main(){   unsigned long int digital; // unsigned long int para ADC maior 10 bits   float tensão;      set_tris_a(0b11111111);   set_tris_c(0b00000000);   porta = 0;  // Reseta portas   portc = 0;   inicializa_lcd();    // Inicializa o LCD      setup_adc(ADC_CLOCK_INTERNAL);    //enables the a/d module and sets the clock to internal adc clock      setup_adc_ports(sAN1);      //sets all the adc pins to analog      setup_adc(adc_clock_div_2);      set_adc_channel(1);      //the next read_adc call will read channel       delay_ms(1);            //a small delay is required after setting the channel         while(true)   {      digital=read_adc();      delay_ms(1);       tensão=5*(float)digital/1023;      caracter_inicio(1,1);      printf(escreve_lcd,"tensão: %2.2f",tensão);      caracter_inicio(2,1);      printf(escreve_lcd,"ADC: %4Lu",digital);  //%4Lu para unsigned long int      delay_ms(1);     }}  

Voltimetro.jpg

Link para o comentário
Compartilhar em outros sites

@cesargos

Muito obrigado. Afinal até é fácil. As ideias é que nem sempre brilham.

Fiz assim (segue o código). Só que queria fazer com o PIC16F676 e com display de 7 segmentos e não consigo resolver, porque o PIC tem poucos pinos e eu não consigo configurá-lo para que dê certo.

#include <16F676.h>#device ADC=10#FUSES NOWDT                    //No Watch Dog Timer#FUSES INTRC_IO                 // osc interno#FUSES PUT                      //Power Up Timer#FUSES NOMCLR                   //Master Clear pin used for I/O#FUSES NOBROWNOUT               //No brownout reset#FUSES NOPROTECT                //Code not protected from reading#FUSES NOCPD                    //No EE protection#use delay(clock=1000000)//Com display de catodo comum// DEFINIÇÃO E INICIALIZAÇÃO DOS PORTS #use fast_io(a)#use fast_io(c)#byte porta = 0x05#byte portc = 0x07unsigned int dez, uni, dec;////////// Apresentar digito das dezenasvoid dezenas(){   output_high(pin_a1);    switch(dez)   {      case 0:      {         portc = 0b111111;      }      break;      case 1:      {         portc = 0b000110;      }      break;      case 2:      {         output_high(pin_a5);          portc = 0b011011;      }      break;      case 3:      {         output_high(pin_a5);          portc = 0b001111;      }      break;      case 4:      {         output_high(pin_a5);          portc = 0b100110;      }      break;      case 5:      {         output_high(pin_a5);          portc = 0b101101;      }      break;      case 6:      {         output_high(pin_a5);          portc = 0b111101;      }      break;      case 7:      {         portc = 0b000111;      }      break;      case 8:      {         output_high(pin_a5);          portc = 0b111111;      }      break;      case 9:      {         output_high(pin_a5);          portc = 0b101111;      }      break;   }   delay_ms(1);   output_low(pin_a1);   output_low(pin_a5);}////////// Apresentar digitovoid unidades(){   output_high(pin_a2);    switch(uni)   {      case 0:      {         portc = 0b111111;      }      break;      case 1:      {         portc = 0b000110;      }      break;      case 2:      {         output_high(pin_a5);          portc = 0b011011;      }      break;      case 3:      {         output_high(pin_a5);          portc = 0b001111;      }      break;      case 4:      {         output_high(pin_a5);          portc = 0b100110;      }      break;      case 5:      {         output_high(pin_a5);          portc = 0b101101;      }      break;      case 6:      {         output_high(pin_a5);          portc = 0b111101;      }      break;      case 7:      {         portc = 0b000111;      }      break;      case 8:      {         output_high(pin_a5);          portc = 0b111111;      }      break;      case 9:      {         output_high(pin_a5);          portc = 0b101111;      }      break;   }   delay_ms(1);   output_low(pin_a2);   output_low(pin_a5);  //Pino do segmento "g"}////////// Apresentar digitovoid decimas(){   output_high(pin_a4);    switch(dec)   {      case 0:      {         portc = 0b111111;      }      break;      case 1:      {         portc = 0b000110;      }      break;      case 2:      {         output_high(pin_a5);         portc = 0b011011;      }      break;      case 3:      {         output_high(pin_a5);         portc = 0b001111;      }      break;      case 4:      {         output_high(pin_a5);         portc = 0b100110;      }      break;      case 5:      {         output_high(pin_a5);         portc = 0b101101;      }      break;      case 6:      {         output_high(pin_a5);         portc = 0b111101;      }      break;      case 7:      {         portc = 0b000111;      }      break;      case 8:      {         output_high(pin_a5);         portc = 0b111111;      }      break;      case 9:      {         output_high(pin_a5);         portc = 0b101111;      }      break;   }   delay_ms(1);   output_low(pin_a4);  //Pino de ativacao das decimas   output_low(pin_a5);  //Pino do segmento "g"}////////// PROGRAMA PRINCIPALvoid main(){   unsigned long int digital, inte; // unsigned long int para ADC maior 10 bits   float tensao;   dez=0;      //Dezenas   uni=0;      //Unidades   dec=0;      //Parte decimal      set_tris_a(0b001001);   set_tris_c(0b000000);   porta = 0;  // Reseta portas   portc = 0;      DISABLE_INTERRUPTS(GLOBAL);   setup_comparator(NC_NC);   setup_vref(FALSE);         setup_adc(ADC_CLOCK_INTERNAL);    //enables the a/d module and sets the clock to internal adc clock   setup_adc_ports(sAN0);      //sets all the adc pins to analog   setup_adc(adc_clock_div_2);   set_adc_channel(0);      //the next read_adc call will read channel    delay_ms(1);            //a small delay is required after setting the channel         while(true)   {      //digital=read_adc();      digital=1228;      delay_ms(1);       tensao=5*(float)digital/1023;      tensao=tensao*10;   //Se tensao=23.657, fica 236.57      inte=(long int)tensao*1;   //Fica 236            dec=inte%10;   //divide por 10 e atribui o resto para a variável (6).      inte=inte/10;  //inte = 23      uni=inte%10;   //uni = 3      dez=inte/10;   //dez = 2            dezenas();     //Escreve o digito das dezenas      unidades();    //Escreve o digito das unidades      decimas();     //Escreve o digito das decimas   }}/////////// FIM DO PROGRAMA
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...

Ebook grátis: Aprenda a ler resistores e capacitores!

EBOOK GRÁTIS!

CLIQUE AQUI E BAIXE AGORA MESMO!