GPIO软件模拟IIC时序--转载
2018-02-01 14:05
453 查看
转载自http://blog.chinaunix.net/uid-29512885-id-5763629.html,仅用作备份,自己平时移植I2C驱动用
一、MPU6050中的IIC时序
1.1 START和STOP
SDA和SCL在高电平时,SDA拉低表示START。SCL拉低,表示可以传输数据。
SDA和SCL在低电平时,SDA拉高表示STOP。 SCL拉高,表示传输数据结束。
/******************************************
*函数原型: void IIC_Start(void)
*功能: 产生IIC起始信号
******************************************/
void IIC_Start(void)
{
SDA_OUT();
IIC_SDA=1;
IIC_SCL=1;
delay_us(4);
IIC_SDA=0; //START:when
CLK is high,SDA change from hig to low
delay_us(4);
IIC_SCL=0; //Ready
Transmit or Receive
}
/***************************
19f12
***************
*函数原型: void IIC_Start(void)
*功能: 产生IIC结束信号
******************************************/
void IIC_Stop(void)
{
SDA_OUT();
IIC_SDA=0;
IIC_SCL=0;
delay_us(4);
IIC_SDA=1; //STOP:when
CLK is low,SDA change from low to high
IIC_SCL=1; //发送I2C总线结束信号
delay_us(4);
}
一些的宏定义:
#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2))
#define MEM_ADDR(addr) *((volatile
unsigned long *)(addr))
#define BIT_ADDR(addr, bitnum) MEM_ADDR(BITBAND(addr, bitnum))
#define GPIOB_ODR_Addr (GPIOB_BASE+12)
#define GPIOB_IDR_Addr (GPIOB_BASE+8)
#define PBout(n) BIT_ADDR(GPIOB_ODR_Addr,n) //输出
#define PBin(n) BIT_ADDR(GPIOB_IDR_Addr,n) //输入
//驱动接口,GPIO模拟IIC
//PB7->I2C_SDA
//PB6->I2C_SCL
#define SDA_IN() {GPIOB->CRL&=0x0FFFFFFF;GPIOB->CRL|=0x80000000;} //上拉输入
#define SDA_OUT() {GPIOB->CRL&=0x0FFFFFFF;GPIOB->CRL|=0x30000000;} //通用推挽输出,不用硬件IIC
//IO操作函数
#define IIC_SCL PBout(6)
#define IIC_SDA PBout(7)
#define READ_SDA PBin(7)
1.2 ACK和NACK时序图
在START信号后,读取8位的数据,STM32需要对MPU6050发出响应以同步。
第九个SCL时,SCL从低电平变成高电平后,SDA如果是低电平则是ACK,如果是高电平则是NACK。
/******************************************
*函数原型: void IIC_Wait_Ack(void)
*功能: 等待应答信号到来
*输出; 1,接收应答失败
0,接收应答成功
******************************************/
u8 IIC_Wait_Ack(void)
{
u8 ucErrTime = 0;
SDA_IN();
IIC_SDA=1;
delay_us(1);
IIC_SCL=1;
delay_us(1);
while(IIC_SDA) //最多等待50us
{
ucErrTime++;
if(ucErrTime>50)
{
IIC_Stop();
return 1;
}
delay_us(1);
}
IIC_SCL=0; //时钟输出0
return 0;
}
/******************************************
*函数原型: void IIC_Ack(void)
*功能: 产生ACK应答信号SDA=0
******************************************/
void IIC_Ack(void)
{
IIC_SCL=0;
SDA_OUT();
IIC_SDA=0;
delay_us(1);
IIC_SCL=1;
delay_us(1);
IIC_SCL=0;
}
/******************************************
*函数原型: void IIC_Ack(void)
*功能: 产生ACK应答信号SDA=0
******************************************/
void IIC_NAck(void)
{
IIC_SCL=0;
SDA_OUT();
IIC_SDA=1;
delay_us(1);
IIC_SCL=1;
delay_us(1);
IIC_SCL=0;
}
1.3 MPU6050写入时序
写时序的步骤:START+(MPU6050地址+W)+等待ACK+寄存器地址+等待ACK+写入的数据+等待ACK+STOP。
读时序的步骤:START+(MPU6050地址+W)+等待ACK+寄存器地址+START+读取数据+ACK响应+STOP。
/****************************************************
*函数原型: u8 IICwriteBytes(u8 dev, u8 reg, u8
length, u8 *data)
*功能: 将多个字节写入指定设备 指定寄存器
*输入: dev 目标设备地址
* reg 寄存器地址
* length 要写的字节数
* *data 将要写的数据的首地址
*返回: 返回是否成功,1成功
****************************************************/
u8 IICwriteBytes(u8 dev, u8 reg, u8 length, u8 *data)
{
u8 count = 0;
IIC_Start();
IIC_Send_Byte(dev); //发送写命令
IIC_Wait_Ack();
IIC_Send_Byte(reg); //发送写入的地址
IIC_Wait_Ack();
for(count=0;count<length;count++)
{
IIC_Send_Byte(data[count]);
IIC_Wait_Ack();
}
IIC_Stop(); //发送停止信号
return 1;
}
/******************************************
*函数原型: u8 IIC_Read_Byte(unsigned char ack)
*功能: 读取一个Byte的字节
*输入: 读取一个字节,ack=1,发送ACK,ack=0,发送nACK
*返回: 读取到的Byte
******************************************/
u8 IIC_Read_Byte(unsigned char ack)
{
unsigned char i, receive = 0;
SDA_IN(); //设置为输入
for(i=0;i<8;i++)
{
IIC_SCL=0;
delay_us(1);
IIC_SCL=1;
receive<<=1;
if(READ_SDA) receive++;
delay_us(1);
}
if(ack)
IIC_Ack(); //发送ACK
else
IIC_NAck(); //发送NACK
return receive;
}
留下了一个不太清楚的内容,按位,位长度写数据:
/****************************************************
*函数原型: u8 IICwriteBits(u8 dev, u8 reg, u8
bitStart, u8 length, u8 data)
*功能: 读、修改、写指定设备、指定寄存器一个字节中的多个位
*输入: dev 目标设备地址
* reg 寄存器地址
* bitStart 目标字节的起始位,自左向右?
* length 位长度
* data 存放改变目标字节位的值
*返回: 返回是否成功,1成功
****************************************************/
u8 IICwriteBits(u8 dev, u8 reg, u8 bitStart, u8
length, u8 data)
{
u8 b;
u8 mask;
if(IICreadByte(dev, reg, &b) != 0)
{
mask = (0xFF << (bitStart +1))| 0xFF >> ((8 - bitStart) + length -1);
data >>= (7 - bitStart);
b &= mask;
b |= data;
return IICwriteByte(dev, reg, b);
} else {
return 0;
}
}
相关文章推荐
- gpio软件模拟IIC与硬件IIC驱动有什么区别
- GPIO模拟I2C快速入门 与程序实现+软件模拟I2C时序
- IIC 时序分析,stm32软件模拟驱动编写
- 【转载】2440的GPIO模拟IIC程序
- 软件模拟gpio 实现
- GPIO软件模拟I2C
- 关于温湿度SHT20传感器,用普通GPIO口来模拟IIC实现驱动
- GPIO模拟IIC接口信号质量分析
- GPIO模拟IIC过程中对IIC的理解
- 51单片机 软件模拟IIC
- STM32 软件模拟SPI时序驱动NRF24L01
- GPIO模拟IIC代码模板
- C51 GPIO口模拟IIC读写24CXX
- GPIO软件模拟IIC时序
- [转载]用ANSYS有限元软件模拟分析声学换能器
- 18、基于 STM32 的 I2C 时序 - GPIO 模拟方式
- STM32F103单片机软件模拟IIC并读取TMP112数字温度传感器
- 嵌入式软件开发培训笔记——S5PC100接口开发(GPIO输入/输出、定时器、中断、UART、ADC、IIC)
- 单片机模拟IIC时序读写24C02
- linux i2c-gpio 模拟i2c时序出现oops错误