I2C实验

IIC概念

1.I2C总线是PHLIPS公司在八十年代初推出的一种串行的半双工同步总线,主要用于连接整体电路。
1)同一个板子两个芯片之间的通信  stm32mp157a<---IIC--->SI7006
2)两个设备之间的通信  SOC<---UART--->Target
2.I2C总线为两线制,只有两根双向信号线。一根是数据线SDA,另一根是时钟线SCL。
3.I2C硬件结构简单,接口连接方便,成本较低。因此在各个领域得到了广泛的应用。
4.IIC总线传输速率
低速 100k	中速 400k	全速 3.4M
5.IIC总线需要接两个上拉电阻,这两个上拉电阻作用在IIC总线为空闲状态时保持高电平。

IIC总线硬件连接

在这里插入图片描述

1.IIC总线支持多主机多从机模式,同一时刻,只能有一个主机和一个从机进行通信
2.在实际开发中,大多数使用单主机多从机模式进行通信
3.挂接到每一个IIC总线上所有的设备,每一个从机都有自己唯一的七位从机地址
4.在总线上,发送数据的叫做发送器,接收数据的叫做接收器
5.主动发起数据通信的叫做主机,只能被动接收数据的叫做从机
6.时钟信号是由主机产生的,作用给从机,保证总线上传输数据同步

IIC硬件电路图

在这里插入图片描述
在这里插入图片描述

IIC框图

在这里插入图片描述

IIC协议

主机给从机发送一个字节

在这里插入图片描述

主机给从机发送多个连续字节在这里插入图片描述

从机给主机发送一个字节

在这里插入图片描述

从机给主机发送多个连续字节

在这里插入图片描述

GPIO模拟IIC协议

在这里插入图片描述

从机地址

在这里插入图片描述

温湿度命令码

在这里插入图片描述
在这里插入图片描述

温湿度转换公式

在这里插入图片描述

si7006寄存器初始化

在这里插入图片描述

代码实现

iic.c文件

#include "iic.h"

extern void printf(const char* fmt, ...);
/*
 * 函数名 : delay_us
 * 函数功能:延时函数
 * 函数参数:无
 * 函数返回值:无
 * */
void delay_us(void)
{
unsigned int i = 2000;
while(i--);
}
/*
 * 函数名 : i2c_init
 * 函数功能: i2C总线引脚的初始化, 通用输出,推挽输出,输出速度,
 * 函数参数:无
 * 函数返回值:无
 * */
void i2c_init(void)
{
 // 使能GPIOF端口的时钟
RCC->MP_AHB4ENSETR |= (0x1 << 5);
// 设置PF14,PF15引脚为通用的输出功能
GPIOF->MODER &= (~(0xF << 28));
GPIOF->MODER |= (0x5 << 28);
// 设置PF14, PF15引脚为推挽输出
GPIOF->OTYPER &= (~(0x3 << 14));
// 设置PF14, PF15引脚为高速输出
GPIOF->OSPEEDR |= (0xF << 28);
// 设置PF14, PF15引脚的禁止上拉和下拉
GPIOF->PUPDR &= (~(0xF << 28));
// 空闲状态SDA和SCL拉高 
I2C_SCL_H;
I2C_SDA_H;
}

/*
 * 函数名:i2c_start
 * 函数功能:模拟i2c开始信号的时序
 * 函数参数:无
 * 函数返回值:无
 * */
void i2c_start(void)
{
/*
 * 开始信号:时钟在高电平期间,数据线从高到低的变化
 *     --------
 * SCL         \
 *              --------
 *     ----
 * SDA     \
 *          --------
 * */
//1.设置数据线为输出模式
SET_SDA_OUT;
//2.时钟线拉高
I2C_SCL_H;
//3.数据线拉高
I2C_SDA_H;
//4.延时函数
delay_us();
//5.数据线拉低
I2C_SDA_L;
delay_us();
I2C_SCL_L; //保持总线处于占用状态
}

/*
 * 函数名:i2c_stop
 * 函数功能:模拟i2c停止信号的时序
 * 函数参数:无
 * 函数返回值:无
 * */

void i2c_stop(void)
{
/*
 * 停止信号 : 时钟在高电平期间,数据线从低到高的变化 
 *             ----------
 * SCL        /
 *    --------
 *    ---         -------
 * SDA   X       /
 *    --- -------
 * */
SET_SDA_OUT; //确保SDA为输出模式
I2C_SCL_L;
delay_us();
I2C_SDA_L; //数据线拉低
delay_us();

I2C_SCL_H;
delay_us();
I2C_SDA_H;
delay_us();
}

/*
 * 函数名: i2c_write_byte
 * 函数功能:主机向i2c总线上的从设备写8bits数据
 * 函数参数:dat : 等待发送的字节数据
 * 函数返回值: 无
 * */

void i2c_write_byte(unsigned char dat)
{
/*
 * 数据信号:时钟在低电平期间,发送器向数据线上写入数据
 * 时钟在高电平期间,接收器从数据线上读取数据 
 *      ----          --------
 * SCL     \        /        \
 *           --------          --------
 *      -------- ------------------ ---
 * SDA         X                  X
 *      -------- ------------------ ---
 *
 *      先发送高位在发送低位 
 * */
unsigned int i;
SET_SDA_OUT;  //设置数据线为输出模式
for(i=0;i<8;i++)
{
I2C_SCL_L; //时钟线拉低,可以向数据线上写数据
delay_us();
if(dat & 0x80) //写高位
{
I2C_SDA_H; //向数据线上写高电平
}
else
{
I2C_SDA_L; //向数据线上写低电平
}
delay_us();
I2C_SCL_H;  //时钟线拉高
delay_us();
delay_us();
dat <<= 1; //移位
}
}

/*
 * 函数名:i2c_read_byte
 * 函数功能: 主机从i2c总线上的从设备读8bits数据, 
 *          主机发送一个应答或者非应答信号
 * 函数参数: 0 : 应答信号   1 : 非应答信号
 * 函数返回值:读到的有效数据
 *
 * */
unsigned char i2c_read_byte(unsigned char ack)
{
/*
 * 数据信号:时钟在低电平期间,发送器向数据线上写入数据
 * 时钟在高电平期间,接收器从数据线上读取数据 
 *      ----          --------
 * SCL     \        /        \
 *           --------          --------
 *      -------- ------------------ ---
 * SDA         X                  X
 *      -------- ------------------ ---
 *
 *      先接收高位, 在接收低位 
 * */
unsigned int i;
unsigned char dat; //返回读到的数据
SET_SDA_IN; //确保总线输入模式
for(i=0;i<8;i++)
{
I2C_SCL_L; //时钟线拉低
delay_us();
delay_us();//保证数据写完整

I2C_SCL_H; //时钟线拉高
delay_us();
dat <<= 1;
if(I2C_SDA_READ) //读取数据
{
dat |= 1;
}
else
{
dat |= 0;
}
delay_us();
}
if(!ack)
i2c_ack(); 
else
i2c_nack();
return dat;
}

/*
 * 函数名: i2c_wait_ack
 * 函数功能: 主机作为发送器时,等待接收器返回的应答信号
 * 函数参数:无
 * 函数返回值:
 *0:接收到的应答信号
 *                  1:接收到的非应答信号
 * */
unsigned char i2c_wait_ack(void)
{ 
/*
 * 主机发送一个字节之后,从机给主机返回一个应答信号
 *
 *                   -----------
 * SCL              /   M:读    \
 *     -------------             --------
 *     --- ---- --------------------
 * SDA    X    X
 *     ---      --------------------
 *     主  释   从机    主机
 *     机  放   向数据  读数据线
 *         总   线写    上的数据
 *         线   数据
 * */
I2C_SCL_L;
I2C_SDA_H; //释放总线
delay_us();
SET_SDA_IN; //变换总线方向

I2C_SCL_H;
delay_us();
if(I2C_SDA_READ)
return 1; //非应答信号
I2C_SCL_L;
return 0; //应答信号
} 
/*
 * 函数名: iic_ack
 * 函数功能: 主机作为接收器时,给发送器发送应答信号
 * 函数参数:无
 * 函数返回值:无
 * */
void i2c_ack(void)
{
/*            --------
 * SCL       /        \
 *    -------          ------
 *    ---
 * SDA   X 
 *    --- -------------
 * */
SET_SDA_OUT; //确保总线输出模式
I2C_SCL_L; //时钟线拉低
delay_us();
I2C_SDA_L; //数据线拉低 应答信号
delay_us();
I2C_SCL_H; //时钟线拉高 读取数据
delay_us();
delay_us();
I2C_SCL_L; //时钟线拉低,总线处于占用状态
}
/*
 * 函数名: iic_nack
 * 函数功能: 主机作为接收器时,给发送器发送非应答信号
 * 函数参数:无
 * 函数返回值:无
 * */
void i2c_nack(void)
{
/*            --------
 * SCL       /        \
 *    -------          ------
 *    --- ---------------
 * SDA   X 
 *    --- 
 * */
SET_SDA_OUT; //确保总线输出模式
I2C_SCL_L; //时钟线拉低
delay_us();
I2C_SDA_H; //数据线拉高 非应答信号
delay_us();
I2C_SCL_H; //时钟线拉高 读取数据
delay_us();
delay_us();
I2C_SCL_L; //时钟线拉低,总线处于占用状态
}

main.c文件

#include "iic.h"
#include "si7006.h"

extern void printf(const char *fmt, ...);
void delay_ms(int ms)
{
int i,j;
for(i = 0; i < ms;i++)
for (j = 0; j < 1800; j++);
}


int main()
{
unsigned short hum;
unsigned short temp;
si7006_init();
while(1)
{
hum = si7006_read_data(SI7006_SLAVE,0xE5);
temp = si7006_read_data(SI7006_SLAVE,0xE3);
printf("hum = %d\n",125*hum/65536-6);
printf("temp = %d\n",175*temp/65536-46);

}
return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值