头文件 iic.h si7006.h
#ifndef __IIC_H__
#define __IIC_H__
#include "stm32mp1xx_rcc.h"
#include "stm32mp1xx_gpio.h"
/*
I2C1_SCL ---> PF14
I2C1_SDA ---> PF15
*/
//发送数据模式
#define SET_SDA_OUT do{GPIOF->MODER &= (~(0x3<<30)); \
GPIOF->MODER |= (0x1<<30);}while(0)
//接收数据模式
#define SET_SDA_IN do{GPIOF->MODER &= (~(0x3<<30));}while(0)
//拉高拉低时钟线
#define SCL_H do{GPIOF->BSRR |= (0x1<<14);}while(0)
#define SCL_L do{GPIOF->BRR |= (0x1<<14);}while(0)
//拉高拉低数据线
#define SDA_H do{GPIOF->BSRR |= (0x1<<15);}while(0)
#define SDA_L do{GPIOF->BRR |= (0x1<<15);}while(0)
//读取当前数据线上的值
#define SDA_READ (GPIOF->IDR & (0x1<<15))
//延时函数
void delay_us();
//IIC初始化
void iic_init();
//起始信号
void iic_start();
//结束信号
void iic_stop();
//发送一个字节
void iic_write_byte(char data);
//接收一个字节
char iic_read_byte(char ack);
//等待应答信号
char iic_wait_ack();
//应答信号
void iic_ack();
//非应答信号
void iic_nack();
#endif
#ifndef __SI7006_H__
#define __SI7006_H__
#include "iic.h"
//si7006初始化
void si7006_init();
//获取数据
short si7006_read_data(char slave_addr, char register_addr);
#endif
功能函数 iic.c si7006.c
#include "iic.h"
//延时函数
void delay_us()
{
int i = 2000;
while (i--);
}
//IIC初始化
void iic_init()
{
/*********RCC使能GPIOF组时钟*********/
RCC->MP_AHB4ENSETR |= (0x1<<5);
/**********GPIO章节配置*************/
//1.模式设置为输出模式 MODER[31:28]=0101
GPIOF->MODER &= (~(0xf<<28));
GPIOF->MODER |= (0x5<<28);
//2.输出类型设置为推挽输出 OTYPER[15:14]=00
GPIOF->OTYPER &= (~(0x3<<14));
//3.输出速度设置为非常高速 OSPEEDR[31:28]=1111
GPIOF->OSPEEDR |= (0xf<<28);
//4.禁止上拉和下拉电阻 PUPDR[31:28]=0000
GPIOF->PUPDR &= (~(0xf<<28));
/***********IIC设置为空闲态*********/
SCL_H; //时钟线拉高
SDA_H; //数据线拉高
}
//起始信号
void iic_start()
{
SET_SDA_OUT;//发送数据模式
SCL_H; //SCL拉高
SDA_H; //SDA拉高
delay_us();
SDA_L; //SDA拉低
delay_us();
SCL_L; //SCL拉低,保持占用状态
}
//停止信号
void iic_stop()
{
SET_SDA_OUT;//设置SDA为输出
SCL_L; //SCL拉低
delay_us();
SDA_L; //SDA拉低
delay_us();
SCL_H; //SCL拉高
delay_us();
SDA_H; //SDA拉高
delay_us();
}
//发送一个字节
void iic_write_byte( char data)
{
SET_SDA_OUT; //发送数据模式
int i;
for (i = 0 ; i < 8; i++) {
SCL_L; //SCL拉低
delay_us();
if (data & 0x80)//判断最高位的值
{
SDA_H; //写入高电平
}else
{
SDA_L; //写入低电平
}
delay_us();
SCL_H; //SCL拉高
delay_us();
delay_us();
data <<= 1; //左移1位
}
}
//接收一个字节
char iic_read_byte( char ack)
{
unsigned char data;
unsigned int i;
SET_SDA_IN; //设置SDA为输入
for (i = 0; i < 8; i++) {
SCL_L; //SCL拉低
delay_us();
delay_us(); //保证数据写完
SCL_H; //SCL拉高
delay_us();
data <<= 1;
if (SDA_READ)
data |= 1;//读到1
else
data |= 0;//读到0
delay_us();
}
if (!ack)
iic_ack(); //发送应答信号
else
iic_nack(); //发送非应答信号
return data;
}
//等待应答信号
char iic_wait_ack()
{
int ack;
SCL_L; //SCL拉低
delay_us();
SDA_H; //SDA拉高, 释放总线
SET_SDA_IN;
delay_us();
SCL_H;
delay_us();
if (SDA_READ)
{
ack = 1; //非应答信号
}else
{
ack = 0; //应答信号
}
delay_us();
SCL_L;
return ack;
}
//应答信号
void iic_ack()
{
SET_SDA_OUT; //发送数据模式
SCL_L; //SCL拉低
delay_us();
SDA_L; //SDA拉低,应答信号
delay_us();
SCL_H; //SCL拉高
delay_us();
delay_us(); //等待从机接收应答信号
SCL_L; //SCL拉低
}
void iic_nack()
{
SET_SDA_OUT; //发送数据模式
SCL_L; //SCL拉低
delay_us();
SDA_H; //SDA拉高,非应答信号
delay_us();
SCL_H; //SCL拉高
delay_us();
delay_us(); //等待从机接收应答信号
SCL_L; //SCL拉低
}
#include "iic.h"
#include "si7006.h"
extern void delay_ms(unsigned int ms);
//SI7006初始化
void si7006_init()
{
//IIC初始化
iic_init();
//起始信号
iic_start();
//发送从机地址
iic_write_byte(0x40<<1);
iic_wait_ack();
//发送寄存器地址
iic_write_byte(0xe6);
iic_wait_ack();
//发送初始值
iic_write_byte(0x3a);
iic_wait_ack();
//结束信号
iic_stop();
}
//获取数据
short si7006_read_data(char slave_addr, char register_addr)
{
//接收的数据
short data;
//接收高8位,低8位
char data_h, data_l;
//起始信号
iic_start();
//发送从机地址+w
iic_write_byte(slave_addr << 1);
iic_wait_ack();
//发送寄存器地址
iic_write_byte(register_addr);
iic_wait_ack();
iic_start();
//发送从机地址+r
iic_write_byte((slave_addr << 1) | 0x1);
iic_wait_ack();
delay_ms(100); // 等待转换结束之后在读取测量的结果
data_h = iic_read_byte(0);//高8位
data_l = iic_read_byte(1);//低8位
//结束信号
iic_stop();
data = data_h;
data <<= 8;
data |= data_l;
return data;
}
主函数 main.c
#include "iic.h"
#include "si7006.h"
extern void printf(const char *fmt, ...);
void delay_ms(unsigned int ms)
{
int i, j;
for (i = 0; i < ms; i++)
for (j = 0; j < 1800; j++)
;
}
int main()
{
short hum;
short temp;
si7006_init();
while (1)
{
hum = si7006_read_data(0x40, 0xe5);
temp = si7006_read_data(0x40, 0xe3);
printf("temp = %d\thum = %d\n", temp*176/65536-47,hum*125/65536-6);
delay_ms(1000);
}
return 0;
}
测试结果: