ICM42688——IIC and SPI驱动

目录

1.IIC软件驱动 

ICM42688.c

ICM42688.h

2.硬件SPI驱动

ICM42688.c

ICM42688.h


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 失败;*******************
以下是icm20948驱动代码 iic接口的示例: ``` #include <Wire.h> #define ICM20948_ADDR 0x69 void setup() { Wire.begin(); Serial.begin(9600); configureICM20948(); } void loop() { readICM20948Data(); delay(100); } void configureICM20948() { // Set up ICM20948 Wire.beginTransmission(ICM20948_ADDR); Wire.write(0x06); // Power Management 1 Wire.write(0x80); // Reset device Wire.endTransmission(); delay(100); Wire.beginTransmission(ICM20948_ADDR); Wire.write(0x06); // Power Management 1 Wire.write(0x01); // Clock source = Gyro X Wire.endTransmission(); delay(100); Wire.beginTransmission(ICM20948_ADDR); Wire.write(0x19); // Sample Rate Divider Wire.write(0x04); // 1kHz / (1+4) = 200Hz Wire.endTransmission(); delay(100); Wire.beginTransmission(ICM20948_ADDR); Wire.write(0x1A); // Config Wire.write(0x03); // Low Pass Filter = 41Hz Wire.endTransmission(); delay(100); Wire.beginTransmission(ICM20948_ADDR); Wire.write(0x1B); // Gyroscope Config Wire.write(0x10); // Full scale range = ±1000dps Wire.endTransmission(); delay(100); Wire.beginTransmission(ICM20948_ADDR); Wire.write(0x1C); // Accelerometer Config Wire.write(0x10); // Full scale range = ±8g Wire.endTransmission(); delay(100); } void readICM20948Data() { // Read ICM20948 data Wire.beginTransmission(ICM20948_ADDR); Wire.write(0x3B); // Starting with register 0x3B (ACCEL_XOUT_H) Wire.endTransmission(false); Wire.requestFrom(ICM20948_ADDR, 14, true); // Request 14 bytes (accelerometer, gyro, temperature) int16_t accelX = Wire.read() << 8 | Wire.read(); int16_t accelY = Wire.read() << 8 | Wire.read(); int16_t accelZ = Wire.read() << 8 | Wire.read(); int16_t temp = Wire.read() << 8 | Wire.read(); int16_t gyroX = Wire.read() << 8 | Wire.read(); int16_t gyroY = Wire.read() << 8 | Wire.read(); int16_t gyroZ = Wire.read() << 8 | Wire.read(); float accelXG = (float)accelX / 4096.0; float accelYG = (float)accelY / 4096.0; float accelZG = (float)accelZ / 4096.0; float tempC = (float)temp / 333.87 + 21.0; float gyroXdeg = (float)gyroX / 65.5; float gyroYdeg = (float)gyroY / 65.5; float gyroZdeg = (float)gyroZ / 65.5; Serial.print("Accelerometer (g): X="); Serial.print(accelXG); Serial.print(" Y="); Serial.print(accelYG); Serial.print(" Z="); Serial.print(accelZG); Serial.print(" Temperature (C): "); Serial.print(tempC); Serial.print(" Gyroscope (deg/s): X="); Serial.print(gyroXdeg); Serial.print(" Y="); Serial.print(gyroYdeg); Serial.print(" Z="); Serial.println(gyroZdeg); } ``` 在这个示例中,我们使用Wire库来控制I2C总线,通过I2C接口与ICM20948通信。在setup()函数中,我们首先调用configureICM20948()函数来配置ICM20948,然后在loop()函数中调用readICM20948Data()函数来读取ICM20948的数据。configureICM20948()函数设置ICM20948的寄存器,以便它可以在所需的采样率和滤波器下工作。readICM20948Data()函数从ICM20948读取加速度计、陀螺仪、温度传感器的数据,并将其打印到串行监视器上。 请注意,ICM20948有多种接口和通信协议可供选择,具体取决于您的应用程序和硬件平台。因此,请确保查阅ICM20948的数据手册和相关参考资料,以了解更多关于ICM20948驱动代码和接口的详细信息。
评论 15
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值