Is it possible to measure acceleration in sports activities with an accelerometer

accelerometermsp430prototypingsensor

I've been trying to make a simple prototype capable of measuring a punch or a shot put throw with an accelerometer, but suddenly stopped working, and "locked" into a value, has I was testing it.
When I was testing it, even tho I tried to make the code The most efficient possible to maximize the measurement frequency, sometimes I would get irregular values (low accuracy).
The way I tested my prototype was dropping it into a hard surface.
The components I used where:

  1. Microcontroller (msp430g2553)
  2. Display (QDSP 6064)
  3. accelerometer (ADXL377):
  4. – range: +/- 200g
    – frequency response: 1000Hz
    – absolute maximum g: 10000g

The code I used is the following (sorry, it's in portuguese):

#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

The design is pretty straightforward, here's a foto:
enter image description here

I'm afraid I broke the acceleration sensor or the microcontroller, but it could also be because its physically impossible to measure this types of accelerations due to unwanted noise from vibration or even amateurish coding.
Is it even possible to measure these physical properties in, for example, a shot put throw?

Best Answer

Dropping a rigid object onto a hard surface produces accelerations in the thousands to tens of thousands of Gs, and you probably exceeded the 10 kG shock rating of your sensor.

There are better ways to test and/or calibrate accelerometers. You can start by turning it to different orientations and making sure you can measure gravity in both directions on every axis. You can put it on a turntable and measure the radial acceleration at various rotational speeds. Or you can get time on a calibrated "shaker table".