MM32F3273G8P火龙果开发板MindSDK开发教程12 -获取msa311加速器的敲击事件
1、功能描述
msa311可以识别单击、双击事件,类似手机上的点击返回,双击截屏功能。
单击,双击都能产生中断事件。
中断事件产生后,从对应的状态寄存器读取是双击还是单击。
中断需要打开映射。
单双击可设置阈值。
对应寄存器的描述如下:
2、设置相关寄存器
a、设置tap_quite
b、设置tap_shock
c、设置tap_duration
d、设置tap_threshole
e、设置中断映射
f、设置中断使能。
对应代码:
#if ENABLE_TAP_DETECT == 1
Msa311_SetTapQuiteParam(MSA311_TAPQUITE_30_MS);
Msa311_GetTapQuiteParam(&tapQuite);
printf("Msa311_getTapQuiteParam == %s\r\n",tapQuite == MSA311_TAPQUITE_30_MS ? "MSA311_TAPQUITE_30_MS" : "MSA311_TAPQUITE_20_MS");
Msa311_SetTapShockParam(MSA311_TAPSHOCK_50_MS);
Msa311_GetTapShockParam(&tapShock);
printf("Msa311_GetTapShockParam == %s\r\n",tapShock == MSA311_TAPSHOCK_50_MS ? "MSA311_TAPSHOCK_50_MS" : "MSA311_TAPSHOCK_70_MS");
Msa311_SetTapDurationParam(MSA311_TAPDUR_250_MS);
Msa311_GetTapDurationParam(&tapDuration);
printf("Msa311_GetTapDurationParam == 0x%02x\r\n",tapDuration);
Msa311_ThresholdConvertToRegister(1.0f,®);
Msa311_SetTapThresholdParam(reg);
Msa311_GetTapThresholdParam(&threshold);
printf("Msa311_GetTapThresholdParam == 0x%02x\r\n",threshold);
//使能S_TAP D_TAP Int
Msa311_SetInterruptMap0(MSA311_INTERRUPT_D_TAP,MSA311_BOOL_TRUE);
Msa311_SetInterruptMap0(MSA311_INTERRUPT_S_TAP,MSA311_BOOL_TRUE);
Msa311_GetInterruptMap0(MSA311_INTERRUPT_D_TAP,&enable);
printf("Msa311_GetInterruptMap0 MSA311_INTERRUPT_D_TAP %s\r\n",enable==MSA311_BOOL_TRUE ? "enable" : "disable");
Msa311_GetInterruptMap0(MSA311_INTERRUPT_S_TAP,&enable);
printf("Msa311_GetInterruptMap0 MSA311_INTERRUPT_S_TAP %s\r\n",enable==MSA311_BOOL_TRUE ? "enable" : "disable");
Msa311_SetInterrupt0Enable(MSA311_INTERRUPT_D_TAP_EN,MSA311_BOOL_TRUE);
Msa311_GetInterrupt0Enable(MSA311_INTERRUPT_D_TAP_EN,&enable);
printf("Msa311_GetInterrupt0Enable MSA311_INTERRUPT_D_TAP %s\r\n",enable==MSA311_BOOL_TRUE ? "enable" : "disable");
Msa311_SetInterrupt0Enable(MSA311_INTERRUPT_S_TAP_EN,MSA311_BOOL_TRUE);
Msa311_GetInterrupt0Enable(MSA311_INTERRUPT_S_TAP_EN,&enable);
printf("Msa311_GetInterrupt0Enable MSA311_INTERRUPT_S_TAP_EN %s\r\n",enable==MSA311_BOOL_TRUE ? "enable" : "disable");
#endif
每个功能函数:
static bool Msa311_SetTapQuiteParam(msa311_tapquite_t tapQuite)
{
uint8_t r_data;
uint8_t w_data;
bool bRet = 0;
bRet = Msa311_ReadReg(MSA311_REG_TAPDUR,&r_data);
if (bRet == false)
{
perror("Msa311_SetTapQuiteParam read error\n");
return false;
}
w_data = ((r_data & MSA311_TAP_QUITE_MASK) | tapQuite);
bRet = Msa311_WirteReg(MSA311_REG_TAPDUR,w_data);
if (bRet == false)
{
perror("Msa311_SetTapQuiteParam write error\n");
return false;
}
return bRet;
}
static bool Msa311_GetTapQuiteParam(msa311_tapquite_t *tapQuite)
{
uint8_t r_data;
bool bRet = 0;
bRet = Msa311_ReadReg(MSA311_REG_TAPDUR,&r_data);
if (bRet == false)
{
perror("Msa311_GetRange read error\n");
return false;
}
*tapQuite = (r_data & ~(MSA311_TAP_QUITE_MASK));
return bRet;
}
static bool Msa311_SetTapShockParam(msa311_tapshock_t tapShock)
{
uint8_t r_data;
uint8_t w_data;
bool bRet = 0;
bRet = Msa311_ReadReg(MSA311_REG_TAPDUR,&r_data);
if (bRet == false)
{
perror("Msa311_SetTapShockParam read error\n");
return false;
}
w_data = ((r_data & MSA311_TAP_SHOCK_MASK) | tapShock);
bRet = Msa311_WirteReg(MSA311_REG_TAPDUR,w_data);
if (bRet == false)
{
perror("Msa311_SetTapShockParam write error\n");
return false;
}
return bRet;
}
static bool Msa311_GetTapShockParam(msa311_tapshock_t *tapShock)
{
uint8_t r_data;
bool bRet = 0;
bRet = Msa311_ReadReg(MSA311_REG_TAPDUR,&r_data);
if (bRet == false)
{
perror("Msa311_GetTapShockParam read error\n");
return false;
}
*tapShock = (r_data & ~(MSA311_TAP_SHOCK_MASK));
return bRet;
}
static bool Msa311_SetTapDurationParam(msa311_tapduration_t tapDuration)
{
uint8_t r_data;
uint8_t w_data;
bool bRet = 0;
bRet = Msa311_ReadReg(MSA311_REG_TAPDUR,&r_data);
if (bRet == false)
{
perror("Msa311_SetTapDurationParam read error\n");
return false;
}
w_data = ((r_data & MSA311_TAP_DUR_MASK) | tapDuration);
bRet = Msa311_WirteReg(MSA311_REG_TAPDUR,w_data);
if (bRet == false)
{
perror("Msa311_SetTapDurationParam write error\n");
return false;
}
return bRet;
}
static bool Msa311_GetTapDurationParam(msa311_tapduration_t *tapDuration)
{
uint8_t r_data;
bool bRet = 0;
bRet = Msa311_ReadReg(MSA311_REG_TAPDUR,&r_data);
if (bRet == false)
{
perror("Msa311_GetTapDurationParam read error\n");
return false;
}
*tapDuration = (r_data & ~(MSA311_TAP_DUR_MASK));
return bRet;
}
static uint8_t Msa311_ThresholdConvertToRegister(float g, uint8_t *reg)
{
msa311_range_t range;
Msa311_GetRange(&range);
switch (range)
{
case MSA311_RANGE_2_G/* constant-expression */:
/* code */
*reg = (int8_t)(g / 0.0625f);
break;
case MSA311_RANGE_4_G/* constant-expression */:
/* code */
*reg = (int8_t)(g / 0.125f);
break;
case MSA311_RANGE_8_G/* constant-expression */:
/* code */
*reg = (int8_t)(g / 0.250f);
break;
case MSA311_RANGE_16_G/* constant-expression */:
/* code */
*reg = (int8_t)(g / 0.5f);
break;
default:
printf("Msa311_ThresholdConvertToRegister error\r\n");
break;
}
return 0;
}
static uint8_t Msa311_ThresholdConvertToData(uint8_t reg, float *g)
{
msa311_range_t range;
Msa311_GetRange(&range);
switch (range)
{
case MSA311_RANGE_2_G/* constant-expression */:
/* code */
*g = (float)(reg) * 0.0625f;
break;
case MSA311_RANGE_4_G/* constant-expression */:
/* code */
*g = (float)(reg) * 0.125f;
break;
case MSA311_RANGE_8_G/* constant-expression */:
/* code */
*g = (float)(reg) * 0.250f;
break;
case MSA311_RANGE_16_G/* constant-expression */:
/* code */
*g = (float)(reg) * 0.500f;
break;
default:
printf("Msa311_ThresholdConvertToData error\r\n");
break;
}
*g = (float)(reg) * 0.0039f;
return 0;
}
static bool Msa311_SetTapThresholdParam(uint8_t threshold)
{
uint8_t r_data;
uint8_t w_data;
bool bRet = 0;
w_data = threshold;
bRet = Msa311_WirteReg(MSA311_REG_TAPTH,w_data);
if (bRet == false)
{
perror("Msa311_SetTapThresholdParam write error\n");
return false;
}
return bRet;
}
static bool Msa311_GetTapThresholdParam(uint8_t *threshold)
{
uint8_t r_data;
bool bRet = 0;
bRet = Msa311_ReadReg(MSA311_REG_TAPTH,&r_data);
if (bRet == false)
{
perror("Msa311_SetTapThresholdParam read error\n");
return false;
}
*threshold = r_data;
return bRet;
}
static bool Msa311_SetInterruptMap0(msa311_interrupt_map0_t type, msa311_bool_t enable)
{
uint8_t r_data;
uint8_t w_data;
bool bRet = 0;
bRet = Msa311_ReadReg(MSA311_REG_INTMAP0,&r_data);
if (bRet == false)
{
perror("Msa311_SetInterruptMap0 read error\n");
return false;
}
r_data &= ~(1 << type); /* clear type */
r_data |= enable << type;
bRet = Msa311_WirteReg(MSA311_REG_INTMAP0,r_data);
if (bRet == false)
{
perror("Msa311_SetInterruptMap0 write error\n");
return false;
}
return bRet;
}
static bool Msa311_GetInterruptMap0(msa311_interrupt_map0_t type, msa311_bool_t *enable)
{
uint8_t r_data;
bool bRet = 0;
bRet = Msa311_ReadReg(MSA311_REG_INTMAP0,&r_data);
if (bRet == false)
{
perror("Msa311_SetInterruptMap0 read error\n");
return false;
}
r_data &= (1 << type); /* clear config */
*enable = (msa311_bool_t)(r_data >> type);
return 0;
}
static bool Msa311_SetInterrupt0Enable(msa311_interrupt_sw0_t type, msa311_bool_t enable)
{
uint8_t r_data;
uint8_t w_data;
bool bRet = 0;
bRet = Msa311_ReadReg(MSA311_REG_INTSET0,&r_data);
if (bRet == false)
{
perror("Msa311_SetInterrupt0Enable read error\n");
return false;
}
r_data &= ~(1 << type); /* clear type */
r_data |= enable << type;
bRet = Msa311_WirteReg(MSA311_REG_INTSET0,r_data);
if (bRet == false)
{
perror("Msa311_SetInterrupt0Enable write error\n");
return false;
}
return bRet;
}
static bool Msa311_GetInterrupt0Enable(msa311_interrupt_sw0_t type, msa311_bool_t *enable)
{
uint8_t r_data;
bool bRet = 0;
bRet = Msa311_ReadReg(MSA311_REG_INTMAP0,&r_data);
if (bRet == false)
{
perror("Msa311_GetInterrupt0Enable read error\n");
return false;
}
r_data &= (1 << type); /* clear config */
*enable = (msa311_bool_t)(r_data >> type);
return 0;
}
static bool Msa311_SetInterrupt1Enable(msa311_interrupt_sw1_t type, msa311_bool_t enable)
{
uint8_t r_data;
uint8_t w_data;
bool bRet = 0;
bRet = Msa311_ReadReg(MSA311_REG_INTSET1,&r_data);
if (bRet == false)
{
perror("Msa311_SetInterrupt1Enable read error\n");
return false;
}
r_data &= ~(1 << type); /* clear type */
r_data |= enable << type;
bRet = Msa311_WirteReg(MSA311_REG_INTSET1,r_data);
if (bRet == false)
{
perror("Msa311_SetInterrupt1Enable write error\n");
return false;
}
return bRet;
}
static bool Msa311_GetInterrupt1Enable(msa311_interrupt_sw1_t type, msa311_bool_t *enable)
{
uint8_t r_data;
bool bRet = 0;
bRet = Msa311_ReadReg(MSA311_REG_INTMAP1,&r_data);
if (bRet == false)
{
perror("Msa311_GetInterrupt1Enable read error\n");
return false;
}
r_data &= (1 << type); /* clear config */
*enable = (msa311_bool_t)(r_data >> type);
return 0;
}
static bool Msa311_GetInterruptState(msa311_int_state_t state, msa311_bool_t *enable)
{
uint8_t r_data;
bool bRet = 0;
bRet = Msa311_ReadReg(MSA311_REG_MOTIONINT,&r_data);
if (bRet == false)
{
perror("Msa311_GetInterrupt1Enable read error\n");
return false;
}
r_data &= (1 << state); /* clear config */
*enable = (msa311_bool_t)(r_data >> state);
return 0;
}
对应头文件:
#ifndef __MSA311_H__
#define __MSA311_H__
#define MSA311_I2CADDR_DEFAULT_7 (0x62) ///< Fixed I2C address
#define MSA311_I2CADDR_DEFAULT_8 (0xC4) ///< Fixed I2C address
/*=========================================================================*/
#define MSA311_REG_RESET 0x00 ///< Register soft reset
#define MSA311_REG_PARTID 0x01 ///< Register that contains the part ID
#define MSA311_REG_OUT_X_L 0x02 ///< Register address for X axis lower byte
#define MSA311_REG_OUT_X_H 0x03 ///< Register address for X axis higher byte
#define MSA311_REG_OUT_Y_L 0x04 ///< Register address for Y axis lower byte
#define MSA311_REG_OUT_Y_H 0x05 ///< Register address for Y axis higher byte
#define MSA311_REG_OUT_Z_L 0x06 ///< Register address for Z axis lower byte
#define MSA311_REG_OUT_Z_H 0x07 ///< Register address for Z axis higher byte
#define MSA311_REG_MOTIONINT 0x09 ///< Register address for motion interrupt
#define MSA311_REG_DATAINT 0x0A ///< Register address for data interrupt
#define MSA311_REG_CLICKSTATUS 0x0B ///< Register address for click/doubleclick status
#define MSA311_REG_ORIENTATION_STATUS 0x0C ///< Register address for orientation status
#define MSA311_REG_RESRANGE 0x0F ///< Register address for resolution range
#define MSA311_REG_ODR 0x10 ///< Register address for data rate setting
#define MSA311_REG_POWERMODE 0x11 ///< Register address for power mode setting
#define MSA311_REG_INTSET0 0x16 ///< Register address for interrupt setting #0
#define MSA311_REG_INTSET1 0x17 ///< Register address for interrupt setting #1
#define MSA311_REG_INTMAP0 0x19 ///< Register address for interrupt map #0
#define MSA311_REG_INTMAP1 0x1A ///< Register address for interrupt map #1
#define MSA311_REG_TAPDUR 0x2A ///< Register address for tap duration
#define MSA311_REG_TAPTH 0x2B ///< Register address for tap threshold
#define MSA311_REG_OFFSET_X 0x38
#define MSA311_REG_OFFSET_Y 0x39
#define MSA311_REG_OFFSET_Z 0x3A
#define MSA311_POWER_MODE_MSAK 0x3F
#define MSA311_POWER_MODE_SHIFT 0x05u
/** The accelerometer power mode */
typedef enum {
MSA311_NORMALMODE = 0x00, ///< Normal (high speed) mode
MSA311_LOWPOWERMODE = 0x40, ///< Low power (slow speed) mode
MSA311_SUSPENDMODE = 0xC0, ///< Suspend (sleep) mode
} msa311_powermode_t;
#define MSA311_AXES_ENABLE_MSAK 0x1F
typedef enum{
AXES_DISABLE = 0x00,
AXES_ENABLE = 0xE0,
}msa311_axes_state_t;
#define MSA311_DATA_RATE_MASK 0xF0
/** The accelerometer data rate */
typedef enum {
MSA311_DATARATE_1_HZ = 0x00, ///< 1 Hz
MSA311_DATARATE_1_95_HZ = 0x01, ///< 1.95 Hz
MSA311_DATARATE_3_9_HZ = 0x02, ///< 3.9 Hz
MSA311_DATARATE_7_81_HZ = 0x03, ///< 7.81 Hz
MSA311_DATARATE_15_63_HZ = 0x04, ///< 15.63 Hz
MSA311_DATARATE_31_25_HZ = 0x05, ///< 31.25 Hz
MSA311_DATARATE_62_5_HZ = 0x06, ///< 62.5 Hz
MSA311_DATARATE_125_HZ = 0x07, ///< 125 Hz
MSA311_DATARATE_250_HZ = 0x08, ///< 250 Hz
MSA311_DATARATE_500_HZ = 0x09, ///< 500 Hz
MSA311_DATARATE_1000_HZ = 0x0A, ///< 1000 Hz
} msa311_dataRate_t;
#define MSA311_BAND_WIDTH_MASK 0xE1
/** The accelerometer bandwidth */
typedef enum {
MSA301_BANDWIDTH_1_95_HZ = 0x00, ///< 1.95 Hz
MSA301_BANDWIDTH_3_9_HZ = 0x06, ///< 3.9 Hz
MSA301_BANDWIDTH_7_81_HZ = 0x08, ///< 7.81 Hz
MSA301_BANDWIDTH_15_63_HZ = 0x0A, ///< 15.63 Hz
MSA301_BANDWIDTH_31_25_HZ = 0x0C, ///< 31.25 Hz
MSA301_BANDWIDTH_62_5_HZ = 0x0E, ///< 62.5 Hz
MSA301_BANDWIDTH_125_HZ = 0x10, ///< 125 Hz
MSA301_BANDWIDTH_250_HZ = 0x12, ///< 250 Hz
MSA301_BANDWIDTH_500_HZ = 0x14, ///< 500 Hz
} msa301_bandwidth_t;
#define MSA311_RANG_MASK 0xFC
/** The accelerometer ranges */
typedef enum {
MSA311_RANGE_2_G = 0x00, ///< +/- 2g (default value)
MSA311_RANGE_4_G = 0x01, ///< +/- 4g
MSA311_RANGE_8_G = 0x02, ///< +/- 8g
MSA311_RANGE_16_G = 0x03, ///< +/- 16g
} msa311_range_t;
#define MSA311_TAP_DUR_MASK 0xF8
/** Tap duration parameter */
typedef enum {
MSA311_TAPDUR_50_MS = 0x00, ///< 50 millis
MSA311_TAPDUR_100_MS = 0x01, ///< 100 millis
MSA311_TAPDUR_150_MS = 0x02, ///< 150 millis
MSA311_TAPDUR_200_MS = 0x03, ///< 200 millis
MSA311_TAPDUR_250_MS = 0x04, ///< 250 millis
MSA311_TAPDUR_375_MS = 0x05, ///< 375 millis
MSA311_TAPDUR_500_MS = 0x06, ///< 500 millis
MSA311_TAPDUR_700_MS = 0x07, ///< 50 millis700 millis
} msa311_tapduration_t;
#define MSA311_TAP_QUITE_MASK 0x7F
typedef enum{
MSA311_TAPQUITE_20_MS = 0x80,
MSA311_TAPQUITE_30_MS = 0x00,
}msa311_tapquite_t;
#define MSA311_TAP_SHOCK_MASK 0xBF
typedef enum{
MSA311_TAPSHOCK_50_MS = 0x00,
MSA311_TAPSHOCK_70_MS = 0x40,
}msa311_tapshock_t;
typedef enum
{
MSA311_BOOL_FALSE = 0x00, /**< false */
MSA311_BOOL_TRUE = 0x01, /**< true */
} msa311_bool_t;
typedef enum
{
MSA311_INTERRUPT_FREE_FALL = 0x00, /**< free fall */
MSA311_INTERRUPT_ACTIVE = 0x02,
MSA311_INTERRUPT_D_TAP = 0x04,
MSA311_INTERRUPT_S_TAP = 0x05,
MSA311_INTERRUPT_ORIENT = 0x06,
} msa311_interrupt_map0_t;
typedef enum
{
MSA311_INTERRUPT_ACTIVE_EN_X = 0x00,
MSA311_INTERRUPT_ACTIVE_EN_Y = 0x01,
MSA311_INTERRUPT_ACTIVE_EN_Z = 0x02,
MSA311_INTERRUPT_D_TAP_EN = 0x04,
MSA311_INTERRUPT_S_TAP_EN = 0x05,
MSA311_INTERRUPT_ORIENT_EN = 0x06,
} msa311_interrupt_sw0_t;
typedef enum
{
MSA311_INTERRUPT_FREE_FALLEN = 0x03,
MSA311_INTERRUPT_NEW_DATA_EN = 0x04,
} msa311_interrupt_sw1_t;
typedef enum{
MSA311_INT_S_TAP_MESSAGE = 0x00,
MSA311_INT_D_TAP_MESSAGE = 0x01,
}msa311_int_message_type;
typedef enum
{
MSA311_FREE_FALL_INT_STATE = 0x00,
MSA311_ACTIVE_INT_STATE = 0x02,
MSA311_D_TAP_INT_STATE = 0x04,
MSA311_S_TAP_INT_STATE = 0x05,
MSA311_ORIENT_INT_STATE = 0x06,
}msa311_int_state_t;
// golbal function
void Msa311_Init(void);
void handle_int_message(void);
#endif
这样设置好msa311的寄存器后,当我们敲击的时候,int脚会拉低。所以我们只需要连接mm32一个gpio,并且配成中断模式,就可以捕获对应的敲击事件了。
3、中断接收并处理数据
将msa311的Int脚连接至mm32 的PC8.
pc8适配中断代码如下:
void BOARD_InitPins(void)
{
/* 调用GPIO的HAL库对象结构体声明GPIO对象 */
GPIO_Init_Type gpio_init;
//pc 8 for msa311 inter detect
uint32_t prioritygroup = 0;
RCC_EnableAPB2Periphs(RCC_APB2_PERIPH_SYSCFG, true);
/* 设置GPIO的模式 */
gpio_init.PinMode = GPIO_PinMode_In_PullUp;
gpio_init.Speed = GPIO_Speed_50MHz;
/* 选择引脚初始化 */
gpio_init.Pins = GPIO_PIN_8;
GPIO_Init(GPIOC, &gpio_init);
/* 将外部中断线设置为复用模式 */
SYSCFG_SetExtIntMux(SYSCFG_EXTIPort_GPIOC, SYSCFG_EXTILine_8);
/* 设置外部中断线的触发方式 */
EXTI_SetTriggerIn(EXTI, EXTI_LINE_8, EXTI_TriggerIn_FallingEdge);
/* 使能外部中断线 */
EXTI_EnableLineInterrupt(EXTI, EXTI_LINE_8, true);
prioritygroup = NVIC_GetPriorityGrouping();
NVIC_SetPriority(SysTick_IRQn, NVIC_EncodePriority(prioritygroup, 0, 2));
/* 使能对应的外部中断 */
NVIC_EnableIRQ(EXTI9_5_IRQn);
}
对应的中断处理函数:
void EXTI9_5_IRQHandler(void)
{
uint32_t flags = EXTI_GetLineStatus(EXTI);
if ( 0u != ( flags & EXTI_LINE_8 ) ) /* Interrupts. */
{
handle_int_message();
}
EXTI_ClearLineStatus(EXTI, flags);
}
中断处理函数将事件处理交给handle_int_message()函数,此函数在msa311.c中定义。
void handle_int_message(void)
{
uint8_t state;
bool bRet;
bRet = Msa311_ReadReg(MSA311_REG_MOTIONINT,&state);
if (bRet == false)
{
perror("Msa311_GetInterrupt1Enable read error\n");
return;
}
if (state & (1 << MSA311_S_TAP_INT_STATE))
{
printf("this is s_tap \r\n");
}
else if (state & (1 << MSA311_D_TAP_INT_STATE))
{
printf("this is d_tap \r\n");
}
}
在中断处理函数中,我们做个一件事,就是去读一下0x09寄存器的值,当第四位为1的时候,表示双击,第五位为1的时候,表示单击。
4、现象
单击模块时候打印 this is s_tap
双击模块时候打印 this is d_tap
5、代码
代码下载