ÍNDICE DE CONTEÚDO
Introdução
Você já tentou descobrir a tecnologia por trás do funcionamento do controle remoto IR? Os controles remotos são dispositivos comuns, presentes em uma variedade de aparelhos, desde televisores até sistemas de som. Muitos desses dispositivos utilizam uma tecnologia relativamente simples para transmitir comandos a um receptor: o infravermelho.
Neste tutorial, vamos aprender como utilizar a Franzininho C0 para receber e decodificar os sinais infravermelhos enviados por um controle remoto IR.
Componentes necessários
- 1 Franzininho C0
- 1 Controle Remoto IR
- 1 Receptor IR
Esquemático para montagem circuito
Funcionamento Controle Remoto IR
O controle remoto IR contém um chip, um ou mais LEDs emissores de infravermelho e um teclado integrado. Quando uma tecla é pressionada, uma sequência de pulsos de luz infravermelha é emitida pelos LEDs. Esses pulsos formam um código único para cada tecla pressionada, permitindo que o aparelho receptor interprete e execute o comando correspondente.
O controle remoto utiliza uma modulação chamada PCM (modulação codificada por pulsos). Com essa modulação, a luz externa não interfere na transmissão dos dados. Quando o pulso de dado é 1, uma frequência específica é transmitida, e quando o pulso é 0, nenhuma frequência é emitida.
Embarcados Experience 2024: Evento Presencial
Participe do Embarcados Experience 2024 em São Paulo. Conhecimento técnico, palestras, workshops e oportunidade de networking com profissionais experientes.
Protocolos de Codificação de Controle Remoto IR
Existem diversos protocolos de codificação dos pulsos de sinais de infravermelho. Sendo os mais comuns: NEC, Sony, Philips, Sharp.
Neste projeto, é utilizado o protocolo NEC. No protocolo NEC cada pulso é uma rajada portadora de 38 kHz com 560 µs de comprimento (cerca de 21 ciclos). O nível lógico “1” leva 2,25 ms para transmitir, enquanto o “0” apenas metade disso, sendo 1,125 ms.
Códigos do controle utilizado
Cada tecla do Controle Remoto corresponde a uma sequência de 32 bits, que são traduzidos em um HEX Code.
Tecla | Código Hex |
0 | 0xFF9867 |
1 | 0xFFA25D |
2 | 0xFF629D |
3 | 0xFFE21D |
4 | 0xFF22DD |
5 | 0xFF02FD |
6 | 0xFFC23D |
7 | 0xFFE01F |
8 | 0xFFA857 |
9 | 0xFF906F |
* | 0xFF6897 |
# | 0xFFB04F |
ok | 0xFF38C7 |
< | 0xFF10EF |
> | 0xFF5AA5 |
^ | 0xFF18E7 |
v | 0xFF4AB5 |
Receptor de Infravermelho
Os receptores infravermelhos são projetados para detectar a radiação emitida por um transmissor IR, como os LEDs de um controle remoto. Quando o transmissor IR emite radiação infravermelha, essa radiação é direcionada ao receptor. Diferentemente de outros sensores infravermelhos que dependem da reflexão da radiação em objetos, os receptores de controles remotos são projetados para detectar diretamente os pulsos de luz infravermelha emitidos pelo transmissor.
Neste exemplo estamos utilizando o Módulo Receptor IR AX-1838Hs. Ele pode trabalhar com tensões de 2,1V a 5,5V. O consumo de energia é bem baixo, com uma corrente de aproximadamente 1,5 mA. A frequência de modulação dos pulsos de dados é de 38 KHz.
Configuração CubeMX
- Abra STM32Cube , crie um novo projeto e selecione o microcontrolador de destino “STM32C011F6P6”.
- Entre na página de configurações de relógio e ajuste HCLK para 48 MHz. Volte para a página de configuração dos pinos, selecione “Trace and Debug” e habilite “Serial Wire.
- Em Sys, habilite o uso dos pinos PA9 e PA10.
- Em seguida, vamos configurar o Timer3. Escolha como fonte de clock “Internal Clock” e ajuste o valor do Prescaler para 48-1. Devido ao protocolo NEC necessitar de tempos pequenos, é necessário ajustar o timer para contar de 1 em 1 micro segundos.
- Nosso receptor IR está conectado ao pino PA4, para essa aplicação vamos configurar esse pino no modo interrupção. Logo, clique sobre PA4 e selecione a opção “GPIO_EXT4”. Em seguida, nas configurações do GPIO, defina o modo como “External Interrupt Mode with Rising/Falling Edge Trigger Detection”.
- Depois, habilite a entrada correspondente no NVIC.
- A última configuração a ser realizada no CubeMX será da UART. Selecione o pino PA10 como “USART1_RX” e PA9 como “USART1_TX”. Em “Connectivity” selecione a opção “USART1” e em Mode escolha o “Asynchronous”. As demais configurações deixe padrão.
- Por fim, gere o código em “Project” > “Generate Code”.
Implementação do código
- Abra o arquivo main.c
- Inclua as seguintes bibliotecas:
1 2 |
#include "stdio.h" #include "string.h" |
- Crie as seguintes variáveis:
1 2 3 4 5 6 |
uint32_t code; uint32_t code_temp; uint8_t bit_counter; uint8_t cmd_h; uint8_t cmd_l; uint8_t flag_ir = 0; |
- Adicione os seguintes protótipos de funções:
1 2 3 4 5 |
void NEC_Init(void); uint8_t NEC_Available(); uint32_t NEC_Get_Code(); void HAL_GPIO_EXTI_Falling_Callback(uint16_t GPIO_Pin); void convert_code(uint32_t code); |
- Iniciaremos pela criação da função NEC_Init():
1 2 3 4 |
void NEC_Init(void){ HAL_TIM_Base_Start(&htim3); __HAL_TIM_SetCounter(&htim3, 0); } |
Essa função inicia a contagem do timer, estabelecendo o valor inicial como 0.
- Depois de NEC_Init(), criaremos uint8_t NEC_Available() e HAL_GPIO_EXTI_Falling_Callback(uint16_t GPIO_Pin).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
uint8_t NEC_Available(){ return flag_ir; } void HAL_GPIO_EXTI_Falling_Callback(uint16_t GPIO_Pin) { if(GPIO_Pin == GPIO_PIN_4) { if(__HAL_TIM_GetCounter(&htim3) > 8000) { code_temp = 0; bit_counter = 0; } else if (__HAL_TIM_GetCounter(&htim3) > 1700) { code_temp |= (1UL << (31-bit_counter)); bit_counter++; } else if (__HAL_TIM_GetCounter(&htim3) > 1000) { code_temp &= ~(1UL << (31-bit_counter)); bit_counter++; } if(bit_counter == 32) { cmd_l = ~code_temp; cmd_h = code_temp >> 8; if(cmd_l == cmd_h) { flag_ir = 1; } bit_counter = 0; } __HAL_TIM_SetCounter(&htim3, 0); } } |
- A função NEC_Available() retorna o valor da variável flag_ir, que é usada para indicar se um código de sinal infravermelho (IR) do protocolo NEC está disponível para ser processado.
- A função HAL_GPIO_EXTI_Falling_Callback() é um callback (retorno de chamada) que é chamado quando ocorre uma interrupção de borda de descida (falling edge) no pino GPIO especificado (GPIO_PIN_4). Dentro da função:
- Usa o temporizador (htim3) para medir o intervalo entre pulsos IR.
- __HAL_TIM_GetCounter(&htim3) obtém o valor do contador do temporizador.
- Dependendo do valor do contador do temporizador, os bits do código IR são lidos e armazenados na variável code_temp.
- Quando todos os 32 bits do código IR são lidos (bit_counter == 32), ele verifica a validade do código IR comparando cmd_l e cmd_h. Se o código IR é válido, flag_ir é setado para 1. Depois, o contador do temporizador é resetado para 0 com __HAL_TIM_SetCounter(&htim3, 0).
- Em seguida, crie a função NEC_Get_Code() que irá retornar o código recebido pelo receptor IR.
1 2 3 4 |
uint32_t NEC_Get_Code(){ flag_ir = 0; return code_temp; } |
- A última função a ser criada será a void convert_code(uint32_t code).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
void convert_code(uint32_t code) { uint8_t mensagem[2] = {'\0', '\0'}; // Buffer para enviar os dados pela UART switch (code) { case 0xFFA25D: mensagem[0] = '1'; break; case 0xFF629D: mensagem[0] = '2'; break; case 0xFFE21D: mensagem[0] = '3'; break; case 0xFF22DD: mensagem[0] = '4'; break; case 0xFF02FD: mensagem[0] = '5'; break; case 0xFFC23D: mensagem[0] = '6'; break; case 0xFFE01F: mensagem[0] = '7'; break; case 0xFFA857: mensagem[0] = '8'; break; case 0xFF906F: mensagem[0] = '9'; break; case 0xFFB04F: mensagem[0] = '#'; break; case 0xFF6897: mensagem[0] = '*'; break; case 0xFF9867: mensagem[0] = '0'; break; case 0xFF38C7: mensagem[0] = 'K'; break; case 0xFF18E7: mensagem[0] = '^'; break; case 0xFF10EF: mensagem[0] = '<'; break; case 0xFF5AA5: mensagem[0] = '>'; break; case 0xFF4AB5: mensagem[0] = 'u'; break; default: return; // Não faz nada para códigos não reconhecidos } // Envia o caractere pela UART1 HAL_UART_Transmit(&huart1, mensagem, 1, 1000); } |
Essa função converte um código IR recebido em um caractere específico, baseado na tabela de códigos hexadecimais apresentada no artigo, e o envia pela UART para outro dispositivo.
- Por fim, ajuste a função principal int main com o seguinte:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
int main(void) { /* USER CODE BEGIN 1 */ /* USER CODE END 1 */ /* MCU Configuration--------------------------------------------------------*/ /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ HAL_Init(); /* USER CODE BEGIN Init */ /* USER CODE END Init */ /* Configure the system clock */ SystemClock_Config(); /* USER CODE BEGIN SysInit */ /* USER CODE END SysInit */ /* Initialize all configured peripherals */ MX_GPIO_Init(); MX_TIM3_Init(); MX_USART1_UART_Init(); /* USER CODE BEGIN 2 */ NEC_Init(); /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ if(NEC_Available() > 0){ code = NEC_Get_Code(); char uart_tx_buffer[50]; sprintf(uart_tx_buffer, "\r\n\Code: 0x%lX\r\n", code); HAL_UART_Transmit(&huart1, (uint8_t *)uart_tx_buffer, strlen(uart_tx_buffer), 1000); convert_code(code); } } /* USER CODE END 3 */ } |
Na main temos:
- Inicialização: O sistema e os periféricos são inicializados e as configurações específicas para o protocolo NEC são inicializadas.
- Loop Infinito: O programa entra em um loop infinito onde constantemente verifica se há um código IR disponível. Se um código IR estiver disponível:
- Obtém o código.
- Formata o código em uma string e envia pela UART1. Passa o código recebido para a função de convert_code.
Gravação
Ao finalizar o código, partiremos para gravação. Nessa etapa você pode utilizar o ST-Link seguindo as conexões da imagem abaixo e clicando em “run” no STM32CubeIde.
Ou você pode optar por utilizar um cabo usb e gravar conforme explicado no seguinte tutorial: gravar-franzininho-c0-via-stm32cubeprogrammer
Funcionamento
Ao clicar em uma tecla específica do controle, o valor é exibido pela Serial.
Conclusão
Neste tutorial, aprendemos a utilizar a Franzininho C0 para receber e decodificar sinais infravermelhos de um controle remoto, implementando o protocolo NEC.
Com a montagem do circuito e a configuração do STM32CubeMX, foi possível implementar o código necessário para ler os sinais infravermelhos, decodificar os códigos recebidos e enviá-los via UART. Além disso, aprendemos a converter esses códigos em comandos específicos, que podem ser utilizados em diversas aplicações, como controle de dispositivos eletrônicos.