Rilevamento motion da accelerometro

Ciao a tutti,
sto utilizzando un accelerometro preso da sparkfun (Triple Axis Accelerometer Breakout - MMA8452Q - SEN-10955 - SparkFun Electronics) connesso ad un ATMega32, e dopo numerosi tentativi, sono riuscito a ricevere dati sulla porta seriale del pc e, leggendo i valori, riuscire a rilevare quando c'è un movimento da parte dell'accelerometro; fin qui tutto ok, ora il problema è che io voglio che l'accelerometro mi mandi un interrupt solo quando rileva un evento motion e non di continuo come mi accade ora, ho cercato di settare tutti i registri correttamente ma nulla.

In pratica io voglio che quando rileva movimento mi mandi un interrupt sul suo pin INT1, che è collegato al PINB0 del mio ATMega, che vede quando il valore di tale pin è alto e fa le sue successive cose.

Di seguito il codice e l'output che ricevo su porta seriale.

CODICE

/*
 * UARTCommunication.cpp
 *
 * Created: 12/02/2015 20:11:39
 *  Author: Marco Mastropasqua
 */ 

/* Librerie per comunicazione UART */
#define F_CPU 1000000UL
#include <avr/io.h>
#include <stdio.h>
#include <stdbool.h>
#include <util/delay.h>
#include <MyLib/UARTMethods.h>

/* Librerie accelerometro */
#include <stdlib.h>
#include <avr/interrupt.h>
#include <MyLib/defs.h>
#include <MyLib/i2c.h>
#include <MyLib/types.h>
#include <MyLib/i2c.c>

/********************************************************************************
Macros and Defines
********************************************************************************/
#define BAUD 4800
#define MYUBRR F_CPU/16/BAUD-1
//#define MYUBRR 12

/* Define e metodi accelerometro */
#define ACC_ADDRESS_R 0x3b
#define ACC_ADDRESS_W 0x3a

/* Registri */
#define XYZ_DATA_CFG 0x0e
#define ASLP_COUNT 0x29
#define CTRL_REG1 0X2a
#define CTRL_REG2 0X2b
#define CTRL_REG3 0X2c
#define CTRL_REG4 0X2d
#define CTRL_REG5 0X2e
#define FF_MT_CFG 0X15
#define FF_MT_SRC 0X16
#define FF_MT_THS 0X17
#define FF_MT_COUNT 0X18

//Metodi
uint8_t readRegister(uint8_t registro);
void writeRegister(uint8_t reg_address, uint8_t reg_data);
uint8_t* readMultipleDataFromRegister(uint8_t registro);
void writeDataOnLcd(uint8_t position_row, uint8_t position_column, uint8_t data, uint8_t base);
void putAccelerometerToActiveMode();
void putAccelerometerToStandByMode();
void initAccelerometer();

/********************************************************************************
Main
********************************************************************************/
int main( void ) {
	//Variabili in cui mettere i valori dei registri dell'accelerometro
	uint8_t received_who_am_i, register_X_MSB, register_X_LSB, register_Y_MSB, register_Y_LSB, register_Z_MSB, register_Z_LSB, register_INT_SOURCE, register_PULSE_SRC;
	uint8_t who_am_i, received_X_MSB, received_X_LSB, received_Y_MSB, received_Y_LSB, received_Z_MSB, received_Z_LSB, received_INT_SOURCE, received_PULSE_SRC;
	uint8_t register_CTRL_REG4, received_CTRL_REG4;
	uint8_t register_FF_MT_SRC, received_FF_MT_SRC;
	int X_data, Y_data, Z_data;
	uint8_t int_reg = 0x2D;
	
	//Setto il PIND2 come input
	DDRB &= ~(1<<PD0);
	int accelCount[3];
	char accelString[3];
	
	//Avvio la comunicazione USART
	usart_init (MYUBRR);
	//Scrivo sulla seriale delle scritte all'accensione del circuito
	usart_printString("SERIALE PRONTA!\n\r");
	//usart_printString("Inserisci un carattere e io lo traspongo di 1:\n\r");
	
	/* Inizializzo la comunicazione i2C */
	initI2C();
	
	//Inizializzo l'accelerometro settando tutti i vari registri opportunamente
	initAccelerometer();
	
	//Loop principale
	while(true) {		
		
		who_am_i = 0x0D;
		received_who_am_i = readRegister(who_am_i);
		
		uint8_t received_int_reg = readRegister(int_reg);
		char int_reg_data[8];
		itoa(received_int_reg, int_reg_data, 16);
		//usart_printString("INTERRUPT REGISTER");
		//usart_printString("\n\r");
		//usart_printString(int_reg_data);
		//usart_printString("\n\r");
		
		uint8_t received_int_who_am_i = readRegister(who_am_i);
		char int_who_am_i[8];
		itoa(received_int_who_am_i, int_who_am_i, 16);

		if (received_who_am_i == 0x2a)	{
			
			/* Alternative per rilevare il movimento */
			// 1 - Uso il motion detect dell'accelerometro
			//LEGGO IL REGISTRO FF_MM_SRC
			//SETTO IL REGISTRO FF_MM_CFG per abilitare solo il motion sull'asse desiderato
			//SETTO IL REGISTRO FF_MT_THS per settare le soglie desiderate per il motion detect
			
			// 2 - Leggo normalmente i dati, quando rilevo un valore alto sul pinb0 del micro e li elaboro
			//LEGGO I REGISTRI 0x01-0x06
			if (PINB & (1<<PINB0)) {
				
				register_FF_MT_SRC = 0x16;
				received_FF_MT_SRC = readRegister(register_FF_MT_SRC);
				usart_printString("MOTION:   ");
				usart_printString("\t");
				char motion[8];
				itoa(received_FF_MT_SRC, motion, 10);
				usart_printString(motion);
				usart_printString("\r");
				
				//Leggo il valore dei registri e li stampo a video
				//usart_printString("RICEVO VALORI");
				//usart_printString("\n\r");

			} else {
				usart_printString("NON RICEVO NULLA");
				usart_printString("\r");
			}
			
		} else {
			usart_printString("who am i non ricevuto");
			usart_printString("\r");
		}
		
	}
}

