裸机软件IIC 通用的驱动(未添加互斥)

裸机软件IIC 通用的驱动(未添加互斥)

软件IIC接口

#ifndef __BSP_IIC_H__
#define	__BSP_IIC_H__
#include "stdint.h"

#define BSP_SOFT_I2C_WR	0		/* 写控制bit */
#define BSP_SOFT_I2C_RD	1		/* 读控制bit */

//#define bsp_soft_iic_delay_us(x)			bsp_delay_us(x)		//根据不同平台定义微秒延时
#ifndef bsp_soft_iic_delay_us
#error "Please configure bsp_soft_iic_delay_us function!"		//若微秒定时未定义
#endif



typedef struct bsp_soft_iic_ops	bsp_soft_iic_ops_t;
typedef struct 	
{
	void (*set_sda)(uint8_t status);
	void (*set_scl)(uint8_t status);
	uint8_t (*get_sda)(void);
	uint8_t (*get_scl)(void);
	uint8_t delay_time;
	const bsp_soft_iic_ops_t* ops;
}bsp_soft_iic_t;			//软件iic 句柄结构体

struct bsp_soft_iic_ops
{
	void (*start)(bsp_soft_iic_t *hsoft_iic);				//发送起始信号
	void (*stop)(bsp_soft_iic_t *hsoft_iic);				//发送停止信号
	uint8_t (*wait_ack)(bsp_soft_iic_t *hsoft_iic);			//等待应答信号
	void (*nack)(bsp_soft_iic_t *hsoft_iic);				//非应答
	void (*ack)(bsp_soft_iic_t *hsoft_iic);					//应答
	
	void (*write)(bsp_soft_iic_t *hsoft_iic, uint8_t data);			//写数据
	uint8_t (*read)(bsp_soft_iic_t *hsoft_iic);						//读数据
	uint8_t (*check)(bsp_soft_iic_t *hsoft_iic, uint8_t address);	//检测通信
};

void bsp_init_iic(	
        bsp_soft_iic_t* hsoft_iic,		//软件iic信息结构体
        void (*set_sda)(uint8_t status),//设置sda数据线电平的函数指针
        void (*set_scl)(uint8_t status),//设置scl时钟线电平的函数指针
        uint8_t (*get_sda)(void),		//获取sda数据线电平的函数指针
        uint8_t (*get_scl)(void),		//获取scl时钟线电平的函数指针
    	uint32_t time 					//延时 时间数 可调整频率
								 );
#endif

软件IIC接口实现

初始化

void bsp_init_iic(	
        bsp_soft_iic_t* hsoft_iic,		//软件iic信息结构体
        void (*set_sda)(uint8_t status),//设置sda数据线电平的函数指针
        void (*set_scl)(uint8_t status),//设置scl时钟线电平的函数指针
        uint8_t (*get_sda)(void),		//获取sda数据线电平的函数指针
        uint8_t (*get_scl)(void),		//获取scl时钟线电平的函数指针
    	uint32_t time 					//延时 时间数 可调整频率
				);


void bsp_init_iic(
	bsp_soft_iic_t *hsoft_iic,
	void (*set_sda)(uint8_t status),
	void (*set_scl)(uint8_t status),
	uint8_t (*get_sda)(void),
	uint8_t (*get_scl)(void), uint32_t time)
{
	hsoft_iic->ops = &bsp_soft_iic_ops;	//赋值 OPS 操作指针
	hsoft_iic->delay_time = time;		//延时时间数
	hsoft_iic->get_scl = get_scl;		//赋值 获取scl电平函数
	hsoft_iic->get_sda = get_sda;		//赋值 获取sda电平函数
	hsoft_iic->set_scl = set_scl;		//赋值 设置scl电平函数
	hsoft_iic->set_sda = set_sda;		//赋值 设置sda电平函数

	hsoft_iic->set_scl(1);				//拉高时钟线
	hsoft_iic->set_sda(1);				//拉高数据线
}

定义 ops

