目录
ICM42688有两种驱动方式,本人在使用的时候,遇到了各种各样的坑。现在提供两种驱动供大家使用,欢迎大家一起讨论问题。
PS:本人使用的是淘宝的模块
1.IIC软件驱动
ICM42688.c
#include “ICM42688.h”
void ICM_Port_Init(void) {
// 启用 GPIOB, GPIOC时钟
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
// 配置 GPIOB 10 为开漏输出
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = GPIO_PIN_10;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
// 设置 GPIOB 10 为高电平
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10, GPIO_PIN_SET);
// 配置 GPIOC 1,2为开漏输出
GPIO_InitStruct.Pin = GPIO_PIN_1|GPIO_PIN_2;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
// 设置 GPIOC 1为高电平 GPIOC 2为低电平
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_1, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_2, GPIO_PIN_RESET);
}
/************************************************************************/
/*函数名:ICM_42688_START;***********************************************/
/*功能:通过IIC协议连接ICM_42688_P模块;**********************************/
/*输入:无;**************************************************************/
/*输出:0:开始信号发送成功,并且得到应答 1:未得到应答;*****************/
/************************************************************************/
void ICM_42688_START(){
ICM_IIC_SDA(1);
ICM_IIC_SCL(1);
rt_hw_us_delay(1);
ICM_IIC_SDA(0);//START:when CLK is high,DATA change form high to low
rt_hw_us_delay(1);
ICM_IIC_SCL(0);//钳住I2C总线,准备发送或接收数据
}
/**************************************************/
/*函数名:ICM_42688_STOP;***********************/
/*功能:停止IIC;************/
/*输入:无;****************************************/
/*输出:无;****************************************/
/**************************************************/
void ICM_42688_STOP(){
ICM_IIC_SCL(0);
ICM_IIC_SDA(0);//STOP:when CLK is high DATA change form low to high
rt_hw_us_delay(1);
ICM_IIC_SCL(1);
ICM_IIC_SDA(1);//发送I2C总线结束信号
rt_hw_us_delay(1);
}
/**************************************************/
/*函数名:ICM_IIC_Wait_Ack;************************/
/*功能:等待应答信号到来;**************************/
/*输入:无;****************************************/
/*输出:1,接收应答失败 0,接收应答成功;***********/
/**************************************************/
unsigned char ICM_IIC_Wait_Ack(void)
{
uint16_t ucErrTime=0;
//ICM_SDA_IN(); //SDA设置为输入
ICM_IIC_SDA(1); rt_hw_us_delay(1);
ICM_IIC_SCL(1); rt_hw_us_delay(1);
while(ICM_READ_SDA())
{
ucErrTime++;
if(ucErrTime>500)
{
ICM_42688_STOP();
return 1;
}
}
ICM_IIC_SCL(0);//时钟输出0
return 0;
}
/**************************************************/
/*函数名:ICM_IIC_Ack;************************/
/*功能:产生ACK应答;**************************/
/*输入:无;****************************************/
/*输出:无;***********/
/**************************************************/
void ICM_IIC_Ack(void)
{
ICM_IIC_SCL(0);
//ICM_SDA_OUT();
ICM_IIC_SDA(0);
rt_hw_us_delay(1);
ICM_IIC_SCL(1);
rt_hw_us_delay(1);
ICM_IIC_SCL(0);
}
/**************************************************/
/*函数名:ICM_IIC_NAck;************************/
/*功能:不产生ACK应答 ;**************************/
/*输入:无;****************************************/
/*输出:无;***********/
/**************************************************/
void ICM_IIC_NAck(void)
{
ICM_IIC_SCL(0);
//ICM_SDA_OUT();
ICM_IIC_SDA(1);
rt_hw_us_delay(1);
ICM_IIC_SCL(1);
rt_hw_us_delay(1);
ICM_IIC_SCL(0);
}
/******************************************************************/
/*函数名:ICM_IIC_Send_Byte;***************************************/
/*功能:IIC发送一个字节,返回从机有无应答;**************************/
/*输入:无;********************************************************/
/*输出:无;***************************************/
/******************************************************************/
void ICM_IIC_Send_Byte(unsigned char txd)
{
uint8_t t;
//ICM_SDA_OUT();
ICM_IIC_SCL(0);//拉低时钟开始数据传输
for (t = 0; t < 8; t++)
{
// 设置 SDA 数据线
ICM_IIC_SDA((txd & 0x80) >> 7);
txd <<= 1;
rt_hw_us_delay(1);
// 产生时钟上升沿
ICM_IIC_SCL(1);
rt_hw_us_delay(1);
// 产生时钟下降沿
ICM_IIC_SCL(0);
rt_hw_us_delay(1);
}
}
/******************************************************************/
/*函数名:ICM_IIC_Read_Byte;***************************************/
/*功能:读1个字节,ack=1时,发送ACK,ack=0,发送nACK ;*************/
/*输入:ack:是否发送应答;********************************************************/
/*输出:data;***************************************/
/******************************************************************/
unsigned char ICM_IIC_Read_Byte(unsigned char ack)
{
unsigned char i,receive=0;
for(i=0;i<8;i++ )
{
ICM_IIC_SCL(0);
rt_hw_us_delay(1);;;
ICM_IIC_SCL(1);
receive<<=1;
if(ICM_READ_SDA())receive++;
//rt_hw_us_delay(1);
}
if (!ack)
ICM_IIC_NAck();//发送nACK
else
ICM_IIC_Ack(); //发送ACK
return receive;
}
/******************************************************************/
/*函数名:ICM_IIC_WRITE_BYTE;***************************************/
/*功能:写一个字节;*************/
/*输入:RA:寄存器地址 data_byte:数据;********************************************************/
/*输出:0 成功 1 失败;***************************************/
/******************************************************************/
unsigned char ICM_IIC_WRITE_BYTE(unsigned char RA, unsigned char data_byte){
ICM_42688_START();
ICM_IIC_Send_Byte(ICM_42688_Addr_AD0_LOW_WRITE);
if(ICM_IIC_Wait_Ack()){
return 1;
}
ICM_IIC_Send_Byte(RA);
if(ICM_IIC_Wait_Ack()){return 1;}
ICM_IIC_Send_Byte(data_byte);
if(ICM_IIC_Wait_Ack()){return 1;}
ICM_42688_STOP();
return 0;
}
/******************************************************************/
/*函数名:ICM_IIC_READ_BYTE;***************************************/
/*功能:读一个字节;*************/
/*输入:RA:寄存器地址;********************************************************/
/*输出:0 成功 1 失败;***************************************/
/******************************************************************/
unsigned char ICM_IIC_READ_BYTE(unsigned char RA, unsigned char *data){
ICM_42688_START();
ICM_IIC_Send_Byte(ICM_42688_Addr_AD0_LOW_WRITE);
if(ICM_IIC_Wait_Ack()){return 1;}
ICM_IIC_Send_Byte(RA);
if(ICM_IIC_Wait_Ack()){return 1;}
ICM_42688_START();
ICM_IIC_Send_Byte(ICM_42688_Addr_AD0_LOW_READ);
if(ICM_IIC_Wait_Ack()){
return 1;
}
*data = ICM_IIC_Read_Byte(0);
ICM_42688_STOP();
return 0;
}
/******************************************************************/
/*函数名:ICM_INIT;***************************************/
/*功能:ICM芯片初始化;*************/
/*输入:无;********************************************************/
/*输出:0 成功 1 失败;***************************************/
/******************************************************************/
unsigned char val;
unsigned char ICM_INIT(void){
ICM_IIC_WRITE_BYTE(REG_BANK_SEL,0x00); //设置bank 0区域寄存器
delay_us(50000);
while(1)
{
ICM_IIC_READ_BYTE(WHO_AM_I,&val);
rt_kprintf("0x%x ",val);
if(val == 0x47) break;
}
if(ICM_IIC_WRITE_BYTE(DEVICE_CONFIG,0x00)) return 1;//Software reset configuration and SPI mode selection
rt_hw_us_delay(50000);
if(ICM_IIC_WRITE_BYTE(DRIVE_CONFIG,0x05)) return 2;//Control the communication speed(I guess)
rt_hw_us_delay(50000);
if(ICM_IIC_WRITE_BYTE(INT_CONFIG,0x02)) return 3;//interrupt settings 0x02
rt_hw_us_delay(50000);
if(ICM_IIC_WRITE_BYTE(PWR_MGMT0,0x2F)) return 4;//power register of sensors(it won't working if we don't turn it on) 0x0f
rt_hw_us_delay(50000);
if(ICM_IIC_WRITE_BYTE(INT_CONFIG1,0x00)) return 5;//this register is to set the interrupt port's Interrupt pulse duration (more details on datasheet)0x00
rt_hw_us_delay(50000);
if(ICM_IIC_WRITE_BYTE(INT_SOURCE0,0x08)) return 6;//setting interrupt port's interrupt source
rt_hw_us_delay(50000);
if(ICM_Gyroscope_INIT()) return 7;//陀螺仪初始化
rt_hw_us_delay(50000);
if(ICM_ACC_INIT()) return 8;//加速度计初始化
rt_hw_us_delay(50000);
if(ICM_IIC_WRITE_BYTE(SELF_TEST_CONFIG,0xFF)) return 9;//自检 0x1f
rt_hw_us_delay(50000);
if(ICM_IIC_WRITE_BYTE(SELF_TEST_CONFIG,0x00)) return 9;//关闭自检 0x80
rt_hw_us_delay(50000);
return 0;
}
/******************************************************************/
/*函数名:ICM_Gyroscope_INIT;***************************************/
/*功能:ICM陀螺仪初始化;*************/
/*输入:无;********************************************************/
/*输出:0 成功 1 失败;*******************