Iluminar simultaneamente um grupo inteiro de LEDs para atingir o brilho máximo pode ser impossível em aplicações de baixa potência devido à limitação da corrente disponível. Para produzir o brilho ideal, a dissipação de energia de cada LED a partir da fonte de baixa potência deve ser gerida de forma eficiente. Isto requer uma técnica de gestão de energia na qual, dentro do grupo de LEDs, apenas um conjunto de LEDs é energizado durante um período específico. Os outros conjuntos de LEDs não serão visualmente detetáveis enquanto o brilho necessário estiver a ser atingido.
A potência disponível e a intensidade luminosa necessária para a aplicação devem ser determinadas para calcular o número de LEDs necessários num determinado intervalo de tempo. Deve ser feita uma comparação entre a intensidade luminosa e as características da corrente contínua para selecionar os LEDs com o nível de intensidade necessário. Uma vez estabelecido o número necessário de LEDs, este número pode ser alimentado por um intervalo de tempo determinado pela relação entre a corrente total requerida pelos LEDs e a corrente disponível, como se segue:
Número de LEDs num banco = Corrente total requerida pelos LEDs / Corrente total disponível da fonte.
A frequência de comutação do banco de LEDs deve ser ajustada de modo a que o tempo LIGADO seja suficientemente longo para iluminar completamente o banco, e o tempo DESLIGADO seja limitado pelo tempo necessário para que o banco comece a perder intensidade visivelmente. O tempo DESLIGADO limita o número de bancos de LEDs adicionais que podem ser controlados gerindo o intervalo de tempo.
Esta técnica pode ser implementada a baixo custo utilizando uma fonte de relógio, flip-flops digitais para controlar bancos de LEDs e uma porta OR para detetar o estado de arranque com um simples interruptor de ligar/desligar. A Figura 1 mostra o diagrama de blocos de uma configuração de flip-flop D para controlar quatro bancos de LEDs.
Inicialmente, o flip-flop está no estado estático e requer um impulso de disparo que deve durar pelo menos um ciclo. Este pulso pode ser detectado pelo primeiro flip-flop no flanco ascendente do relógio. O sinal de disparo deve ser momentâneo e não pode durar mais do que um ciclo de relógio; caso contrário, as duas primeiras saídas do flip-flop serão ativadas simultaneamente. Uma vez que a corrente fornecida é limitada, a aplicação de iluminação não funcionará corretamente. Com esta configuração, um conjunto de LEDs é totalmente iluminado no flanco ascendente de cada ciclo de relógio e, para o olho humano, parece que todos os LEDs estão totalmente acesos ao mesmo tempo.
No entanto, esta implementação é monótona e não oferece flexibilidade de design. Possui apenas um estado ligado/desligado. Este circuito pode ser adequado para aplicações como a retroiluminação de LCD, mas se precisar de controlar o brilho ou gerar sequências, um circuito baseado num microcontrolador oferece a máxima flexibilidade com um impacto mínimo no custo total da solução. A construção do circuito é mais simples, exigindo menos componentes, uma vez que o microcontrolador controla cada banco de LEDs e também pode detetar entradas do utilizador para controlo de brilho e seleção de sequência.
Um microcontrolador de 8 bits de baixo custo e com poucos pinos, como os das famílias PIC10F ou PIC12F da Microchip, combinado com um expansor de portas de E/S como o MCP23018 da Microchip, ofereceria uma solução económica. A expansão de E/S também pode ser útil para controlar LEDs quando o circuito de iluminação está localizado remotamente a partir do microcontrolador.
Os expansores de portas de E/S ampliam as portas de E/S de um microcontrolador. Nesta aplicação, o microcontrolador controla o expansor de E/S utilizando o protocolo I2C™ para ligar/desligar os LEDs. Os pinos de E/S do microcontrolador podem ser utilizados para detetar a entrada do utilizador através de um botão ou de um conversor A/D integrado para detetar o nível de um potenciómetro para controlo da intensidade luminosa.
Os expansores de E/S estão disponíveis em configurações de saída de dreno aberto ou push-pull. Os microcontroladores podem operar com 3,3 V ou menos, pelo que um expansor de E/S com saída de drenagem aberta é ideal para esta aplicação. A vantagem é que permite que os LEDs operem com 5 V ou mais, desde que o microcontrolador e o expansor de E/S sejam alimentados com uma tensão mais baixa. O MCP23018 é um expansor de portas de E/S de 16 bits com saída de dreno aberto e interface I2C. A Figura 2 mostra o esquema do circuito de um expansor de E/S com uma saída de dreno aberto elevada para uma tensão superior à tensão de alimentação do microcontrolador.
Quando a porta de E/S está em nível baixo, a tensão no amplificador de E/S é de 0V e a corrente flui, polarizando diretamente e fazendo com que o LED conduza. O resistor de polarização do LED limita a corrente para o LED de acordo com o brilho necessário e também atua como um resistor de pull-up para a saída de dreno aberto.
Quando a porta de saída do amplificador de E/S está configurada para nível alto, a saída de dreno aberto entra em corte ou em alta impedância, e a tensão na porta do amplificador de E/S é elevada para 5V pela resistência de pull-up. O LED permanece em corte porque não haverá fluxo de corrente. Uma configuração de dreno aberto também oferece a vantagem de que, quando a porta está configurada para alta impedância, demora mais tempo para o LED se desligar devido à capacitância parasita. Isto permite que o próximo conjunto de LEDs conduza durante um tempo ligeiramente mais longo em comparação com aplicações semelhantes de saída push-pull.
As 16 portas de E/S do MCP23018 podem controlar até 16 LEDs. A quantidade de corrente que pode ser fornecida à porta de E/S quando o LED está em plena condução pode ser limitada controlando a saída do amplificador de E/S. A tensão de nível baixo da porta de E/S é especificada até um máximo de 0,6 V para uma corrente de 8,5 mA. Se a corrente exceder 8,5 mA, a tensão de nível baixo aumentará exponencialmente. A corrente máxima absoluta é de 25 mA.
Se a corrente fornecida estiver limitada a 5V/50mA, por exemplo, e forem alocados 2mA ao microcontrolador, ao expansor de E/S e às resistências para deteção de entrada do utilizador, a corrente restante poderá ser utilizada para a iluminação dos LEDs. Podem ser acionados quatro LEDs por banco se a intensidade luminosa do LED com aproximadamente 10mA for adequada. Neste exemplo, o resistor limitador de corrente teria uma classificação de aproximadamente 440Ω.
void main (Void){
initialize(); //inicializa os periféricos do PICmicro, incluindo o Timer0 e os periféricos do expansor de E/S
bank_counter = 0; //Limpa a variável do contador de bancos
while(1){} //loop while infinito
}
Void Interrupt int_service(void){
TurnOffAll_LEDs(); //sub-rotina para desligar todos os LEDs previamente acesos
I2C_start(); //sub-rotina do sinal de início do protocolo I2C
I2C_send(Comand_byte); //sub-rotina do byte de envio do protocolo I2C
Se(banco_contador == banco1){ // banco1 é uma constante definida como 0
I2C_send(Endereço_pionter_banco1n2); //Envia o ponteiro de endereço do registo periférico
I2C_send('0000 1111'); //Protocolo I2C – envia o estado do banco (banco 1 ligado e banco 2 desligado)
bank_counter = bank_counter + 1;
}
Se(banco_contador == banco2){ // banco1 é uma constante definida como 1
I2C_send(Endereço_pionter_banco1n2); //Envia o ponteiro de endereço do registo periférico
I2C_send('1111 0000'); //Protocolo I2C – envia o estado do banco (banco 2 ligado e banco 1 desligado)
bank_counter = bank_counter + 1;
}
Se(contador_banco == banco3){ // banco1 é uma constante definida como 2
I2C_send(Ponteiro_endereço_banco3n4); //Envia o ponteiro de endereço do registo periférico
I2C_send('0000 1111'); //Protocolo I2C – envia o estado do banco (banco 3 ligado e banco 4 desligado)
contador_banco = contador_banco + 1;
}
Se(contador_banco == banco4){ // banco1 é uma constante definida como 3
I2C_send(Ponteiro_endereço_banco3n4); //Envia o ponteiro de endereço do registo periférico
I2C_send('1111 0000'); //Protocolo I2C – envia o estado do banco (banco 4 ligado e banco 3 desligado)
contador_banco = 0;
}
I2C_stop(); //Protocolo I2C – sub-rotina de sinal de paragem
}
Pseudocódigo 1: Código da rotina de serviço de interrupção do microcontrolador
*
*
*
Se(contador_banco == banco1){ // banco1 é uma constante definida como 0
I2C_send(Ponteiro_endereço_banco1n2); //Envia o ponteiro de endereço do registo periférico
Padrão_banco1n2 = ~Padrão_banco1n2; //Complementa a variável utilizando '~'
I2C_send((Padrão_banco1n2 | '0000 1111')); //Protocolo I2C – envia o estado do banco
//(utilizar OR '|' para activar o banco 1 e desactivar o banco 2)
contador_banco = contador_banco + 1;
}
*
*
*
Pseudocódigo 2: Geração de sequências.
*
*
*
Void Interrupt int_service(void){
TurnOffAll_LEDs(); //sub-rotina para desligar todos os LEDs previamente acesos
If (Delay_ON == ON){ // ON é uma constante definida como 1
Update_Timer0_Counter(Timer0delay_interval); //sub-rotina para actualizar o Timer0
// Timer0delay_interval é uma constante para definir o atraso mínimo
Delay_Counter = Delay_Counter – 1; //conta regressivamente o número de interrupções para o atraso
If(Delay_Counter == 0){
Delay_ON = OFF; // Limpa o flag de atraso para a próxima interrupção
Delay_Counter = Get_Delay_Counter(); //sub-rotina para detetar a entrada do utilizador
//e definir a variável do contador de atraso
}else{
Delay_ON = ON; // mantém o flag de atraso ON
Return; //sai da rotina de serviço de interrupção
}
}
I2C_start(); // Subrotina de sinal de início do protocolo I2C
I2C_send(Comand_byte); // Subrotina de envio de bytes do protocolo I2C
If(bank_counter == banco1){ // banco1 é uma constante definida como 0
I2C_send(Address_pointer_bank1n2); // Envia o ponteiro de endereço do registo periférico
Bank1n2_pattern = ~Bank1n2_pattern; // Complementa a variável utilizando '~'
I2C_send((Bank1n2_pattern | '0000 1111')); // Envia o estado do banco do protocolo I2C
// (use OR '|' para activar o banco 1 e desactivar o banco 2)
bank_counter = bank_counter + 1;
delay_ON = ON; // Activa o flag de atraso
}
*
*
*
Pseudocódigo 3: Implementação do código de atraso para visualizar uma sequência de iluminação.
O diagrama de temporização apresentado na Figura 1 pode ser reproduzido utilizando um pequeno código de instruções do microcontrolador. Por exemplo, para o Pseudocódigo 1, a sub-rotina principal poderá ser um ciclo while infinito. Para cada intervalo de tempo do microcontrolador (Timer0), uma rotina de serviço de interrupção envia uma instrução I2C para o expansor de E/S para controlar apenas um banco de LEDs. A rotina de serviço de interrupção conta ou monitoriza o estado do banco de LEDs, como por exemplo se o banco está a conduzir e a configuração da porta correspondente do expansor de E/S como alta ou baixa. Inicialmente, ou após o reset do microcontrolador, o banco 1 é activado na primeira interrupção do Timer0. Na segunda interrupção, o banco 1 é desativado e o banco 2 é ativado. De seguida, na terceira interrupção, o banco 2 é desativado e o banco 3 é ativado. Finalmente, na quarta interrupção, o banco 1 é desativado e o banco 4 é ativado, e a variável contadora do banco é reiniciada. Na interrupção seguinte, o ciclo repete-se, ativando o banco 1 e desativando o banco 4. Outras variáveis, como Command_byte, Address_pointer_bank1n2 e Address_pointer_bank3n4, são constantes definidas no ficheiro de arranque. Neste tipo de implementação, o circuito gera a intensidade de luz necessária, dando a impressão de que todos os LEDs estão a ser activados simultaneamente pela fonte de alimentação disponível.
void get_PWM_ratio(void) {
Double PotScale; //variável local para guardar a escala de saída do ADC
Double PWM_Percentage; //variável local para armazenar a percentagem de alteração do PWM
PotScale = (ADRESH)/16 + 1; //Escala o byte alto da saída do ADC
PWM_Percentage = 1/16 * PotScale; //Escala a saída de 0 a 1, equivalente a 100%
PWM_High = Frequency_counter * PWM_Percentage; //Define o valor alto do Timer0 para PWM
PWM_Low = Frequency_counter * (1 – PWM_Percentage); //Define o valor baixo do Timer0 para PWM
//PWM_High e PWM_Low são variáveis globais,
//e Frequency_counter é um valor constante do Timer0 para definir a frequência.
}
Pseudocódigo 4: Sub-rotina para calcular a relação PWM
*
*
*
Se(banco_contador == banco1){ // banco1 é uma constante definida como 0
Se (PWM_High_Low_flag == OFF){ //verifica o sinalizador de estado PWM
get_PWM_ratio(); //Deteta a entrada do utilizador para a taxa PWM
Timer0_counter = 65535 – PWM_High; //define a variável contadora do Timer0
Update_Timer0_Counter(Timer0_counter); //sub-rotina para actualizar o Timer0
I2C_send(Address_pionter_bank1n2); //Envia o ponteiro de endereço do registo periférico
Bank1n2_pattern = ~Bank1n2_pattern; //complementa a variável utilizando '~'
I2C_send((Bank1n2_pattern | '0000 1111')); //Protocolo I2C – enviar o estado do banco
//(utilizar OR '|' para activar o banco 1 e desactivar o banco 2)
PWM_High_Low_flag = ON; //Definir flag
Delay_ON = OFF;
} else {
Timer0_counter = 65535 – PWM_Low; //define a variável contadora do Timer0
Update_Timer0_Counter(Timer0_counter); //sub-rotina para atualizar o Timer0
I2C_send(Address_pointer_bank1n2); //envia o ponteiro de endereço do registo periférico
I2C_send('1111 1111')); //protocolo I2C – desliga todos os LEDs
bank_counter = bank_counter + 1;
PWM_High_Low_flag = OFF; //limpa o flag
Delay_ON = ON;
}
}
*
*
*
Pseudocódigo 5: Fluxo de código para ajustar a relação PWM.
Controlo da intensidade luminosa e geração de sequências de LEDs.
Sequências de luz interessantes podem ser geradas com uma aplicação baseada em microcontrolador. Os estados de saída do expansor de portas de E/S são carregados de
Existem 2 bytes de variáveis na RAM denominadas Bank1n2_pattern e Bank3n4_pattern. O meio byte corresponde a cada banco. Uma tabela de consulta predefinida contém diversas sequências de uns e zeros para cada banco.
Para monitorizar continuamente o estado do botão de alimentação, é adicionada uma instrução IF THEN ao código do microcontrolador: o ciclo infinito 'while' da sub-rotina principal. Quando o botão é pressionado momentaneamente, é carregada uma sequência da tabela de consulta para os dois bytes de RAM, denominados Bank1n2_pattern e Bank3n4_pattern. Quando ocorre a interrupção do Timer0, a nova sequência é enviada para o expansor de E/S e os LEDs acendem de acordo com a sequência. A sub-rotina principal itera pela tabela de consulta enquanto o botão estiver momentaneamente pressionado pelo utilizador. Para visualizar outra sequência de iluminação, basta enviar o complemento da sequência anterior. Por exemplo, se a sequência no banco 1 for ‘0101’, o complemento é ‘1010’, como se mostra no Pseudocódigo 2, que é um excerto do Pseudocódigo 1.
No entanto, deve ser adicionado um atraso à sub-rotina de interrupção antes que as instruções IF THEN para ligar/desligar o banco inspecionem visualmente as sequências alternativas. Este é gerado por um sinalizador Delay_ON, de modo a que, na interrupção seguinte, apenas o contador de atraso seja subtraído para contar o número de interrupções para o atraso. O utilizador pode também selecionar o valor do atraso com um potenciómetro cujo terminal estaria ligado à entrada do conversor A/D integrado no microcontrolador. Os dados digitais do conversor A/D são escalonados de um atraso mínimo para um máximo através da deteção dos quatro bits mais significativos, que fornecem 16 níveis. Um ajuste mais preciso pode ser feito através da detecção dos cinco bits mais significativos, ou seja, 32 níveis. O atraso máximo é a taxa mais lenta a que os LEDs podem piscar e, com um atraso mínimo, parece que todos os LEDs estão acesos. A Figura 3 mostra a posição do atraso, tDELAY.
Para controlar a duração do intervalo de tempo para cada banco de lâmpadas, o controlo de regulação utiliza a modulação por largura de pulso (PWM). A duração da interrupção do Timer0 tem dois valores, uma duração longa e uma duração curta, proporcionais à percentagem de PWM ajustada por um potenciómetro rotativo cujo terminal central está ligado à entrada do conversor A/D. O nível de resolução pode ser ajustado seleccionando os 4 ou 5 bits superiores do conversor A/D. A posição do contador do Timer0 é ajustada proporcionalmente e numa escala dos dados do conversor A/D, em que 100% de PWM corresponde à posição máxima do contador (totalmente iluminado) e 0% é o nível mínimo de regulação. O pseudocódigo 4 mostra a equação da escala do PWM para 16 níveis, e a Figura 3 mostra o diagrama de tempo durante o PWM, tPWM_LOW e tPWM_HIGH.
A rotina de tratamento de interrupções deve atualizar a posição do contador do Timer0 para a interrupção seguinte. Deve também detetar se o sinal PWM é longo ou curto. Assim, devem ser adicionadas algumas instruções para detetar o nível do potenciómetro para controlo de dimerização e escalonamento proporcional da posição do contador Timer0 utilizando os valores PWM_High e PWM_Low mostrados no pseudocódigo 4. O pseudocódigo 5 mostra o código para ajustar o PWM; é utilizada uma instrução IF THEN para detetar o estado do PWM.
Esta metodologia também pode ser implementada num microcontrolador de 8 bits de gama média com memória de programa adicional, como a família PIC16F da Microchip. Uma atualização permitiria que a sub-rotina principal lidasse com sequências de iluminação avançadas, como luzes com movimento contínuo. O módulo Timer1 do microcontrolador pode ser utilizado para variar a duração, e os dois bytes de RAM são atualizados para a sequência de movimento contínuo.
Os projetistas estão sempre à procura de novas formas de reduzir custos sem comprometer o desempenho. Existem inúmeros métodos para controlar eficientemente bancos de LEDs utilizados na retroiluminação de LCD ou em aplicações de sequências de iluminação para uma iluminação eficiente. Em aplicações de baixo consumo de energia, os LEDs podem ser controlados gerindo o intervalo de temporização para cada banco de LEDs. Além disso, os microcontroladores com poucos pinos e os expansores de portas de E/S oferecem uma alternativa de baixo custo às soluções de iluminação com maior flexibilidade de design.
Autor:
Ezana Haile, Engenheira-Chefe de Aplicações, Divisão de Produtos Analógicos e de Interface, Microchip Technology Inc.