static const bsp_soft_iic_ops_t bsp_soft_iic_ops =
	{
		.start = bsp_soft_iic_start,
		.stop = bsp_soft_iic_stop,
		.wait_ack = bsp_soft_iic_wait_ack,
		.ack = bsp_soft_iic_ack,
		.nack = bsp_soft_iic_nack,
		.write = bsp_soft_iic_write_byte,
		.read = bsp_soft_iic_read_byte,
		.check = bsp_soft_iic_check_device,
};

ops 接口实现

发送开始信号

/**
 * @brief 软件iic 发送开始信号
 * 
 * @param hsoft_iic 软件iic 对象结构体指针
 */
void bsp_soft_iic_start(bsp_soft_iic_t *hsoft_iic)
{
	hsoft_iic->set_sda(1);
	hsoft_iic->set_scl(1);
	bsp_soft_iic_delay_us(hsoft_iic->delay_time); 
	hsoft_iic->set_sda(0);
	bsp_soft_iic_delay_us(hsoft_iic->delay_time);
	hsoft_iic->set_scl(0);
	bsp_soft_iic_delay_us(hsoft_iic->delay_time);
}

发送停止信号

/**
 * @brief 软件iic 发送停止信号
 * 
 * @param hsoft_iic 软件iic 对象结构体指针
 */
void bsp_soft_iic_stop(bsp_soft_iic_t *hsoft_iic)
{
	hsoft_iic->set_sda(0);
	bsp_soft_iic_delay_us(hsoft_iic->delay_time);
	hsoft_iic->set_scl(1);
	bsp_soft_iic_delay_us(hsoft_iic->delay_time);
	hsoft_iic->set_sda(1);
	bsp_soft_iic_delay_us(hsoft_iic->delay_time);
}

等待应答

/**
 * @brief 软件iic等待应答信号 返回应答结果
 * 
 * @param hsoft_iic 软件iic 对象结构体指针
 * @return uint8_t 应答电平
 */
uint8_t bsp_soft_iic_wait_ack(bsp_soft_iic_t *hsoft_iic)
{
	uint8_t re;
	hsoft_iic->set_sda(1);
	bsp_soft_iic_delay_us(hsoft_iic->delay_time);
	hsoft_iic->set_scl(1);
	bsp_soft_iic_delay_us(hsoft_iic->delay_time);
	if (hsoft_iic->get_sda())
	{
		re = 1;
	}
	else
	{
		re = 0;
	}
	hsoft_iic->set_scl(0);
	bsp_soft_iic_delay_us(hsoft_iic->delay_time);
	return re;
}

发送应答

#/**
 * @brief 软件iic 发送应答信号
 * 
 * @param hsoft_iic 软件iic 对象结构体指针
 */
void bsp_soft_iic_ack(bsp_soft_iic_t *hsoft_iic)
{
	hsoft_iic->set_sda(0);
	bsp_soft_iic_delay_us(hsoft_iic->delay_time);
	hsoft_iic->set_scl(1);
	bsp_soft_iic_delay_us(hsoft_iic->delay_time);
	hsoft_iic->set_scl(0);
	bsp_soft_iic_delay_us(hsoft_iic->delay_time);
	hsoft_iic->set_sda(1);
	bsp_soft_iic_delay_us(hsoft_iic->delay_time);
}

发送非应答

/**
 * @brief 软件iic 发送nack应答信号
 * 
 * @param hsoft_iic 软件iic 对象结构体指针
 */
void bsp_soft_iic_nack(bsp_soft_iic_t *hsoft_iic)
{
	hsoft_iic->set_sda(1);
	bsp_soft_iic_delay_us(hsoft_iic->delay_time);
	hsoft_iic->set_scl(1);
	bsp_soft_iic_delay_us(hsoft_iic->delay_time);
	hsoft_iic->set_scl(0);
	bsp_soft_iic_delay_us(hsoft_iic->delay_time);
}

写数据

/**
 * @brief 软件iic 写数据(byte)
 * 
 * @param hsoft_iic 软件iic 对象结构体指针
 * @param data 写的数据
 */
