Ir ao conteúdo
  • Cadastre-se
valecovo

Multiplexar display de 7 segmentos em C

Recommended Posts

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á.

Compartilhar este post


Link para o post
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. 

Compartilhar este post


Link para o post
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

Compartilhar este post


Link para o post
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

Compartilhar este post


Link para o post
Compartilhar em outros sites

Crie uma conta ou entre para comentar

Você precisar ser um membro para fazer um comentário

Criar uma conta

Crie uma nova conta em nossa comunidade. É fácil!

Crie uma nova conta

Entrar

Já tem uma conta? Faça o login.

Entrar agora





Sobre o Clube do Hardware

No ar desde 1996, o Clube do Hardware é uma das maiores, mais antigas e mais respeitadas publicações 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

×