目录
iic.h
iic.c
ap3216c.h
ap3216.c
main.c
实验效果
iic.h
#ifndef __IIC_H__
#define __IIC_H__
#include "stm32mp1xx_gpio.h"
#include "stm32mp1xx_rcc.h"
//SDA 数据线为PF15
//SCL 时钟线为PF14
//配置PF15为输出模式
#define SET_SDA_OUT do{GPIOF->MODER &=(~(0x3<<30));\
GPIOF->MODER |=(0x1<<30);}while(0)
//配置PF15为输入模式
#define SET_SDA_IN do{GPIOF->MODER &=(~(0x3<<30));}while(0)
//读取PF15输入寄存器的值
#define I2C_SDA_READ GPIOF->IDR & (0x1<<15)
//PF14输出高电平、低电平
#define I2C_SCL_H do{GPIOF->BSRR |= (0x1<<14);}while(0)
#define I2C_SCL_L do{GPIOF->BRR |= (0x1<<14);}while(0)
//PF15输入高电平、低电平
#define I2C_SDA_H do{GPIOF->BSRR |= (0x1<<15);}while(0)
#define I2C_SDA_L do{GPIOF->BRR |= (0x1<<15);}while(0)
void delay_us(void);
//模拟I2C
void i2c_init(void);
void i2c_start(void);
void i2c_stop(void);
void i2c_write_byte(unsigned char dat);
unsigned char i2c_read_byte(unsigned char ack);
unsigned char i2c_wait_ack(void);
void i2c_ack(void);
void i2c_nack(void);
#endif
iic.c
#include "iic.h"
//微妙级的延时
void delay_us(void){
unsigned int i=2000;
while(i--);
}
//模拟I2C
//I2C初始化
void i2c_init(void){
//GPIOF时钟使能
RCC->MP_AHB4ENSETR |= (0x1<<5);
//配置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和SDA输出高电平
I2C_SCL_H;
I2C_SDA_H;
}
//发送起始信号
void i2c_start(void){
//设置SDA为输出模式
SET_SDA_OUT;
//拉高数据线和时钟线
I2C_SCL_H;
I2C_SDA_H;
delay_us(); //延时
//拉低数据线
I2C_SDA_L;
delay_us(); //延时
//拉低时钟线
I2C_SCL_L;
}
//发送停止信号
void i2c_stop(void){
//设置SDA为输出模式
SET_SDA_OUT;
//拉低时钟线
I2C_SCL_L;
delay_us();
delay_us();
//修改数据线为低电平
I2C_SDA_L;
delay_us();
//拉高时钟线
I2C_SCL_H;
delay_us();
//拉高数据线
I2C_SDA_H;
}
//发送数据
void i2c_write_byte(unsigned char dat){
unsigned int i;
//PF14配置为输出模式
SET_SDA_OUT;
for(i=0;i<8;i++){
//拉低时钟线
I2C_SCL_L;
delay_us();
//修改数据线的值
if(dat&(0x1<<7)){
I2C_SDA_H;
}
else{
I2C_SDA_L;
}
delay_us();
//拉高时钟线
I2C_SCL_H;
delay_us(); //拉高是时钟线后延时
delay_us(); //延时等待从机读取
dat<<=1;
}
}
//读取数据
unsigned char i2c_read_byte(unsigned char ack){
//配置为输入模式
SET_SDA_IN;
unsigned char data;
for(unsigned int i=0;i<8;i++){
//从机需要向寄存器写入数据
//所有需要拉低时钟线
I2C_SCL_L;
delay_us(); //延时
delay_us(); //等待从机写入数据
//拉高时钟线读取数据
I2C_SCL_H;
delay_us(); //延时
data<<=1;
if(I2C_SDA_READ){
data|=0x1;
}
else data|=0x0;
}
if(!ack){
i2c_nack();
}
else{
i2c_ack();
}
//返回读取的数值
return data;
}
//等带从机ack
unsigned char i2c_wait_ack(void){
//拉低时钟线,修改SDA电平
I2C_SCL_L;
delay_us();
I2C_SDA_H; //释放给从机
delay_us();
//SDA配置为输入模式
SET_SDA_IN;
delay_us();
delay_us();
//拉高时钟线读取从机ack
I2C_SCL_H;
delay_us();
if(I2C_SDA_READ){
return 1;
}
I2C_SCL_L;
return 0;
}
//ack应答
void i2c_ack(void){
//配置为输出模式
SET_SDA_OUT;
//拉低时钟线
I2C_SCL_L;
delay_us();
//拉低数据线
I2C_SDA_L;
delay_us();
//拉高时钟线
I2C_SCL_H;
delay_us();
delay_us();
//拉低时钟线?
I2C_SCL_L;
}
//非ack应答
void i2c_nack(void){
//配置为输出模式
SET_SDA_OUT;
//拉低时钟线
I2C_SCL_L;
delay_us();
//拉高数据线
I2C_SDA_H;
delay_us();
//拉高时钟线
I2C_SCL_H;
delay_us();
delay_us();
//拉低时钟线?
I2C_SCL_L;
}
ap3216c.h
#ifndef __AP3216C_H__
#define __AP3216C_H__
//ap3216c初始化
void ap3216c_init();
void ap3216c_init1();
//读取ap3216c环境光
unsigned char ap3216c_read_alsl();
unsigned char ap3216c_read_alsh();
#endif
ap3216.c
#include "ap3216c.h"
#include "iic.h"
//ap3216c初始化
void ap3216c_init(){
//发送起始信号
i2c_start();
//发送七位从机地址+1位写标志 0x1E | 0x0 = 0x3c
i2c_write_byte(0x3c);
//等待从机应答
i2c_wait_ack();
//发送8位寄存器地址0x00
i2c_write_byte(0x00);
//等待从机应答
i2c_wait_ack();
//写入数据0x3A,si7006初始值
i2c_write_byte(0x1);
//等待应答
i2c_wait_ack();
//发送停止信号
i2c_stop();
}
//读取ap3216c环境光
unsigned char ap3216c_read_alsl(){
//发送起始信号
i2c_start();
//发送七位从机地址+1位写标志 0x1E | 0x0 = 0x3C
i2c_write_byte(0x3C);
//等待从机应答
i2c_wait_ack();
//发送8位寄存器地址0xE3
i2c_write_byte(0x0C);
//等待从机应答
i2c_wait_ack();
//发送重复开始信号
i2c_start();
//发送从机地址和读写标志 0x40 | 0x1 = 0x81
i2c_write_byte(0x3D);
//等待从机应答
i2c_wait_ack();
//读取环境光
char als_l;
als_l=i2c_read_byte(1);
//发送应答
//发送停止信号
i2c_stop();
return als_l;
}
//读取ap3216c环境光
unsigned char ap3216c_read_alsh(){
//发送起始信号
i2c_start();
//发送七位从机地址+1位写标志 0x1E | 0x0 = 0x3C
i2c_write_byte(0x3C);
//等待从机应答
i2c_wait_ack();
//发送8位寄存器地址0xE3
i2c_write_byte(0x0D);
//等待从机应答
i2c_wait_ack();
//发送重复开始信号
i2c_start();
//发送从机地址和读写标志 0x40 | 0x1 = 0x81
i2c_write_byte(0x3D);
//等待从机应答
i2c_wait_ack();
//读取环境光
char als_h;
als_h=i2c_read_byte(1);
//发送应答
//发送停止信号
i2c_stop();
return als_h;
}
main.c
#include "gpio.h"
#include "led.h"
#include "uart4.h"
#include "keyip.h"
#include "iic.h"
#include "si7006.h"
#include "ap3216c.h"
extern void printf(const char *fmt, ...);
int main()
{
led1_init();
i2c_init();
ap3216c_init();
unsigned short als;
unsigned char als_l;
unsigned char als_h;
while (1)
{
als_l=ap3216c_read_alsl(1);
als_h=ap3216c_read_alsh(1);
als=((unsigned short)als_h<<8) | als_l;
printf("als=%d\n",als);
if(als<100){
led1_ctl(1);
}
else{
led1_ctl(0);
}
delay(1000);
}
return 0;
}
实验效果