Sistemas Operacionais de Tempo Real - Displays de 7 segmentos

displays de 7 segmentos

Introdução

 

Este artigo faz parte da série de artigos que apresenta Bibliotecas de funções e rotinas padronizadas em linguagem C para MCS-51, que podem facilmente ser adaptadas para outros microcontroladores. Para a melhor compreensão do que será desenvolvido aqui, é recomendável que você leia os artigos anteriores dessa série e esse sobre displays de LED de 7 seguimentos.

 

A filosofia utilizada para o desenvolvimento das rotinas para os displays de 7 segmentos é a mesma utilizada nas rotinas apresentadas no artigo Sistemas Operacionais de Tempo Real – Timers. Cria-se um temporizador virtual por software, que é baseado na interrupção de um timer de hardware definindo assim a frequência com a qual os displays são atualizados. Deve-se escolher uma frequência de atualização alta o suficiente para que  não se tenha a desagradável sensação de que o display está “piscando”. Em geral essa frequência é da ordem de 20 a 30 vezes por segundo para cada display. A transferência de dados entre o programa principal e a rotina de interrupção é feita através de um vetor dedicado cujo conteúdo é o que deve ser apresentado no display e de eventuais mecanismos para controlar o acesso a esse vetor.

 

A biblioteca permite que se opere com algumas soluções de hardware distintas, tais como linhas de seleção multiplexadas, ou então separadas, dependendo do tipo de solução e compromissos desenvolvidos no projeto. Também é ilustrado como se pode de maneira simples codificar as letras e símbolos a serem mostrados nos displays.

 

 

Arquitetura de Hardware

 

Para que se possa desenvolver rotinas de programação padronizadas para os displays de 7 segmentos e cuja adaptação ao hardware seja simples é necessário definir arbitrariamente e fixar alguns modelos físicos para as conexões. A mais óbvia é a alocação de um port inteiro de 8 bits para gerar os segmentos e o ponto decimal dos displays. Para recordar como que é uma interface com um display de 7 segmentos, veja um exemplo na Figura 1.

 

Conexões de acionamento de um display de 7 segmentos
Figura 1: Conexões de acionamento de um display de 7 segmentos

 

 

 

Acionamento dos segmentos de LED

 

A atribuição dos segmentos de LED aos pinos do Port foi arbitrária. Por questão de simplicidade eles foram conectados em sequência numa mesma porta: bits 0123456 nos segmentos ABCDEFG e o ponto decimal foi colocado no bit 7. Pode-se observar na Figura 2 uma ilustração simplificada disso. Essa solução de hardware para conexão dos segmentos do display ao microcontrolador é pressuposta nas rotinas em linguagem C da biblioteca, que serão apresentadas mais adiante, agrupadas como ROTINA DOS DISPLAYS DE 7 SEGMENTOS I e ROTINA DOS DISPLAYS DE 7 SEGMENTOS II. O que diferencia os dois grupos, são as formas de seleção dos displays.

 

Exemplo de alocação dos segmentos dos Displays de 7 segmentos a um port de 8 bits
Figura 2: Exemplo de alocação dos segmentos dos displays a um port de 8 bits

 

Nessa atribuição arbitrária, pode-se formar os dígitos e alguns caracteres alfabéticos conforme ilustrado na Tabela 1.

 

Tabela 1: Códigos para acender os segmentos de acordo com o dígito ou caractere desejado.

// SEGMENTOS:                                   g f e | d c b a    Código Hexadecimal
//-----------------------------------------
// Dígito:                  apagado             0 0 0 | 0 0 0 0         = 0x00
//                              0               0 1 1 | 1 1 1 1         = 0x3f
//                              1               0 0 0 | 0 1 1 0         = 0x06
//                              2               1 0 1 | 1 0 1 1         = 0x5b
//                              3               1 0 0 | 1 1 1 1         = 0x4f
//                              4               1 1 0 | 0 1 1 0         = 0x66
//                              5               1 1 0 | 1 1 0 1         = 0x6d
//                              6               1 1 1 | 1 1 0 0         = 0x7c
//                              7               0 0 0 | 0 1 1 1         = 0x07
//                              8               1 1 1 | 1 1 1 1         = 0x7f
//                              9               1 1 0 | 0 1 1 1         = 0x67
//
//                              P               1 1 1 | 0 0 1 1         = 0x73
//                              r               1 0 1 | 0 0 0 0         = 0x50
//                              E               1 1 1 | 1 0 0 1         = 0x79
//                              F               1 1 1 | 0 0 0 1         = 0x71
//                              i               0 0 0 | 0 1 0 0         = 0x04

 

Outra forma de conectar o display de LED de 7 segmentos a um microprocessador é por meio de um decodificador BCD para 7 segmentos, tais como por exemplo os circuitos integrados 74LS49, ou então o 74HC4511. Na Figura 3 é ilustrada uma solução de hardware onde é utilizado um decodificador desse tipo, com a atribuição arbitrária dos pinos e ports utilizada nas rotinas padronizadas em linguagem C agrupadas como  ROTINA DOS DISPLAYS DE 7 SEGMENTOS III.

Displays de 7 segmentos decodificador
Figura 3: Solução de hardware com decodificador BCD / display de 7 segmentos

 

 

Formas de seleção dos displays

 

Nas rotinas padronizadas foram previstas duas formas de seleção dos displays: linhas de seleção separadas, utilizadas nos grupos de rotinas ROTINA DOS DISPLAYS DE 7 SEGMENTOS II e III, e linhas de seleção codificadas, utilizadas na ROTINA DOS DISPLAYS DE 7 SEGMENTOS I.

 

Linhas Separadas

 

As linhas de seleção separadas são alocadas num segundo Port. Uma definição cuidadosa das variáveis do programa padronizado, permite que se selecione em que bit do Port começam essas linhas. Essas linhas de seleção devem estar necessariamente alocadas em ordem crescente e na sequência dos pinos do Port. Veja por exemplo o código em C mostrado na Figura 4.

 

No exemplo da Figura 4 foram definidos que são utilizados 3 displays, os segmentos conectados ao Port 3, as linhas de seleção ao Port 1 e será utilizado o ponto decimal. Na parte específica relacionado com as linhas de seleção, é definido que as linhas estão alocadas nos pinos 5, 6 e 7 do Port 1 (0xE0).

 

#define NUMERO_DE_LINHAS_DO_DISPLAY                   3   // Número de linhas de seleção
#define PORTA_DE_SAIDA_DOS_DISPLAYS                  P3   // Define o Port onde estão conectados os displays
#define PORTA_DE_SAIDA_DA_SELECAO_DOS_DISPLAYS       P1   // Define o port onde estão conectadas as linhas de seleção

//#define TEM_PONTO_DECIMAL			              1

#ifdef TEM_PONTO_DECIMAL
	#define MASCARA_DOS_DISPLAYS                    0xff   // Filtra os bits de saída do port dos Displays	incluindo o do Ponto decimal
    #define FIM_DO_TESTE_DISPLAY                    0x08
#else
	#define MASCARA_DOS_DISPLAYS                    0x7f   // Filtra os bits de saída do port dos Displays, sem o ponto decimal
    #define FIM_DO_TESTE_DISPLAY                    0x07
#endif

#define LIGA_PONTO_DECIMAL                          0x80
#define MASCARA_DA_SELECAO_DE_DISPLAY               0xE0   // Filtra os bits dos sinais de seleção dos displays 
.
.
.
.

#define SELETOR_DOS_SINAIS_DE_SELECAO_DISPLAY	   0x20		// Define posição do primeiro bit do conjunto de seleção


 Figura 4: Definições relacionadas com as linhas de seleção

 

Linhas codificadas

 

Nessa forma de seleção dos displays são utilizados poucos pinos do port para codificar o número do display a ser ativado em código binário. Ou seja, 1 bit seleciona até dois displays, 2 bits quatro etc. A intenção foi a de economizar pinos nos Ports do microcontrolador, especialmente se o número de displays for grande. É necessária a utilização de um decodificador / multiplexador na saída do Port, conforme ilustrado na Figura 5. Um exemplo desse tipo de componente é o 74LS139.

Displays de 7 segmentos Selecao Multiplexada
Figura 5: Solução de hardware usando um multiplexador  para seleção dos Display de 7 segmentos

 

 

Rotinas padronizadas em C para os displays de 7 segmentos

 

O código em linguagem C para os displays segue o mesmo padrão do desenvolvido para os timers em Sistemas Operacionais de Tempo Real – Timers. Tem um conjunto de definições e variáveis, uma parte a ser inserida na rotina de interrupção do timer, de forma que quando o timer virtual do display terminar a contagem, é executado um trecho curto de código para atualizar os displays. No programa principal são inseridas algumas inicializações.

 

Definições e variáveis

 

A seguir os códigos exemplo referentes às definições e configurações correspondentes às arquiteturas descritas anteriormente. Esse trecho de código é inserido tipicamente num arquivo do tipo .h do programa.

 

ROTINA DOS DISPLAYS DE 7 SEGMENTOS I (Sinais de seleção codificados)

 

//*******************************************************************************
//*																			 *
//*		ROTINAS PADRONIZADAS PARA USO EM APLICAÇÕES 						 *
//*	 	 DE SISTEMAS MICROCONTROLADOS (FAMÍLIA 8051)						*
//*			      (Resp. Engº Puhlmann)                                      *												*
//*																			 *
//*			(31/05/2000 - Rev. 16/05/2005)								   *
//*																			 *
//*******************************************************************************

