程序由STM32中移植分离出来,目前在其他类型开发板上测试也能成功
myiic.h
#ifndef __MYIIC_H__
#define __MYIIC_H__
#include "gpio.h"
#include "uart.h"
#include "app_user_api.h"
//#include "stdio.h"
#include <math.h>
//
//本程序只供学习使用,未经作者许可,不得用于其它任何用途
//宇文工作室编写
//IIC驱动 代码
//宇文工作室@haitian
//修改日期:2023/9/9
//All rights reserved
//
//#define SCLK 0X04
//#define SDAT 0X05
//extern void Delay_us(int num);
//extern void Delay_ms(int num);
//#define delay_us Delay_us
//#define delay_ms Delay_ms
void iic_delay_us(uint16_t dly_cnt);
void iic_delay_ms(uint16_t dly_cnt);
#define delay_us iic_delay_us
#define delay_ms iic_delay_ms
//下面需更改成为自己使用的开发板类型
//IO方向设置
#define SDA_OUT() gpio_config(SDAT,OUTPUT,PULL_NONE)//SDA设置为输出
#define SDA_IN() gpio_config(SDAT,INPUT,PULL_NONE)//SDA设置为输入
//IO操作函数
#define SCL0_HIGH() gpio_set(SCLK,1)//SCL置高
#define SCL0_LOW() gpio_set(SCLK,0)//SCL置低
#define SDA0_HIGH() gpio_set(SDAT,1)//SDA置高
#define SDA0_LOW() gpio_set(SDAT,0)//SDA置低
#define SDA0_READ() gpio_get_input(SDAT)//获取SDA电平状态
//IIC所有操作函数
void IIC_Init(void); //初始化IIC的IO口
void IIC_Start(void); //发送IIC开始信号
void IIC_Stop(void); //发送IIC停止信号
void IIC_Send_Byte(uint8_t txd); //IIC发送一个字节
uint8_t IIC_Read_Byte(unsigned char ack);//IIC读取一个字节
uint8_t IIC_Wait_Ack(void); //IIC等待ACK信号
void IIC_Ack(void); //IIC发送ACK信号
void IIC_NAck(void); //IIC不发送ACK信号
void IIC_Write_One_Byte(uint8_t daddr,uint8_t addr,uint8_t data);
uint8_t IIC_Read_One_Byte(uint8_t daddr,uint8_t addr);
#define Soft_I2C_READY 0x00
#define Soft_I2C_BUS_BUSY 0x01
#define Soft_I2C_BUS_ERROR 0x02
#define I2C_Direction_Transmitter 0x00
#define I2C_Direction_Receiver 0x01
int Sensors_I2C_ReadRegister(unsigned char Address, unsigned char RegisterAddr,
unsigned short RegisterLen, unsigned char *RegisterValue);
int Sensors_I2C_WriteRegister(unsigned char Address, unsigned char RegisterAddr,
unsigned short RegisterLen, const unsigned char *RegisterValue);
#endif
myiic.c
#include "myiic.h"
//
//本程序只供学习使用,未经作者许可,不得用于其它任何用途
//宇文工作室编写
//IIC驱动 代码
//宇文工作室@haitian
//修改日期:2023/9/9
//All rights reserved
//
void iic_delay_us(uint16_t dly_cnt)
{
while(dly_cnt--)
{
__nop();
__nop();
}
}
void iic_delay_ms(uint16_t dly_cnt)
{
while(dly_cnt--)
{
iic_delay_us(1000);
}
}
//初始化IIC
void IIC_Init(void)
{
gpio_config(SCLK,OUTPUT,PULL_HIGH);
gpio_config(SDAT,OUTPUT,PULL_HIGH);
// SCL0_HIGH();
// SDA0_HIGH();
// delay_ms(100);
}
//产生IIC起始信号
void IIC_Start(void)
{
SDA_OUT(); //sda线输出
SDA0_HIGH();
SCL0_HIGH();
delay_us(4);
SDA0_LOW();//START:when CLK is high,DATA change form high to low
delay_us(4);
SCL0_LOW();//钳住I2C总线,准备发送或接收数据
}
//产生IIC停止信号
void IIC_Stop(void)
{
SDA_OUT();//sda线输出
SCL0_LOW();
SDA0_LOW();//STOP:when CLK is high DATA change form low to high
delay_us(4);
SCL0_HIGH();
SDA0_HIGH();//发送I2C总线结束信号
delay_us(4);
}
//等待应答信号到来
//返回值:1,接收应答失败
// 0,接收应答成功
uint8_t IIC_Wait_Ack(void)
{
uint8_t ucErrTime=0;
SDA_IN(); //SDA设置为输入
SDA0_HIGH();delay_us(1);
SCL0_HIGH();delay_us(1);
while(SDA0_READ())
{
ucErrTime++;
if(ucErrTime>250)
{
IIC_Stop();
return 1;
}
}
SCL0_LOW();//时钟输出0
return 0;
}
//产生ACK应答
void IIC_Ack(void)
{
SCL0_LOW();
SDA_OUT();
SDA0_LOW();
delay_us(2);
SCL0_HIGH();
delay_us(2);
SCL0_LOW();
}
//不产生ACK应答
void IIC_NAck(void)
{
SCL0_LOW();
SDA_OUT();
SDA0_HIGH();
delay_us(2);
SCL0_HIGH();
delay_us(2);
SCL0_LOW();
}
//IIC发送一个字节
//返回从机有无应答
//1,有应答
//0,无应答
void IIC_Send_Byte(uint8_t txd)
{
uint8_t t;
SDA_OUT();
SCL0_LOW();//拉低时钟开始数据传输
for(t=0;t<8;t++)
{
// gpio_set(SDAT,(txd&0x80)>>7);
if((txd&0x80)>>7)
SDA0_HIGH();
else
SDA0_LOW();
txd<<=1;
delay_us(2); //对TEA5767这三个延时都是必须的
SCL0_HIGH();
delay_us(2);
SCL0_LOW();
delay_us(2);
}
}
//读1个字节,ack=1时,发送ACK,ack=0,发送nACK
uint8_t IIC_Read_Byte(unsigned char ack)
{
unsigned char i,receive=0;
SDA_IN();//SDA设置为输入
for(i=0;i<8;i++ )
{
SCL0_LOW();
delay_us(2);
SCL0_HIGH();
receive<<=1;
if(SDA0_READ())receive++;
delay_us(1);
}
if (!ack)
IIC_NAck();//发送nACK
else
IIC_Ack(); //发送ACK
return receive;
}
static uint8_t Soft_I2C_SendByte(uint8_t soft_i2c_data)//发送一字节,带返回
{
uint8_t i;
SDA_OUT();
SCL0_LOW();
for(i=0; i<8; i++)
{
if(soft_i2c_data & 0x80)
SDA0_HIGH();
else
SDA0_LOW();
soft_i2c_data <<= 1;
delay_us(10);
SCL0_HIGH();
delay_us(10);
SCL0_LOW();
delay_us(10);
}
//return Soft_I2C_Wait_Ack();
return IIC_Wait_Ack();
}
static uint8_t Soft_I2C_ReceiveByte(void)//接收一字节,带返回
{
uint8_t i,soft_i2c_data;
SDA0_HIGH();
SCL0_LOW();
soft_i2c_data = 0;
SDA_IN(); //SDA设置为输入
for(i=0; i<8; i++)
{
SCL0_HIGH();
delay_us(10);
soft_i2c_data <<= 1;
if(SDA0_READ())
soft_i2c_data |= 0x01;
SCL0_LOW();
delay_us(10);
}
// Soft_I2C_SendNACK();
IIC_NAck();
return soft_i2c_data;
}
static uint8_t Soft_I2C_ReceiveByte_WithACK(void)//接收应答
{
uint8_t i,soft_i2c_data;
SDA0_HIGH();
SCL0_LOW();
soft_i2c_data = 0;
SDA_IN(); //SDA设置为输入
for(i=0; i<8; i++)
{
SCL0_HIGH();
delay_us(10);
soft_i2c_data <<= 1;
if(SDA0_READ())
soft_i2c_data |= 0x01;
SCL0_LOW();
delay_us(10);
}
// Soft_I2C_SendACK();
IIC_Ack();
return soft_i2c_data;
}
static uint8_t Soft_DMP_I2C_Write(uint8_t soft_dev_addr, uint8_t soft_reg_addr, uint8_t soft_i2c_len,unsigned char *soft_i2c_data_buf)
{
uint8_t i, result = 0;
//Soft_I2C_START();
IIC_Start();
result = Soft_I2C_SendByte(soft_dev_addr << 1 | I2C_Direction_Transmitter);
if(result != 0) return result;
result = Soft_I2C_SendByte(soft_reg_addr);
if(result != 0) return result;
for (i=0; i<soft_i2c_len; i++)
{
result = Soft_I2C_SendByte(soft_i2c_data_buf[i]);
if (result != 0) return result;
}
// Soft_I2C_STOP();
IIC_Stop();
return 0x00;
}
static uint8_t Soft_DMP_I2C_Read(uint8_t soft_dev_addr, uint8_t soft_reg_addr, uint8_t soft_i2c_len,unsigned char *soft_i2c_data_buf)
{
uint8_t result;
// Soft_I2C_START();
IIC_Start();
result = Soft_I2C_SendByte(soft_dev_addr << 1 | I2C_Direction_Transmitter);
if(result != 0) return result;
result = Soft_I2C_SendByte(soft_reg_addr);
//printf("addr:0x%x\n",result);
if(result != 0) return result;
// Soft_I2C_START();
IIC_Start();
result = Soft_I2C_SendByte(soft_dev_addr << 1 | I2C_Direction_Receiver);
if(result != 0) return result;
while (soft_i2c_len)
{
if (soft_i2c_len == 1)
*soft_i2c_data_buf = Soft_I2C_ReceiveByte();
else
*soft_i2c_data_buf = Soft_I2C_ReceiveByte_WithACK();
soft_i2c_data_buf ++;
soft_i2c_len --;
}
// Soft_I2C_STOP();
IIC_Stop();
return 0x00;
}
/**
* @brief 向IIC设备的寄存器连续写入数据,带超时重试设置,供mpu接口调用
* @param Address: IIC设备地址
* @param RegisterAddr: 寄存器地址
* @param RegisterLen: 要写入数据的长度
* @param RegisterValue: 要指向写入数据的指针
* @retval 0正常,非0异常
*/
int Sensors_I2C_WriteRegister(unsigned char slave_addr,
unsigned char reg_addr,
unsigned short len,
const unsigned char *data_ptr)
{
char retries = 0;
int ret = 0;
unsigned short retry_in_mlsec = 5;
tryWriteAgain:
ret = 0;
ret = Soft_DMP_I2C_Write( slave_addr, reg_addr, len, ( unsigned char *)data_ptr);
if(ret && retry_in_mlsec)
{
if( retries++ > 4 )
return ret;
delay_ms(retry_in_mlsec);
goto tryWriteAgain;
}
return ret;
}
/**
* @brief 向IIC设备的寄存器连续读出数据,带超时重试设置,供mpu接口调用
* @param Address: IIC设备地址
* @param RegisterAddr: 寄存器地址
* @param RegisterLen: 要读取的数据长度
* @param RegisterValue: 指向存储读出数据的指针
* @retval 0正常,非0异常
*/
int Sensors_I2C_ReadRegister(unsigned char slave_addr,
unsigned char reg_addr,
unsigned short len,
unsigned char *data_ptr)
{
char retries = 0;
int ret = 0;
unsigned short retry_in_mlsec = 5;
tryReadAgain:
ret = 0;
ret = Soft_DMP_I2C_Read( slave_addr, reg_addr, len, ( unsigned char *)data_ptr);
if(ret && retry_in_mlsec)
{
if( retries++ > 4 )
return ret;
delay_ms(retry_in_mlsec);
goto tryReadAgain;
}
return ret;
}