裸机软件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版权协议,转载请附上原文出处链接和本声明。