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.
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.
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
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.
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 aqui. (obrigado Rob Gray, te pago uma gelada quando te encontrar)
- 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
CONFIGURANDO O ATMEL STUDIO PARA GRAVAR O ARDUINO DUE
- 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)
desenha_pixel(...)
desenha_linha(...)
desenha_circulo(...)
desenha_retangulo(...)
desenha_triangulo(...)
desenha_figura(...)
escreve_Nr_Peq(...)
- 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.
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
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.
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 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.
Assinar:
Postagens (Atom)