//===============================================================================
//
//		DEFINIÇÕES DOS DÍGITOS UTILIZADOS NA ROTINA DOS DISPLAYS DE 7 SEGMENTOS I
//							 Linhas de seleção codificadas
//		(Necessita de decodificador na saída para acinar as linhas de seleção)
//
//	Entradas : - 
//	Saídas   : - ucFilaDeSaidaDosDisplays[]		       - Vetor de saídas para os displays
//			   - ucIndiceDisplayAtivo				     - ìndica o display que está ativo
//
//		Deve-se definir um port dedicado a isso, configurado da seguinte maneira:
//
//		PORT.Bit	- Segmento do Display
//
//			Px.0	- a
//			Px.1	- b
//			Px.2	- c
//			Px.3	- d
//			Px.4	- e
//			Px.5	- f
//			Px.6	- g
//			Px.7	- DP
//
//			Composição dos números decimais utilizando a especificação acima:
//
//																	a
//																--------
//																|		|
//															  f |		| b 
//																|	g   |
//																---------
//																|		|
//															  e |		| c 
//																|	d   |
//																 -------
//
// SEGMENTOS:                                   g f e | d c b a    Código Hexadecimal
//-----------------------------------------
// Dígito:                  apagado             0 0 0 | 0 0 0 0         = 0x00
//                              0               0 1 1 | 1 1 1 1         = 0x3f
//                              1               0 0 0 | 0 1 1 0         = 0x06
//                              2               1 0 1 | 1 0 1 1         = 0x5b
//                              3               1 0 0 | 1 1 1 1         = 0x4f
//                              4               1 1 0 | 0 1 1 0         = 0x66
//                              5               1 1 0 | 1 1 0 1         = 0x6d
//                              6               1 1 1 | 1 1 0 0         = 0x7c
//                              7               0 0 0 | 0 1 1 1         = 0x07
//                              8               1 1 1 | 1 1 1 1         = 0x7f
//                              9               1 1 0 | 0 1 1 1         = 0x67
//
//                              P               1 1 1 | 0 0 1 1         = 0x73
//                              r               1 0 1 | 0 0 0 0         = 0x50
//                              E               1 1 1 | 1 0 0 1         = 0x79
//                              F               1 1 1 | 0 0 0 1         = 0x71
//                              i               0 0 0 | 0 1 0 0         = 0x04
//
//=====									    =====

//#define DISPLAY_INVERTIDO                               1
#define TEM_PONTO_DECIMAL                                1

#ifdef DISPLAY_INVERTIDO
	#ifdef TEM_PONTO_DECIMAL
		#define MASCARA_INV_DISPLAY                       0xff 
		#define DESLIGA_TODOS_SEGMENTOS_DISP_7_SEG_E_PD   MASCARA_INV_DISPLAY
 	   #define LIGA_TODOS_SEGMENTOS_DISP_7_SEG_E_PD      0x00
	#else
		#define MASCARA_INV_DISPLAY			  0x7f 
		#define DESLIGA_TODOS_SEGMENTOS_DISP_7_SEG_E_PD   MASCARA_INV_DISPLAY
 	   #define LIGA_TODOS_SEGMENTOS_DISP_7_SEG_E_PD      0x00
	#endif
#else
	#define MASCARA_INV_DISPLAY                            0x00 

	#ifdef TEM_PONTO_DECIMAL
		#define DESLIGA_TODOS_SEGMENTOS_DISP_7_SEG_E_PD    MASCARA_INV_DISPLAY
	    #define LIGA_TODOS_SEGMENTOS_DISP_7_SEG_E_PD       0xff
    #else
		#define DESLIGA_TODOS_SEGMENTOS_DISP_7_SEG_E_PD    MASCARA_INV_DISPLAY
	    #define LIGA_TODOS_SEGMENTOS_DISP_7_SEG_E_PD       0x7f
	#endif
#endif


#define DISPLAY_7_SEG_APAGADO				 0x00 ^ MASCARA_INV_DISPLAY

#define DISPLAY_7_SEG_ZERO					0x3f ^ MASCARA_INV_DISPLAY
#define DISPLAY_7_SEG_UM					  0x06 ^ MASCARA_INV_DISPLAY
#define DISPLAY_7_SEG_DOIS					0x5b ^ MASCARA_INV_DISPLAY
#define DISPLAY_7_SEG_TRES					0x4f ^ MASCARA_INV_DISPLAY
#define DISPLAY_7_SEG_QUATRO				  0x66 ^ MASCARA_INV_DISPLAY
#define DISPLAY_7_SEG_CINCO				   0x6d ^ MASCARA_INV_DISPLAY
#define DISPLAY_7_SEG_SEIS					0x7c ^ MASCARA_INV_DISPLAY
#define DISPLAY_7_SEG_SETE					0x07 ^ MASCARA_INV_DISPLAY
#define DISPLAY_7_SEG_OITO					0x7f ^ MASCARA_INV_DISPLAY
#define DISPLAY_7_SEG_NOVE					0x67 ^ MASCARA_INV_DISPLAY

#define DISPLAY_7_SEG_PE					  0x73 ^ MASCARA_INV_DISPLAY
#define DISPLAY_7_SEG_ERRE					0x50 ^ MASCARA_INV_DISPLAY
#define DISPLAY_7_SEG_E					   0x79 ^ MASCARA_INV_DISPLAY
#define DISPLAY_7_SEG_EFE					 0x71 ^ MASCARA_INV_DISPLAY
#define DISPLAY_7_SEG_I					   0x04 ^ MASCARA_INV_DISPLAY

#define NUMERO_DE_DISPLAYS					0x03

#define FREQ_DE_INTERRUP_TIMER_DISPLAYS  	90.0	// Hz

// ************* Precisa revisar essas linhas !!!!! *****

//#define PRESET_TEMPORIZADOR_DOS_DISPLAYS  (unsigned int)(((FREQUENCIA_DE_INTERRUPCAO_TIMER_0 * NUMERO_DE_DISPLAYS)/ FREQ_DE_INTERRUP_TIMER_DISPLAYS)+ 0.5) // Original, mas acho que está errado
#define PRESET_TEMPORIZADOR_DOS_DISPLAYS  (unsigned int)(((FREQUENCIA_DE_INTERRUPCAO_TIMER_0 )/ (FREQ_DE_INTERRUP_TIMER_DISPLAYS * NUMERO_DE_DISPLAYS))+ 0.5) 

//********************************************************

#define NUMERO_DE_LINHAS_DO_DISPLAY                 2		 // Número de linhas de seleção
#define PORTA_DE_SAIDA_DOS_DISPLAYS                 P3		// Define o Port onde estão conectados os displays
#define PORTA_DE_SAIDA_DA_SELECAO_DOS_DISPLAYS      P1		// Define o port onde estão conectadas as linhas de seleção


#ifdef TEM_PONTO_DECIMAL
	#define MASCARA_DOS_DISPLAYS				   0xff		// Filtra os bits de saída do port dos Displays	incluindo o do Ponto decimal
    #define FIM_DO_TESTE_DISPLAY				   0x08
#else
	#define MASCARA_DOS_DISPLAYS				   0x7f		// Filtra os bits de saída do port dos Displays, sem o ponto decimal
    #define FIM_DO_TESTE_DISPLAY				   0x07
#endif

#define LIGA_PONTO_DECIMAL	                     0x80
#define MASCARA_DA_SELECAO_DE_DISPLAY		      0xe0		// Filtra os bits dos sinais de seleção dos displays 
#define INCREMENTO_PARA_O_CONTADOR_DE_SELECAO_DISP 0x40		// Define o "mais 1" no contador

//#define SAIDAS_INVERTIDAS_SEL_DISP				 1		 // Define se as saidas de selecao sao invertidas ou nao

#ifdef SAIDAS_INVERTIDAS_SEL_DISP
	#define MASCARA_DE_INVERSAO_SEL_DISP			MASCARA_DA_SELECAO_DE_DISPLAY
#else
	#define MASCARA_DE_INVERSAO_SEL_DISP			0x00
#endif


volatile int unTimerDosDisplays  = PRESET_TEMPORIZADOR_DOS_DISPLAYS;
unsigned char ucFilaDeSaidaDosDisplays[NUMERO_DE_DISPLAYS] = { DESLIGA_TODOS_SEGMENTOS_DISP_7_SEG_E_PD,
															   DESLIGA_TODOS_SEGMENTOS_DISP_7_SEG_E_PD,
														       DESLIGA_TODOS_SEGMENTOS_DISP_7_SEG_E_PD};
unsigned char ucIndiceDisplayAtivo = 0;
unsigned char ucContadorDeSelecaoDisplay = 0;

//-------- Definição das variáveis globais ---------------

code unsigned char ucTabelaDeDisplayDeSeteSegmentos[10] = { DISPLAY_7_SEG_ZERO,
															DISPLAY_7_SEG_UM,
															DISPLAY_7_SEG_DOIS,
															DISPLAY_7_SEG_TRES,
															DISPLAY_7_SEG_QUATRO,
															DISPLAY_7_SEG_CINCO,
															DISPLAY_7_SEG_SEIS,
															DISPLAY_7_SEG_SETE,
															DISPLAY_7_SEG_OITO,
															DISPLAY_7_SEG_NOVE};


//----------------- Fim dos parâmetros e variáveis dos displays  do tipo I ---------

 

ROTINA DOS DISPLAYS DE 7 SEGMENTOS II (Sinais de seleção separados)

 

