当前位置:首页 » 《关注互联网》 » 正文

M0G3507完美移植江科大软件IIC MPU6050

17 人参与  2024年09月28日 12:02  分类 : 《关注互联网》  评论

点击全文阅读


经过两天两夜的查阅文献资料、整理学习,成功的把江科大的软件IIC读写MPU6050移植到MSPM0G3507,亲测有效!!包的,为了让大家直观地感受下,先上图。记得点个赞哦!

学过江科大的STM32的小伙伴是不是觉得这个画面非常熟悉,在这里我选的是满量程为16g,且陀螺仪水平放置,根据Z轴的读数可以计算出当地的重力加速度值,计算公式为读数(X/2^15)*16,即1963/32768*16=0.96。

思路讲解

1.软硬件型号

选择CCS theia进行M0G3507的开发,显示屏为0.96寸4引脚OLED显示屏,陀螺仪选择常见的MPU6050,GY-521模块。

 2.软件IIC时序模拟

//IIC写SDA引脚void MyI2C_W_SDA(uint8_t BitValue){    SDA_OUT();    if(BitValue)        DL_GPIO_setPins(GPIO_sda_PORT, GPIO_sda_PIN_0_PIN);    else        DL_GPIO_clearPins(GPIO_sda_PORT, GPIO_sda_PIN_0_PIN);Delay_us(8);//延时8us,防止时序频率超过要求}//IIC写SCL引脚void MyI2C_W_SCL(uint8_t BitValue){    if(BitValue)        DL_GPIO_setPins(GPIO_scl_PORT, GPIO_scl_PIN_1_PIN);    else        DL_GPIO_clearPins(GPIO_scl_PORT, GPIO_scl_PIN_1_PIN);Delay_us(8);//延时8us,防止时序频率超过要求}//IIC开始void MyI2C_Start(void){    SDA_OUT();MyI2C_W_SDA(1);//释放SDA,确保SDA为高电平MyI2C_W_SCL(1);//释放SCL,确保SCL为高电平MyI2C_W_SDA(0);//在SCL高电平期间,拉低SDA,产生起始信号MyI2C_W_SCL(0);//起始后拉低SCL,为了占用总线,方便总线时序的拼接}

 3.IIC发送一个字节数据

void MyI2C_SendByte(uint8_t Byte){    SDA_OUT();uint8_t i;for (i = 0; i < 8; i ++)//循环8次,主机依次发送数据的每一位{MyI2C_W_SDA(Byte & (0x80 >> i));//使用掩码的方式取出Byte的指定一位数据并写入到SDA线MyI2C_W_SCL(1);//释放SCL,从机在SCL高电平期间读取SDAMyI2C_W_SCL(0);//拉低SCL,主机开始发送下一位数据}}
4.IIC接收一个字节的数据
uint8_t MyI2C_ReceiveByte(void){    SDA_OUT();uint8_t i, Byte = 0x00;//定义接收的数据,并赋初值0x00MyI2C_W_SDA(1);//接收前,主机先确保释放SDA,避免干扰从机的数据发送for (i = 0; i < 8; i ++)//循环8次,主机依次接收数据的每一位{        SDA_IN();MyI2C_W_SCL(1);//释放SCL,主机机在SCL高电平期间读取SDAif (MyI2C_R_SDA() == 1){Byte |= (0x80 >> i);}//读取SDA数据,并存储到Byte变量//当SDA为1时,置变量指定位为1,当SDA为0时,不做处理,指定位为默认的初值0MyI2C_W_SCL(0);//拉低SCL,从机在SCL低电平期间写入SDA}return Byte;//返回接收到的一个字节数据}
5.IIC发送应答位
void MyI2C_SendAck(uint8_t AckBit){    SDA_OUT();MyI2C_W_SDA(AckBit);//主机把应答位数据放到SDA线MyI2C_W_SCL(1);//释放SCL,从机在SCL高电平期间,读取应答位MyI2C_W_SCL(0);//拉低SCL,开始下一个时序模块}
6.IIC接收应答位
uint8_t MyI2C_ReceiveAck(void){    SDA_OUT();uint8_t AckBit;MyI2C_W_SDA(1);//接收前,主机先确保释放SDA,避免干扰从机的数据发送MyI2C_W_SCL(1);//释放SCL,主机机在SCL高电平期间读取SDA    SDA_IN();AckBit = MyI2C_R_SDA();MyI2C_W_SCL(0);//拉低SCL,开始下一个时序模块return AckBit;//返回定义应答位变量}
7.MPU6050写数据
void MPU6050_WriteReg(uint8_t RegAddress, uint8_t Data){MyI2C_Start();//I2C起始MyI2C_SendByte(MPU6050_ADDRESS);//发送从机地址(0xD0),读写位为0,表示即将写入MyI2C_ReceiveAck();//接收应答MyI2C_SendByte(RegAddress);//发送寄存器地址MyI2C_ReceiveAck();//接收应答MyI2C_SendByte(Data);//发送要写入寄存器的数据MyI2C_ReceiveAck();//接收应答MyI2C_Stop();//I2C终止}
8.MPU6050读数据
uint8_t MPU6050_ReadReg(uint8_t RegAddress){uint8_t Data;  MyI2C_Start();//I2C起始MyI2C_SendByte(MPU6050_ADDRESS);//发送从机地址,读写位为0,表示即将写入MyI2C_ReceiveAck();//接收应答MyI2C_SendByte(RegAddress);//发送寄存器地址MyI2C_ReceiveAck();//接收应答MyI2C_Start();//I2C重复起始MyI2C_SendByte(MPU6050_ADDRESS | 0x01);//发送从机地址,读写位为1,表示即将读取MyI2C_ReceiveAck();//接收应答Data = MyI2C_ReceiveByte();//接收指定寄存器的数据MyI2C_SendAck(1);//发送应答,给从机非应答,终止从机的数据输出MyI2C_Stop();//I2C终止return Data;}
9.myi2c.c
#include "ti_msp_dl_config.h"#include "ti/driverlib/dl_gpio.h"//打开SDA引脚(输出)void SDA_OUT(void)   {    DL_GPIO_initDigitalOutput(GPIO_sda_PIN_0_IOMUX);     DL_GPIO_setPins(GPIO_sda_PORT, GPIO_sda_PIN_0_PIN);       DL_GPIO_enableOutput(GPIO_sda_PORT, GPIO_sda_PIN_0_PIN); }//关闭SDA引脚(输入)void SDA_IN(void){    DL_GPIO_initDigitalInputFeatures(GPIO_sda_PIN_0_IOMUX, DL_GPIO_INVERSION_DISABLE, DL_GPIO_RESISTOR_PULL_UP, DL_GPIO_HYSTERESIS_DISABLE, DL_GPIO_WAKEUP_DISABLE);}void Delay_us(uint16_t us){    while(us--)    delay_cycles(CPUCLK_FREQ/1000000);}//CPUCLK_FREQ为时钟频率,可以根据配置的改变而改变/*引脚配置层*//**  * 函    数:I2C写SCL引脚电平  * 参    数:BitValue 协议层传入的当前需要写入SCL的电平,范围0~1  * 返 回 值:无  * 注意事项:此函数需要用户实现内容,当BitValue为0时,需要置SCL为低电平,当BitValue为1时,需要置SCL为高电平  */void MyI2C_W_SCL(uint8_t BitValue){    if(BitValue)        DL_GPIO_setPins(GPIO_scl_PORT, GPIO_scl_PIN_1_PIN);    else        DL_GPIO_clearPins(GPIO_scl_PORT, GPIO_scl_PIN_1_PIN);Delay_us(8);//延时8us,防止时序频率超过要求}/**  * 函    数:I2C写SDA引脚电平  * 参    数:BitValue 协议层传入的当前需要写入SDA的电平,范围0~0xFF  * 返 回 值:无  * 注意事项:此函数需要用户实现内容,当BitValue为0时,需要置SDA为低电平,当BitValue非0时,需要置SDA为高电平  */void MyI2C_W_SDA(uint8_t BitValue){    SDA_OUT();    if(BitValue)        DL_GPIO_setPins(GPIO_sda_PORT, GPIO_sda_PIN_0_PIN);    else        DL_GPIO_clearPins(GPIO_sda_PORT, GPIO_sda_PIN_0_PIN);Delay_us(8);//延时8us,防止时序频率超过要求}/**  * 函    数:I2C读SDA引脚电平  * 参    数:无  * 返 回 值:协议层需要得到的当前SDA的电平,范围0~1  * 注意事项:此函数需要用户实现内容,当前SDA为低电平时,返回0,当前SDA为高电平时,返回1  */uint8_t MyI2C_R_SDA(void){uint8_t b;    uint32_t BitValue;    SDA_IN();BitValue = DL_GPIO_readPins(GPIO_sda_PORT, GPIO_sda_PIN_0_PIN);//读取SDA电平    {        if(BitValue)   b=1;        else           b=0;    }Delay_us(8);//延时8us,防止时序频率超过要求return b;        //返回SDA电平}/**  * 函    数:I2C初始化  * 参    数:无  * 返 回 值:无  * 注意事项:此函数需要用户实现内容,实现SCL和SDA引脚的初始化  */void MyI2C_Init(void){    SYSCFG_DL_GPIO_init();/*设置默认电平*/DL_GPIO_setPins(GPIOA, GPIO_sda_PIN_0_PIN |GPIO_scl_PIN_1_PIN);//设置PA8和PA9引脚初始化后默认为高电平(释放总线状态)}/*协议层*//**  * 函    数:I2C起始  * 参    数:无  * 返 回 值:无  */void MyI2C_Start(void){    SDA_OUT();MyI2C_W_SDA(1);//释放SDA,确保SDA为高电平MyI2C_W_SCL(1);//释放SCL,确保SCL为高电平MyI2C_W_SDA(0);//在SCL高电平期间,拉低SDA,产生起始信号MyI2C_W_SCL(0);//起始后拉低SCL,为了占用总线,方便总线时序的拼接}/**  * 函    数:I2C终止  * 参    数:无  * 返 回 值:无  */void MyI2C_Stop(void){    SDA_OUT();MyI2C_W_SDA(0);//拉低SDA,确保SDA为低电平MyI2C_W_SCL(1);//释放SCL,使SCL呈现高电平MyI2C_W_SDA(1);//在SCL高电平期间,释放SDA,产生终止信号}/**  * 函    数:I2C发送一个字节  * 参    数:Byte 要发送的一个字节数据,范围:0x00~0xFF  * 返 回 值:无  */void MyI2C_SendByte(uint8_t Byte){    SDA_OUT();uint8_t i;for (i = 0; i < 8; i ++)//循环8次,主机依次发送数据的每一位{MyI2C_W_SDA(Byte & (0x80 >> i));//使用掩码的方式取出Byte的指定一位数据并写入到SDA线MyI2C_W_SCL(1);//释放SCL,从机在SCL高电平期间读取SDAMyI2C_W_SCL(0);//拉低SCL,主机开始发送下一位数据}}/**  * 函    数:I2C接收一个字节  * 参    数:无  * 返 回 值:接收到的一个字节数据,范围:0x00~0xFF  */uint8_t MyI2C_ReceiveByte(void){    SDA_OUT();uint8_t i, Byte = 0x00;//定义接收的数据,并赋初值0x00MyI2C_W_SDA(1);//接收前,主机先确保释放SDA,避免干扰从机的数据发送for (i = 0; i < 8; i ++)//循环8次,主机依次接收数据的每一位{        SDA_IN();MyI2C_W_SCL(1);//释放SCL,主机机在SCL高电平期间读取SDAif (MyI2C_R_SDA() == 1){Byte |= (0x80 >> i);}//读取SDA数据,并存储到Byte变量//当SDA为1时,置变量指定位为1,当SDA为0时,不做处理,指定位为默认的初值0MyI2C_W_SCL(0);//拉低SCL,从机在SCL低电平期间写入SDA}return Byte;//返回接收到的一个字节数据}/**  * 函    数:I2C发送应答位  * 参    数:Byte 要发送的应答位,范围:0~1,0表示应答,1表示非应答  * 返 回 值:无  */void MyI2C_SendAck(uint8_t AckBit){    SDA_OUT();MyI2C_W_SDA(AckBit);//主机把应答位数据放到SDA线MyI2C_W_SCL(1);//释放SCL,从机在SCL高电平期间,读取应答位MyI2C_W_SCL(0);//拉低SCL,开始下一个时序模块}/**  * 函    数:I2C接收应答位  * 参    数:无  * 返 回 值:接收到的应答位,范围:0~1,0表示应答,1表示非应答  */uint8_t MyI2C_ReceiveAck(void){    SDA_OUT();uint8_t AckBit;//定义应答位变量MyI2C_W_SDA(1);//接收前,主机先确保释放SDA,避免干扰从机的数据发送MyI2C_W_SCL(1);//释放SCL,主机机在SCL高电平期间读取SDA    SDA_IN();AckBit = MyI2C_R_SDA();//将应答位存储到变量里MyI2C_W_SCL(0);//拉低SCL,开始下一个时序模块return AckBit;//返回定义应答位变量}
10.myi2c.h
#ifndef __MYI2C_H#define __MYI2C_H#include "stdint.h"void MyI2C_Init(void);void MyI2C_Start(void);void MyI2C_Stop(void);void MyI2C_SendByte(uint8_t Byte);uint8_t MyI2C_R_SDA(void);uint8_t MyI2C_ReceiveByte(void);void MyI2C_SendAck(uint8_t AckBit);uint8_t MyI2C_ReceiveAck(void);void MyI2C_W_SCL(uint8_t BitValue);void MyI2C_W_SDA(uint8_t BitValue);void Delay_us(uint16_t us);#endif
11.mpu6050.c
#include "ti_msp_dl_config.h"#include "myi2C.h"#include "MPU6050_Reg.h"#define MPU6050_ADDRESS0xD0//MPU6050的I2C从机地址/**  * 函    数:MPU6050写寄存器  * 参    数:RegAddress 寄存器地址,范围:参考MPU6050手册的寄存器描述  * 参    数:Data 要写入寄存器的数据,范围:0x00~0xFF  * 返 回 值:无  */void MPU6050_WriteReg(uint8_t RegAddress, uint8_t Data){MyI2C_Start();//I2C起始MyI2C_SendByte(MPU6050_ADDRESS);//发送从机地址,读写位为0,表示即将写入MyI2C_ReceiveAck();//接收应答MyI2C_SendByte(RegAddress);//发送寄存器地址MyI2C_ReceiveAck();//接收应答MyI2C_SendByte(Data);//发送要写入寄存器的数据MyI2C_ReceiveAck();//接收应答MyI2C_Stop();//I2C终止}/**  * 函    数:MPU6050读寄存器  * 参    数:RegAddress 寄存器地址,范围:参考MPU6050手册的寄存器描述  * 返 回 值:读取寄存器的数据,范围:0x00~0xFF  */uint8_t MPU6050_ReadReg(uint8_t RegAddress){uint8_t Data;  MyI2C_Start();//I2C起始MyI2C_SendByte(MPU6050_ADDRESS);//发送从机地址,读写位为0,表示即将写入MyI2C_ReceiveAck();//接收应答MyI2C_SendByte(RegAddress);//发送寄存器地址MyI2C_ReceiveAck();//接收应答MyI2C_Start();//I2C重复起始MyI2C_SendByte(MPU6050_ADDRESS | 0x01);//发送从机地址,读写位为1,表示即将读取MyI2C_ReceiveAck();//接收应答Data = MyI2C_ReceiveByte();//接收指定寄存器的数据MyI2C_SendAck(1);//发送应答,给从机非应答,终止从机的数据输出MyI2C_Stop();//I2C终止return Data;}/**  * 函    数:MPU6050初始化  * 参    数:无  * 返 回 值:无  */void MPU6050_Init(void){MyI2C_Init();//先初始化底层的I2C/*MPU6050寄存器初始化,需要对照MPU6050手册的寄存器描述配置,此处仅配置了部分重要的寄存器*/MPU6050_WriteReg(MPU6050_PWR_MGMT_1, 0x01);//电源管理寄存器1,取消睡眠模式,选择时钟源为X轴陀螺仪MPU6050_WriteReg(MPU6050_PWR_MGMT_2, 0x00);//电源管理寄存器2,保持默认值0,所有轴均不待机MPU6050_WriteReg(MPU6050_SMPLRT_DIV, 0x09);//采样率分频寄存器,配置采样率MPU6050_WriteReg(MPU6050_CONFIG, 0x06);//配置寄存器,配置DLPFMPU6050_WriteReg(MPU6050_GYRO_CONFIG, 0x18);//陀螺仪配置寄存器,选择满量程为±2000°/sMPU6050_WriteReg(MPU6050_ACCEL_CONFIG, 0x18);//加速度计配置寄存器,选择满量程为±16g}/**  * 函    数:MPU6050获取ID号  * 参    数:无  * 返 回 值:MPU6050的ID号  */uint8_t MPU6050_GetID(void){return MPU6050_ReadReg(MPU6050_WHO_AM_I);//返回WHO_AM_I寄存器的值}/**  * 函    数:MPU6050获取数据  * 参    数:AccX AccY AccZ 加速度计X、Y、Z轴的数据,使用输出参数的形式返回,范围:-32768~32767  * 参    数:GyroX GyroY GyroZ 陀螺仪X、Y、Z轴的数据,使用输出参数的形式返回,范围:-32768~32767  * 返 回 值:无  */void MPU6050_GetData(int16_t *AccX, int16_t *AccY, int16_t *AccZ, int16_t *GyroX, int16_t *GyroY, int16_t *GyroZ){uint8_t DataH, DataL;//定义数据高8位和低8位的变量DataH = MPU6050_ReadReg(MPU6050_ACCEL_XOUT_H);//读取加速度计X轴的高8位数据DataL = MPU6050_ReadReg(MPU6050_ACCEL_XOUT_L);//读取加速度计X轴的低8位数据*AccX = (DataH << 8) | DataL;//数据拼接,通过输出参数返回DataH = MPU6050_ReadReg(MPU6050_ACCEL_YOUT_H);//读取加速度计Y轴的高8位数据DataL = MPU6050_ReadReg(MPU6050_ACCEL_YOUT_L);//读取加速度计Y轴的低8位数据*AccY = (DataH << 8) | DataL;//数据拼接,通过输出参数返回DataH = MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_H);//读取加速度计Z轴的高8位数据DataL = MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_L);//读取加速度计Z轴的低8位数据*AccZ = (DataH << 8) | DataL;//数据拼接,通过输出参数返回DataH = MPU6050_ReadReg(MPU6050_GYRO_XOUT_H);//读取陀螺仪X轴的高8位数据DataL = MPU6050_ReadReg(MPU6050_GYRO_XOUT_L);//读取陀螺仪X轴的低8位数据*GyroX = (DataH << 8) | DataL;//数据拼接,通过输出参数返回DataH = MPU6050_ReadReg(MPU6050_GYRO_YOUT_H);//读取陀螺仪Y轴的高8位数据DataL = MPU6050_ReadReg(MPU6050_GYRO_YOUT_L);//读取陀螺仪Y轴的低8位数据*GyroY = (DataH << 8) | DataL;//数据拼接,通过输出参数返回DataH = MPU6050_ReadReg(MPU6050_GYRO_ZOUT_H);//读取陀螺仪Z轴的高8位数据DataL = MPU6050_ReadReg(MPU6050_GYRO_ZOUT_L);//读取陀螺仪Z轴的低8位数据*GyroZ = (DataH << 8) | DataL;//数据拼接,通过输出参数返回}
12.mpu6050.h
#ifndef __MPU6050_H#define __MPU6050_H#include "myi2C.h"void MPU6050_WriteReg(uint8_t RegAddress, uint8_t Data);uint8_t MPU6050_ReadReg(uint8_t RegAddress);void MPU6050_Init(void);uint8_t MPU6050_GetID(void);void MPU6050_GetData(int16_t *AccX, int16_t *AccY, int16_t *AccZ, int16_t *GyroX, int16_t *GyroY, int16_t *GyroZ);#endif
13.mpu6050_Reg.h
#ifndef __MPU6050_REG_H#define __MPU6050_REG_H#defineMPU6050_SMPLRT_DIV0x19#defineMPU6050_CONFIG0x1A#defineMPU6050_GYRO_CONFIG0x1B#defineMPU6050_ACCEL_CONFIG0x1C#defineMPU6050_ACCEL_XOUT_H0x3B#defineMPU6050_ACCEL_XOUT_L0x3C#defineMPU6050_ACCEL_YOUT_H0x3D#defineMPU6050_ACCEL_YOUT_L0x3E#defineMPU6050_ACCEL_ZOUT_H0x3F#defineMPU6050_ACCEL_ZOUT_L0x40#defineMPU6050_TEMP_OUT_H0x41#defineMPU6050_TEMP_OUT_L0x42#defineMPU6050_GYRO_XOUT_H0x43#defineMPU6050_GYRO_XOUT_L0x44#defineMPU6050_GYRO_YOUT_H0x45#defineMPU6050_GYRO_YOUT_L0x46#defineMPU6050_GYRO_ZOUT_H0x47#defineMPU6050_GYRO_ZOUT_L0x48#defineMPU6050_PWR_MGMT_10x6B#defineMPU6050_PWR_MGMT_20x6C#defineMPU6050_WHO_AM_I0x75#endif
14.main.c
#include "ti_msp_dl_config.h"#include "oled.h"#include "mpu6050.h"#include "ti/driverlib/dl_gpio.h"int16_t AX,AY,AZ,GX,GY,GZ;int main(void){    SYSCFG_DL_init();    OLED_Init();    OLED_CLS();    MPU6050_Init();    //MPU6050_WriteReg(0x19,0x00);    while (1)    {        MPU6050_GetData(&AX,&AY,&AZ,&GX,&GY,&GZ);        OLED_ShowString(2,1,"AX:");OLED_ShowSignedNum(2,4,AX,4);        OLED_ShowString(3,1,"AY:");OLED_ShowSignedNum(3,4,AY,4);        OLED_ShowString(4,1,"AZ:");OLED_ShowSignedNum(4,4,AZ,4);        OLED_ShowString(2,9,"GX:");OLED_ShowSignedNum(2,12,AX,4);        OLED_ShowString(3,9,"GY:");OLED_ShowSignedNum(3,12,GY,4);        OLED_ShowString(4,9,"GZ:");OLED_ShowSignedNum(4,12,GZ,4);    }}
15.总结

        在syscfg中配置好MPU6050的SDA和SCL引脚,通过软件模拟IIC时序,对MPU6050进行读写操作。作为嵌入式的小伙伴们,都知道MPU6050的重要性,它可以用于飞行控制和姿态稳定,提供的角速度和加速度数据对于无人机的稳定飞行至关重要,能够帮助无人机实现精确的姿态调整和位置控制,在智能小车中,MPU6050可用于检测机器人的姿态和运动状态,帮助机器人实现自主导航和避障。

        现在比较成功的案例是嘉立创的1306系列的开发板,但是讲解资料少,羞涩难懂,小编这个成功地将江科大讲解的MPU6050移植到M0G3507,视频讲解细致,函数形式和参数通俗易懂,包会的!!需要完整的MPU6050代码可以留言哦,然后可以搭配自己的OLED进行结果的展示,这是小编花了两天多的时间才成功移植,成功地读取到了陀螺仪的六轴数据,接下来就可以进行姿态解算继续完成M0G3507的项目啦!

MPU6050引脚M0G3507引脚
GNDGND
SCLPA9
SDAPA8
VCCVCC

参考资料:STM32入门教程-2023版 细致讲解 中文字幕_哔哩哔哩_bilibili

百度网盘,无需密码,配合自己的OLED


点击全文阅读


本文链接:http://zhangshiyu.com/post/165728.html

<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1