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

06-02 1355阅读

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

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

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

思路讲解

1.软硬件型号

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

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

 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,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们。

相关阅读

目录[+]

取消
微信二维码
微信二维码
支付宝二维码