Mensagem

"Sonhar mais um sonho impossível, lutar quando é fácil ceder, vencer o inimigo invencível, negar quando a regra é vender."
Miguel de Cervantes.

"Os microprocessadores RISC funcionam a partir do princípio genial de se encarregar das coisas mais fáceis e deixar todas as partes difíceis para outras pessoas resolverem."
Douglas Adams.

Mostrando postagens com marcador Programação. Mostrar todas as postagens
Mostrando postagens com marcador Programação. Mostrar todas as postagens

Atualização da Biblioteca para o LCD 16x2

   Depois de algum tempo segue atualização da biblioteca do livro AVR e Arduino: Técnicas de Projeto. Incorporei novas funções e simplifiquei outras, bem como melhorei a padronização do código.
    Código e projeto no AVR Studio 6.2, com exemplos de uso das funções, arquivos AQUI.


Protocolo 1 Wire usando UART com o STM32

   O protocolo 1 wire é muito interessante para uso de somente um pino de I/O de um microcontrolado. Protocolo simples e baseado em janelas de tempo entre os sinais. Todavia, o uso de atrasos para escrita e leitura do pino pode resultar em perda de desempenho e complicar a vida do programador. Isso ocorrerá se a temporização for feita através da execução de laços vazios.
   Visando superar essas complicações e otimizar a programação e desempenho do microcontrolador, a Maxim (compradora da Dallas Semiconductor Corp. , que criou o protocolo), apresenta uma nota de aplicação para realizar a comunicação 1 wire empregando o protocolo serial simples (UART). 

   O detalhe está em trocar a taxa de transmissão entre 9600 e 115200 bps. No Reset usa-se 9600 e envia-se o dado 0xF0. Para escrita e leitura, 115200 bps. Na escrita de 1 lógico envia-se 0xFF, de 0, 0x00. Na leitura se envia 0xFF para cada bit a ser lido, retorno 0xFF significa bit 1. O uso da UART é, portanto, simples e prático.
   A comunicação deve ser configurada para 8 bits de dados, um bit de parada, sem bit de paridade.

   A seguir código exemplo para o DS80B20 (sensor de temperatura), empregado para um Corte-M0+ da STM, baseado na camada de abstração de hardware (HAL). Os detalhes foram suprimidos, pois a ideia é apresentar o algoritmo básico.


//--------------------------------------------------------------------------
// 1 WIRE functions - UART 2
//--------------------------------------------------------------------------
// 1 WIRE functions - UART 2
void reset_1w()
{
unsigned char  buff[2];
buff[0]=0xF0;

huart2.Init.BaudRate = 9600; // para o reset a taxa deve ser 9600
HAL_UART_Init(&huart2);

HAL_UART_Transmit(&huart2, buff, 1, HAL_MAX_DELAY);

huart2.Init.BaudRate = 115200; // 115200 para rescrita e leitura
HAL_UART_Init(&huart2);
}
//--------------------------------------------------------------------------
void write_byte_1w(unsigned char data)
{
uint32_t i;

for(i=0; i<8; i++)
{
if(tst_bit(data,i))
USART2->TDR = 0xFF; // logico 1 envia FF
else
USART2->TDR = 0x00; // logico 0 envia 00

HAL_UART_Receive(&huart2, (uint8_t *)aRxBuffer, 1,0xFFFF);
}
}
//---------------------------------------------------------------------------
unsigned char read_byte_1w()
{
unsigned int i;
unsigned char dado = 0; // todos os bits são zero por default

for (i=0;i<8;i++)
{
   USART2->TDR = 0xFF; // para ler um bit envia FF

   HAL_UART_Receive(&huart2, (uint8_t *)aRxBuffer, 1,0xFFFF);

   if(aRxBuffer[0] == 0xFF) //se for igual a FF o bit é um, zero se contrário
      set_bit(dado,i);

}
return (dado);
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------


//DS18B20 - uma conversão

reset_1w(); //reset do sensor (a resposta de presença é retornada mas não avaliada).
write_byte_1w(0xCC); //comando para pular ROM (só 1 dispositivo no barramento).
write_byte_1w(0x44); //manda iniciar a conversão
HAL_Delay(750);
reset_1w();
write_byte_1w(0xCC);
write_byte_1w(0xBE); //avisa que quer ler a memória

temp_LSB = read_byte_1w();//só interesse em ler os dois bytes da temperatura
temp_MSB = read_byte_1w();


temp_16bits = (temp_MSB<<8) | (temp_LSB);

if (temp_MSB > 7)
{
  temp_16bits = 0xFFFF - temp_16bits + 1; 
  sinal = '-';
}
else
  sinal = '+';

  temperatura = (5*temp_16bits)/8;


ARM CORTEX-M3 ATSAM3X8E - Arduino Due

    OBSERVAÇÃO: not for Dummies!

   Para aplicações relativamente simples um microcontrolado de 8 bits é suficiente. Entretanto, quando se necessita mais desempenho, memória e periféricos, é preciso um microcontrolador mais turbinado e com motor mais potente. Minha escolha foi o Arduino Due devido aos inúmeros Shields disponíveis e por poder ser programado no Atmel Studio, incluindo o FreeRTOS e todas as ferramentas necessárias para um desenvolvimento profissional de firmware.
   Comecei a programação com alguns programas básicos para entender a complexidade dos registradores de configuração do ATSAM3X. O datasheet da Atmel é algo terrível, pesadelo para estudar e compreender (a Atmel deveria evitar que estagiários escrevessem datasheets!). Assim, resolvi disponibilizar os códigos desenvolvidos e materiais de suporte para ajudar os iniciantes.
   Bueno, vamos ao que importa:

   PRINCIPAIS CARACTERÍSTICAS DO ARDUINO DUE

  • Pinagem compativel com o Arduino Uno (Shields compatíveis), cuidado deve ser tomado pois o Due trabalha com 3.3V (5V pode danificá-lo permanentemente).
  • Entrada de alimentação externa 9 VDC.
  • Gravação através de conversor serial-usb com bootloader (similar ao Uno).
  • Conector SPI.
  • Conector JTAG para programação e depuração.
  • Botão de reset.
  • Botão para apagamento da memória do microcontrolador.
  • Possui um microcontrolador ATSAM3X8E.
  • 54 pinos de I/O.
  • 12 entradas analógicas (ADC).
  • 4 UARTs.
  • 1 USB OTG.
  • 2 saídas DAC.

     PINAGEM  aqui. (obrigado Rob Gray, te pago uma gelada quando te encontrar)

   
   PRINCIPAIS CARACTERÍSTICAS DO ATSAM3X8E
  • Processador de 32 bits (ARM - Cortex-M3).
  • 512 kB de memória Flash.
  • 96 kB de memória RAM.
  • 84 MHz de frequência de operação máxima.
  • Oscilador interno (PLL) para geração precisa de sinais de frequência para os seu trabalho.
  • Controlador DMA
  • 9 Timers de 32 bits com modos de comparação, captura e PWM.
  • RTC
  • USB 2.0 On To Go
  • 4 UARTs
  • 2 I2C
  • 2 CAN
  • 1 Ethernet MAC10/100 com DMA dedicado.
  • 16 canais AD de 12 bits de 1 Msps (com sensor de temperatura interno).
  • 2 canais DA de 12 bits 1 MSPs.
  • 1 Gerador de Números Aleatórios Verdadeiro.
  • 103 I/Os com capacidade de interrupção, filtro para debouncing e glitch, coletor aberto, pull-up.
  • Modos para economia de energia.


   CONFIGURANDO O ATMEL STUDIO PARA GRAVAR O ARDUINO DUE

   Uma característica interessante do Atmel Studio é poder gravar o Due através de sua IDE. São necessários alguns passos de configuração (nada muito complicado) e o programa bossac.exe encontrado nas pastas de instalação da IDE do Arduino. Aqui link explicativo (figuras auxiliares abaixo).




    Programa e exemplo do arquivo bat, aqui (eu coloquei a pasta bossa no C:\ e não usei a localização da IDE do Arduino).


  CÓDIGOS EXEMPLOS EM C PARA O ARDUINO DUE (sob a licença Beerware)


  • Programa Pisca LED: pisca o LED ligado ao pino 13 (PB27). Apresenta as rotinas de atraso, tão importantes em programação: atraso_ms( ), atraso_us( ) e atraso_loops( ). Código das funções em assembly, funções aferidas com o uso de um osciloscópio.
  • Programa para controle de LCDs 16x2 (controlador HD44780 pino RW aterrado): Apresenta as funções para inicialização e trabalho com esses LCD, incluindo a função para conversão de um número inteiro em seus dígitos individuais.
  • Programa teste do RTC (Relógio de Tempo Real): uso do RTC interno do ATSAM, ajuste de horas com a leitura de botões, tempo apresentado em um LCD 16x2.
  • Programa para uso da UART ligado ao conversor USB/serial do Arduino Due: teste e funções de transmissão e recepção de dados, incluindo um buffer de recepção com tamanho ajustável. As mensagens podem ser recebidas em qualquer terminal virtual em um PC.
  • Programa teste do ADC usando um sensor LM35 e o sensor interno de temperatura: leitura da tensão gerada por um LM35 e pelo sensor interno do ATSAM, resultado enviado ao computador usando a UART. (Obs.: cuidado, ao habilitar o sensor interno de temperatura AD15, o pino PB27 é desabilitado!!! Pergunte à ATMEL o porquê ..., parece que alguns chips já foram corrigidos!? Referência nula a esse problema apresentada pela ATMEL!)
  • Programa para teste do uso dos TIMERs (TCs): emprega a interrupção do TC0 e seus 3 canais. O estudo inicial dos TCs é confuso e este programa ajuda a entender como utilizá-los. O LED ligado ao pino PB27 troca de estado a cada estouro do TC correspondente.
  • Programa para o uso do MAX7219 (driver para displays de 7 segmentos): testado com um módulo made in China. Este CI é bem interessante.
  • Programa para o LCD NOKIA 5110 (gráfico 48x84 pixels): funções de trabalho para esse display fácil de utilizar e barato, adaptação do código para a IDE do Arduino da Sparkfun. Permite escrever mensagens e imprimir figuras. Inclui programa para gerar os dados da imagem e arquivos auxiliares. Fiz algumas funções para gráficos, só fiz o preenchimento para o retângulo. Produzir uma biblioteca gráfica é relativamente complicado, então aproveite.
         //Funções do Borges:
        desenha_pixel(...)
        desenha_linha(...)
        desenha_circulo(...)
        desenha_retangulo(...)
        desenha_triangulo(...)
        desenha_figura(...)

        escreve_Nr_Peq(...)
      

Sensor de Temperatura LM35 na IDE do Arduino

   Tenho visto algumas coisas bizarras relativas a programação do LM35 na IDE do Arduino. Então, resolvi apresentar um código mais elegantes aos robistas.
   O primeiro ponto é a tensão de referência que deve ser empregada pelo conversor AD do ATmega328 (o microcontrolador do Arduino), que deve ser ajustada para 1,1V e não 5V como visto por aí. Melhorando a resolução da conversão significativamente.
   O segundo ponto é a equação de transformação que deve converter o número digital puro do AD para o valor de temperatura, utilizar ponto flutuante é deveras péssimo em termos de desempenho e consumo de memória.
   Os detalhes técnicos podem ser encontrados no meu livro AVR e Arduino: Técnicas de Projeto, Seção 19.4, para aqueles que apenas gostariam de usar o código, segue comentado.

   
//LEITURA DE TEMPERATURA COM O LM35
//sensor no pino A4

unsigned int valor_temp=0;

void setup()
{
   Serial.begin(9600); 

  //definicao da tensão de final de escala para a conversao (1.1V)
   analogReference(INTERNAL);   
}

void loop()
{
   //equacao de conversao otimizada 
   valor_temp = analogRead(A4) + analogRead(A4)*19/256;   

   Serial.print("Temperatura = ");
   Serial.print(valor_temp/10); 
   Serial.print(".");
   Serial.print(valor_temp%10); 
   Serial.write(186);
   Serial.println("C");

  delay(1000);
}

/* O LM35 apresenta uma saída de 10mV/°C. O valor de leitura do AD é dado por ADC = Vin*1024/Vref, como Vref = 1,1V, para converter o valor do AD para graus Celsius, é necessário multiplicar o valor ADC por 1100/1024 (considerando uma casa decimal antes da vírgula). Utilizando a simplificação matemática e mantendo a variável temperatura com 16 bits, resulta: 1100/1024 = 1 + 19/256 */

Gerando Tons DTMF com o Arduino

   A pedido, analisei brevemente o application note AVR314:DTMF Generator, da Atmel, que explica como usar um AVR para gerar tons DTMF. Pesquisando na rede encontrei alguns códigos que me auxiliaram. Dessa forma, fiz apenas uma organização e adequação desses programas para o ATmega328P do Arduino. Nao fiz nenhuma análise do sinal produzido, apenas um teste rápido para verificar o funcionamento do código.

   O programa foi desenvolvido em C no Atmel Studio e empreguei o meu Shield com teclado em conjunto com um buzzer para o teste

DOWNLOAD AQUI - DTMF_Generator

RTOS

   Este post trata de uma importante ferramenta de programação para desenvolvimento de projetos de mais alto nível, os sistemas operacionais de tempo real - RTOS, compatíveis principalmente com arquiteturas de 32 bits. Entretanto, com o desenvolvimento de novos firmwares e com a maior disponibilidade de memória, os microcontroladores de 8 bits podem suportar sistemas operacionais mínimos e ainda apresentar desempenho satisfatório. A utilização de um RTOS se justifica pelas facilidade de programação, permitindo a solução de problemas complexos, difíceis de tratar com a programação convencional. Assim, com algum sacrifício de desempenho, pode-se utilizar um RTOS em um microcontrolador de 8 bits. O uso de um RTOS com esses microcontroladores não é usual dado a limitação da CPU. Todavia, é possível utilizar sistemas mínimos que podem produzir desempenho satisfatório dependendo dos tempos de acionamento e processamento necessários para uma determinada tarefa.
   A seguir disponibilizo o capítulo 21 do livro AVR e Arduino: Técnicas de Projeto, utilizando o BRTOS para o ATmega328. Esse capítulo formaliza as definições e traz exemplos de uso da programação C com o ATMEL Studio.


DOWNLOAD AQUI ->  RTOS


O Importantíssimo Trabalho com Bits

   A programação de um microcontrolador exige o bom trabalho com bits. Dessa forma, a otimização do programa pode ser feita em qualquer acesso aos registradores de I/O (trabalho). 
   Quando se programa em C é fundamental conhecer como trabalhar com bits, assim estou disponibilizando o material básico que utilizo com meus alunos, parte do capítulo 4 do livro AVR e Arduino: Técnicas de Projeto, (O Importantíssimo Trabalho com Bits).
   Em resumo são 4 macros: set_bit( ), clr_bit( ), cpl_bit( ) e tst_bit( ). O compilador GCC para o AVR faz um bom trabalho com elas e gera o menor número de instruções Assembly possível.
   A programação microcontrolada também exige o uso direto de registradores com mascára de bits, conforme lógica de programação. Isto é visível nos programas disponibilizados no livro supracitado. Por exemplo: PORTD |= 0x0F  preserva os 4 MSBs do PORTD e ativa somente os 4 LSBs. Ao contrário de PORTD &=0x0F, que limpa os 4 MSBs. 
   Dependendo da lógica necessária, podem ser necessárias várias funções lógicas para alterar um determinado bit/conjunto em um registrador/variável.

Programação C para Arduino

Na data de 26/05/2013 fiz uma breve introdução à programação C para Arduino no The Developer´s Conference (TDC2013), aqui em Florianópolis. A apresentação é apenas um indicativo do que foi falado. Download na figura abaixo.



Filtro de Média Móvel


    Muitas vezes, para eliminar ou diminuir algum ruído indesejável em um sinal, é necessário filtrá-lo. Isso é comum quando se trabalha com sinais provenientes do ADC. Essa filtragem é, então, feita através da programação. O problema é que a teoria sobre filtros digitais é complexa e o programador a evita sempre que possível. Todavia, pode-se utilizar um filtro bem simples, chamado de média móvel, que pode resolver o problema do ruído.
     O filtro de média móvel é obtido calculando-se a média de um conjunto de valores, sempre se adicionando um novo valor ao conjunto e se descartando o mais velho. Não é apenas uma média de um conjunto isolado de valores. O filtro de média móvel é representado por:


onde n é o tempo atual (é o índice dos vetores utilizados), N +1 é o número de amostras utilizadas para a filtragem, y[n] é o sinal filtrado e x[n-k] representa o conjunto dos valores a serem somados. A equação acima pode ser representada pelo diagrama da figura 1, com os valores de b0,b1...bN iguais a 1/(N+1).


Fig. 1 - Diagrama de um filtro digital não recursivo.

     O diagrama da fig. 1 representa um filtro chamado não recursivo, pois o sinal de saída y[n] depende somente do sinal de entrada x[n]. Caso o sinal de saída dependesse de valores passados da saída, o filtro seria chamada recursivo. No projeto de um filtro digital, determinam-se os coeficientes de multiplicação para as amostras, no caso b0, b1, ... bN para o diagrama citado. Esses coeficientes podem ser determinados com o uso de alguma ferramenta computacional como o MATLAB® ou MATCAD®, e o programador apenas necessita realizar as somas e multiplicações nas amostras certas. A qualidade do filtro e o tipo de filtro (passa baixa, passa alta, passa faixa) vai depender do número de coeficientes utilizados (quantidade de amostras) e dos seus valores.
     Ao utilizar coeficientes fixos, o filtro de média móvel produz um filtro passa baixa suave, reduzindo os sinais de alta frequência. Caso se deseje outro tipo de filtragem, será necessário a multiplicação com valores fracionários, o que exigirá o uso de ponto flutuante no programa. Isso pode ser um problema para microcontroladores de 8 bits pelo consumo maior de memória e da limitada capacidade de processamento da CPU.
     Na fig. 2, é apresentada a resposta em frequência de um filtro de média móvel para 16 amostras. O eixo horizontal é a frequência em Hertz, o número 1 representa a frequência de amostragem do sinal dividida por 2. Desta forma, supondo uma frequência de amostragem 20 kHz, cada linha vertical do gráfico corresponderia a 1 kHz.


 Fig. 2 – Resposta em frequência de um filtro de média móvel de 16 amostras.

     A resposta apresentada na fig. 2 mostra que o desempenho de um filtro de média móvel é razoável, estando a atenuação dos sinais indesejados   na   faixa  de aproximadamente -20 dB (90 %).
     A seguir, é apresentado um exemplo para a programação de um filtro de média móvel de 16 amostras para os valores convertidos pelo ADC do ATmega (deve-se observar o tamanho das variáveis declaradas para não ocorrer estouro na contagem).
   Obs.: havia um erro no algoritmo abaixo, faltava inicializar com zero o valor media antes do somatório das amostras, o que aumentava um pouco a média.

//---------------------------------------------------------------------
// Filtro de média móvel com 16 amostras para o sinal do ADC
//---------------------------------------------------------------------

unsigned int filtro[16], media,
unsigned char k=0;
. . .
ISR(ADC_vect)
{
    unsigned char j;


    filtro[k] = ADC;    //valor do ADC entra no filtro, na amostra mais antiga
    k++; if(k==16) k=0;



    media = 0;

    for(j=0; j<16; j++)
       media += filtro[j];  //somatório das amostras

    media /=16;             //média dos valores
}

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

Obs.: Este material faz parte do capítulo 19 do livro AVR e Arduino: Técnicas de Projeto. O programa é diferente no livro, aconselho comparação.