//*******************************************************************************
//*																			 *
//*		ROTINAS PADRONIZADAS PARA USO EM APLICAÇÕES 						 *
//*	 	 DE SISTEMAS MICROCONTROLADOS (FAMÍLIA 8051)						*
//*			      (Resp. Engº Puhlmann)                                      *												*
//*																			 *
//*			(31/05/2000 - Rev. 16/05/2005)								   *
//*																			 *
//*******************************************************************************

//===============================================================================
//
//		DEFINIÇÕES DOS DÍGITOS UTILIZADOS NA ROTINA DOS DISPLAYS DE 7 SEGMENTOS II
//							 Linhas de seleção separadas
//			(Cada linha de seleção corresponde a um bit da Porta)
//
//	Entradas : - 
//	Saídas   : - ucFilaDeSaidaDosDisplays[]		       - Vetor de saídas para os displays
//			   - ucIndiceDisplayAtivo				     - ìndica o display que está ativo
//
//		Deve-se definir um port dedicado a isso, configurado da seguinte maneira:
//
//		PORT.Bit	- Segmento do Display
//
//			Px.0	- a
//			Px.1	- b
//			Px.2	- c
//			Px.3	- d
//			Px.4	- e
//			Px.5	- f
//			Px.6	- g
//			Px.7	- DP
//
//			Composição dos números decimais utilizando a especificação acima:
//
//																	a
//																--------
//																|		|
//															  f |		| b 
//																|	g   |
//																---------
//																|		|
//															  e |		| c 
//																|	d   |
//																 -------
//
// SEGMENTOS:                                   g f e | d c b a    Código Hexadecimal
//-----------------------------------------
// Dígito:                  apagado             0 0 0 | 0 0 0 0         = 0x00
//                              0               0 1 1 | 1 1 1 1         = 0x3f
//                              1               0 0 0 | 0 1 1 0         = 0x06
//                              2               1 0 1 | 1 0 1 1         = 0x5b
//                              3               1 0 0 | 1 1 1 1         = 0x4f
//                              4               1 1 0 | 0 1 1 0         = 0x66
//                              5               1 1 0 | 1 1 0 1         = 0x6d
//                              6               1 1 1 | 1 1 0 0         = 0x7c
//                              7               0 0 0 | 0 1 1 1         = 0x07
//                              8               1 1 1 | 1 1 1 1         = 0x7f
//                              9               1 1 0 | 0 1 1 1         = 0x67
//
//                              P               1 1 1 | 0 0 1 1         = 0x73
//                              r               1 0 1 | 0 0 0 0         = 0x50
//                              E               1 1 1 | 1 0 0 1         = 0x79
//                              F               1 1 1 | 0 0 0 1         = 0x71
//                              i               0 0 0 | 0 1 0 0         = 0x04
//
//=====									    =====

//#define DISPLAY_INVERTIDO                               1
#define TEM_PONTO_DECIMAL                                1

#ifdef DISPLAY_INVERTIDO
	#ifdef TEM_PONTO_DECIMAL
		#define MASCARA_INV_DISPLAY                       0xff 
		#define DESLIGA_TODOS_SEGMENTOS_DISP_7_SEG_E_PD   MASCARA_INV_DISPLAY
 	   #define LIGA_TODOS_SEGMENTOS_DISP_7_SEG_E_PD      0x00
	#else
		#define MASCARA_INV_DISPLAY			  0x7f 
		#define DESLIGA_TODOS_SEGMENTOS_DISP_7_SEG_E_PD   MASCARA_INV_DISPLAY
 	   #define LIGA_TODOS_SEGMENTOS_DISP_7_SEG_E_PD      0x00
	#endif
#else
	#define MASCARA_INV_DISPLAY                            0x00 

	#ifdef TEM_PONTO_DECIMAL
		#define DESLIGA_TODOS_SEGMENTOS_DISP_7_SEG_E_PD    MASCARA_INV_DISPLAY
	    #define LIGA_TODOS_SEGMENTOS_DISP_7_SEG_E_PD       0xff
    #else
		#define DESLIGA_TODOS_SEGMENTOS_DISP_7_SEG_E_PD    MASCARA_INV_DISPLAY
	    #define LIGA_TODOS_SEGMENTOS_DISP_7_SEG_E_PD       0x7f
	#endif
#endif


#define DISPLAY_7_SEG_APAGADO				 0x00 ^ MASCARA_INV_DISPLAY

#define DISPLAY_7_SEG_ZERO					0x3f ^ MASCARA_INV_DISPLAY
#define DISPLAY_7_SEG_UM					  0x06 ^ MASCARA_INV_DISPLAY
#define DISPLAY_7_SEG_DOIS					0x5b ^ MASCARA_INV_DISPLAY
#define DISPLAY_7_SEG_TRES					0x4f ^ MASCARA_INV_DISPLAY
#define DISPLAY_7_SEG_QUATRO				  0x66 ^ MASCARA_INV_DISPLAY
#define DISPLAY_7_SEG_CINCO				   0x6d ^ MASCARA_INV_DISPLAY
#define DISPLAY_7_SEG_SEIS					0x7c ^ MASCARA_INV_DISPLAY
#define DISPLAY_7_SEG_SETE					0x07 ^ MASCARA_INV_DISPLAY
#define DISPLAY_7_SEG_OITO					0x7f ^ MASCARA_INV_DISPLAY
#define DISPLAY_7_SEG_NOVE					0x67 ^ MASCARA_INV_DISPLAY

#define DISPLAY_7_SEG_PE					  0x73 ^ MASCARA_INV_DISPLAY
#define DISPLAY_7_SEG_ERRE					0x50 ^ MASCARA_INV_DISPLAY
#define DISPLAY_7_SEG_E					   0x79 ^ MASCARA_INV_DISPLAY
#define DISPLAY_7_SEG_EFE					 0x71 ^ MASCARA_INV_DISPLAY
#define DISPLAY_7_SEG_I					   0x04 ^ MASCARA_INV_DISPLAY

#define NUMERO_DE_DISPLAYS					0x04

#define FREQ_DE_INTERRUP_TIMER_DISPLAYS  	120.0	// Hz

// ************* Precisa revisar essas linhas !!!!! *****

//#define PRESET_TEMPORIZADOR_DOS_DISPLAYS  (unsigned int)(((FREQUENCIA_DE_INTERRUPCAO_TIMER_0 * NUMERO_DE_DISPLAYS)/ FREQ_DE_INTERRUP_TIMER_DISPLAYS)+ 0.5) // Original, mas acho que está errado
#define PRESET_TEMPORIZADOR_DOS_DISPLAYS  (unsigned int)(((FREQUENCIA_DE_INTERRUPCAO_TIMER_0 )/ (FREQ_DE_INTERRUP_TIMER_DISPLAYS * NUMERO_DE_DISPLAYS))+ 0.5) 

//********************************************************

#define NUMERO_DE_LINHAS_DO_DISPLAY                 4		 // Número de linhas de seleção
#define PORTA_DE_SAIDA_DOS_DISPLAYS                 P3		// Define o Port onde estão conectados os displays
#define PORTA_DE_SAIDA_DA_SELECAO_DOS_DISPLAYS      P1		// Define o port onde estão conectadas as linhas de seleção


#ifdef TEM_PONTO_DECIMAL
	#define MASCARA_DOS_DISPLAYS				   0xff		// Filtra os bits de saída do port dos Displays	incluindo o do Ponto decimal
    #define FIM_DO_TESTE_DISPLAY				   0x08
#else
	#define MASCARA_DOS_DISPLAYS				   0x7f		// Filtra os bits de saída do port dos Displays, sem o ponto decimal
    #define FIM_DO_TESTE_DISPLAY				   0x07
#endif

#define LIGA_PONTO_DECIMAL	                     0x80
#define MASCARA_DA_SELECAO_DE_DISPLAY		      0xf0		// Filtra os bits dos sinais de seleção dos displays 

// Bit de seleção a ser shiftado, para gerar o sinal de seleção ...  bit 1 (define a primeira linha a ser lida)

#define SELETOR_DOS_SINAIS_DE_SELECAO_DISPLAY	  0x10		// Define posição do primeiro bit do conjunto de seleção


//#define SAIDAS_INVERTIDAS_SEL_DISP				 1		 // Define se as saidas de selecao sao invertidas ou nao

#ifdef SAIDAS_INVERTIDAS_SEL_DISP
	#define MASCARA_DE_INVERSAO_SEL_DISP			MASCARA_DA_SELECAO_DE_DISPLAY
#else
	#define MASCARA_DE_INVERSAO_SEL_DISP			0x00
#endif


volatile int unTimerDosDisplays  = PRESET_TEMPORIZADOR_DOS_DISPLAYS;
unsigned char ucFilaDeSaidaDosDisplays[NUMERO_DE_DISPLAYS] = { DESLIGA_TODOS_SEGMENTOS_DISP_7_SEG_E_PD,
                                                               DESLIGA_TODOS_SEGMENTOS_DISP_7_SEG_E_PD,
                                                               DESLIGA_TODOS_SEGMENTOS_DISP_7_SEG_E_PD,
                                                               DESLIGA_TODOS_SEGMENTOS_DISP_7_SEG_E_PD};

unsigned char ucIndiceDisplayAtivo = 0;
unsigned char ucContadorDeSelecaoDisplay = 0;

//-------- Definição das variáveis globais ---------------

code unsigned char ucTabelaDeDisplayDeSeteSegmentos[10] = { DISPLAY_7_SEG_ZERO,
															DISPLAY_7_SEG_UM,
															DISPLAY_7_SEG_DOIS,
															DISPLAY_7_SEG_TRES,
															DISPLAY_7_SEG_QUATRO,
															DISPLAY_7_SEG_CINCO,
															DISPLAY_7_SEG_SEIS,
															DISPLAY_7_SEG_SETE,
															DISPLAY_7_SEG_OITO,
															DISPLAY_7_SEG_NOVE};


