He estado tratando de hacer un prototipo simple capaz de medir un puñetazo o un lanzamiento con un acelerómetro, pero repentinamente dejó de funcionar y se "fijó" en un valor, si lo estaba probando.
Cuando lo estaba probando, aunque intenté que el código fuera lo más eficiente posible para maximizar la frecuencia de medición, a veces obtenía valores irregulares (baja precisión).
La forma en que probé mi prototipo fue dejarlo caer sobre una superficie dura.
Los componentes que utilicé donde:
- Microcontrolador (msp430g2553)
- Mostrar (QDSP 6064)
- acelerómetro (ADXL377): - Rango: +/- 200g
- respuesta de frecuencia: 1000Hz
- máximo absoluto g: 10000g
El código que usé es el siguiente (lo siento, está en portugués):
#include <msp430.h>
#include <math.h>
#include <stdio.h>
#define CAT_1 BIT3
#define CAT_2 BIT4
#define CAT_3 BIT5
#define CAT_4 BIT6
#define SEG_A BIT0
#define SEG_B BIT1
#define SEG_C BIT2
#define SEG_D BIT3
#define SEG_E BIT4
#define SEG_F BIT5
#define SEG_G BIT6
#define SEG_DP BIT7
#define EIXO_X BIT0
#define EIXO_Y BIT1
#define EIXO_Z BIT2
#define BOTAO BIT7
unsigned int adc[3];
unsigned int eixo_x = 0;
unsigned int eixo_y = 0;
unsigned int eixo_z = 0;
unsigned int maior = 0;
unsigned int soma = 0;
float gx;
float gy;
float gz;
float gxy;
float gxyz;
int total;
char total_string[3];
int flag_display = 0;
const int zero_g = 512;
const float escala = 2.6165;
int i = 0; // tempo de atraso
void escolher_digito(int digito);
void escolher_numero(char numero);
void digito_um(void);
void digito_dois(void);
void digito_tres(void);
void digito_quatro(void);
void zero(void);
void um(void);
void dois(void);
void tres(void);
void quatro(void);
void cinco(void);
void seis(void);
void sete(void);
void oito(void);
void nove(void);
void vazio(void);
void atraso(void);
void main(void) {
WDTCTL = WDTPW | WDTHOLD;
P1REN |= BOTAO; // Ativa resistância interna para os modos "pull-up"/"pull-down"
P1IES |= BOTAO; // Selecionar botão de alto para baixo (modo "pull-up") (alto -> baixo, 1 -> 0)
P1IFG &= ~BOTAO; // Limpar a flag BOTAO antes de permitir interrupções
// Desta forma previne-se uma possível interrupção imediata
P1IE |= BOTAO; // Permitir interupções em BOTAO
_enable_interrupt(); // Permitir interrupções
P2SEL &= ~(SEG_G | SEG_DP); // Seleciona modo I/O para P1.6 e P1.7 (por defeito estão configurados para o cristal do relógio externo)
P1OUT |= CAT_1 | CAT_2 | CAT_3 | CAT_4;
P2OUT = 0;
P1DIR |= CAT_1 | CAT_2 | CAT_3 | CAT_4;
P2DIR |= SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F | SEG_G | SEG_DP;
BCSCTL1 = CALBC1_16MHZ;
DCOCTL = CALDCO_16MHZ;
ADC10CTL1 = INCH_2 + CONSEQ_1; // Canal máximo: A2, modo de conversão: sequência de canais
ADC10CTL0 = ADC10SHT_1 + MSC + ADC10ON; // Tempo de amostra: 8 x ADC10CLK ????????? alterar?
// Multiplas amostras e conversão (apenas válido para modo de sequência ou repetição)
// ADC10 ligado
ADC10DTC1 = 0x03; // Transferência de dados -> numero de transferências por bloco: 3
ADC10AE0 |= 0x07; // Ligar entradas analógicas A2, A1 e A0
for(;;) {
// Modo de observação (quando o display se encontra desligado) (ciclo infinito)
if(!flag_display) {
ADC10CTL0 &= ~ENC; // Desligar conversão
while (ADC10CTL1 & BUSY); // Esperar que ADC10 fique ativo
ADC10SA = (unsigned int)adc; // Copia dados em ADC10SA para o array adc
ADC10CTL0 |= ENC + ADC10SC; // Iniciar conversão de amostra
//__bis_SR_register(CPUOFF + GIE); // Modo de poupança de energia LPM0 (CPU e MCLK) desativados
// Permitir interrupções
soma = adc[2] + adc[1] + adc[0];
if(soma > maior) {
maior = soma;
eixo_x = adc[2];
eixo_y = adc[1];
eixo_z = adc[0];
}
}
// Modo de display (ciclo infinito)
if(flag_display) {
escolher_digito(2);
escolher_numero(total_string[2]);
atraso();
escolher_digito(3);
escolher_numero(total_string[1]);
atraso();
escolher_digito(4);
escolher_numero(total_string[0]);
atraso();
escolher_digito(1);
escolher_numero(' ');
atraso();
}
} // ciclo infinito
} // main
// Rotina de serviço de interrupção
#pragma vector = PORT1_VECTOR
__interrupt void P1_ISR(void) {
atraso();
switch(P1IFG & BOTAO) { // Se a flag de interrupção for ativada
// xxxx1xxx & 00001000 = 00001000
// xxxx1xxx & 00001000 = 00000000
case BOTAO:
P1IFG &= ~BOTAO; // Fazer reset à flag de interrupção
// Ciclo único
// Se o display não estiver ativo, fazer os cálculos para determinar a soma vetorial
if(!flag_display) {
// valor em Gs de cada eixo
gx = (eixo_x - zero_g) / escala;
gy = (eixo_y - zero_g) / escala;
gz = (eixo_z - zero_g) / escala;
// soma vetoral dos eixos
gxy = sqrt((gx*gx) + (gy*gy));
gxyz = sqrt((gxy*gxy) + (gz*gz));
total = gxyz - 1;
// Conversão de inteiro para string da soma vetorial
sprintf(total_string, "%d", total);
}
// Se o display estiver ativo, desligar display (ao calcar em BOTAO)
if(flag_display) {
// desligar display
//P1OUT |= CAT_1 | CAT_2 | CAT_3 | CAT_4;
P2OUT = 0;
}
// Ligar/desligar display
flag_display = !flag_display;
return;
default:
P1IFG = 0; // Caso ocorra outra interrupção em P1, limpar a flag
// Provavelmente desnecessário, mas uma boa prática
return;
} // switch
} // interrupção para P1
void escolher_digito(int digito) {
switch(digito) {
case 1: digito_um(); break;
case 2: digito_dois(); break;
case 3: digito_tres(); break;
case 4: digito_quatro(); break;
}
}
void escolher_numero(char numero) {
switch(numero) {
case '1': um(); break;
case '2': dois(); break;
case '3': tres(); break;
case '4': quatro(); break;
case '5': cinco(); break;
case '6': seis(); break;
case '7': sete(); break;
case '8': oito(); break;
case '9': nove(); break;
case '0': zero(); break;
case ' ': vazio(); break;
}
}
void digito_um(void) {
P1OUT |= CAT_1 | CAT_2 | CAT_3;
P1OUT &= ~CAT_4;
}
void digito_dois(void) {
P1OUT |= CAT_1 | CAT_2 | CAT_4;
P1OUT &= ~CAT_3;
}
void digito_tres(void) {
P1OUT |= CAT_1 | CAT_3 | CAT_4;
P1OUT &= ~CAT_2;
}
void digito_quatro(void) {
P1OUT |= CAT_2 | CAT_3 | CAT_4;
P1OUT &= ~CAT_1;
}
void zero(void) {
P2OUT &= ~(SEG_G | SEG_DP);
P2OUT |= SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F;
}
void um(void) {
P2OUT &= ~(SEG_A | SEG_D | SEG_E | SEG_F | SEG_G | SEG_DP);
P2OUT |= SEG_B | SEG_C;
}
void dois(void) {
P2OUT &= ~(SEG_C | SEG_F| SEG_DP);
P2OUT |= SEG_A | SEG_B | SEG_D | SEG_E | SEG_G;
}
void tres(void) {
P2OUT &= ~(SEG_E | SEG_F | SEG_DP);
P2OUT |= SEG_A | SEG_B | SEG_C | SEG_D | SEG_G;
}
void quatro(void) {
P2OUT &= ~(SEG_A | SEG_D | SEG_E | SEG_DP);
P2OUT |= SEG_B | SEG_C | SEG_F | SEG_G;
}
void cinco(void) {
P2OUT &= ~(SEG_B | SEG_E | SEG_DP);
P2OUT |= SEG_A | SEG_C | SEG_D | SEG_F | SEG_G;
}
void seis(void) {
P2OUT &= ~(SEG_B | SEG_DP);
P2OUT |= SEG_A | SEG_C | SEG_D | SEG_E | SEG_F | SEG_G;
}
void sete(void) {
P2OUT &= ~(SEG_D | SEG_E | SEG_F | SEG_G | SEG_DP);
P2OUT |= SEG_A | SEG_B | SEG_C;
}
void oito(void) {
P2OUT &= ~SEG_DP;
P2OUT |= SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F | SEG_G;
}
void nove(void) {
P2OUT &= ~(SEG_D | SEG_E | SEG_DP);
P2OUT |= SEG_A | SEG_B | SEG_C | SEG_F | SEG_G;
}
void vazio(void) {
P2OUT = 0;
}
void atraso(void) {
for(i = 0; i < 0xFFF; i++) {
}
} // atraso
El diseño es bastante sencillo, aquí hay una foto:
Me temo que rompí el sensor de aceleración o el microcontrolador, pero también podría ser debido a que es físicamente imposible medir este tipo de aceleraciones debido al ruido no deseado de la vibración o incluso a la codificación de aficionados. ¿Es posible medir estas propiedades físicas, por ejemplo, en un lanzamiento de lanzamiento?