【STM32】软件IIC读取陀螺仪JY61p的代码分享_jy61p 六轴姿态角度传感器模组驱动代码
前言:代码可放心食用已验证,也有配套工程在gitee
gitee连接:https://gitee.com/hongscholar/ModuleLearn
陀螺仪配置:
打开维特官方的上位机,对JY61p进行配置。(需要陀螺仪和电脑连接)
查看IIC的从机地址是否是 0x50,代码例程的从机地址是0x50;
思路:
JY61p的数据寄存器是连续的,单片机每次连续读出陀螺仪的数据(欧拉角,角速度,加速度)。
函数JY61p_Get的参数是结构体指针的typedef,JY61p_AX是寄存器地址(陀螺仪x轴加速度)。函数JY61p_Read是读取陀螺仪的寄存器函数,JY61p_DeviceAddr从机地址(宏定义在JY61p.h中),“24”:连续读取从JY61p_AX后面的23个地址存储在tmp中。
代码:
JY61p.h
#ifndef __JY61P_H_#define __JY61P_H_/**** 头文件 ****/#include \"main.h\"/**** 宏定义 ****/#define JY61p_DeviceAddr 0x50// JY61p 寄存器地址#define JY61p_SAVE (0x00)#define JY61p_CALSW (0x01)#define JY61p_RSW (0x02)#define JY61p_RRATE (0x03)#define JY61p_BAUD (0x04)#define JY61p_AXOFFSET (0x05)#define JY61p_AYOFFSET (0x06)#define JY61p_AZOFFSET (0x07)#define JY61p_GXOFFSET (0x08)#define JY61p_GYOFFSET (0x09)#define JY61p_GZOFFSET (0x0a)#define JY61p_HXOFFSET (0x0b)#define JY61p_HYOFFSET (0x0c)#define JY61p_HZOFFSET (0x0d)#define JY61p_D0MODE (0x0e)#define JY61p_D1MODE (0x0f)#define JY61p_D2MODE (0x10)#define JY61p_D3MODE (0x11)#define JY61p_D0PWMH (0x12)#define JY61p_D1PWMH (0x13)#define JY61p_D2PWMH (0x14)#define JY61p_D3PWMH (0x15)#define JY61p_D0PWMT (0x16)#define JY61p_D1PWMT (0x17)#define JY61p_D2PWMT (0x18)#define JY61p_D3PWMT (0x19)#define JY61p_IICADDR (0x1a)#define JY61p_LEDOFF (0x1b)#define JY61p_GPSBAUD (0x1c)#define JY61p_YYMM 0x30 // 年月#define JY61p_DDHH 0x31 // 日时#define JY61p_MMSS 0x32 // 分秒#define JY61p_MS 0x33 // 毫秒#define JY61p_AX 0x34 // 加速度#define JY61p_AY 0x35#define JY61p_AZ 0x36#define JY61p_GX 0x37 // 角速度#define JY61p_GY 0x38#define JY61p_GZ 0x39#define JY61p_HX 0x3a // #define JY61p_HY 0x3b#define JY61p_HZ 0x3c#define JY61p_Roll 0x3d // 欧拉角#define JY61p_Pitch 0x3e#define JY61p_Yaw 0x3f#define JY61p_TEMP 0x40 // 温度#define JY61p_D0Status 0x41#define JY61p_D1Status 0x42#define JY61p_D2Status 0x43#define JY61p_D3Status 0x44#define JY61p_PressureL 0x45#define JY61p_PressureH 0x46#define JY61p_HeightL 0x47#define JY61p_HeightH 0x48#define JY61p_LonL 0x49#define JY61p_LonH 0x4a#define JY61p_LatL 0x4b#define JY61p_LatH 0x4c#define JY61p_GPSHeight 0x4d#define JY61p_GPSYAW 0x4e#define JY61p_GPSVL 0x4f#define JY61p_GPSVH 0x50 #define DIO_MODE_AIN 0#define DIO_MODE_DIN 1#define DIO_MODE_DOH 2#define DIO_MODE_DOL 3#define DIO_MODE_DOPWM 4#define DIO_MODE_GPS 5typedef struct Time_Param{ __IO u16 year; // 年 __IO u8 month; // 月 __IO u8 day; // 日 __IO u8 hour; // 时 __IO u8 minute; // 分 __IO u8 sec; // 秒 __IO u16 Ms; // 毫秒} Time_Param;typedef struct Acc_Param{ __IO float Ax; // x轴 加速度 __IO float Ay; // y __IO float Az; // z} Acc_Param;typedef struct Gyro_Param{ __IO float Gx; // x轴 角速度 __IO float Gy; // y __IO float Gz; // z} Gyro_Param;typedef struct EulerAngle_Param{ __IO float Roll; // 横滚角 __IO float Pitch; // 俯仰角 __IO float Yaw; // 偏航角} EulerAngle_Param;/**** 函数 ****/void JY61p_Init(void);u8 JY61p_Check(void);void JY61p_Get(Acc_Param *a, EulerAngle_Param *p, Gyro_Param *v);// IIC时序void JY61p_IIC_Init(void);void JY61p_IIC_Start(void);void JY61p_IIC_Stop(void);u8 JY61p_IIC_SendAck(uint8_t AckBit);u8 JY61p_IIC_WaitAck(void);void JY61p_IIC_SendByte(uint8_t dat);u8 JY61p_IIC_ReceiveByte(void);u8 JY61p_Write(u8 addr, u8 reg, u8 len, u8* buf);u8 JY61p_Read(u8 addr, u8 reg, u8 len, u8 *buf);#endif // __JY61P_H_
JY61p.c
#include \"JY61p.h\"#define delay_3us() Delay_us(1)#define JY61p_IIC_SDA_IO_IN() {GPIOB->MODER &= ~(0x03<MODER |= (0x01<<2*9);} // 设置JY61p_W_SDA为输出模式#define JY61p_W_SCL(BIT) GPIO_WriteBit( GPIOB, GPIO_Pin_8, (BitAction)BIT)#define JY61p_W_SDA(BIT) GPIO_WriteBit( GPIOB, GPIO_Pin_9, (BitAction)BIT)#define JY61p_R_SDA() GPIO_ReadInputDataBit( GPIOB, GPIO_Pin_9)u8 JY61p_AngleData[9];// 8位角度原始数据 1位完成位void JY61p_Init(void){ JY61p_IIC_Init(); // 检测 JY61p 是否存在 while( JY61p_Check()) { LED_ON(); Delay_ms(500); LED_OFF(); Delay_ms(500); }}/************************************************************@fuction: JY61p_IIC_Init*@brief: JY61p 的软件iic的gpio初始化*@param: None*@return: None*@author: HongScholar*@date: 2025.04.02***********************************************************/void JY61p_IIC_Init(void){RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;GPIO_Init(GPIOB, &GPIO_InitStructure);}/************************************************************@fuction: JY61p_IIC_Start*@brief: 产生MPU6050_IIC起始信号*@param: None*@return: None*@author: HongScholar*@date: 2025.04.02***********************************************************/void JY61p_IIC_Start(void){JY61p_IIC_SDA_IO_OUT();JY61p_W_SDA(1);delay_3us();JY61p_W_SCL(1);delay_3us();JY61p_W_SDA(0);delay_3us();JY61p_W_SCL(0);delay_3us();}/************************************************************@fuction: JY61p_IIC_Stop*@brief: 产生JY61p_IIC停止信号*@param: None*@return: None*@author: HongScholar*@date: 2025.04.02***********************************************************/void JY61p_IIC_Stop(void){JY61p_IIC_SDA_IO_OUT(); JY61p_W_SCL(0);JY61p_W_SDA(0);JY61p_W_SCL(1);delay_3us();JY61p_W_SDA(1);delay_3us();}/************************************************************@fuction: JY61p_IIC_SendAck*@brief: 发送ACK应答*@param: None*@return: None*@author: HongScholar*@date: 2025.04.02***********************************************************/uint8_t JY61p_IIC_SendAck(uint8_t AckBit){JY61p_IIC_SDA_IO_OUT(); JY61p_W_SCL(0);JY61p_W_SDA(0);delay_3us();if(!AckBit)\\ JY61p_W_SDA(0);else JY61p_W_SDA(1);JY61p_W_SCL(1);delay_3us();JY61p_W_SCL(0);JY61p_W_SDA(1);return 0;}/************************************************************@fuction: JY61p_IIC_WaitAck*@brief: 等待 JY61p 应答信号到来*@param: None*@return: 应答位, 0:应答; 1:无应答*@author: HongScholar*@date: 2025.04.02***********************************************************/uint8_t JY61p_IIC_WaitAck(void){char ack = 0;uint8_t ack_flag = 10;JY61p_IIC_SDA_IO_IN(); delay_3us();JY61p_W_SCL(1);delay_3us();while( (JY61p_R_SDA()==1) && ( ack_flag ) ){ack_flag--;delay_3us();}if( ack_flag <= 0 ){JY61p_IIC_Stop();return 1;}else{JY61p_W_SCL(0);JY61p_IIC_SDA_IO_OUT();}return ack;}/************************************************************@fuction: JY61p_IIC_SendByte*@brief: JY61p 软件IIC发送一个字节*@param: 数据*@return: None*@author: HongScholar*@date: 2025.04.02***********************************************************/void JY61p_IIC_SendByte(uint8_t dat){int i = 0;JY61p_IIC_SDA_IO_OUT();JY61p_W_SCL(0);for( i = 0; i > 7 );__nop();JY61p_W_SCL(1);delay_3us();JY61p_W_SCL(0);delay_3us();dat<<=1;}}/************************************************************@fuction: JY61p_IIC_SendByte*@brief: JY61p 软件IIC发送一个字节*@param: 数据*@return: None*@author: HongScholar*@date: 2025.04.02***********************************************************/uint8_t JY61p_IIC_ReceiveByte(void){uint8_t i,receive=0;JY61p_IIC_SDA_IO_IN(); for(i=0; i<8; i++ ){JY61p_W_SCL(0);delay_3us();JY61p_W_SCL(1);delay_3us();receive<<=1;if( JY61p_R_SDA() ){receive |= 1;}delay_3us();}JY61p_W_SCL(0);return receive;}/** * @brief 对接官方i2c_write * @retval 0: 读成功 */u8 JY61p_Write(u8 addr, u8 reg, u8 len, u8* buf){u8 i;JY61p_IIC_Start();JY61p_IIC_SendByte((addr<<1) | 0x00);//发送器件地址+写命令if(JY61p_IIC_WaitAck()){JY61p_IIC_Stop();return 1;}JY61p_IIC_SendByte(reg);JY61p_IIC_WaitAck();for(i=0; i<len; i++){JY61p_IIC_SendByte(buf[i]);if(JY61p_IIC_WaitAck()){JY61p_IIC_Stop();return 1;}}JY61p_IIC_Stop();return 0;}/** * @brief 对接官方dmp库的i2c_read函数 * @retval 0: 读成功 */u8 JY61p_Read(u8 addr, u8 reg, u8 len, u8 *buf){JY61p_IIC_Start();JY61p_IIC_SendByte((addr<<1) | 0x00);//发送器件地址+写命令if(JY61p_IIC_WaitAck()){JY61p_IIC_Stop();return 1;}JY61p_IIC_SendByte(reg);JY61p_IIC_WaitAck();JY61p_IIC_Start();JY61p_IIC_SendByte((addr<<1) | 0x01);JY61p_IIC_WaitAck();while(len){if(len==1){*buf=JY61p_IIC_ReceiveByte();JY61p_IIC_SendAck(1);}else{*buf=JY61p_IIC_ReceiveByte(); // 1JY61p_IIC_SendAck(0);}len--;buf++;}JY61p_IIC_Stop();return 0;}/************************************************************@fuction: JY61p_Check*@brief: JY61p 检测是否存在*@param: None*@return: 0: 存在*@author: HongScholar*@date: 2025.04.02***********************************************************/uint8_t JY61p_Check(void){ uint8_t ack = 0; JY61p_IIC_Start(); JY61p_IIC_SendByte(JY61p_DeviceAddr<Ax = ((short)(tmp[1]<Ay = ((short)(tmp[3]<Az = ((short)(tmp[5]<Gx = ((short)(tmp[7]<Gy = ((short)(tmp[9]<Gz = ((short)(tmp[11]<<8) | tmp[10]) /32768.00f*2000; /**** JY61p没有 ****/// ((short)(tmp[13]<<8) | tmp[12]);// ((short)(tmp[15]<<8) | tmp[14]);// ((short)(tmp[17]<Roll = ((short)(tmp[19]<Pitch = ((short)(tmp[21]<Yaw = ((short)(tmp[23]<<8) | tmp[22]) /32768.00f*180;}
使用教程main.c
#include \"main.h\"Acc_Param Acc; // 加速度Gyro_Param Gyro; // 角速度EulerAngle_Param Angle; // 欧拉角uint8_t ack=1;int main(void){ NVIC_Conflg(); Delay_Init(168); LED_Init(); OLED_Init(); USART1_Init();// 调试口 JY61p_Init(); OLED_ShowString(1,1, \"Roll:\"); OLED_ShowString(2,1, \"Pitch:\"); OLED_ShowString(3,1, \"Yaw:\"); ack = JY61p_Check(); // 0为正常, 1为异常 OLED_ShowNum(4,1,ack, 1); while(1) { JY61p_Get(&Acc, &Angle, &Gyro); OLED_ShowFloat(1,8,Angle.Roll,3,2); OLED_ShowFloat(2,8,Angle.Pitch,3,2); OLED_ShowFloat(3,8,Angle.Yaw,3,2); // OLED_ShowFloat(1,1,Acc.Ax,7,2);// OLED_ShowFloat(2,1,Acc.Ay,7,2);// OLED_ShowFloat(3,1,Acc.Az,7,2);// // OLED_ShowFloat(1,1,Gyro.Gx,7,2);// OLED_ShowFloat(2,1,Gyro.Gy,7,2);// OLED_ShowFloat(3,1,Gyro.Gz,7,2); }}
嵌入式很有趣,希望你也是,敬请期待...