【I2C总线传输数据原理】
I2C是同步半双工的通信方式,主机和从机依赖于同一根时钟线,通过SCL和SDL两根线相互配合传输数据。先查看硬件原理图
从上面两张硬件原理图可知从机(温湿度传感器)通过I2C总线连接到本单片机的PF14,PF15引脚。所以对于主机来说依旧需要使用到GPIO模块,并使用通过控制GPIO模块的输出、输入的高低电平来实现与从机的通信。所以本次的大致工作框图如下:
本次实验不使用I2C控制器操控GPIO模块,纯纯手敲对GPIO两个引脚的控制实现通信
【GPIO模块】
对于该模块的操作只有一个RCC使能,将RCC_MP_AHB4ENSETR寄存器的第五位设置为1即可。由于要实现主机和从机之间的通信需要大量切换两个引脚的输出/输入模式,本实验直接使用现成的I2C库函数了.
【温湿度传感器】
本实验使用的温湿度传感器是SI7006芯片,具体工作框图如下:
传感器会将采集到的数据通过数模转换存储在内存中,当主机发送读取数据的请求时,从机从内取出中数据并通过I2C总线传输给主机。所以在使用这款芯片时需要明确:
1、从机的地址
2、传感器储存数据的地址
3、初始化芯片
这些都可以在芯片手册中查询到。
从上表可知该芯片的从机地址在0x40,湿度存储在0xe5,温度存储在0xe3,初始化只需要往0xe6内存中写入0x3a即可
【I2C总线】
I2C总线使用时钟信号和数据信号相互配合传递信息,这就有必要提一下I2C总线产生的四种信号和产生方式:
开始信号 | 再时钟信号和数据信号都是高电平时、数据信号产生一个下降沿 |
结束信号 | 在时钟信号为高电平时,数据信号产生一个上升沿 |
应答信号 | 在第九个时钟周期数据信号为低电平 |
非应答信号 | 在第九个时钟周期数据信号为高电平 |
除了上述四个信号外,I2C总线还有着在高电平读取数据,在低电平修改数据的读写时机。
在结合信号与读写时机,就可以根据I2C总线的时序进行通信了。
【I2C总线的时序】
主机向从机写数据只需要遵循以下时序即可,如果数据需要多个数据包只需要重复红框中内容即可
主机向从机读数据
本次实验直接使用I2C库文件进行start、发送数据、接收数据。只需要按照时序排列即可实现通信。这个库函数帮我们封装了通过控制引脚的高低电平来传输数据的函数。直接调用即可
【实验现象】
https://blink.csdn.net/details/1668233?spm=1001.2014.3001.5501
【代码】
main.c
#include "si7006.h"
int main()
{
short tem;
unsigned short hum;
i2c_init();
beep_init();
led_init();
while(1)
{
tem = si7006_read_tem();
hum = si7006_read_hum();
tem = tem * 175.72 / 65536 - 46.85;
hum = hum * 125 / 65535 - 6;
if(tem > 28)
{
beep_once();
bee_once();
}
if(hum > 58)
{
led1_on();
}
else
{
led1_off();
}
printf("tem = %d hum = %d\n", tem, hum);
delay(1000);
}
return 0;
}
si7006.c
#include "si7006.h"
void si7006_init()
{
//iic初始化
i2c_init();
//发起起始信号
i2c_start();
//发送从机地址+写标志
i2c_write_byte(0x80);
//等待从机应答
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_h, tem_l;
//发起起始信号
i2c_start();
//发送从机地址+写标志
i2c_write_byte(0x80);
// 等待从机应答
i2c_wait_ack();
// 发送寄存器地址
i2c_write_byte(0xe3);
// 等待从机应答
i2c_wait_ack();
// 重复起始信号
i2c_start();
// 发送从机地址+读标志
i2c_write_byte(0x81);
// 等待从机应答
i2c_wait_ack();
delay(100); //等待从机测量数据
// 接受数据高8位
tem_h = i2c_read_byte(0);
// 发送应答信号
// 接受数据低8位
tem_l = i2c_read_byte(1);
// 发送非应答
// 将高8位和低8位合成一个数据
tem = tem_h << 8 | tem_l;
// 返回
return tem;
}
unsigned short si7006_read_hum()
{
unsigned short hum;
unsigned char hum_h, hum_l;
i2c_start();
i2c_write_byte(0x80);
i2c_wait_ack();
i2c_write_byte(0xe5);
i2c_wait_ack();
i2c_start();
i2c_write_byte(0x81);
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;
}
si7006.h
#ifndef __SI7006_H__
#define __SI7006_H__
#include "stm32mp1xx_rcc.h"
#include "stm32mp1xx_i2c.h"
#include "stm32mp1xx_gpio.h"
#include "iic.h"
#include "gpio.h"
#include "led.h"
void iic_init();
short si7006_read_tem();
unsigned short si7006_read_hum();
#endif