iic.h
#ifndef __IIC_H__
#define __IIC_H__
#include "stm32mp1xx_rcc.h"
#include "stm32mp1xx_gpio.h"
#include "stm32mp1xx_i2c.h"
/*
* CLK---->PF14
* SDA---->PF15
*/
//初始化RCC、GPIO、IIC空闲态
void iic_init();
//IIC主机发送(SDA引脚为输入模式)
#define SET_WRITE do{GPIOF->MODER &= (~(0x3<<30));}while(0)
//IIC主机接收(SDA引脚为输出模式)
#define SET_READ do{GPIOF->MODER &= (~(0x3<<30));\
GPIOF->MODER |= (0x1<<30);}while(0)
//CLK高电平
#define CLK_H do{GPIOF->BSRR |= (0x1<<14);}while(0)
//CLK低电平
#define CLK_L do{GPIOF->BRR |= (0x1<<14);}while(0)
//SDA高电平
#define SDA_H do{GPIOF->BSRR |= (0x1<<15);}while(0)
//SDA低电平
#define SDA_L do{GPIOF->BRR |= (0x1<<15);}while(0)
//获取SDA当前值
#define SDA_READ (GPIOF->IDR & (0x1<<15))
//延时函数
void delay_us();
//开始信号
void start();
//停止信号
void stop();
//发送数据
void write_byte(unsigned char data);
//读取数据
unsigned char read_byte(unsigned char reack);
//等待应答
unsigned char wait_ack();
//应答
void ack();
//非应答
void no_ack();
#endif
iic.c
#include "iic.h"
/*
* CLK---->PF14
* SDA---->PF15
*/
//初始化RCC、GPIO、IIC空闲态
void iic_init()
{
//GPIOF组使能
RCC->MP_AHB4ENSETR |= (0x1<<5);
//设置输出模式
GPIOF->MODER &= (~(0xf<<28));
GPIOF->MODER |= (0x5<<28);
//设置输出类型为推挽输出
GPIOF->OTYPER &= (~(0x3<<14));
//输出速度设置为高速输出
GPIOF->OSPEEDR |= (0xf<<28);
//禁止上下拉电阻
GPIOF->PUPDR &= (~(0xf<<28));
//设置IIC为空闲态
CLK_H;
SDA_H;
}
//延时函数
void delay_us()
{
unsigned short i=2000;
while(i--);
}
//开始信号
void start()
{
//写入模式
SET_WRITE;
//拉高时钟线和数据线
CLK_H;
SDA_H;
//延时
delay_us();
//拉低数据线
SDA_L;
delay_us();
//保持总线被占用状态
CLK_L;
}
//停止信号
void stop()
{
//写入模式
SET_WRITE;
CLK_L;
delay_us();
//拉低数据线
SDA_L;
delay_us();
//拉高时钟线
CLK_H;
delay_us();
//拉高数据线
SDA_H;
delay_us();
}
//发送数据
void write_byte(unsigned char data)
{
SET_WRITE;
unsigned int i;
for(i=0; i<8;i++)
{
//拉低时钟线,准备写入数据
CLK_L;
delay_us();
if(data & 0x80)//取最高位
{
SDA_H;//高位为1写高电平
}else
{
SDA_L;//高位为0写低电平
}
delay_us();
CLK_H;
delay_us();
delay_us();
data <<= 1;//数据左移一位准备发送下一位
}
}
//读取数据
unsigned char read_byte(unsigned char reack)
{
SET_READ;
unsigned int i;
unsigned char data;
for(i=0; i<8; i++)
{
//保证数据写完整
CLK_L;
delay_us();
delay_us();
//拉高时钟线,准备读数据
CLK_H;
delay_us();
data <<= 1;
if(SDA_READ)
{
data |= 1;//读取到1
}else
{
data |= 0;//读取到0
}
delay_us();
}
if(reack)
{
no_ack();//非应答
}else
{
ack();//应答
}
return data;
}
//等待应答
unsigned char wait_ack()
{
SET_WRITE;
CLK_L;
SDA_H;
delay_us();
SET_READ;
CLK_H;
delay_us();
if(SDA_READ)
{
return 1;
}
CLK_L;
return 0;
}
//应答
void ack()
{
SET_WRITE;
CLK_L;
delay_us();
SDA_L;//应答信号
delay_us();
CLK_H;
delay_us();
delay_us();
CLK_L;
}
//非应答
void no_ack()
{
SET_WRITE;
CLK_L;
delay_us();
SDA_H;//非应答信号
delay_us();
CLK_H;
delay_us();
delay_us();
CLK_L;
}
si7006.h
#ifndef __SI7006_H__
#define __SI7006_H__
#include "iic.h"
//初始化si7006
void si7006_init();
//获取数据
unsigned short read_data(unsigned char slave_addr, unsigned char reg_addr);
#endif
si7006.c
#include "si7006.h"
extern void delay_ms(int ms);
//初始化si7006
void si7006_init()
{
iic_init();
start();
write_byte(0x40<<1);
wait_ack();
write_byte(0xE6);
wait_ack();
write_byte(0x3A);
wait_ack();
stop();
}
//获取数据
unsigned short read_data(unsigned char slave_addr, unsigned char reg_addr)
{
unsigned short data;
//高8位和低8位
unsigned char data_h, data_l;
start();
write_byte(slave_addr<<1);
wait_ack();
write_byte(reg_addr);
wait_ack();
write_byte(slave_addr |= 1);
wait_ack();
//转换时间
delay_ms(100);
//读取高8位
data_h = read_byte(0);
//读取低8位
data_l = read_byte(1);
stop();
//把高8位和低8位组合在一起
data = data_h;
data <<= 8;
data |= data_l;
return data;
}
main.c
#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, tem;
si7006_init();
while(1)
{
hum = read_data(0x40, 0xE5);
tem = read_data(0x40, 0xE3);
printf("hum = %d\n", (hum*125)/65536-6);
printf("tem = %d\n", (tem*176)/65536-47);
delay_ms(1000);
}
return 0;
}
实验结果: