1. I2C总线
1.1 i2c概述
I2C总线是PHLIPS公司在八十年代初推出的一种串行的半双工总线,主要用于连接整体电路。
I2C总线为两线制,只有两根双向信号线。一根是数据线SDA,另一根是时钟线SCL。
I2C硬件结构简单,接口连接方便,成本较低。因此在各个领域得到了广泛的应用。
I2C:同步半双工串行总线
i2c支持一主机多从机通信,每个接到I2C总线上的器件都有唯一的地址。主机如果想和哪一个从机进行通信需要先发送一个从机地址到I2C总线上,每一个从机都会将这个从机地址和自己的地址进行匹配,匹配成功的从机会往数据线上发送一个应答信号,主机确认从机应答后开始进行通信
主机与其它器件进行数据传送时总线上发送数据的器件为发送器,总线上接收数据的器件则为接收器。
1.2 I2C的寻址
I2C总线上传输的数据信号既有地址信号,也有数据信号
主机在起始信号之后必须要传输一个从机的地址信号(7位),第八位是数据的传送方向位,0表示主机发送数据(W),1表示主机接收数据(R)。从机上每个器件都会将七位地址码进行比较,如果相同则认为被主机寻址,并根据R/W位确定是接收器还是发送器
1.3 i2c总线的信号
在I2C总线数据传输过程中存在四种信号:起始信号、终止信号、应答信号、非应答信号
起始信号:i2c总线传输数据的开始
SCL线为高电平期间,SDA线由高电平向低电平的变化表示起始信号
终止信号:i2c总线一次数据传输的结束标志
SCL线为高电平期间,SDA线由低电平向高电平的变化表示终止信号
应答信号和非应答信号
每一个字节必须保证是8位长度。数据传送时,先传送最高位(MSB),每一个被传送的字节后面都必须跟随一位应答位(即一帧共有9位)。
应答信号:第九个时钟周期,接收方往数据线上发送了一个低电平,就是应答信号
非应答信号:第九个时钟周期,接收方往数据线上发送了一个高电平,就是非应答信号
当接收方接收到数据后不想再接收数据,此时会回应发送方一个非应答信号
当接收方接收到数据后还想再接收数据,此时会回应发送方一个应答信号
1.4 I2C总线上数据读写的时机
当时钟线为高电平时,接收方可以读取数据
当时钟线为低电平时,发送方可以写入数据
1.5 i2c主机的读写时序(重点)
主机向从机发送一个字节数据
主机发起起始信号
主机发送7bit从机地址+1bit写标志位
从机回应应答信号
主机发送8bit寄存器地址
从机回应应答信号
主机发送8bit数据
从机回应应答信号
主机发起终止信号
主机向从机发送多个字节数据
主机发起起始信号
主机发送7bit从机地址+1bit写标志位
从机回应应答信号
主机发送8bit寄存器地址
从机回应应答信号
主机发送8bit数据
从机回应应答信号
.。。。。。
主机发起终止信号
主机读取从机一个字节数据
主机发起起始信号
主机发送7bit从机地址+1bit写标志
从机回应一个应答信号
主机发送8bit寄存器地址
从机回应一个应答信号
主机发起一个重复起始信号
主机发送7bit从机地址+1bit读标志位
从机回应应答信号
从机发送一个字节数据
主机回应非应答信号
主机发起终止信号
主机读取多个字节的时序
主机发起起始信号
主机发送7bit从机地址+1bit写标志
从机回应一个应答信号
主机发送8bit寄存器地址
从机回应一个应答信号
主机发起一个重复起始信号
主机发送7bit从机地址+1bit读标志位
从机回应应答信号
从机发送一个字节数据
主机回应回应应答信号
只要主机回应应答信号,从机就一直发,直到主机回应非应答信号
主机回应非应答信号
主机发起终止信号
2. I2C总线读取温湿度传感器数据实验
STM32MP157AAA读取SI7006数据框图
2.1查询SI7006数据手册
1.SI7006的从机地址
2.确定读取温度和湿度的对应寄存器地址
3.确定温度数据和湿度数据的字节数
4.如何初始化si7006芯片
5.如何将读取到的温湿度数据转换成标准温湿度形式
从机地址
读取温度和湿度数据的寄存器地址
读取湿度的寄存器地址是0XE5
读取温度的寄存器地址是0XE3
读取上一次测量的温度的寄存器地址是0XE0
完成SI7006芯片的初始化需要向用户写寄存器中写入一个数值,用户写寄存器地址是0XE6
主机保持模式下读取温湿度数据的时序
关于SI7006的初始化
完成SI7006的初始化,需要向用户写寄存器(0XE6)中写入一个0X3A
温湿度数据的计算公式
作业
设置温度湿度阈值,当温度过高时,打开风扇,蜂鸣器报警
当湿度比较高时,打开LED1灯,蜂鸣器报警
main.c
#include "uart4.h"
#include "led.h"
#include "key_in.h"
#include "iic.h"
#include "si7006.h"
int main()
{
i2c_init();
si7006_init();
all_led_init();
while(1)
{
short tem;
unsigned short hum;
tem=si7006_read_tem();
hum=si7006_read_hum();
hum=125*hum/65536-6;
tem=175.72*tem/65536-46.85;
printf("hum:%d\n",hum);
printf("tem:%d\n",tem);
if(tem>30)
{
fan_on();
}else
{
fan_off();
}
if(hum>44)
{
bee_on();
}else
{
bee_off();
}
delay(1000);
bee_off();
}
return 0;
}
si7600.c
#include "si7006.h"
void delay(int ms)
{
int i,j;
for(i=0;i<ms;i++)
{
for(j=0;j<2000;j++)
{
}
}
}
void si7006_init()
{
i2c_start();
i2c_write_byte(0x40<<1|0);
i2c_wait_ack();
i2c_write_byte(0xe6);
i2c_wait_ack();
i2c_write_byte(0x3a);
i2c_wait_ack();
i2c_stop();
}
short si7006_read_tem()
{
short tem;
char tem_l,tem_h;
i2c_start();
i2c_write_byte(0x40<<1|0);
i2c_wait_ack();
i2c_write_byte(0xe3);
i2c_wait_ack();
i2c_start();
i2c_write_byte(0x40<<1|1);
i2c_wait_ack();
delay(100);
tem_h=i2c_read_byte(0);
tem_l=i2c_read_byte(1);
tem=tem_h<<8|tem_l;
return tem;
}
unsigned short si7006_read_hum()
{
short hum;
char hum_l,hum_h;
i2c_start();
i2c_write_byte(0x40<<1|0);
i2c_wait_ack();
i2c_write_byte(0xe5);
i2c_wait_ack();
i2c_start();
i2c_write_byte(0x40<<1|1);
i2c_wait_ack();
delay(100);
hum_h=i2c_read_byte(0);
hum_l=i2c_read_byte(1);
hum=hum_h<<8|hum_l;
return hum;
}
led.c
#include "led.h"
void all_led_init()
{
RCC->MP_AHB4ENSETR |= (0x3<<4);
//pe10 设置输出
GPIOE->MODER &= (~(0x3 <<20));
GPIOE->MODER |= (0x1 <<20);
//pf10设置输出
GPIOF->MODER &= (~(0x3 <<20));
GPIOF->MODER |= (0x1 <<20);
//pe8设置输出
GPIOE->MODER &= (~(0x3 <<16));
GPIOE->MODER |= (0x1 <<16);
//蜂鸣器设置输出
GPIOB->MODER &= (~(0x3 <<12));
GPIOB->MODER |= (0x1 <<12);
//风扇设置输出
GPIOE->MODER &= (~(0x3 <<18));
GPIOE->MODER |= (0x1 <<18);
//马达设置输出
GPIOF->MODER &= (~(0x3 <<12));
GPIOF->MODER |= (0x1 <<12);
//设置推挽
GPIOE->OTYPER &= (~(0x1 <<10));
GPIOF->OTYPER &= (~(0x1 <<10));
GPIOE->OTYPER &= (~(0x1 <<8));
//设置低速
GPIOE->OSPEEDR &= (~(0x3 <<20));
GPIOF->OSPEEDR &= (~(0x3 <<20));
GPIOE->OSPEEDR &= (~(0x3 <<16));
//设置无上拉下拉
GPIOE->PUPDR &= (~(0x3 <<20));
GPIOF->PUPDR &= (~(0x3 <<20));
GPIOE->PUPDR &= (~(0x3 <<16));
//默认输出低电平
GPIOE->ODR &=(~(0x1 <<10));
GPIOF->ODR &=(~(0x1 <<10));
GPIOE->ODR &=(~(0x1 <<8));
}
void LED1_ON()
{
GPIOE->ODR |=(0x1 <<10);
}
void LED2_ON()
{
GPIOF->ODR |= (0x1 <<10);
}
void LED3_ON()
{
GPIOE->ODR |=(0x1 <<8);
}
void LED1_OFF()
{
GPIOE->ODR &=(~(0x1 <<10));
}
void LED2_OFF()
{
GPIOF->ODR &=(~(0x1 <<10));
}
void LED3_OFF()
{
GPIOE->ODR &=(~(0x1 <<8));
}
void bee_on()
{
GPIOB->ODR |=(0x1 <<6);
}
void bee_off()
{
GPIOB->ODR &=(~(0x1 <<6));
}
void fan_on()
{
GPIOE->ODR |=(0x1 <<9);
}
void fan_off()
{
GPIOE->ODR &=(~(0x1 <<9));
}
void motor_on()
{
GPIOF->ODR |=(0x1 <<6);
}
void motor_off()
{
GPIOF->ODR &=(~(0x1 <<6));
}