//----------------- Fim dos parâmetros e variáveis dos displays  do tipo II ---------

 

ROTINA DOS DISPLAYS DE 7 SEGMENTOS III (Utiliza decodificador BCD para 7 segmentos e sinais de seleção separados)

 

//*******************************************************************************
//*																			 *
//*		ROTINAS PADRONIZADAS PARA USO EM APLICAÇÕES 						 *
//*	 	 DE SISTEMAS MICROCONTROLADOS (FAMÍLIA 8051)						*
//*			      (Resp. Engº Puhlmann)                                      *												*
//*																			 *
//*			(31/05/2000 - Rev. 16/05/2005)								   *
//*																			 *
//*******************************************************************************

//===============================================================================
//
//		DEFINIÇÕES DOS DÍGITOS UTILIZADOS NA ROTINA DOS DISPLAYS DE 7 SEGMENTOS III
//							 Linhas de seleção separadas
//			(Cada linha de seleção corresponde a um bit da Porta)
//
//	Entradas : - 
//	Saídas   : - ucFilaDeSaidaDosDisplays[]		       - Vetor de saídas para os displays
//			   - ucIndiceDisplayAtivo				     - ìndica o display que está ativo
//
//		Deve-se definir um port dedicado a isso, configurado da seguinte maneira:
//
//		PORT.Bit	- Segmento do Display
//
//			Px.0	- a
//			Px.1	- b
//			Px.2	- c
//			Px.3	- d
//			Px.4	- e
//			Px.5	- f
//			Px.6	- g
//			Px.7	- DP
//
//			Composição dos números decimais utilizando a especificação acima:
//
//																	a
//																--------
//																|		|
//															  f |		| b 
//																|	g   |
//																---------
//																|		|
//															  e |		| c 
//																|	d   |
//																 -------
//
// SEGMENTOS:                                   g f e | d c b a    Código Hexadecimal
//-----------------------------------------
// Dígito:                  apagado             0 0 0 | 0 0 0 0         = 0x00
//                              0               0 1 1 | 1 1 1 1         = 0x3f
//                              1               0 0 0 | 0 1 1 0         = 0x06
//                              2               1 0 1 | 1 0 1 1         = 0x5b
//                              3               1 0 0 | 1 1 1 1         = 0x4f
//                              4               1 1 0 | 0 1 1 0         = 0x66
//                              5               1 1 0 | 1 1 0 1         = 0x6d
//                              6               1 1 1 | 1 1 0 0         = 0x7c
//                              7               0 0 0 | 0 1 1 1         = 0x07
//                              8               1 1 1 | 1 1 1 1         = 0x7f
//                              9               1 1 0 | 0 1 1 1         = 0x67
//
//                              P               1 1 1 | 0 0 1 1         = 0x73
//                              r               1 0 1 | 0 0 0 0         = 0x50
//                              E               1 1 1 | 1 0 0 1         = 0x79
//                              F               1 1 1 | 0 0 0 1         = 0x71
//                              i               0 0 0 | 0 1 0 0         = 0x04
//
//=====									    =====

//#define DISPLAY_INVERTIDO                               1
#define TEM_PONTO_DECIMAL                                1

#ifdef DISPLAY_INVERTIDO
	#ifdef TEM_PONTO_DECIMAL
		#define MASCARA_INV_DISPLAY                       0xff 
		#define DESLIGA_TODOS_SEGMENTOS_DISP_7_SEG_E_PD   MASCARA_INV_DISPLAY
 	   #define LIGA_TODOS_SEGMENTOS_DISP_7_SEG_E_PD      0x00
	#else
		#define MASCARA_INV_DISPLAY			  0x7f 
		#define DESLIGA_TODOS_SEGMENTOS_DISP_7_SEG_E_PD   MASCARA_INV_DISPLAY
 	   #define LIGA_TODOS_SEGMENTOS_DISP_7_SEG_E_PD      0x00
	#endif
#else
	#define MASCARA_INV_DISPLAY                            0x00 

	#ifdef TEM_PONTO_DECIMAL
		#define DESLIGA_TODOS_SEGMENTOS_DISP_7_SEG_E_PD    MASCARA_INV_DISPLAY
	    #define LIGA_TODOS_SEGMENTOS_DISP_7_SEG_E_PD       0xff
    #else
		#define DESLIGA_TODOS_SEGMENTOS_DISP_7_SEG_E_PD    MASCARA_INV_DISPLAY
	    #define LIGA_TODOS_SEGMENTOS_DISP_7_SEG_E_PD       0x7f
	#endif
#endif


#define DISPLAY_7_SEG_APAGADO				 0x00 ^ MASCARA_INV_DISPLAY

#define DISPLAY_7_SEG_ZERO					0x3f ^ MASCARA_INV_DISPLAY
#define DISPLAY_7_SEG_UM					  0x06 ^ MASCARA_INV_DISPLAY
#define DISPLAY_7_SEG_DOIS					0x5b ^ MASCARA_INV_DISPLAY
#define DISPLAY_7_SEG_TRES					0x4f ^ MASCARA_INV_DISPLAY
#define DISPLAY_7_SEG_QUATRO				  0x66 ^ MASCARA_INV_DISPLAY
#define DISPLAY_7_SEG_CINCO				   0x6d ^ MASCARA_INV_DISPLAY
#define DISPLAY_7_SEG_SEIS					0x7c ^ MASCARA_INV_DISPLAY
#define DISPLAY_7_SEG_SETE					0x07 ^ MASCARA_INV_DISPLAY
#define DISPLAY_7_SEG_OITO					0x7f ^ MASCARA_INV_DISPLAY
#define DISPLAY_7_SEG_NOVE					0x67 ^ MASCARA_INV_DISPLAY

#define DISPLAY_7_SEG_PE					  0x73 ^ MASCARA_INV_DISPLAY
#define DISPLAY_7_SEG_ERRE					0x50 ^ MASCARA_INV_DISPLAY
#define DISPLAY_7_SEG_E					   0x79 ^ MASCARA_INV_DISPLAY
#define DISPLAY_7_SEG_EFE					 0x71 ^ MASCARA_INV_DISPLAY
#define DISPLAY_7_SEG_I					   0x04 ^ MASCARA_INV_DISPLAY

#define NUMERO_DE_DISPLAYS					0x04

#define FREQ_DE_INTERRUP_TIMER_DISPLAYS  	90.0	// Hz

// ************* Precisa revisar essas linhas !!!!! *****

//#define PRESET_TEMPORIZADOR_DOS_DISPLAYS  (unsigned int)(((FREQUENCIA_DE_INTERRUPCAO_TIMER_0 * NUMERO_DE_DISPLAYS)/ FREQ_DE_INTERRUP_TIMER_DISPLAYS)+ 0.5) // Original, mas acho que está errado
#define PRESET_TEMPORIZADOR_DOS_DISPLAYS  (unsigned int)(((FREQUENCIA_DE_INTERRUPCAO_TIMER_0 )/ (FREQ_DE_INTERRUP_TIMER_DISPLAYS * NUMERO_DE_DISPLAYS))+ 0.5) 

//********************************************************

#define NUMERO_DE_LINHAS_DO_DISPLAY                 4		 // Número de linhas de seleção
#define PORTA_DE_SAIDA_DOS_DISPLAYS                 P3		// Define o Port onde estão conectados os displays
#define PORTA_DE_SAIDA_DA_SELECAO_DOS_DISPLAYS      P1		// Define o port onde estão conectadas as linhas de seleção


#ifdef TEM_PONTO_DECIMAL
	#define MASCARA_DOS_DISPLAYS				   0xff		// Filtra os bits de saída do port dos Displays	incluindo o do Ponto decimal
    #define FIM_DO_TESTE_DISPLAY				   0x08
#else
	#define MASCARA_DOS_DISPLAYS				   0x7f		// Filtra os bits de saída do port dos Displays, sem o ponto decimal
    #define FIM_DO_TESTE_DISPLAY				   0x07
#endif

#define LIGA_PONTO_DECIMAL	                     0x80
#define MASCARA_DA_SELECAO_DE_DISPLAY		      0xf0		// Filtra os bits dos sinais de seleção dos displays 

// Bit de seleção a ser shiftado, para gerar o sinal de seleção ...  bit 1 (define a primeira linha a ser lida)

#define SELETOR_DOS_SINAIS_DE_SELECAO_DISPLAY	  0x10		// Define posição do primeiro bit do conjunto de seleção


//#define SAIDAS_INVERTIDAS_SEL_DISP				 1		 // Define se as saidas de selecao sao invertidas ou nao

#ifdef SAIDAS_INVERTIDAS_SEL_DISP
	#define MASCARA_DE_INVERSAO_SEL_DISP			MASCARA_DA_SELECAO_DE_DISPLAY
#else
	#define MASCARA_DE_INVERSAO_SEL_DISP			0x00
#endif


volatile int unTimerDosDisplays  = PRESET_TEMPORIZADOR_DOS_DISPLAYS;
unsigned char ucFilaDeSaidaDosDisplays[NUMERO_DE_DISPLAYS] = { DESLIGA_TODOS_SEGMENTOS_DISP_7_SEG_E_PD,
                                                               DESLIGA_TODOS_SEGMENTOS_DISP_7_SEG_E_PD,
                                                               DESLIGA_TODOS_SEGMENTOS_DISP_7_SEG_E_PD,
                                                               DESLIGA_TODOS_SEGMENTOS_DISP_7_SEG_E_PD};

