sexta-feira, abril 24, 2009

Spoke-o-dometer - Parte 6

Nesta parte vamos testar o circuito na roda de uma bicicleta. Mas antes vamos usar as informações do teste anterior para codificar a detecção de imã.

Detectando o Imã

Relembrando, o sensor usado fornece uma tensão proporcional ao campo magnético a que é submetido. Longe do imã, temos uma tensão de 4.5/2 V. À medida que o sensor se aproximar de um imã esta tensão irá baixar ou subir, dependendo do polo. Pelo teste anterior, a leitura do SD16 com o sensor longe do imã é de 88 (considerando somente o byte mais significativo do resultado).

Uma primeira ideia seria usar um limite único para detectar o imã. Por exemplo, considerar que quando o valor passar de 110 estamos próximos do imã. Entretanto, é provável que as leituras oscilem o que poderia causar uma sequência de detecções em uma única passagem pelo imã.

O mais seguro é colocar uma histerese no teste. Por exemplo, considerar que estamos próximos do imã quando o valor passar de 120 e só voltar a considerar que estamos longe quando o valor cair abaixo de 100. Desta forma, mesmo que o valor passe de 120, baixe para 110 e depois volte para 120 consideramos uma única detecção.

Para ficarmos independentes da polaridade do imã, usamos também dois valores abaixo do de repouso (neste teste, vamos detectar o imã quando o valor ficar abaixo de 56 e considerar que nos afastamos dele quando o valor ficar acima de 76).

Fixando o Circuito e o Imã

O circuito é fixado na válvula do pneu. A posição do imã é relativamente crítica, neste teste ele ficou preso ao freio.

O imã é o "botão" metálico na parte inferior central da foto. As pilhas (que não aprecem na foto), estão diametralmente opostas ao circuito porém mais próximas do centro.

O Software de Teste

