O Hardware
O projeto de hardware resistiu inalterado desde o começo. Repetindo o circuito (clique para ampliar):


O Software
Segue abaixo a listagem completa do software, que vou explicar nos post seguintes.
- /*
- Spoke-o-dometer
- Teste 5 - Versão Completa
- Daniel & Flávio Quadros - abril/junho, 2009
- */
- #include <msp430.h>
- // Constantes lógicas
- #define FALSE 0
- #define TRUE 1
- // Tipo byte
- typedef unsigned char byte;
- // Circunferência aprox. da roda em milimetros
- #define CIRCUNF 2090L
- // Valor para contar 100us c/ clock de 1MHz
- #define TEMPO_100uS 99 // (100us * 1MHz) - 1
- // Gerador de Caracteres
- // Cada caracter corresponde a 5 bytes
- // Cada byte corresponde a uma coluna
- static const byte gc[16][5] =
- {
- 0x7C, 0x82, 0x82, 0x82, 0x7C, // 0
- 0x02, 0x42, 0xFE, 0x02, 0x02, // 1
- 0x46, 0x8A, 0x92, 0xA2, 0x42, // 2
- 0x44, 0x82, 0x92, 0x92, 0x6C, // 3
- 0xF0, 0x10, 0x10, 0x10, 0xFE, // 4
- 0xF2, 0x92, 0x92, 0x92, 0x8C, // 5
- 0x6C, 0x92, 0x92, 0x92, 0x0C, // 6
- 0x80, 0x86, 0x98, 0xA0, 0xC0, // 7
- 0x6C, 0x92, 0x92, 0x92, 0x6C, // 8
- 0x60, 0x92, 0x92, 0x92, 0x6C, // 9
- 0x00, 0x00, 0x00, 0x00, 0x00, // SPACE (10)
- 0x00, 0x04, 0x06, 0x00, 0x00, // , (11)
- 0x7E, 0x08, 0x14, 0x22, 0x00, // k (12)
- 0x1E, 0x10, 0x0C, 0x10, 0x1E, // m (13)
- 0x03, 0x0C, 0x18, 0x30, 0x60, // / (14)
- 0x7E, 0x08, 0x08, 0x06, 0x00 // h (15)
- };
- #define CHAR_SPACE 10;
- #define CHAR_COMMA 11;
- #define CHAR_K 12;
- #define CHAR_M 13;
- #define CHAR_SLASH 14;
- #define CHAR_H 15;
- // Limites para detectar passagem pelo ímã
- #define VREPOUSO 88 // 01011000
- #define VPOS_1 120 // 01111000
- #define VPOS_2 100 // 01111000
- #define VNEG_1 56 // 00111000
- #define VNEG_2 76 // 00111000
- static byte bAmostrando = FALSE; // TRUE enquanto aguarda ADC
- static byte bDetectou = FALSE; // TRUE qdo detecta o imã
- // Contagem do tempo de uma volta e
- // controle da escrita da mensagem
- #define NFRAMES 360 // frames por volta
- #define POS_MSG 45 // inicio da mensagem
- #define SPACE 3 // frames de espaço entre letras
- static unsigned long tickVolta; // número de ticks em uma volta
- static unsigned long tickVoltaAnt; // número de ticks da volta anterior
- static unsigned long tickFrame = 0; // número de ticks por frame
- static unsigned long contFrame; // ticks até o próximo frame
- static byte col; // coluna sendo apresentada
- static char *pMsg; // caracter sendo apresentado
- static char msg[16]; // mensagem a apresentar
- // Rotinas locais
- int escreve_kmh (unsigned int vel, char *pv);
- int char_index (char c);
- // Programa Principal
- void main (void)
- {
- unsigned int cont = 0;
- // Desliga Watchdog
- WDTCTL = WDTPW + WDTSSEL + WDTHOLD;
- // Altera a configuração de clock para ativar o VLOCLK
- BCSCTL3 |= LFXT1S1;
- // SMCLK = MCLK / 8
- BCSCTL2 = DIVS_3;
- // Programa entradas e saídas
- P1SEL = 0xC0; // P1.0 a P1.5 -> LEDs
- // P1.6 e P1.7 são A3+ e A3-
- P1DIR = 0x3F;
- P1OUT = 0; // Todos as saídas em zero
- P2SEL = 0; // Todos os pinos como I/O
- P2DIR = 0xFF; // Todos os pinos como saída
- P2OUT = 0; // Todos as saídas em zero
- // Programa o ADC
- // MSP430F2013 -> SD16
- SD16CTL = SD16VMIDON + SD16REFON + SD16DIV_0 + SD16SSEL_1; // 1.2V ref, SMCLK
- SD16INCTL0 = SD16INCH_3; // PGA = 1x, Diff inputs A3- & A3+
- SD16CCTL0 = SD16SNGL + SD16UNI + SD16IE; // Single conversion, Unipolar, 256 SR, Int enable
- SD16CTL &= ~SD16VMIDON; // VMID off: used to settle ref cap
- SD16AE = SD16AE6 + SD16AE7; // P1.6 & P1.7: A3+/- SD16_A inputs
- // Dá um tempinho para estabilizar a alimentação
- while (cont < 0xFF)
- cont++;
- cont = 0;
- // Alimentação já deve estar estável, vamos ligar o DCO
- BCSCTL1 = CALBC1_8MHZ;
- DCOCTL = CALDCO_8MHZ;
- // Programar a interrupção de tempo real p/ cada 100us
- TACCR0 = TEMPO_100uS;
- TACTL = TASSEL_2 + MC_1 + TAIE; // SCLK, up mode, interrupt
- // O nosso programa principal vai ficar dormindo,
- // todo o tratamento será feito na interrupção
- _BIS_SR(GIE);
- LPM0; // Dorme tratando interrupção
- // Nuca vai chegar aqui
- while (1)
- ;
- }
- // Tratamento da interrupção do Timer A
- #pragma vector=TIMERA1_VECTOR
- __interrupt void Timer_A_TO(void)
- {
- byte valor;
- switch (TAIV)
- {
- case 10: // overflow
- tickVolta++; // mais um tick na volta atual
- if (tickFrame != 0)
- {
- if (contFrame == 0) // fim do frame atual
- {
- if (col > 0)
- {
- // vamos para a coluna anterior
- col--;
- valor = gc [char_index(*pMsg)][col];
- P1OUT &= 0xC1;
- P1OUT |= (valor & 0x3E);
- P2OUT &= 0x3F;
- P2OUT |= (valor & 0xC0);
- contFrame = tickFrame;
- }
- else
- {
- // passar ao caracter seguinte
- P1OUT = P1OUT & 0xC1;
- P2OUT = P2OUT & 0x3F;
- col = 5;
- pMsg++;
- if (*pMsg == 0)
- tickFrame = 0; // fim da mensagem
- else
- contFrame = tickFrame * SPACE;
- }
- }
- else
- contFrame--;
- }
- if (!bAmostrando)
- {
- SD16CTL |= SD16REFON; // Liga a referência do SD16
- SD16CCTL0 |= SD16SC; // Inicia uma conversão
- bAmostrando = TRUE;
- }
- break;
- case 2: // CCR1, não utilizado
- break;
- }
- }
- // Tratamento da interrupção do SD16
- #pragma vector = SD16_VECTOR
- __interrupt void SD16ISR(void)
- {
- unsigned int medida;
- unsigned int veloc;
- unsigned long delta;
- int tmsg;
- SD16CTL &= ~SD16REFON; // Desliga referência do SD16_A
- medida = SD16MEM0 >> 8; // Pega medida (limpa IFG)
- bAmostrando = FALSE; // Fim da amostragem
- if (!bDetectou && ((medida > VPOS_1) || (medida < VNEG_1)))
- {
- // fim de uma volta
- bDetectou = TRUE;
- // Calcula variação em relação à volta anterior
- if (tickVolta > tickVoltaAnt)
- delta = tickVolta - tickVoltaAnt;
- else
- delta = tickVoltaAnt - tickVolta;
- // Calcula a velocidade em 0,1 Km/h
- // veloc = distância / tempo
- // CIRCUNF em mm, ticVolta em 100 us
- // veloc = 3600 * (CIRCUNF / 100000) / (ticVolta / 10000)
- veloc = (unsigned int) ((CIRCUNF*360L)/tickVolta);
- // Só mostra velocidade se maior que 7.0 Km/h
- // e não variou mais que 25%
- if ((veloc > 70) && (delta < (tickVolta >> 2)))
- tmsg = escreve_kmh(veloc, msg);
- else
- {
- msg[0] = ' ';
- msg[1] = 0;
- tmsg = 1;
- }
- pMsg = &msg[0];
- // Calcula o tempo por frame e a contagem para a posição inicial
- tickFrame = tickVolta / NFRAMES;
- contFrame = (tickVolta *(NFRAMES - POS_MSG - tmsg*(5+SPACE))) / NFRAMES;
- tickVoltaAnt = tickVolta;
- tickVolta = 0;
- col = 5;
- P1OUT |= 1;
- }
- else
- {
- if (bDetectou && (medida < VPOS_2) && (medida > VNEG_2))
- {
- // pode procurar imã de novo
- bDetectou = FALSE;
- P1OUT &= 0xFE;
- }
- }
- }
- // Formata a velocidade para apresentação
- // Mensagem é montada em ordem reversa
- // "h/mk#,###"
- int escreve_kmh (unsigned int vel, char *pv)
- {
- int tam = 7;
- *pv++ = 'h';
- *pv++ = '/';
- *pv++ = 'm';
- *pv++ = 'k';
- *pv++ = '0' + (vel % 10); vel /= 10;
- *pv++ = ',';
- *pv++ = '0' + (vel % 10); vel /= 10;
- if (vel != 0)
- {
- *pv++ = '0' + (vel % 10); vel /= 10;
- tam++;
- if (vel != 0)
- {
- *pv++ = '0' + (vel % 10);
- tam++;
- }
- }
- *pv = 0;
- return tam;
- }
- // c_index: retorna o índice do caractere na matriz gc
- int char_index(char c)
- {
- if ((c - '0') >= 0 && (c - '0') < 10)
- return (c - '0');
- if (c == ' ') return CHAR_SPACE;
- if (c == ',') return CHAR_COMMA;
- if (c == 'k') return CHAR_K;
- if (c == 'm') return CHAR_M;
- if (c == '/') return CHAR_SLASH;
- if (c == 'h') return CHAR_H;
- //else (caractere estranho)
- return CHAR_SLASH;
- }
O vídeo abaixo mostra o Spoke-o-dometer em funcionamento:
Nenhum comentário:
Postar um comentário