unsigned char ucIndiceDisplayAtivo = 0;
unsigned char ucContadorDeSelecaoDisplay = 0;

//-------- Definição das variáveis globais ---------------

code unsigned char ucTabelaDeDisplayDeSeteSegmentos[10] = { DISPLAY_7_SEG_ZERO,
															DISPLAY_7_SEG_UM,
															DISPLAY_7_SEG_DOIS,
															DISPLAY_7_SEG_TRES,
															DISPLAY_7_SEG_QUATRO,
															DISPLAY_7_SEG_CINCO,
															DISPLAY_7_SEG_SEIS,
															DISPLAY_7_SEG_SETE,
															DISPLAY_7_SEG_OITO,
															DISPLAY_7_SEG_NOVE};


//----------------- Fim dos parâmetros e variáveis dos displays  do tipo III ---------

 

São utilizadas algumas convenções com relação às definições e uso das constantes. Em todo o programa, 1 quer dizer ligado ou ativo e 0 desligado ou inativo. Este trecho de código é na sua essência o configurador dos displays, amarrando as particularidades do hardware com o software. O código é muito parecido com o da primeira rotina. Existem apenas algumas pequenas diferenças O que deve ser configurado:

  • #define DISPLAY_INVERTIDO: Essa linha deve ser colocada como comentário, se acaso as saídas para os segmentos não necessitam de inversão lógica;
  • #define TEM_PONTO_DECIMAL: Essa linha deve ser colocada como comentário, se acaso não for utilizado o ponto decimal;
  • #define NUMERO_DE_DISPLAYS: Nessa linha deverá ser colocado o número de displays multiplexados que existem no hardware;
  • #define FREQ_DE_INTERRUP_TIMER_DISPLAYS: é a frequência de atualização de um display multiplicada pelo número de displays;
  • #define NUMERO_DE_LINHAS_DO_DISPLAY: Aqui é definido o número de linhas de seleção que serão utilizadas;
  • #define PORTA_DE_SAIDA_DOS_DISPLAYS: Aqui deve ser definida em que Port estão conectados os segmentos dos displays;
  • #define PORTA_DE_SAIDA_DA_SELECAO_DOS_DISPLAYS: Aqui é definido em que Port estão conectadas as linhas de seleção;
  • #define MASCARA_DA_SELECAO_DE_DISPLAY: Aqui é definida a posição e abrangência das linhas de seleção;
  • #define SELETOR_DOS_SINAIS_DE_SELECAO_DISPLAY: Define a posição do bit de seleção que será deslocado em anel para selecionar os diversos displays;
  • #define SAIDAS_INVERTIDAS_SEL_DISP : Colocar essa linha como comentário, se acaso as linhas de seleção não precisarem ser invertidas;
  • unsigned char ucFilaDeSaidaDosDisplays[NUMERO_DE_DISPLAYS]: É necessário dimensionar e inicializar corretamente esse vetor.

 

As demais variáveis e constantes são calculadas automaticamente pelo programa.

 

Código a ser inserido na rotina de interrupção do Timer 0

 

Os trechos de códigos a seguir implementam um temporizador virtual para o acionamento dos displays. Sempre que o contador termina a contagem, é desligado o display atual e ativado o próximo, tomando as providências de hardware para isso.

 

ROTINA DOS DISPLAYS DE 7 SEGMENTOS I        (Sinais de seleção codificados)

 

//**********************************************************************************************
//************* Trecho a ser inserido na rotina de interrupção do Timer (exemplo) **************
//************* 																  **************

//*******************************************************************************
//								 TIMER 0 	
//							rotina de interrupção
//


void vInterrupcaoTimer0() interrupt 1 
{
  .
  .
  .
  //*******************************************************************************
  //****** Trecho a ser inserido na rotina de interrupção do timer - DISPLAYS I ***
  //******                                                                      ***

  if(--unTimerDosDisplays == 0)
  {
    unsigned char ucAux;

    unTimerDosDisplays = PRESET_TEMPORIZADOR_DOS_DISPLAYS;          // Reinicializa temporizador

	ucAux = PORTA_DE_SAIDA_DOS_DISPLAYS & ~MASCARA_DOS_DISPLAYS;    // Lê o conteúdo do port, para salvar o bit do Ponto decinal, se for o caso
	ucAux |= DISPLAY_7_SEG_APAGADO;	                             // Apaga o display
    PORTA_DE_SAIDA_DOS_DISPLAYS = ucAux;                            // Atualiza a saída


	if(ucIndiceDisplayAtivo == NUMERO_DE_DISPLAYS)                  // Testa se atualizou o último display
	{
      ucIndiceDisplayAtivo = 0;                                     // Reinicializa o Indice do display
      ucContadorDeSelecaoDisplay = 0;                               // Reinicializa o contador de seleção
	}

    ucAux = ~MASCARA_DA_SELECAO_DE_DISPLAY;                         // Inverte os bits da mascara
    ucAux &= PORTA_DE_SAIDA_DA_SELECAO_DOS_DISPLAYS;                // Filtra os bits de seleção

    ucAux |= (ucContadorDeSelecaoDisplay ^ MASCARA_DE_INVERSAO_SEL_DISP);
    PORTA_DE_SAIDA_DA_SELECAO_DOS_DISPLAYS = ucAux;

	ucAux = PORTA_DE_SAIDA_DOS_DISPLAYS & ~MASCARA_DOS_DISPLAYS;    // Lê o conteúdo do port, para salvar o bit do Ponto decinal, se for o caso
	ucAux |= ucFilaDeSaidaDosDisplays[ucIndiceDisplayAtivo++];      // Lê o valor a ser apresentado no display
    PORTA_DE_SAIDA_DOS_DISPLAYS = ucAux;			                // Atualiza a saída
  
    ucContadorDeSelecaoDisplay += INCREMENTO_PARA_O_CONTADOR_DE_SELECAO_DISP;  // Incrementa o contador
   }
  //************** Fim da Rotina Displays I ***************************************
  .
  .
  .
}

 

ROTINA DOS DISPLAYS DE 7 SEGMENTOS II (Sinais de seleção separados)

 

Para examinar o código, “clique” na barra a seguir.

//**********************************************************************************************
//************* Trecho a ser inserido na rotina de interrupção do Timer (exemplo) **************
//*************                                                                   **************

//*******************************************************************************
//								 TIMER 0 	
//							rotina de interrupção
//


void vInterrupcaoTimer0() interrupt 1 
{
  .
  .
  .
 //********************************************************************************
 //****** Trecho a ser inserido na rotina de interrupção do timer - DISPLAYS II ***
 //******                                                                       ***

 if(--unTimerDosDisplays == 0)
 {
 unsigned char ucAux;

 unTimerDosDisplays = PRESET_TEMPORIZADOR_DOS_DISPLAYS;       // Reinicializa temporizador

 ucAux = PORTA_DE_SAIDA_DOS_DISPLAYS & ~MASCARA_DOS_DISPLAYS; // Lê o conteúdo do port, para salvar o bit do Ponto decinal, se for o caso
 ucAux |= DISPLAY_7_SEG_APAGADO;                              // Apaga o display
 PORTA_DE_SAIDA_DOS_DISPLAYS = ucAux;                         // Atualiza a saída

 if(ucIndiceDisplayAtivo == NUMERO_DE_DISPLAYS)               // Testa se atualizou o último display
 {
 ucIndiceDisplayAtivo = 0;                                    // Reinicializa o Indice do display
 ucContadorDeSelecaoDisplay = 0;                              // Reinicializa o contador de seleção
 }

 ucAux = ~MASCARA_DA_SELECAO_DE_DISPLAY;                     // Inverte os bits da mascara
 ucAux &= PORTA_DE_SAIDA_DA_SELECAO_DOS_DISPLAYS;            // Filtra os bits de seleção


 ucAux |= ((SELETOR_DOS_SINAIS_DE_SELECAO_DISPLAY << ucIndiceDisplayAtivo) ^ MASCARA_DE_INVERSAO_SEL_DISP);
 PORTA_DE_SAIDA_DA_SELECAO_DOS_DISPLAYS = ucAux;

 ucAux = PORTA_DE_SAIDA_DOS_DISPLAYS & ~MASCARA_DOS_DISPLAYS; // Lê o conteúdo do port, para salvar o bit do Ponto decinal, se for o caso
 ucAux |= ucFilaDeSaidaDosDisplays[ucIndiceDisplayAtivo++];   // Lê o valor a ser apresentado no display
 PORTA_DE_SAIDA_DOS_DISPLAYS = ucAux;                        // Atualiza a saída
 }
 //************** Fim da Rotina Displays II ***************************************
  .
  .
  .

}

 

ROTINA DOS DISPLAYS DE 7 SEGMENTOS III (Utiliza decodificador BDC para 7 segmmentos e sinais de seleção separados)

 

Para examinar o código, “clique” na barra a seguir.

//**********************************************************************************************
//************* Trecho a ser inserido na rotina de interrupção do Timer (exemplo) **************
//*************                                                                   **************

//*******************************************************************************
//								 TIMER 0 	
//							rotina de interrupção
//