O software de teste implementa a histerese mencionada acima. A cada detecção é incrementado um contador, que é apresentado nos LEDs.

  1. /* 
  2.   Spoke-o-dometer 
  3.   Teste3 - Teste do sensor em movimento 
  4.  
  5.   Daniel Quadros - abril, 2009 
  6. */  
  7.   
  8. #include <msp430.h>  
  9.   
  10. // Valor para contar 1ms c/ clock de 12KHz  
  11. #define TEMPO_1MS   12   // 1ms * 12KHz  
  12.   
  13. // Limites para detectar passagem pelo imã  
  14. #define VREPOUSO    88      // 01011000  
  15. #define VPOS_1      120     // 01111000  
  16. #define VPOS_2      100     // 01111000  
  17. #define VNEG_1      56      // 00111000  
  18. #define VNEG_2      76      // 00111000  
  19.   
  20. #define FALSE       0  
  21. #define TRUE        1  
  22.   
  23. typedef unsigned char  byte;  
  24.   
  25. static byte bDetectou = FALSE;  // TRUE qdo detecta o imã  
  26. static unsigned int cont = 0;  
  27.   
  28. // Rotinas Locais  
  29. static void Led (unsigned int valor);  
  30.   
  31. // Programa Principal  
  32. void main (void)  
  33. {  
  34.   // Desliga Watchdog  
  35.   WDTCTL = WDTPW + WDTSSEL + WDTHOLD;  
  36.   
  37.   // Altera a configuração de clock para ativar o VLOCLK  
  38.   BCSCTL3 |= LFXT1S1;  
  39.   
  40.   // Programa entradas e saídas  
  41.   P1SEL = 0xC0;               // P1.0 a P1.5 -> LEDs  
  42.                               // P1.6 e P1.7 são A3+ e A3-  
  43.   P1DIR = 0x3F;  
  44.   P1OUT = 0;                  // Todos as saídas em zero  
  45.     
  46.   P2SEL = 0;                  // Todos os pinos como I/O  
  47.   P2DIR = 0xFF;               // Todos os pinos como saída  
  48.   P2OUT = 0;                  // Todos as saídas em zero  
  49.   
  50.   // Programa o ADC  
  51.   // MSP430F2013 -> SD16  
  52.   SD16CTL = SD16VMIDON + SD16REFON + SD16SSEL_1;  // 1.2V ref, SMCLK  
  53.   SD16INCTL0 = SD16INCH_3;                        // PGA = 1x, Diff inputs A3- & A3+  
  54.   SD16CCTL0 =  SD16SNGL + SD16UNI + SD16IE;       // Single conversion, Unipolar, 256 SR, Int enable  
  55.   SD16CTL &= ~SD16VMIDON;                         // VMID off: used to settle ref cap  
  56.   SD16AE = SD16AE6 + SD16AE7;                     // P1.6 & P1.7: A3+/- SD16_A inputs  
  57.   
  58.   // Dá um tempinho para estabilizar a alimentação  
  59.   while (cont < 0xFF)  
  60.     cont++;  
  61.   cont = 0;  
  62.   
  63.   // Alimentação já deve estar estável, vamos ligar o DCO  
  64.   BCSCTL1 = CALBC1_1MHZ;  
  65.   DCOCTL  = CALDCO_1MHZ;  
  66.   
  67.   // Programar a interrupção de tempo real p/ cada 10ms  
  68.   TACCR0 = TEMPO_1MS;  
  69.   TACTL = TASSEL_1 + MC_1 + TAIE; // ACLK, up mode, interrupt  
  70.   
  71.   // O nosso programa principal vai ficar dormindo,  
  72.   // todo o tratamento será feito na interrupção  
  73.   _BIS_SR(LPM3_bits + GIE);     // Dorme tratando interrupção  
  74.   
  75.   // Nuca vai chegar aqui  
  76.   while (1)  
  77.     ;  
  78. }  
  79.   
  80. // Tratamento da interrupção do Timer A  
  81. #pragma vector=TIMERA1_VECTOR  
  82. __interrupt void Timer_A_TO(void)  
  83. {  
  84.   switch (TAIV)  
  85.   {  
  86.       case 10:        // overflow  
  87.           SD16CTL |= SD16REFON;       // Liga a referência do SD16  
  88.           SD16CCTL0 |= SD16SC;        // Inicia uma conversão  
  89.           _BIC_SR_IRQ (SCG1+SCG0);    // Manter osciladores ligados  
  90.           break;  
  91.       
  92.       case 2:         // CCR1, não utilizado  
  93.           break;  
  94.   }  
  95. }  
  96.   
  97. // Tratamento da interrupção do SD16  
  98. #pragma vector = SD16_VECTOR  
  99. __interrupt void SD16ISR(void)  
  100. {  
  101.   unsigned int result;  
  102.   
  103.   SD16CTL &= ~SD16REFON;        // Desliga referência do SD16_A  
  104.   result = SD16MEM0 >> 8;       // Pega resultado (limpa IFG)  
  105.   
  106.   if (!bDetectou && ((result > VPOS_1) || (result < VNEG_1)))  
  107.   {  
  108.       bDetectou = TRUE;  
  109.       Led (++cont);  
  110.   }  
  111.   else if (bDetectou && (result < VPOS_2) && (result > VNEG_2))  
  112.       bDetectou = FALSE;  
  113.   
  114.   _BIS_SR_IRQ (SCG1+SCG0);      // voltar para LPM3  
  115. }  
  116.   
  117. // Mostra resultado nos LEDs  
  118. static void Led (unsigned int valor)  
  119. {  
  120.   // vamos mostrar somente os 7 bits menos significativos  
  121.   valor &= 0x7F;  
  122.   valor <<= 1;  
  123.   P1OUT = (P1OUT & 0xC0) | (valor & 0x3E);  
  124.   P2OUT = (P2OUT & 0x3F) | (valor & 0xC0);  
  125. }  
Para finalizar, o vídeo abaixo mostra o teste em ação:



Na próxima parte (se tudo correr bem) vamos começar a mostrar mensagens.

Nenhum comentário: