Você está aqui: Kiko > PostsEmPortugues > PtBrBlogEntry2008Feb24A | Imprimível | fim do tópico |
freqüência da linha elétrica, mas ainda nenhum evento. temos a EEPROM TWI, LCD, baterias e o buzzer. |
RW
. Ajustando apropriadamente atrasos, rapidamente obtive sucesso.
Então reestruturei as rotinas de sorte que uma sub-tarefa do laço
principal se encarregasse de mover os bytes de um buffer para o LCD,
de sorte que imprimir coisas se torne tão simples quanto jogar os
dados nesse buffer -- a vantagem é que podemos imprimir tão rápido
quanto possível sem nos preocuparmos com a temporização.
Também fiquei satisfeito com o fato que o módulo de LCD consumia
meros 0,8mA, contribuindo muito pouco para o consumo total do dispositivo,
de apenas 8mA (ou seja: ainda estamos abaixo dos 10mA projetados).
Mas logo após eu adicionar o LCD, a primeira armadilha se apresentou: as
medidas de freqüência, outrora impecáveis, começaram a exibir uma variações
esporádicas: uma hora ficava em 60.000Hz, no instante seguinte pulava para
63Hz, depois um número bem baixo, depois de volta ao normal. Eu tinha adicionado
acumuladores para contar quantos semiciclos "rápidos" ou "lentos" haviam
ocorrido (isto é, semiciclos com períodos fora de +/- 10% das 1.042 contagens
esperadas do Timer1) e notei que o contador de "semiciclos rápidos" sempre
incrementava quanto essas anomalias aconteciam.
Confiante demais que eu estava com os resultados anteriores, quase descartei
o probelma como sendo alguma esquisitice da minha rede elétrica, tal como a
onda senoidal achatada. Então piorou, depois melhorou e eu fiquei muito confuso.
Então pensei que poderia ser um problema de software e logo descobri que ele
desaparecia se eu desabilitasse o código do LCD.
Algumas horas de frustrante depuração me levaram a uma instrução assembly em
particular: aquela que movia os 4 bits inferiores para o LCD para o barramento de
dados do LCD. Então caiu a ficha: a linha D7
do LCD está ligada ao pino exatamente
ao lado do pino ICP
, de sorte que meu problema era ruído de chaveamento elétrico:
toda vez que o caractere que estava sendo enviado para o LCD tinha o bit 3 ligado
e o pino ICP
estava em zero, ele disparava o detector de transição de nível do
sistema de captura de eventos. Aparentemente, esse circuito é sensível demais.
Em retrospectiva, talvez a coisa certa a fazer tivesse sido mover o barramento
de dados do LCD todo para outros pinos, digamos, para os pinos da porta SPI
que estão em grande medida sem uso (eu os tinha deixado intencionalmente sem
uso para que pudéssemos usá-los para a programação "in-system" e para uma futura
expansão para usar cartões SD como armazenamento). Mas eu estava cansado e
sem paciência para um longo trabalho de resoldagem, então eu simplesmente movi
a linha D7
para o pino PD2/INT0
-- o que fez a manipulação de bits nas rotinas
de LCD um pouco feiosas e arruinou um plano que eu vinha cogitando de usar o
INT0
como uma segunda porta serial para obter medidas do meu multímetro
digital ET-2210 e adicionar um sistema de auto-calibração
bem preciso.
De qualquer forma, após esse conserto gambiarresco, tudo funcionou perfeitamente.
Preciso me lembrar disso tudo ao projetar a placa de circuito impresso.
Também adicionei o 24C512, uma memória EEPROM TWI de 512 kibibits
(64KiB x 8bits). O barramento TWI requer resistores de pull-up, mas eu nem me dei
ao trabalho de adicioná-los porque podemos usar os pull-ups embutidos nos pinos do AVR,
bastando para isso ativá-los por software.
Enquanto eu estava no ciclo de desenvolvimento (codificação-upload-teste) da
rotina de tratamento da interrupção da porta TWI, percebi um problema de temporização
em potencial: as escritas de bytes para a EEPROM podem demorar até 10ms para
serem completadas, de sorte que escrever 32 bytes (o tamanho da estrutura de dados
que representa um evento) pode levar mais de 320ms ou quase 40 semiciclos
Isso significa que se tivermos dois eventos acontecendo em menos de 40 semiciclos
de distância um do outro, poderemos não ser capazes de registrá-los.
Relendo o datasheet da 24C512, achei uma solução fácil: o chip é capaz
de receber uma página completa de 128 bytes de uma só vez, em uma única
transação do barramento TWI e salvar a página completa em um único período
de 10ms. Por isso, reescrevi as rotinas de armazenamento de eventos da seguinte
forma: criei uma fila capaz de armazenar até 8 eventos (256 bytes) em RAM.
Toda vez que acumulamos 4 eventos (exatamente uma página de 128 bytes), o
sistema joga os dados para a EEPROM TWI, liberando em seguida o espaço na fila.
Rereading the 24C512 datasheet I found an easy solution: the chip is capable
Quatro eventos requerem no mínimo 8 semiciclos (um início e um final em
diferentes semiciclos, vezes quatro), mas com esse esquema de escrita
por página, podemos descarregar 4 eventos pendentes para a EEPROM em menos
de 15ms (os 10ms da escrita na EEPROM mais o tempo de transmissão dos bytes
no barramento), ou apenas dois semiciclos. Em outras palavras, podemos
armazenar eventos quatro vezes mais rápido do que eles são gerados,
o que nos permite arcar com trens de eventos bem rápidos. Os 128 bytes
excedentes na fila se encarregam de segurar as pontas mesmo que a EEPROM
esteja ocupada salvando uma página ou recuperando dados.
Isso também significa que deve ser seguro usar um chip com tamanho de página
menor desde que a taxa de armazenamento versus de geração de eventos seja
maior que 1. Uma 24C256 (32KiB x 8), com páginas de 64 bytes, deve ser
usável, com uma razão de 2 para 1. Já uma 24C128 (16KiB x 8), com páginas
de 32 bytes, dá uma razão de apenas um pouco mais que um pra um, deixando-nos
com uma temporização desconfortavelmente crítica mas talvez factível (EEPROMs
mais novas têm tempos de escrita menores, às vezes tão baixos quanto 5ms).
Mas o mesmo argumento diz que EEPROMs de 64 kibibits ou menores provavelmente
nos darão problemas.
Eis aqui a versão 0.4 do firmware com os seguintes recursos adicionais:
event
: sem argumentos, diz quantos eventos temos armazenados; com um argumento numérico, imprime detalhes daquele evento;
clear
: apaga dos os eventos armazenados (zera os contadores, de sorte que os novos dados sobrescrevem os anteriores)
param
: com um argumento, mostra o valor daquele parametro; com dois argumentos, define seu valor;
HAVE_XTRA_CMDS
for definida:
start
: artificialmente inicia um evento: dá partida no contador de tempo decorrido e a data/hora atual do relógio de tempo real é copiada para a data inical do evento. O argumento é o tipo do evento;
finish
: artificialmente termina um evento, descarregando-os para a EEPROM quando uma página é completada;
poke
: escreve um byte na EEPROM no endereço especificado;
fill
: prenche uma página da EEPROM com uma seqüência de bytes
dump
: imprime o conteúdo de uma região da EEPROM em hexa.
params
:
0
: Bit mapped flags:
0
: Bits contendo alguns flags:
1
: Variações de freqüência também geram eventos;
2
: Subtensão/sobretensão também geram eventos;
1
: Valor mínimo cru do ADC para detecção de queda de energia: se menor que esse valor, inicia um novo evento de falha de energia. Se mais que isso, termina o evento atual, se havia algum;
2
: Valor mínimo cru do ADC para detecção de subtensão: se menor que isso mas maior que o valor do parâmetro 1, incrementa o contador de "semiciclos em subtensão";
3
: Valor máximo cru do ADC para detecção de sobretensão: se maior que isso, incrementa o contador de "semiciclos em sobretensão";
4
: Valor mínimo cru do ICR: se menor que isso, incrementa o contador de "semiciclos em alta freqüência";
5
: Valor máximo cru do ICR: se maior que isso, incrementa o contador de "semiciclos em baixa freqüência";
6
: Bipa por essa quantidade de milissegundos quando a energia cai;
7
: Bipa por essa quantidade de milissegundos quando a energia volta;
8
: Bipa por essa quantidade de milissegundos quando há subtensão;
9
: Bipa por essa quantidade de milissegundos quando há sobretensão;
10
: Bipa por essa quantidade de milissegundos quando há baixa de freqüência;
11
: Bipa por essa quantidade de milissegundos quando há freqüência muito alta;