void vInterrupcaoTimer0() interrupt 1 
{
  .
  .
  .
 //*********************************************************************************
 //****** Trecho a ser inserido na rotina de interrupção do timer - DISPLAYS III ***
 //******                                                                        ***

 if(--unTimerDosDisplays == 0)
 {
 unsigned char ucAux;

 unTimerDosDisplays = PRESET_TEMPORIZADOR_DOS_DISPLAYS;              // Reinicializa temporizador

 ucAux = PORTA_DE_SAIDA_DOS_DISPLAYS & ~MASCARA_DOS_DISPLAYS;        // Lê o conteúdo do port, para salvar o bit do Ponto decinal, se for o caso
 ucAux |= DISPLAY_BCD_APAGADO;                                       // Apaga o display
 PORTA_DE_SAIDA_DOS_DISPLAYS = ucAux;                                // Atualiza a saída
 ucAux = PORTA_DA_LINHA_DE_STROBE_DOS_DISPLAYS & ~MASCARA_DO_STROBE; // Le e apaga o strobe
 PORTA_DA_LINHA_DE_STROBE_DOS_DISPLAYS = ucAux;
 PORTA_DA_LINHA_DE_STROBE_DOS_DISPLAYS = ucAux | MASCARA_DO_STROBE;  // Gera pulso e carrega o dado
 
 if(ucIndiceDisplayAtivo == NUMERO_DE_DISPLAYS)                      // Testa se atualizou o último display
 {
 ucIndiceDisplayAtivo = 0;                                           // Reinicializa o Indice do display
 ucContadorDeSelecaoDisplay = 0;                                     // Reinicializa o contador de seleção
 }

 ucAux = ~MASCARA_DA_SELECAO_DE_DISPLAY;                             // Inverte os bits da mascara
 ucAux &= PORTA_DE_SAIDA_DA_SELECAO_DOS_DISPLAYS;                    // Filtra os bits de seleção


 ucAux |= ((SELETOR_DOS_SINAIS_DE_SELECAO_DISPLAY << ucIndiceDisplayAtivo) ^ MASCARA_DE_INVERSAO_SEL_DISP);
 PORTA_DE_SAIDA_DA_SELECAO_DOS_DISPLAYS = ucAux;

 ucAux = PORTA_DE_SAIDA_DOS_DISPLAYS & ~MASCARA_DOS_DISPLAYS;        // Lê o conteúdo do port, para salvar o bit do Ponto decinal, se for o caso
 ucAux |= ucFilaDeSaidaDosDisplays[ucIndiceDisplayAtivo++];          // Lê o valor a ser apresentado no display
 PORTA_DE_SAIDA_DOS_DISPLAYS = ucAux;                                // Atualiza a saída
 ucAux = PORTA_DA_LINHA_DE_STROBE_DOS_DISPLAYS & ~MASCARA_DO_STROBE; // Le e apaga o strobe
 PORTA_DA_LINHA_DE_STROBE_DOS_DISPLAYS = ucAux;
 PORTA_DA_LINHA_DE_STROBE_DOS_DISPLAYS = ucAux | MASCARA_DO_STROBE;  // Gera pulso e carrega o dado
 }
 //************** Fim da Rotina Displays III ***************************************  .
  .
  .

}

 

Código a ser inserido nas inicializações do programa principal

 

O trecho de código a seguir inicializa uma variável auxiliar e desativa as linhas de seleção dos displays.

.
.
.

 // Trecho a ser inserido na rotina principal - nas inicializações

 // Inicializa Displays
 {
    unsigned char ucAux;

    ucAux = ~MASCARA_DA_SELECAO_DE_DISPLAY; 				       // Inverte os bits da mascara
    ucAux &= PORTA_DE_SAIDA_DA_SELECAO_DOS_DISPLAYS;			   // Filtra os bits de seleção
    PORTA_DE_SAIDA_DA_SELECAO_DOS_DISPLAYS = ucAux;				// Inicializa bits de selecao
 }
.
.
.

 

 

Como transferir dígitos para os displays?

 

Da forma como foi projetado esse programa, o gerenciamento do display de 7 segmentos propriamente dito é totalmente automático e transparente para o programa principal. Você só precisa converter o dígito para o código, usando-o como índice na tabela ucTabelaDeDisplayDeSeteSegmentos[dígito] e transferí-lo para a fila de saída dos displays (ucFilaDeSaidaDosDisplays[]) na posição correspondente. Veja no exemplo a seguir.

 

 

EXEMPLO

 

Nesse programa foi aproveitado o mesmo programa desenvolvido para a demonstração de operação dos timers de tempo real, acrescidos os trechos relativos aos displays. Aqui será programado o Timer 0 no modo 2 de operação, com o microcontrolador operando com um clock de 4 MHz e uma frequência de interrupção de 1,5 kHz. Foram definidos 3 displays de 7 segmentos do tipo II com a seleção separada, e atualizados a cada 30 contagens cada um. Confira o código no quadro abaixo.

 

//***************************************************************************
//**                                                                       **
//**         ROTINA EXEMPLO PARA TESTE DO USO DO TIMER E DISPLAYS          **
//**         PARA SISTEMAS OPERACIONAIS DE TEMPO REAL                      **
//**                   (Resp. Eng. Puhlmann)                               **
//**                                                                       **
//**              (22/11/2014 - rev. 22/11/2014)                           **
//**                                                                       **
//***************************************************************************

#include <AT89S53.H>                   // AT89S8253

//----------------------------

#define DESLIGA	0
#define LIGA	1

// Define-se aqui a freqüência de clock da CPU

#define FREQUENCIA_DO_CLOCK_DA_CPU	   4.0e+6   // Hz ----> 4 MHz por exemplo

// Define o pre-scaler

#define FATOR_DE_ESCALA_CLOCK_TIMER    12.0f     // Divide o clock por 12

// Define a freqüência de interrupção do timer

#define FREQUENCIA_DE_INTERRUPCAO_TIMER_0 1.5e+3  // Hz ---- > 1,5 kHz

//--------------

// Definição de variáveis referentes aos timers

//------- Timer 0 ----------

#define MASCARA_CT_0					0xfb

// Definição utilizada apenas quando o timer estiver no modo 2 de operação
// se acaso nao for usado no modo 2, comentar a linha abaixo

// Define o Timer 0 como operando no modo 2
// A conta desse preset tem que dar um número de 0 a 255, senão não funciona... 
 
#define PRESET_TIMER_0_MODO_2          (255 - (unsigned char)((FREQUENCIA_DO_CLOCK_DA_CPU/(FATOR_DE_ESCALA_CLOCK_TIMER * FREQUENCIA_DE_INTERRUPCAO_TIMER_0))+ 0.5))


#define MASCARA_DO_MODO_DO_TIMER_0      0xfc
#define MODO_0_TIMER_0                  0x00
#define MODO_1_TIMER_0                  0x01
#define MODO_2_TIMER_0                  0x02
#define MODO_3_TIMER_0                  0x03


//=============== Fim da definição dos parâmetros do Timer 0 ===========

#define PRESET_TIMER_DE_SOFTWARE        10        // Define o valor inicial do temporizador de software
int nTimerDeSoftware = PRESET_TIMER_DE_SOFTWARE;  // Inicializa o temporizador de software com 10
bit bFlagTimerDeSoftware = DESLIGA;               // Inicializa a sinalização de término de contagem


//===============================================================================
//
//        DEFINIÇÕES DOS DÍGITOS UTILIZADOS NA ROTINA DOS DISPLAYS DE 7 SEGMENTOS II
//                             Linhas de seleção separadas
//            (Cada linha de seleção corresponde a um bit da Porta)
//
//    Entradas : -
//    Saídas   : - ucFilaDeSaidaDosDisplays[]               - Vetor de saídas para os displays
//               - ucIndiceDisplayAtivo                     - ìndica o display que está ativo
//
//        Deve-se definir um port dedicado a isso, configurado da seguinte maneira:
//
//        PORT.Bit    - Segmento do Display
//
//            Px.0    - a
//            Px.1    - b
//            Px.2    - c
//            Px.3    - d
//            Px.4    - e
//            Px.5    - f
//            Px.6    - g
//            Px.7    - DP
//
//            Composição dos números decimais utilizando a especificação acima:
//
//                                                                    a
//                                                                --------
//                                                                |        |
//                                                              f |        | b
//                                                                |    g   |
//                                                                ---------
//                                                                |        |
//                                                              e |        | c
//                                                                |    d   |
//                                                                 -------
//
// SEGMENTOS:                                   g f e | d c b a    Código Hexadecimal
//-----------------------------------------
// Dígito:                  apagado             0 0 0 | 0 0 0 0         = 0x00
//                              0               0 1 1 | 1 1 1 1         = 0x3f
//                              1               0 0 0 | 0 1 1 0         = 0x06
//                              2               1 0 1 | 1 0 1 1         = 0x5b
//                              3               1 0 0 | 1 1 1 1         = 0x4f
//                              4               1 1 0 | 0 1 1 0         = 0x66
//                              5               1 1 0 | 1 1 0 1         = 0x6d
//                              6               1 1 1 | 1 1 0 0         = 0x7c
//                              7               0 0 0 | 0 1 1 1         = 0x07
//                              8               1 1 1 | 1 1 1 1         = 0x7f
//                              9               1 1 0 | 0 1 1 1         = 0x67
//
//                              P               1 1 1 | 0 0 1 1         = 0x73
//                              r               1 0 1 | 0 0 0 0         = 0x50
//                              E               1 1 1 | 1 0 0 1         = 0x79
//                              F               1 1 1 | 0 0 0 1         = 0x71
//                              i               0 0 0 | 0 1 0 0         = 0x04
//
//=====                                        =====
 
//#define DISPLAY_INVERTIDO                               1
#define TEM_PONTO_DECIMAL                                1
 
#ifdef DISPLAY_INVERTIDO
    #ifdef TEM_PONTO_DECIMAL
        #define MASCARA_INV_DISPLAY                       0xff
        #define DESLIGA_TODOS_SEGMENTOS_DISP_7_SEG_E_PD   MASCARA_INV_DISPLAY
       #define LIGA_TODOS_SEGMENTOS_DISP_7_SEG_E_PD      0x00
    #else
        #define MASCARA_INV_DISPLAY              0x7f
        #define DESLIGA_TODOS_SEGMENTOS_DISP_7_SEG_E_PD   MASCARA_INV_DISPLAY
       #define LIGA_TODOS_SEGMENTOS_DISP_7_SEG_E_PD      0x00
    #endif
#else
    #define MASCARA_INV_DISPLAY                            0x00
 
    #ifdef TEM_PONTO_DECIMAL
        #define DESLIGA_TODOS_SEGMENTOS_DISP_7_SEG_E_PD    MASCARA_INV_DISPLAY
        #define LIGA_TODOS_SEGMENTOS_DISP_7_SEG_E_PD       0xff
    #else
        #define DESLIGA_TODOS_SEGMENTOS_DISP_7_SEG_E_PD    MASCARA_INV_DISPLAY
        #define LIGA_TODOS_SEGMENTOS_DISP_7_SEG_E_PD       0x7f
    #endif
#endif
 
 
#define DISPLAY_7_SEG_APAGADO                 0x00 ^ MASCARA_INV_DISPLAY
 
#define DISPLAY_7_SEG_ZERO                    0x3f ^ MASCARA_INV_DISPLAY
#define DISPLAY_7_SEG_UM                      0x06 ^ MASCARA_INV_DISPLAY
#define DISPLAY_7_SEG_DOIS                    0x5b ^ MASCARA_INV_DISPLAY
#define DISPLAY_7_SEG_TRES                    0x4f ^ MASCARA_INV_DISPLAY
#define DISPLAY_7_SEG_QUATRO                  0x66 ^ MASCARA_INV_DISPLAY
#define DISPLAY_7_SEG_CINCO                   0x6d ^ MASCARA_INV_DISPLAY
#define DISPLAY_7_SEG_SEIS                    0x7c ^ MASCARA_INV_DISPLAY
#define DISPLAY_7_SEG_SETE                    0x07 ^ MASCARA_INV_DISPLAY
#define DISPLAY_7_SEG_OITO                    0x7f ^ MASCARA_INV_DISPLAY
#define DISPLAY_7_SEG_NOVE                    0x67 ^ MASCARA_INV_DISPLAY
 
#define DISPLAY_7_SEG_PE                      0x73 ^ MASCARA_INV_DISPLAY
#define DISPLAY_7_SEG_ERRE                    0x50 ^ MASCARA_INV_DISPLAY
#define DISPLAY_7_SEG_E                       0x79 ^ MASCARA_INV_DISPLAY
#define DISPLAY_7_SEG_EFE                     0x71 ^ MASCARA_INV_DISPLAY
#define DISPLAY_7_SEG_I                       0x04 ^ MASCARA_INV_DISPLAY
 
#define NUMERO_DE_DISPLAYS                    0x03
 
#define FREQ_DE_INTERRUP_TIMER_DISPLAYS      90.0    // Hz
 
// ************* Precisa revisar essas linhas !!!!! *****
 
//#define PRESET_TEMPORIZADOR_DOS_DISPLAYS  (unsigned int)(((FREQUENCIA_DE_INTERRUPCAO_TIMER_0 * NUMERO_DE_DISPLAYS)/ FREQ_DE_INTERRUP_TIMER_DISPLAYS)+ 0.5) // Original, mas acho que está errado
#define PRESET_TEMPORIZADOR_DOS_DISPLAYS  (unsigned int)(((FREQUENCIA_DE_INTERRUPCAO_TIMER_0 )/ (FREQ_DE_INTERRUP_TIMER_DISPLAYS * NUMERO_DE_DISPLAYS))+ 0.5)
 
//********************************************************
 
#define NUMERO_DE_LINHAS_DO_DISPLAY                 3         // Número de linhas de seleção
#define PORTA_DE_SAIDA_DOS_DISPLAYS                 P3        // Define o Port onde estão conectados os displays
#define PORTA_DE_SAIDA_DA_SELECAO_DOS_DISPLAYS      P1        // Define o port onde estão conectadas as linhas de seleção
 
 
#ifdef TEM_PONTO_DECIMAL
    #define MASCARA_DOS_DISPLAYS                   0xff        // Filtra os bits de saída do port dos Displays    incluindo o do Ponto decimal
    #define FIM_DO_TESTE_DISPLAY                   0x08
#else
    #define MASCARA_DOS_DISPLAYS                   0x7f        // Filtra os bits de saída do port dos Displays, sem o ponto decimal
    #define FIM_DO_TESTE_DISPLAY                   0x07
#endif
 
#define LIGA_PONTO_DECIMAL                         0x80
#define MASCARA_DA_SELECAO_DE_DISPLAY              0xE0        // Filtra os bits dos sinais de seleção dos displays
 
// Bit de seleção a ser shiftado, para gerar o sinal de seleção ...  bit 1 (define a primeira linha a ser lida)
 
#define SELETOR_DOS_SINAIS_DE_SELECAO_DISPLAY      0x20        // Define posição do primeiro bit do conjunto de seleção
 
 
//#define SAIDAS_INVERTIDAS_SEL_DISP                 1         // Define se as saidas de selecao sao invertidas ou nao
 
#ifdef SAIDAS_INVERTIDAS_SEL_DISP
    #define MASCARA_DE_INVERSAO_SEL_DISP            MASCARA_DA_SELECAO_DE_DISPLAY
#else
    #define MASCARA_DE_INVERSAO_SEL_DISP            0x00
#endif
 
 
volatile int unTimerDosDisplays  = PRESET_TEMPORIZADOR_DOS_DISPLAYS;
unsigned char ucFilaDeSaidaDosDisplays[NUMERO_DE_DISPLAYS] = { DESLIGA_TODOS_SEGMENTOS_DISP_7_SEG_E_PD,
                                                               DESLIGA_TODOS_SEGMENTOS_DISP_7_SEG_E_PD,
                                                               DESLIGA_TODOS_SEGMENTOS_DISP_7_SEG_E_PD};
 
unsigned char ucIndiceDisplayAtivo = 0;
unsigned char ucContadorDeSelecaoDisplay = 0;
 
//-------- Definição das variáveis globais ---------------
 
code unsigned char ucTabelaDeDisplayDeSeteSegmentos[10] = { DISPLAY_7_SEG_ZERO,
                                                            DISPLAY_7_SEG_UM,
                                                            DISPLAY_7_SEG_DOIS,
                                                            DISPLAY_7_SEG_TRES,
                                                            DISPLAY_7_SEG_QUATRO,
                                                            DISPLAY_7_SEG_CINCO,
                                                            DISPLAY_7_SEG_SEIS,
                                                            DISPLAY_7_SEG_SETE,
                                                            DISPLAY_7_SEG_OITO,
                                                            DISPLAY_7_SEG_NOVE};
 
 
//----------------- Fim dos parâmetros e variáveis dos displays  do tipo II ---------

//*******************************************************************************
//								 TIMER 0 	
//							rotina de interrupção
//

void vInterrupcaoTimer0() interrupt 1 
{
	nTimerDeSoftware--;                            // Decrementa o temporizador de software
	if(nTimerDeSoftware == 0)
	{
		bFlagTimerDeSoftware = LIGA;                 // Sinaliza que terminou a temporização de software
		nTimerDeSoftware = PRESET_TIMER_DE_SOFTWARE; // Reinicializa o temporizador
		
	}
	//********************************************************************************
	//****** Trecho a ser inserido na rotina de interrupção do timer - DISPLAYS II ***
	//******                                                                       ***
		 
	if(--unTimerDosDisplays == 0)
	{
		unsigned char ucAux;
		 
		unTimerDosDisplays = PRESET_TEMPORIZADOR_DOS_DISPLAYS;       // Reinicializa temporizador
		 
		ucAux = PORTA_DE_SAIDA_DOS_DISPLAYS & ~MASCARA_DOS_DISPLAYS; // Lê o conteúdo do port, para salvar o bit do Ponto decinal, se for o caso
		ucAux |= DISPLAY_7_SEG_APAGADO;                              // Apaga o display
		PORTA_DE_SAIDA_DOS_DISPLAYS = ucAux;                         // Atualiza a saída
		 
		if(ucIndiceDisplayAtivo == NUMERO_DE_DISPLAYS)               // Testa se atualizou o último display
		{
			ucIndiceDisplayAtivo = 0;                                    // Reinicializa o Indice do display
			ucContadorDeSelecaoDisplay = 0;                              // Reinicializa o contador de seleção
		}
		 
		ucAux = ~MASCARA_DA_SELECAO_DE_DISPLAY;                     // Inverte os bits da mascara
		ucAux &= PORTA_DE_SAIDA_DA_SELECAO_DOS_DISPLAYS;            // Filtra os bits de seleção
		 
		 
		ucAux |= ((SELETOR_DOS_SINAIS_DE_SELECAO_DISPLAY << ucIndiceDisplayAtivo) ^ MASCARA_DE_INVERSAO_SEL_DISP);
		PORTA_DE_SAIDA_DA_SELECAO_DOS_DISPLAYS = ucAux;
		 
		ucAux = PORTA_DE_SAIDA_DOS_DISPLAYS & ~MASCARA_DOS_DISPLAYS; // Lê o conteúdo do port, para salvar o bit do Ponto decinal, se for o caso
		ucAux |= ucFilaDeSaidaDosDisplays[ucIndiceDisplayAtivo++];   // Lê o valor a ser apresentado no display
		PORTA_DE_SAIDA_DOS_DISPLAYS = ucAux;                        // Atualiza a saída
	}
		//************** Fim da Rotina Displays II ************************************
}



