江科大學習筆記 _12.軟件IIC
IIC硬件電路

IIC兩條線(SCL/SDA)開漏輸出 ???????三極管導通時,接地,強下拉;截止時,浮空;
開漏加弱上拉模式
添加上拉電阻,阻值4.7KΩ
?
?
void MyIIC_W_SCL(uint8_t Bitvalue)//控制SCL電平 ?Bitvalue:0 or 1
{
????GPIO_WriteBit(IIC_Port,IIC_SCL,(BitAction)Bitvalue);
????Delay_us(10);
}
?
void MyIIC_W_SDA(uint8_t Bitvalue)//控制SDA電平 ?Bitvalue:0 or 1
{
????GPIO_WriteBit(IIC_Port,IIC_SDA,(BitAction)Bitvalue);
????Delay_us(10);
}
?
uint8_t MyIIC_R_SDA(void)//讀SDA電平 ?返回:0 or 1
{
????uint8_t Bitvalue;
????Bitvalue = GPIO_ReadInputDataBit(IIC_Port,IIC_SDA);
????Delay_us(10);
?
????return Bitvalue;
}
?
IIC初始化
//初始化IIC:配置兩個GPIO端口,開漏輸出
void MyIIC_Init(void)
{
????RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
?
????GPIO_InitTypeDef GPIO_InitStruct;
????GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_OD;//開漏輸出
????GPIO_InitStruct.GPIO_Pin = IIC_SCL|IIC_SDA;
????GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
????GPIO_Init(IIC_Port,&GPIO_InitStruct);
?
????GPIO_SetBits(IIC_Port,IIC_SCL|IIC_SDA);//置高電平,IIC中的空閑狀態(tài)
}
?
?
IIC起始、結(jié)束
?

