
A medição da velocidade em RPM é, do ponto de vista teórico, muito simples. Basta usar a interrupção de timer para medir o tempo entre as detecções dos imãs. Sabendo que em cada volta teremos duas detecções, se o tempo entre elas é t segundos, a velocidade em RPM será 30/t.
Na prática temos algumas dificuldades. A taxa de interrupção que eu estava usando (256 uSeg) se mostrou inadequada. O meu processamento dentro da interrupção estava demorado demais, tornando a contagem de tempo não confiável. Uma solução seria colocar um cristal para aumentar o clock do processador, mas acabei optando pela saída mais simples de dividir por dois o clock do timer, obtendo uma interrupção a cada 512 uSeg.
Um outro cuidado a tomar é com os extremos da operação. O display permite mostrar um valor de até 9999 RPM, o que corresponde a uma contagem de 5 interrupções. Valores a cima disto serão apresentados como 9999. Para apresentar 0000 rapidamente quando estiver parado, coloquei um timeout de 10 segundos na detecção do imã.
O código final, abaixo, é bem semelhante ao que vimos na parte anterior. O tempo é contado através do contador cnta. Quando um imã é detectado, o valor em cnta é copiado para cntb que será usado na apresentação. Como na parte anterior, tempos uma pequena máquina de estados, desta vez com 4 estados:
- 0: estamos contando o tempo até a próxima detecção para calcular a velocidade.
- 1: cntb contém o tempo contado, é necessário calcular a velocidade
- 2: a velocidade foi calculada e a nova apresentação do display está em newsegto
- 3: segto foi atualizado, aguardar a próxima detecção para abrir uma nova contagem de tempo
- #include <16F676.h>
- #device adc=8
- #use delay(clock=4000000)
- #fuses NOWDT, NOCPD, NOPROTECT
- #fuses INTRC_IO, PUT, BROWNOUT, MCLR
- #define DLY_SR 2 // delay p/ shift register
- #define TAXA_DISP 3 // taxa de varredura dos displays
- #define TEMPO_LED 300 // tempo que o LED fica aceso
- #define TIMEOUT 19531 // timeout p/ sensor
- // Pinos de E/S
- #define SENSOR PIN_A5
- #define LED PIN_A4
- #define SHIFT_DS PIN_A2
- #define SHIFT_ST PIN_C0
- #define SHIFT_SH PIN_C1
- #define SEL_1 PIN_C5
- #define SEL_2 PIN_C4
- #define SEL_3 PIN_C3
- #define SEL_4 PIN_C2
- // Controle do LED
- volatile int16 cntLed;
- // Tempo entre passagens do imã
- volatile unsigned int16 cnta = 0;
- volatile unsigned int16 cntb = 0;
- // Controle dos segmentos do display
- // Um byte para cada segmento
- // Bit 7 = segto G, Bit 6 = segto F, .. Bit 1 = segto A
- unsigned int8 segto [4];
- unsigned int8 newsegto [4];
- unsigned int8 passo = 0;
- // Segmentos a serem acesos para cada dígito
- const unsigned int8 digitos[10] =
- {
- 0b01111110, 0b00001100, 0b10110110, 0b10011110, 0b11001100,
- 0b11011010, 0b11111010, 0b00001110, 0b11111110, 0b11011110
- };
- // Rotinas locais
- static void AtlDisp (void);
- static void VarreDisp (void);
- /*********************************************************************/
- // P R O G R A M A P R I N C I P A L
- void main()
- {
- unsigned int16 aux;
- // Iniciações do hardware
- set_tris_a (0xEB); // A4 e A2 output
- #use fast_io(A)
- set_tris_c (0xC0); // C0 a C5 output
- #use fast_io(C)
- setup_timer_0(RTCC_INTERNAL|RTCC_DIV_2);
- setup_timer_1(T1_DISABLED);
- setup_comparator(NC_NC);
- setup_vref(FALSE);
- setup_adc(ADC_OFF);
- output_low (LED);
- output_low (SEL_1);
- output_low (SEL_2);
- output_low (SEL_3);
- output_low (SEL_4);
- enable_interrupts(INT_RA5);
- enable_interrupts(INT_RTCC);
- enable_interrupts(GLOBAL);
- for (;;)
- {
- if (passo == 1)
- {
- if (cntb >= TIMEOUT)
- aux = 0; // considerar parado
- else if (cntb > 5)
- aux = 58594/cntb;
- else
- aux = 9999;
- newsegto[0] = digitos [aux / (unsigned int16) 1000];
- newsegto[1] = digitos [(aux/100) % 10];
- newsegto[2] = digitos [(aux/10) % 10];
- newsegto[3] = digitos [aux % 10];
- passo = 2;
- }
- }
- }
- /*********************************************************************/
- // S E N S O R
- //////////////////////////////////////////////
- // Interrupcao de mudança do sinal
- // Ocorre qdo sensor detecta imã
- //////////////////////////////////////////////
- #int_ra
- void Sensor_ISR ()
- {
- output_high (LED);
- input_a();
- clear_interrupt (INT_RA5);
- cntLed = TEMPO_LED;
- if (passo == 0)
- {
- cntb = cnta;
- cnta = 0;
- passo = 1;
- }
- else if (passo == 3)
- {
- cnta = 0;
- passo = 0;
- }
- }
- /*********************************************************************/
- // T E M P O
- //////////////////////////////////////////////
- // Interrupcao de tempo real
- // Ocorre a cada 512 uSeg
- //////////////////////////////////////////////
- #int_RTCC
- void RTCC_isr()
- {
- static unsigned int8 cont_disp = TAXA_DISP;
- // Tratamento do LED
- if (cntLed)
- {
- if (--cntLed == 0)
- output_low (LED);
- }
- // Atualização do Display
- if (passo == 2)
- {
- AtlDisp ();
- passo = 3;
- }
- if (--cont_disp == 0)
- {
- VarreDisp ();
- cont_disp = TAXA_DISP;
- }
- // Medida do tempo
- if ((passo == 0) || (passo == 3))
- {
- if (cnta < TIMEOUT)
- cnta++;
- else
- {
- // não detectou
- cntb = cnta;
- cnta = 0;
- passo = 1;
- }
- }
- }
- /*********************************************************************/
- // D I S P L A Y
- static void AtlDisp (void)
- {
- segto[0] = newsegto[0];
- segto[1] = newsegto[1];
- segto[2] = newsegto[2];
- segto[3] = newsegto[3];
- }
- static void VarreDisp (void)
- {
- static unsigned int8 disp = 0;
- unsigned int8 i, mask;
- // coloca os valores dos segmentos no registrador
- for (i = 0, mask = 0x80; i < 8; i++)
- {
- if (segto[disp] & mask)
- output_low (SHIFT_DS);
- else
- output_high (SHIFT_DS);
- delay_us (DLY_SR);
- output_high (SHIFT_SH);
- delay_us (DLY_SR);
- output_low (SHIFT_SH);
- delay_us (DLY_SR);
- mask = mask >> 1;
- }
- // seleciona o display atual
- if (disp == 0)
- {
- output_low (SEL_4);
- output_high (SEL_1);
- }
- else if (disp == 1)
- {
- output_low (SEL_1);
- output_high (SEL_2);
- }
- else if (disp == 2)
- {
- output_low (SEL_2);
- output_high (SEL_3);
- }
- else
- {
- output_low (SEL_3);
- output_high (SEL_4);
- }
- // acende os segmentos
- output_high (SHIFT_ST);
- delay_us (DLY_SR);
- output_low (SHIFT_ST);
- // passa para o dígito seguinte
- disp = (disp + 1) & 3;
- }
O vídeo abaixo mostra um teste do software. Para conferir o cálculo, o sinal do sensor é monitorado em um osciloscópio. A frequência indicada no osciloscópio é 19.57Hz, o que corresponde a 1174 RPM, um valor bastante próximo do apresentado no display.
A adaptação do software para os outros sensores fica para o próximo post.
7 comentários:
Nossa muito bom mesmo seu projeto adorei, gostaria de saber qual o ci que ultilizou para controlar o display (BCD?), se possivel me passe o esquema elétrico.
Obrigado
tecnico_eletronico@hotmail.com
O circuito e uma descrição detalhada está em um post anterior: http://dqsoft.blogspot.com/2011/04/pequenos-imas-e-micro-controladores_19.html
Tem a lista de componentes que é preciso?
Os principais componentes são um PIC 16F676, um 74HC595, um display sete segmentos quatro dígitos anodo comum (YSD-439AK2B-35) e o sensor efeito hall US1881. O display e o sensor foram comprados da Sparkfun através do Lab de Garagem. Além deles o meu circuito usa vários resistores e um LED comum. Além dos componentes, você vai precisar gravar o firmware no PIC, no meu circuito tem a conexão de um programador.
quais os valores dos resistors? e qual o seu programa? dá para fazer com microgenios?
Os valores dos resistores estão no esquema (veja os links nas respostas anteriores). O programa está listado e explicado neste post. Não sei a que "microgenios" você se refere.
Boa tarde a todos , a muito tempo que não via uma pagina excelente como essa , e excelentes projetos , como sempre digo o mundo sera melhor só com o compartilhamento de conhecimentos.´.
Postar um comentário