Conhecimento prévio:
[HW] User Interface Module,
[AVR] Digital Inputs/Outputs,
[LIB] Pins,
[PRT] Light-emitting Diode
Um interruptor é um dispositivo eletromecânico que pode conectar ou interromper o circuito elétrico. Existem muitos tipos diferentes de interruptores; o interruptor mecânico mais comum são conectores eléctricos ligados mecánicamente. Se os conectores estão conectados, o circuito elétrico é fechado e a eletricidade flui através do interruptor. Se os conectores estão desligados, a eletricidade não pode fluir através do interruptor.
Interruptores são habitualmente usados para electrificação de circuitos eléctricos, mas também podem ser usados como sensores. Interruptores como sensores é também o assunto deste exercício e, por conseguinte, examinar interruptores de alta tensão e de alta amperagem foi excluído. Os interruptores podem ser diferenciados pelo número de contactos e pelo seu método de conexão. Diferentes tipos incluem: interruptores de dois contactos ou interruptores duplos, onde pares de contato estão conectados, mas também podem ser botão, deslizante, rocker ou toggle, bem como interruptores que desligam em vez de ligar circuitos elétricos.
Diferentes símbolos esquemáticos são utilizados para identificar diferentes tipos de interruptores. Em baixo estão exemplos de típicos interruptores elétricos usados em desenhos elétricos com os seus símbolos:
A fim de utilizar um interruptor como um sensor ligado a um microcontrolador, um contacto do interruptor é ligado ao pino do microcontroladore e é configurado como entrada no programa. Se o contato for ligado à terra ou ao potencial de entrada, a taxa de bits do barramento de pinos do microcontrolador é alterada. Seria lógico usar interruptor toggle, que permite conectar um contato com o contato desejado (neste caso à terra ou entrada). Para o nosso propósito não é tão simples, uma vez que no momento do deslocamento das conexões os contatos não estão conectados. O momento em si é muito curto (milissegundos), mas durante este momento o pino de entrada do microcontrolador não está ligado a nenhum lado, e por conseguinte, tem um valor indefinido. Devido à interferência eletromagnética (que existe em todos os lugares) o pino de entrada que está ligado a nenhum lugar pode ter um valor de 0 ou 1 em momentos aleatórios no tempo.
As interferências complicam o uso de interruptores. O método mais comum para evitar os resultados indeterminados é conectar a entrada de microcontrolador à terra ou através de uma resistência. Uma resistência para esta função é chamada resistência pull-down ou pull-up. Normalmente, a resistência de pull-down ou pull-up varia de 1Ω a 1MΩ. Com o interruptor aberto, a entrada é carregada com a tensão da resistência, ao fechar o interruptor, a entrada recebe a tensão do interruptor dado que a resistividade do interruptor é muito menor (próxima de zero) em comparação com a da resistência. Basicamente, pode ser referido como um divisor de tensão.
Um interruptor simples de dois contactos pode ser usado como um sensor com resistência pull-up ou pull-down, o interruptor connecta a entrada com uma e a resistência ao outro potencial. Normalmente os microcontroladores têm incorporado opções de resistência pull-up ou pull-down; portanto, não há necessidade de se adicionar uma resistência ao circuito. Por exemplo, microcontroladores AVR tem resistências 20 kΩ – 50 kΩ pull-up nos seus pinos IO.
Deve ser mencionado que, interruptores mecânicos têm um problema adicional - salto do interruptor. Isso faz com que várias curtas má ligações no momento da conexão. Deve-se ressaltar, que os exemplos usados neste capítulo não são afetados pelo salto de interruptor e que o assunto será abordado com mais detalhes no próximo capítulo.
// Homelab User interface board button test code #include <homelab/pin.h> // Main program int main(void) { // Set LED pins as output and switch pins as input pin_setup_output(led_green); pin_setup_input(S1); // Endless loop while (1) { // green LED turns on when switch S1 is pressed if(pin_get_value(S1) == 1) { pin_set(led_green); } else { pin_clear(led_green); } } }
Principal método usado para evitar cintilação causadas pelo salto de contatos é a filtragem. A filtragem pode ser feita electricamente ou por software. Para filtrar electricamente o interruptor tem de estar ligado através de um filtro passa-baixo - por exemplo, um filtro RC - com alterações de tensão suaves e portanto o pino do microcontrolador não tem valores transitórios. Filtro RC é mostrado no desenho. A filtragem por software é feita através da avaliação do valor do pino quando o interruptor se encontra ligado; se o valor se mantém o mesma um número de vezes em tempo limite pré-definido, é considerado como tendo uma posição estável e portanto, não tem problemas de cintilação. No entanto, com cada tipo de filtragem há um factor de atraso para definir o estado que tem de ser levado em consideração.
Várias soluções de software são utilizadas para filtrar, isto pode ser realizado de maneiras simples ou complexas com ambas as suas vantagens e desvantagens. Se o programa é configurado para ter apenas algumas mudanças infrequentes do botão, uma longa pausa pode ser configurada para seguir a mudança, esta solução descarta reacção ao salto do interruptor. No entanto, durante a utilização desta solução deve ser considerada - no caso de o utilizador segurar o botão para baixo por um longo período de tempo, o programa reage também na falta de libertação do botão.
Um programa que controla o estado do interruptor várias vezes num período fixo de tempo é mais fiável (quanto mais longo é o tempo e o número de controlos, melhor será o resultado).
Há três interruptores de botão no módulo de interface de utilizador. Esses interruptores conectam os pinos do microcontrolador à terra, porém não diretamente através de uma resistência, isso é para evitar curtos-circuitos ao pressionar o botão quando se define os pinos como saída. Os interruptores também têm resistências de pull-up, mas essas têm muito mais resistância do que as resistências de proteção, portanto, enquanto pressionam o botão, ainda haverá tensões de cerca de 0 V no pino correspondente.
As posições do interruptor são mostradas na descrição de hardware. A fim de ler o estado dos interruptores, os pinos correspondentes do microcontrolador devem ser definidos como entradas. Não há necessidade de colocar as resistências pull-up internas do AVR em operação, porque os pinos já tem resistências externas. Quando o botão é pressionado, o bus correspondente do pino tem valor 0, quando o botão é largado, o valor é 1. Indicadores LED podem ser usados para verificar se o microcontrolador compreendeu as açôes dos botões.
Abaixo está uma função para leitura de valores filtrados de um botão para o módulo de interface do utilizador:
// Function for reading filtered values of a IO extension module unsigned char button_read(pin button) { unsigned char buffer = 0xAA; unsigned char timeout = 100; // We wait until the status of the button is celar // or clearing the state expires while (timeout-- > 0) { // Having 8 place (bit) bufffer of state // All previous states (bits) are shifted to left // and a new state(bit) is added to the right buffer <<= 1; buffer |= (pin_get_value(button) ? 0x01 : 0x00); // If all 8 bits are high, then the button is pressed down if (buffer == 0xFF) { return 0; } // If all 8 bits are low, then the button is definitely up if (buffer == 0x00) { return 1; } // 1 ms break // This function can be found from the library of the HomeLab _delay_ms(1); } // If can't examine the state, then assume that button was not pressed return 0; }
Esta função gera um atraso usando uma função que é explicado no exercício correspondente. Neste momento, tudo o que precisamos saber sobre a função de atraso é que gera um atraso de 1 ms no final de cada ciclo para a leitura do estado do botão. Se o botão está na mesma posição durante 8 leituras, retorna para a posição contada. No caso de o botão estar instável todo o procedimento pode levar até 100 ms. Esta função está incluída na biblioteca de pinos, por conseguinte, não é necessário adicioná-lo ao programa exemplo.
O exemplo seguinte ilustra o uso de botões e a eliminação de contagem múltipla utilizando um ciclo vazio. O botão é esperado para libertar-se durante um ciclo vazio.
// The program for filtering the debounce of buttons of User interface module #include <homelab/pin.h> // Main program int main(void) { int counter = 0; // Set LED pins as output and switch pin as input pin_setup_output(led_red); pin_setup_output(led_yellow); pin_setup_output(led_green); pin_setup_input(S1); // Endless loop while(1) { // Check if switch S1 is pressed if(button_read(S1)) { // Light the corresponding LED if(counter == 0) led_on(led_green); else led_off(led_green); if(counter == 1) led_on(led_yellow); else led_off(led_yellow); if(counter == 2) led_on(led_red); else led_off(led_red); // Add counter and take a module counter = (counter + 1) % 3; // Wait until switch is unpressed while(button_read(S1) != 0); } } }
Se testamos este programa agora, os LEDs ficam iluminando exatamente nesta sequência enquanto o utilizador pressiona o interruptor. O exemplo deste código é baseado na biblioteca de pinos do Robotic HomeLab que é introduzido no capítulo LED.
Na tabela abaixo constam as descrições constantes dos botões e pinos apropriados do módulo controlador.
Nome da constante | pino HomeLab I & II | pino HomeLab III | Descrição |
---|---|---|---|
S0 | PC2 | PQ2 | Botão de teste no módulo controlador |
S1 | PC0 | PH2 | Botão baixo no módulo de interface do utilizador |
S2 | PC1 | PH1 | Botão médio no módulo de interface do utilizador |
S3 | PC2 | PH0 | Botão alto no módulo de interface do utilizador |
// Button demonstration example of User interface module #include <homelab/pin.h> // Main program int main(void) { // Set LED pins as output and switch pin as input pin_setup_output(led_red); pin_setup_output(led_yellow); pin_setup_output(led_green); pin_setup_input(S1); pin_setup_input(S2); pin_setup_input(S3); // Endless loop while (1) { // Every button press lights one LED if(button_read(S1)) led_on(led_green); else led_off(led_green); if(button_read(S2)) led_on(led_yellow); else led_off(led_yellow); if(button_read(S3)) led_on(led_red); else led_off(led_red); } }