//================================================================================
//
//                   PROGRAMA PRINCIPAL

void main(void)
{
	int nContadorSemFuncao = 0;
	
	//********************* Inicializações *************
  
	//************************ TIMER 0	********************************************
	// Inicializa os bits do timer 0

	TR0   = DESLIGA;
	TMOD &= MASCARA_CT_0;					// Seleciona função de "timer"

	T2CON = 0x00;
	TR2   = DESLIGA;
	T2MOD &= 0x0f;							// Seleciona função de "timer"


	TH0	  = PRESET_TIMER_0_MODO_2;			// Inicializa o preset do contador
	TL0   = PRESET_TIMER_0_MODO_2;

	TMOD &= MASCARA_DO_MODO_DO_TIMER_0;		// Seta M1 e M0 para timer 0 - modo 2
	TMOD |= MODO_2_TIMER_0;
    
	//******
	
  //********************* Inicializa Displays para demostração ******
	
	ucFilaDeSaidaDosDisplays[0] = DISPLAY_7_SEG_UM;
	ucFilaDeSaidaDosDisplays[1] = DISPLAY_7_SEG_DOIS;
	ucFilaDeSaidaDosDisplays[2] = DISPLAY_7_SEG_TRES;
	
  {
		unsigned char ucAux1;
	
		ucAux1 = ~MASCARA_DA_SELECAO_DE_DISPLAY;                        // Inverte os bits da mascara
		ucAux1 &= PORTA_DE_SAIDA_DA_SELECAO_DOS_DISPLAYS;               // Filtra os bits de seleção
		PORTA_DE_SAIDA_DA_SELECAO_DOS_DISPLAYS = ucAux1;               // Inicializa bits de selecao
	}
	
	//******


	//********** Fim das Inicializações ******************

		
	//********************************************************************************
  //
  //						   TIMER 0
  //
  // Este bloco deve ser colocado no programa principal, para iniciar a operação do timer


  TR0 = LIGA;								// Liga o timer
  ET0 = LIGA;								// Libera a interrupção do timer
  EA  = LIGA;								// Habilita as interrupções

  //****
	
	

	for(;;)                              // Loop principal
	{
		nContadorSemFuncao++;              // Soma um no contador. Essa instrução foi inserida aqui apenas para não dar a impressão que a simulação está parada             
		
		if(bFlagTimerDeSoftware == LIGA)   // Verifica se terminou a temporização por software (10 vezes a interrupção do Timer 0)
		{
			P1_1 = ~P1_1;					           // Inverte o bit 1 da porta 1 - ;
			bFlagTimerDeSoftware = DESLIGA;  // Desliga a sinalização de término
		}
	}
	
}

 

Se você quiser simular o programa exemplo acima e explorá-lo um pouco mais, siga os seguintes passos:

  • Instale o KEIL C51 μVision;
  • Baixe o arquivo Testa_Display.zip;
  • Instale os arquivos de Testa_Display.zip num diretório para testes;
  • Navegue até o diretório de testes e acione o arquivo Testa_Display.uvproj (2 “clickes”)  (Figura 6).

 

display de 7 segmentos
Figura 6: Arquivos no diretório de teste

 

Nesse instante deverá abrir o programa Keil e a tela deverá ser a retratada na Figura 7. Esse painel permite navegar no código em C, editá-lo e compilá-lo. Não é necessário fazer isso para realizar a simulação, mas você poderá posteriormente alterar alguns parâmetros do código e testar o programa com as novas alterações.

 

displays de 7 segmentos - Programa Keil pronto com o programa exemplo carregado
Figura 7: Programa Keil pronto com o programa exemplo carregado

 

A seguir coloque o programa no modo de Debug (Figura 8, Figura 9 e Figura10) para que se possa iniciar a simulação.

 

displays de 7 segmentos - Selecionando o modo Debug do programa
Figura 8: Selecionando o modo Debug do programa

 

 Antes de entrar no modo de depuração, aparece na tela a mensagem da Figura 9. Clique no “OK” para continuar.

 

displays de 7 segmentos - Aviso de que no modo de avaliação, o código fica limitado a 2K
Figura 9: Aviso de que no modo de avaliação, o código fica limitado a 2K

 

 

displays de 7 segmentos - Modo Debug de operação
Figura 10: Modo Debug de operação

 

Observe que já estão destacados os painéis de monitoramento do Timer 0,  do Port 1, cujo bit 1 deverá ser alternado a cada término de contagem do temporizador de software do teste do timer e cujos bits 5, 6 e 7 são usados como linhas de seleção dos 3 displays, e o Port 3, onde aparecem os códigos de cada dígito de 7 segmentos. Nessa simulação, aparecem os números 1, 2 e 3 respectivamente nos displays 0, 1 e 2.

 

É possível utilizar as teclas de função F11 para executar o programa passo a passo ou F5 entrar em execução. Recomendo que você inicie a simulação utilizando o passo a passo para poder observar detalhadamente como que funciona o mecanismo de operação desse programa.

 

 

Resumo

 

Neste artigo técnico foram apresentadas algumas possíveis soluções padronizadas para acionamento de displays de 7 segmentos com auxílio de um timer de hardware. Essas soluções constituem uma biblioteca padronizada para a utilização dos displays de 7 segmentos em microcontroladores da família MCS-51, codificada em C, para ser compilada no programa da Keil. Depois foi desenvolvido um programa exemplo para que você possa simular o que foi apresentado e observar os detalhes dessa implementação.

 

Este artigo é o terceiro da série de artigos que abordam algumas funções comuns em projetos de sistemas embarcados de tempo real. Confira os demais artigos (em breve).

 

Bibliotecas de funções e rotinas padronizadas em linguagem C para MCS-51

 

  • Timers - É apresentada uma biblioteca desenvolvida em linguagem C para a inicialização e o uso dos Timers do MCS-51;
  • Displays de 7 segmentos (este artigo) – É apresentada uma biblioteca desenvolvida em linguagem C para a inicialização e o uso em displays de 7 segmentos;
  • Teclados Matriciais – É apresentada uma biblioteca desenvolvida em linguagem C para varredura, leitura, debounce, identificação da tecla acionada e desvio para a rotina de tratamento. A forma como as rotinas foram escritas, permitem sua fácil reutilização em outros projetos;
  • Periféricos - É apresentada uma biblioteca desenvolvida em linguagem C para a inicialização e o uso de alguns periféricos, tais como conversores A/D, sensor de temperatura e memórias seriais.

 

 

Outros artigos da série

<< Sistemas Operacionais de Tempo Real - TimersSistemas Operacionais de Tempo Real - Teclados Matriciais >>
NEWSLETTER

Receba os melhores conteúdos sobre sistemas eletrônicos embarcados, dicas, tutoriais e promoções.

Obrigado! Sua inscrição foi um sucesso.

Ops, algo deu errado. Por favor tente novamente.

Licença Creative Commons Esta obra está licenciada com uma Licença Creative Commons Atribuição-CompartilhaIgual 4.0 Internacional.

Henrique Frank Werner Puhlmann
Sou paulistano, 59 anos, formado em Engenharia Eletrônica pela Escola Politécnica da Universidade de São Paulo (formado em 1982) e trabalho há pelo menos 33 anos no Instituto de Pesquisas Tecnológicas do Estado de São Paulo S/A - IPT com Pesquisa e Desenvolvimento, principalmente pesquisa aplicada e desenvolvimento tecnológico de protótipos e produtos eletrônicos dedicados.

4
Deixe um comentário

avatar
 
3 Comment threads
1 Thread replies
0 Followers
 
Most reacted comment
Hottest comment thread
2 Comment authors
Henrique Frank Werner PuhlmannRafael DiasSistemas Operacionais de Tempo Real – Alguns Periféricos | Blog do Engenheiro PuhlmannSistemas Operacionais de Tempo Real – Teclados Matriciais | Blog do Engenheiro Puhlmann Recent comment authors
  Notificações  
recentes antigos mais votados
Notificar
trackback

[…] Displays de 7 segmentos  – É apresentada uma biblioteca desenvolvida em linguagem C para a inicialização e o uso em displays de 7 segmentos; […]

trackback

[…] foi aproveitado o mesmo programa desenvolvido para a demonstração de operação dos timers e displays de 7 segmentos de tempo real, acrescidos os trechos relativos ao teclado. Aqui será programado o Timer 0 no modo […]

Rafael Dias
Visitante
Rafael Dias

Muito legal esta biblioteca.
Um ponto interessante que não poderia passar batido é a importância de se apagar o display antes de escrever um novo dígito. Esta prática evita o surgimento de fantasmas no display.

Henrique Frank Werner Puhlmann
Visitante

Caro Rafael,

muito bem observado destacar a necessidade de se apagar o display antes de acionar o próximo.De fato neste artigo não abordei explicitamente esse assunto, mas no artigo anterior, "Displays de LED de 7 segmentos", foi comentado isso no tópico "Como acionar um arranjo com vários displays de 7 segmentos?"

De qualquer maneira, no código em C acima é realizada essa operação.
Agradeço o seu comentário.

Abraço