類型串口中的起始位和停止位
void MyIIC_Start(void)
{
????MyIIC_W_SDA(1);
????MyIIC_W_SCL(1);
????
????MyIIC_W_SDA(0);
????MyIIC_W_SCL(0);
}
void MyIIC_Stop(void)
{
????MyIIC_W_SDA(0);
????//MyIIC_W_SCL(0);
?
????MyIIC_W_SCL(1);
????MyIIC_W_SDA(1);
}
?
SCL全程由主機控制
主機發(fā)送數(shù)據(jù):
SCL低電平時,主機放置數(shù)據(jù)位到SDA線上,然后拉高SCL;經(jīng)過一段時間(等待從機讀?。?,繼續(xù)拉低SCL傳輸下一位數(shù)據(jù),重復8次即為一個字節(jié)。
從機在SCL高電平時(上升沿)讀取SDA電平(數(shù)據(jù));
?

低電平主機放數(shù)據(jù),高電平從機讀數(shù)據(jù)
?
void MyIIC_SendByte(uint8_t Byte)
{
????int8_t i;
????//寫SDA時 默認SCL低電平
????for(i = 7; i >= 0; i--)
????{
????????//一個字節(jié)分為 8位,從高到低一次發(fā)送
????????MyIIC_W_SDA(Byte & (1 << i));
????????MyIIC_W_SCL(1);//從機在SCL高電平時讀走這個電平
????????MyIIC_W_SCL(0);//拉低再寫電平
????} ?
}
?
主機接收數(shù)據(jù):
?

主機需要釋放SDA線的控制權(quán),將控制權(quán)交給從機
在SCL低電平期間,從機將數(shù)據(jù)位放在SDA線上,SCL高電平時,主機讀取SDA數(shù)據(jù)(電平)
低電平從機放數(shù)據(jù),高電平主機讀數(shù)據(jù)
?
uint8_t MyIIC_ReceiveByte(void)
{
????uint8_t Byte = 0x00;
????int8_t i;
?
????//主機讀SDA時,默認SCL低電平
????MyIIC_W_SDA(1);//釋放SDA
?
????for(i = 7; i >= 0; i--)
????{
????????//這時從機寫SDA電平
????????MyIIC_W_SCL(1);//SCL置高,主機讀
????????if(MyIIC_R_SDA() == 1) {Byte |= (1 << i);}
?
????????MyIIC_W_SCL(0);//讀取完之后,繼續(xù)把SCL拉低,等待從機寫
????}
????return Byte;
}
?
應答機制
?

和發(fā)送一位數(shù)據(jù)的機制相同;
主機接收完一個字節(jié),發(fā)送一個應答位,0為應答,1為非應答
?
void MyIIC_SendAck(uint8_t AckBit)
{
????MyIIC_W_SDA(AckBit);
????MyIIC_W_SCL(1);//從機在SCL高點平時讀走這個電平
????MyIIC_W_SCL(0);//拉低再寫電平
}
?
主機接收應答
主機發(fā)送完一個字節(jié),接收一個應答位,0為應答,1為非應答
(判斷從機是否應答)(需要釋放SDA控制權(quán)給從機)
uint8_t MyIIC_ReceiveAck(void)
{
????uint8_t AckByte;
?
????MyIIC_W_SDA(1);//釋放SDA
????//這時從機寫SDA電平
????MyIIC_W_SCL(1);//SCL置高,主機讀
????AckByte = MyIIC_R_SDA();
????MyIIC_W_SCL(0);//讀取完之后,繼續(xù)把SCL拉低,等待從機寫
?
????return AckByte;
}
?
?
?

?

S:起始 ?從機地址7位 + 讀寫1位 ?應答位
?? ? ?讀取位:(0寫入/1讀入)
#define MPU6050_ADDRESS ?0XD0 //芯片地址
//MPU6050 在寄存器地址上寫數(shù)據(jù)時序
void MPU6050_WriteReg(uint8_t RegAddress, uint8_t Data)
{
????MyIIC_Start();
????MyIIC_SendByte(MPU6050_ADDRESS);
????MyIIC_ReceiveAck();
????MyIIC_SendByte(RegAddress);
????MyIIC_ReceiveAck();
????MyIIC_SendByte(Data);
????MyIIC_ReceiveAck();
????MyIIC_Stop();
}
?
?

較少用,因為不能指定讀地址,只能根據(jù)寄存器地址指針讀數(shù)據(jù)
?

?
?

看圖
?

先起始,第一個字節(jié)為地址(7位)加寫(1位),一個應答位 ,
再發(fā)一個寄存器地址,寄存器地址指針這時指向了這個地址
重新起始,讀當前位置,SDA交給從機寫,應答,停止
uint8_t MPU6050_ReadReg(uint8_t RegAddress)
{
????uint8_t Data;
?
????MyIIC_Start();
????MyIIC_SendByte(MPU6050_ADDRESS);
????MyIIC_ReceiveAck();
????MyIIC_SendByte(RegAddress);
????MyIIC_ReceiveAck();
?
????MyIIC_Start();
????MyIIC_SendByte(MPU6050_ADDRESS|0x01);
????MyIIC_ReceiveAck();
????Data = MyIIC_ReceiveByte();
????MyIIC_SendAck(1);//只讀一個字節(jié),不給應答
????//如果要讀取多個字節(jié) for循環(huán)32 33 行,最后一個字節(jié)應答1,之前應答0
????MyIIC_Stop();
?
????return Data;
}
?
?
?
?
?
?
?
?
MPU6050參數(shù)
?

void MPU6050_Init()
{
????MyIIC_Init();
????//以下配置需要看芯片的寄存器手冊
????MPU6050_WriteReg(MPU6050_PWR_MGMT_1, 0x01);//電源管理寄存器1,解除睡眠,選擇X軸陀螺儀時鐘
????MPU6050_WriteReg(MPU6050_PWR_MGMT_2, 0x00);//電源管理寄存器2,6軸均不待機
?
????MPU6050_WriteReg(MPU6050_SMPLRT_DIV, 0x09);//時鐘分頻 0x09 ?10分頻
????MPU6050_WriteReg(MPU6050_CONFIG, 0x06); ???//數(shù)字低通濾波器 , 最大濾波參數(shù)
????MPU6050_WriteReg(MPU6050_GYRO_CONFIG, 0x18);//陀螺儀配置寄存器 ,最大量程
????MPU6050_WriteReg(MPU6050_ACCEL_CONFIG, 0x18);//加速度計配置寄存器 , 最大量程
}
?
獲取數(shù)據(jù)全部封裝在這個函數(shù)中
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;
?
????DataH = MPU6050_ReadReg(MPU6050_ACCEL_XOUT_H);
????DataL = MPU6050_ReadReg(MPU6050_ACCEL_XOUT_L);
????*AccX = (DataH << 8) | DataL;//uint8_t 左移8位 會自動類型轉(zhuǎn)換 為uint16
????
????DataH = MPU6050_ReadReg(MPU6050_ACCEL_YOUT_H);
????DataL = MPU6050_ReadReg(MPU6050_ACCEL_YOUT_L);
????*AccY = (DataH << 8) | DataL;
????
????DataH = MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_H);
????DataL = MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_L);
????*AccZ = (DataH << 8) | DataL;
?
????DataH = MPU6050_ReadReg(MPU6050_GYRO_XOUT_H);
????DataL = MPU6050_ReadReg(MPU6050_GYRO_XOUT_L);
????*GyroX = (DataH << 8) | DataL;
????
????DataH = MPU6050_ReadReg(MPU6050_GYRO_YOUT_H);
????DataL = MPU6050_ReadReg(MPU6050_GYRO_YOUT_L);
????*GyroY = (DataH << 8) | DataL;
?
????DataH = MPU6050_ReadReg(MPU6050_GYRO_ZOUT_H);
????DataL = MPU6050_ReadReg(MPU6050_GYRO_ZOUT_L);
????*GyroZ = (DataH << 8) | DataL;
?
}
?
?
uint8_t MPU6050_GetID(void)
{
????return (MPU6050_ReadReg(MPU6050_WHO_AM_I));
}
?