/* Metodo che scrive un dato sul monitor LCD */
//void writeDataOnLcd(uint8_t position_row, uint8_t position_column, uint8_t data, uint8_t base) {
//	GotoMrLCDsLocation(position_column,position_row);
//	char snum[8];
	//Converto il valore in formato intero preso dal pin ADC in string
//	itoa(data, snum, base);
//	Send_A_String(snum);
//}

/* Metodo che setta i registri per il corretto funzionamento dell'accelerometro */
void initAccelerometer() {
	//Metto l'accelerometro in modalità standby per poter scrivere i registri
	uint8_t ctrlreg1 = readRegister(CTRL_REG1);
	writeRegister(CTRL_REG1, ctrlreg1 &~ 0x01);
	
	writeRegister(CTRL_REG1, 00000000); //Set with default parameters
	writeRegister(CTRL_REG2, 00000100); //Sleep mode enable
	writeRegister(CTRL_REG3, 00001010); //Wake from Sleep, WAKE_FF_MT, IPOL
	writeRegister(CTRL_REG4, 10000100); //Interrupt enable register
	writeRegister(ASLP_COUNT, 00000001); // Time before sleeping
	writeRegister(CTRL_REG5, 00000100); //Interrupt pin (INT1/INT2) map
	
	//MOTION DETECTION
	writeRegister(FF_MT_CFG, 11111000); //Freefall-Motion Config
	writeRegister(FF_MT_THS, 10000001); //Freefall-Motion Threshold
	//writeRegister(FF_MT_COUNT, 00000001); //Freefall-Motion time 
	
	//Metto l'accelerometro in modalità attiva
	uint8_t ctrl_reg1 = readRegister(0x2A);
	writeRegister(0x2A, ctrl_reg1 | 0x01);	
}

/* Metodo che scrive un dato in un registro dell'accelerometro */
void writeRegister(uint8_t reg_address, uint8_t reg_data) {
	i2cStart();
	i2cSend(ACC_ADDRESS_W);
	i2cSend(reg_address);
	i2cSend(reg_data);
	i2cStop();
}


/* Metodo che legge un registro dall'accelerometro */
uint8_t readRegister(uint8_t registro) {
		i2cStart();
		i2cSend(ACC_ADDRESS_W);
		i2cSend(registro);
		i2cStart();
		i2cSend(ACC_ADDRESS_R);
		uint8_t data = i2cReadNoAck();
		//receivedByte2 = i2cReadNoAck();
		i2cStop();	
	return data;
}

OUTPUT SU PORTA SERIALE

Ovviamente il valore che si vede nell'output cambia se muovo l'accelerometro, ma se resta fermo continua a darmi sempre di continuo lo stesso valore, non solo in caso di variazione.

Qualche suggerimento???

non ho quel sensore non posso darti consigli specifici.

una cosa che ti consiglio e informarti come creare dei interrupt time, per esempio la prima guida che mi è arrivata a volo http://www.engblaze.com/microcontroller-tutorial-avr-and-arduino-timer-interrupts/
poi non ho mai testato questo su arduino gli interrupt gli usavo in assembly.

cmq ti consiglio di creare uno di questi e di analizzare il tuo sensore ogni tempo x e imporre un IF che quando il valore cambia richiama la tua funzione print o quello che devi fare..

ultimo consiglio a meno che non hai dei tuoi motivi personali ti direi di non fare tutta sta filata ma di mettere tutto su loop e quindi mettere li anche l'IF per la variazione

anche perché se non mi sbaglio quel sensore lavora in bus quindi non avrà mai una sua spontanea volontà nel comunicarti la variazione mentre sarà sempre il tuo arduino a richiedere il valore per analizzarlo, ergo non puoi costruire neanche un interrupt sul pin digitale .. spero che mi hai capito :smiley: :stuck_out_tongue:

Dal datasheet desumo che ci sono 6 tipi diversi di eventi che possono tradursi in segnali di interrupt.

Il registro 2E stabilisce su quale pin (INT1 o INT2) associare i vari eventi.

Ammesso che voglia usare il pin INT1 ed ad esso associare tutti i tipi di eventi, devi porre HIGH i bit 0, 2, 3, 4, 5 e 7 e a LOW i bit 6 ed 1.

Se invece desideri la stessa cosa per il pin INT2, tutti i bit del registro devono essere posti a LOW.

Il registro 2D decide quali interrupt attivare ed il registro 2C le modalità con cui attivarli.