void bsp_soft_iic_write_byte(bsp_soft_iic_t *hsoft_iic, uint8_t data)
{
	uint8_t i;
	for (i = 0; i < 8; i++)
	{
		if (data & 0x80)
		{
			hsoft_iic->set_sda(1);
		}
		else
		{
			hsoft_iic->set_sda(0);
		}
		bsp_soft_iic_delay_us(hsoft_iic->delay_time);
		hsoft_iic->set_scl(1);
		bsp_soft_iic_delay_us(hsoft_iic->delay_time);
		hsoft_iic->set_scl(0);
		hsoft_iic->set_scl(0); /* 针对GT811电容触摸,添加一行,相当于延迟几十ns */
		if (i == 7)
		{
			hsoft_iic->set_sda(1);
		}
		data <<= 1;
	}
}

读数据

/**
 * @brief 软件iic 写数据(byte)
 * 
 * @param hsoft_iic 软件iic 对象结构体指针
 * @param data 写的数据
 */
void bsp_soft_iic_write_byte(bsp_soft_iic_t *hsoft_iic, uint8_t data)
{
	uint8_t i;
	for (i = 0; i < 8; i++)
	{
		if (data & 0x80)
		{
			hsoft_iic->set_sda(1);
		}
		else
		{
			hsoft_iic->set_sda(0);
		}
		bsp_soft_iic_delay_us(hsoft_iic->delay_time);
		hsoft_iic->set_scl(1);
		bsp_soft_iic_delay_us(hsoft_iic->delay_time);
		hsoft_iic->set_scl(0);
		hsoft_iic->set_scl(0); /* 针对GT811电容触摸,添加一行,相当于延迟几十ns */
		if (i == 7)
		{
			hsoft_iic->set_sda(1);
		}
		data <<= 1;
	}
}

检测通信是否正常 发送地址 检查应答

/**
 * @brief 检测通信是否正常 发送地址 检查应答
 * 
 * @param hsoft_iic 软件iic 对象结构体指针
 * @param address 器件地址
 * @return uint8_t 应答状态: 1/0
 * 							1:通信失败
 * 							2:通信成功
 */
uint8_t bsp_soft_iic_check_device(bsp_soft_iic_t *hsoft_iic, uint8_t address)
{
	uint8_t ucack;
	if (hsoft_iic->get_scl() && hsoft_iic->get_sda())
	{
		bsp_soft_iic_start(hsoft_iic);
		bsp_soft_iic_write_byte(hsoft_iic, address | BSP_SOFT_I2C_WR);
		ucack = bsp_soft_iic_wait_ack(hsoft_iic); /* 检测设备的ACK应答 */
		bsp_soft_iic_stop(hsoft_iic); /* 发送停止信号 */

		return ucack;
	}
	return 1;
}

使用实例 (stm32 HAL 为例子 驱动 PCF8574 IO 扩展芯片)


#define PCF8457_IIC_ADDR 0X40
bsp_soft_iic_t hsoft_iic_pcf8574;

/**
 * @brief 设置scl
 *
 * @param level 设置电平
 */
void bsp_pcf8574_set_scl(uint8_t level)
{
    if (level)
        HAL_GPIO_WritePin(GPIOH, GPIO_PIN_4, GPIO_PIN_SET);
    else
        HAL_GPIO_WritePin(GPIOH, GPIO_PIN_4, GPIO_PIN_RESET);
}

/**
 * @brief 设置sda
 *
 * @param level 设置电平
 */
void bsp_pcf8574_set_sda(uint8_t level)
{
    if (level)
        HAL_GPIO_WritePin(GPIOH, GPIO_PIN_5, GPIO_PIN_SET);
    else
        HAL_GPIO_WritePin(GPIOH, GPIO_PIN_5, GPIO_PIN_RESET);
}

/**
 * @brief 读取scl
 *
 * @return uint8_t 读取电平
 */
uint8_t bsp_pcf8574_get_scl(void)
{
    return HAL_GPIO_ReadPin(GPIOH, GPIO_PIN_4);
	return 0;
}

/**
 * @brief 读取sda
 *
 * @return uint8_t 读取电平
 */
