I2C.h
#ifndef I2C_DRIVER_H
#define I2C_DRIVER_H
#include "gpio.h"
#define NACK 1
#define ACK 0
#define SCL_PIN 14
#define SCL_PORT GPIOF
#define SCL_PIN_CLK_EN() do{RCC->MP_AHB4ENSETR |= (0x1 << 5);}while(0)
#define SDA_PIN 15
#define SDA_PORT GPIOF
#define SDA_PIN_CLK_EN() do{RCC->MP_AHB4ENSETR |= (0x1 << 5);}while(0)
#define SCL_H() do{GPIOF->BSRR |= (0x1 << 14);}while(0)
#define SCL_L() do{GPIOF->BRR |= (0x1 << 14);}while(0)
#define SCL_INPUT() (GPIOF->IDR & (0x1 << 14))
#define SDA_H() do{GPIOF->BSRR |= (0x1 << 15);}while(0)
#define SDA_L() do{GPIOF->BRR |= (0x1 << 15);}while(0)
#define SDA_INPUT() (GPIOF->IDR & (0x1 << 15))
#define I2C_Delay() us_timer_delay(10)
void us_timer_delay(unsigned short t);
void I2C_Init(void);
void I2C_SDA_OUT(void);
void I2C_SDA_IN(void);
void I2C_Start(void);
void I2C_Stop(void);
void I2C_ACK(void);
void I2C_NACK(void);
unsigned char I2C_GetACK(void);
void I2C_SendByte(unsigned char data);
unsigned char I2C_ReadByte(unsigned char ack);
#endif
I2C.C
#include "i2c_driver.h"
void us_timer_delay(unsigned short t)
{
unsigned short counter = 0;
while(t--)
{
counter=10;
while(counter--);
}
}
/* 初始化两个引脚 */
void I2C_Init(void)
{
/* 使能RCC时钟 */
SCL_PIN_CLK_EN();
// 设置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));
/* 拉高引脚电平 */
SCL_H();
SDA_H();
}
/* 配置SDA引脚为输出 */
void I2C_SDA_OUT(void)
{
GPIOF->MODER &= (~(0x3 << 30));
GPIOF->MODER |= (0x1 << 30);
}
/* 配置SDA引脚为输入 */
void I2C_SDA_IN(void)
{
GPIOF->MODER &= (~(0x3 << 30));
}
/* 开始信号 */
void I2C_Start(void)
{
I2C_SDA_OUT();
SCL_H();
I2C_Delay();
SDA_H();
I2C_Delay();
SDA_L();
I2C_Delay();
SCL_L();
I2C_Delay();
}
/* I2C停止信号 */
void I2C_Stop(void)
{
I2C_SDA_OUT();
SCL_L();
I2C_Delay();
SDA_L();
I2C_Delay();
SCL_H();
I2C_Delay();
SDA_H();
I2C_Delay();
}
/* I2C发出应答信号 */
void I2C_ACK(void)
{
I2C_SDA_OUT();
SCL_L();
I2C_Delay();
SDA_L();
I2C_Delay();
SCL_H();
I2C_Delay();
I2C_Delay();
SCL_L();
I2C_Delay();
}
/* I2C发出非应答信号 */
void I2C_NACK(void)
{
I2C_SDA_OUT();
SCL_L();
I2C_Delay();
SDA_H();
I2C_Delay();
SCL_H();
I2C_Delay();
I2C_Delay();
SCL_L();
I2C_Delay();
}
unsigned char I2C_GetACK(void)
{
unsigned char time = 0;
SDA_H();
SCL_L();
I2C_Delay();
I2C_SDA_IN();
I2C_Delay();
I2C_Delay();
SCL_H();
I2C_Delay();
while (SDA_INPUT())
{
time++;
if(time>250)
{
SCL_L();
return 1;
}
}
SCL_L();
return 0;
}
void I2C_SendByte(unsigned char data)
{
unsigned int cnt = 0;
I2C_SDA_OUT();
for(cnt=0; cnt<8; cnt++)
{
SCL_L();
I2C_Delay();
if(data & 0x80)
{
SDA_H();
}
else
{
SDA_L();
}
I2C_Delay();
SCL_H();
I2C_Delay();
I2C_Delay();
data = data<<1;
I2C_Delay();
}
SCL_L();
I2C_Delay();
I2C_GetACK();
}
unsigned char I2C_ReadByte(unsigned char ack)
{
unsigned int cnt;
unsigned char data = 0xff;
for(cnt=0; cnt<8; cnt++)
{
SCL_L();
I2C_Delay();
I2C_Delay();
SCL_H();
I2C_Delay();
data <<= 1;
if(SDA_INPUT())
{
data |= 0x01;
}
I2C_Delay();
}
if(ack == 0)
{
I2C_ACK();
}
else
{
I2C_NACK();
}
return data;
}
SPI.h
#ifndef __SPI_H__
#define __SPI_H__
#include "stm32mp1xx_gpio.h"
#include "stm32mp1xx_rcc.h"
// MOSI对应的引脚输出高低电平的信号
#define MOSI_OUTPUT_H() do{GPIOE->ODR |= (0x1 << 14);}while(0)
#define MOSI_OUTPUT_L() do{GPIOE->ODR &= (~(0x1 << 14));}while(0)
// 对应595芯片的锁存引脚输出高低电平
#define NSS_OUTPUT_H() do{GPIOE->ODR |= (0x1 << 11);}while(0)
#define NSS_OUTPUT_L() do{GPIOE->ODR &= (~(0x1 << 11));}while(0)
// 时钟信号对应的引脚输出高低电平
#define SCK_OUTPUT_H() do{GPIOE->ODR |= (0x1 << 12);}while(0)
#define SCK_OUTPUT_L() do{GPIOE->ODR &= (~(0x1 << 12));}while(0)
static delay_us(unsigned int us);
/*
* 函数功能: SPI初始化函数,推挽输出,高速,禁止上拉和下拉
* 函数参数:无
* 函数返回值:无
*/
void SPI_init(void);
/*
* 函数功能:SPI发送数据的函数
* 函数参数:dat : 要发送的数据
* 函数返回值:无
*
*/
void SPI_write(unsigned char dat);
#endif // __SPI_H__
SPI.c
#include "spi.h"
/*
SPI4_NSS PE11
SPI4_SCK PE12
SPI4_MOSI PE14
SPI4_MISO PE13
*/
static delay_us(unsigned int us)
{
int i = 0;
int j = 0;
for(i=0; i<us; i++)
{
for(j=0; j<10;j++);
}
}
void SPI_init(void)
{
/* RCC时钟使能 */
RCC->MP_AHB4ENSETR |= (0x1<<4);
/* MOSI引脚配置 */
GPIOE->MODER &= (~(0x3 << 28));
GPIOE->MODER |= (0x1 << 28);
GPIOE->OTYPER &= (~(0x1 << 14));
GPIOE->OSPEEDR &=(~(0x3 << 28));
GPIOE->PUPDR &= (~(0x3 << 28));
/* MISO引脚配置 */
GPIOE->MODER &= (~(0x3 << 26));
GPIOE->OTYPER &= (~(0x1 << 13));
GPIOE->OSPEEDR &=(~(0x3 << 26));
GPIOE->PUPDR &= (~(0x3 << 28));
/* SCLK引脚配置 */
GPIOE->MODER &= (~(0x3 << 24));
GPIOE->MODER |= (0x1 << 24);
GPIOE->OTYPER &= (~(0x1 << 12));
GPIOE->OSPEEDR &=(~(0x3 << 24));
GPIOE->PUPDR &= (~(0x3 << 24));
/* CS引脚配置 */
GPIOE->MODER &= (~(0x3 << 22));
GPIOE->MODER |= (0x1 << 22);
GPIOE->OTYPER &= (~(0x1 << 11));
GPIOE->OSPEEDR &=(~(0x3 << 22));
GPIOE->PUPDR &= (~(0x3 << 22));
/* CS引脚拉低电平起始信号 */
NSS_OUTPUT_L();
/* SPI时钟线拉低 */
SCK_OUTPUT_L();
}
void SPI_write(unsigned char dat)
{
unsigned char i;
for(i=0; i<8; i++)
{
if(dat & 0x01)
{
MOSI_OUTPUT_H();
}
else
{
MOSI_OUTPUT_L();
}
dat>>=1;
/* 时钟线电平上升沿,数据写入 */
SCK_OUTPUT_L();
delay_us(5);
SCK_OUTPUT_H();
delay_us(5);
}
}
SI7006.h
#ifndef SI7006_H
#define SI7006_H
#include "i2c_driver.h"
void delay_ms(unsigned int ms);
void si7006_init(void);
unsigned short si7006_read_hum_data(unsigned char slave_addr,
unsigned char cmd_code);
short si7006_read_temp_data(unsigned char slave_addr,
unsigned char cmd_code);
#endif
SI7006.c
#include "i2c_driver.h"
#include "si7006.h"
void delay_ms(unsigned int ms)
{
unsigned int i = 0;
unsigned int j = 0;
for(i=0; i<ms; i++)
{
for(j=0; j<2000; j++);
}
}
/*
* 函数名:si7006_init
* 函数功能:SI7006芯片的初始化
* 函数参数:无
* 函数返回值:无
*/
void si7006_init(void)
{
I2C_Init();
I2C_Start();
I2C_SendByte(0x40 << 1 | 0);
I2C_SendByte(0xE6);
I2C_SendByte(0x3A);
I2C_Stop();
}
/*
* 函数名:si7006_read_hum_data
* 函数功能:读取SI7006的湿度转换结果
* 函数参数:
* slave_addr : 从机地址
* cmd_code : 命令码
* 函数返回值:湿度测量的数字量
*/
unsigned short si7006_read_hum_data(unsigned char slave_addr,
unsigned char cmd_code)
{
unsigned short data;
unsigned char d_h;
unsigned char d_l;
I2C_Start();
I2C_SendByte(slave_addr << 1 | 0);
I2C_SendByte(cmd_code);
I2C_Start();
I2C_SendByte(slave_addr << 1 | 1);
delay_ms(2000);
d_h = I2C_ReadByte(ACK);
d_l = I2C_ReadByte(NACK);
I2C_Stop();
data = (d_h<<8)|d_l;
return data;
}
/*
* 函数名:si7006_read_temp_data
* 函数功能:读取SI7006的温度转换结果
* 函数参数:
* slave_addr : 从机地址
* cmd_code : 命令码
* 函数返回值:温度测量的数字量
*/
short si7006_read_temp_data(unsigned char slave_addr,
unsigned char cmd_code)
{
short data;
unsigned char d_h;
unsigned char d_l;
I2C_Start();
I2C_SendByte(slave_addr << 1 | 0);
I2C_SendByte(cmd_code);
I2C_Start();
I2C_SendByte(slave_addr << 1 | 1);
delay_ms(2000);
d_h = I2C_ReadByte(ACK);
d_l = I2C_ReadByte(NACK);
I2C_Stop();
data = (d_h<<8)|d_l;
return data;
}
main.c
#include "key_it.h"
#include "uart.h"
#include "beep.h"
#include "si7006.h"
#include "spi.h"
void delay(volatile unsigned int d)
{
int i,j;
for(i = 0; i < d;i++)
for (j = 0; j < 1800; j++);
}
static int num[10] = {0xFC,0x60,0xDA,0xF2,0x66,0xB6,0xBE,0xE0,0xFE,0xF6};
static int data[5] = {0};
int main(void)
{
unsigned short hum;
unsigned short h_g;
unsigned short h_s;
short tem;
short t_g;
short t_s;
unsigned char i;
unsigned int j;
si7006_init();
SPI_init();
while(1)
{
j = 800;
hum = si7006_read_hum_data(0x40, 0xE5);
tem = si7006_read_temp_data(0x40, 0xE3);
hum = 125*hum/65536-6;
tem = 175.72*tem/65536-46.85;
h_s = hum / 10;
h_g = hum % 10;
t_s = tem / 10;
t_g = tem % 10;
data[0] = num[t_s];
data[1] = num[t_g]+1;
data[2] = num[h_s];
data[3] = num[h_g];
printf("tem = %d\n\r", tem);
printf("hum = %d\n\r", hum);
while(j--)
{
for(i = 0; i < 5; i++)
{
SPI_write(0x80 >> i);
SPI_write(data[i]);
NSS_OUTPUT_L();
delay_ms(1);
NSS_OUTPUT_H();
}
}
}
return 0;
}
效果图
小数点仅作为分割数字使用,两边各自是两个整数