M0G3507完美移植江科大软件IIC MPU6050
经过两天两夜的查阅文献资料、整理学习,成功的把江科大的软件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 > i)); //使用掩码的方式取出Byte的指定一位数据并写入到SDA线 MyI2C_W_SCL(1); //释放SCL,从机在SCL高电平期间读取SDA MyI2C_W_SCL(0); //拉低SCL,主机开始发送下一位数据 } }
4.IIC接收一个字节的数据
uint8_t MyI2C_ReceiveByte(void) { SDA_OUT(); uint8_t i, Byte = 0x00; //定义接收的数据,并赋初值0x00 MyI2C_W_SDA(1); //接收前,主机先确保释放SDA,避免干扰从机的数据发送 for (i = 0; i > i);} //读取SDA数据,并存储到Byte变量 //当SDA为1时,置变量指定位为1,当SDA为0时,不做处理,指定位为默认的初值0 MyI2C_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 > i)); //使用掩码的方式取出Byte的指定一位数据并写入到SDA线 MyI2C_W_SCL(1); //释放SCL,从机在SCL高电平期间读取SDA MyI2C_W_SCL(0); //拉低SCL,主机开始发送下一位数据 } } /** * 函 数:I2C接收一个字节 * 参 数:无 * 返 回 值:接收到的一个字节数据,范围:0x00~0xFF */ uint8_t MyI2C_ReceiveByte(void) { SDA_OUT(); uint8_t i, Byte = 0x00; //定义接收的数据,并赋初值0x00 MyI2C_W_SDA(1); //接收前,主机先确保释放SDA,避免干扰从机的数据发送 for (i = 0; i > i);} //读取SDA数据,并存储到Byte变量 //当SDA为1时,置变量指定位为1,当SDA为0时,不做处理,指定位为默认的初值0 MyI2C_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_ADDRESS 0xD0 //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); //配置寄存器,配置DLPF MPU6050_WriteReg(MPU6050_GYRO_CONFIG, 0x18); //陀螺仪配置寄存器,选择满量程为±2000°/s MPU6050_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
免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们。