uint8_t bsp_pcf8574_get_sda(void)
{
    return HAL_GPIO_ReadPin(GPIOH, GPIO_PIN_5);
		return 0;
}

/**
 * @brief pcf8574 初始化
 *
 * @return int 暂时无意义
 */
int bsp_pcf8574_init(void)
{
    uint8_t ret = 0;
    bsp_init_iic(&hsoft_iic_pcf8574,
                 bsp_pcf8574_set_sda,
                 bsp_pcf8574_set_scl,
                 bsp_pcf8574_get_sda,
                 bsp_pcf8574_get_scl, 4);
    ret = hsoft_iic_pcf8574.ops->check(&hsoft_iic_pcf8574, PCF8457_IIC_ADDR);
    sys_assert_param(!ret);

    bsp_pcf8574_write_bit(0, 0); 
    bsp_pcf8574_write_bit(1, 0);
    bsp_pcf8574_write_bit(2, 0);

    bsp_pcf8574_write_bit(3, 0);
    bsp_pcf8574_write_bit(4, 0);
    bsp_pcf8574_write_bit(5, 0);
    bsp_pcf8574_write_bit(6, 0);
    bsp_pcf8574_write_bit(7, 0); //初始化全低
    return ret;
}
//SYS_INIT_BOARD_EXPORT(bsp_pcf8574_init);

/**
 * @brief 读取pcf8574 io值 对应 8 位的每一个位
 *
 * @return uint8_t
 */
uint8_t bsp_pcf8574_read_byte(void)
{
    uint8_t temp = 0;
    hsoft_iic_pcf8574.ops->start(&hsoft_iic_pcf8574);
    hsoft_iic_pcf8574.ops->write(&hsoft_iic_pcf8574, PCF8457_IIC_ADDR | BSP_SOFT_I2C_RD);
    hsoft_iic_pcf8574.ops->wait_ack(&hsoft_iic_pcf8574);
    temp = hsoft_iic_pcf8574.ops->read(&hsoft_iic_pcf8574);
    hsoft_iic_pcf8574.ops->nack(&hsoft_iic_pcf8574);
    hsoft_iic_pcf8574.ops->stop(&hsoft_iic_pcf8574);
    return temp;
}

/**
 * @brief 一起写pcf8574的8个 io
 * 
 * @param data 写数据
 */
void bsp_pcf8574_write_byte(uint8_t data)
{
    hsoft_iic_pcf8574.ops->start(&hsoft_iic_pcf8574);
    hsoft_iic_pcf8574.ops->write(&hsoft_iic_pcf8574, PCF8457_IIC_ADDR | BSP_SOFT_I2C_WR);
    hsoft_iic_pcf8574.ops->wait_ack(&hsoft_iic_pcf8574);
    hsoft_iic_pcf8574.ops->write(&hsoft_iic_pcf8574, data);
    hsoft_iic_pcf8574.ops->wait_ack(&hsoft_iic_pcf8574);
    hsoft_iic_pcf8574.ops->stop(&hsoft_iic_pcf8574);
    //bsp_delay_ms(10);
}

/**
 * @brief 设置pcf8574的 单个io  过程是先读整个 再修改 再写整个 
 * 
 * @param bit 对应io序号
 * @param sta 要设置的电平状态
 */
void bsp_pcf8574_write_bit(uint8_t bit, uint8_t sta)
{
    uint8_t data;
    data = bsp_pcf8574_read_byte();
    if (sta == 0)
        data &= ~(1 << bit);
    else
        data |= 1 << bit;
    bsp_pcf8574_write_byte(data);
}

/**
 * @brief 读 pcf8574的 单个io  读整个 提取对应序号的 io对应的位  返回其状态
 * 
 * @param bit 读的io序号
 * @return uint8_t 返回 0/1 高或低
 */
uint8_t bsp_pcf8574_read_bit(uint8_t bit)
{
    uint8_t data;
    data = bsp_pcf8574_read_byte();
    if (data & (1 << bit))
        return 1;
    else
        return 0;
}

源码下载

无需c币
https://download.csdn.net/download/qq_42385764/81893160


版权声明:本文为qq_42385764原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。