软件i2c
记录
i2c程序
#include "iic.h"
#include "port.h"
#include "sys.h"
/*IIC应用配置*/
const iic_handle item_i2c[iic_even_num] =
{
{GPIOB, GPIOB, GPIO_PIN_7, GPIO_PIN_6},
};
/**
* @brief: 设置SDA引脚输出电平
* @param[in] orgn: IIC句柄指针
* @param[in] level: 输出电平(0:低电平,1:高电平)
* @param[out] None
* @retval: None
*/
void iic_sda_out(const iic_handle *orgn, uint8_t level)
{
if (level)
{
gpio_set(orgn->iic_SDA, orgn->iic_SDA_PIN);
}
else
{
gpio_reset(orgn->iic_SDA, orgn->iic_SDA_PIN);
}
}
/**
* @brief: 读取SDA引脚输入电平
* @param[in] orgn: IIC句柄指针
* @param[out] None
* @retval: SDA引脚电平(0:低电平,1:高电平)
*/
uint8_t iic_sda_in(const iic_handle *orgn)
{
if (1 == gpio_read(orgn->iic_SDA, orgn->iic_SDA_PIN))
{
return 1;
}
else
{
return 0;
}
}
/**
* @brief: 设置SCL引脚输出电平
* @param[in] orgn: IIC句柄指针
* @param[in] level: 输出电平(0:低电平,1:高电平)
* @param[out] None
* @retval: None
*/
void iic_scl_out(const iic_handle *orgn, uint8_t level)
{
if (level)
{
gpio_set(orgn->iic_SCL, orgn->iic_SCL_PIN);
}
else
{
gpio_reset(orgn->iic_SCL, orgn->iic_SCL_PIN);
}
}
/**
* @brief: 产生IIC起始信号
* @param[in] orgn: IIC句柄指针
* @param[out] None
* @retval: None
*/
void iic_start(const iic_handle *orgn)
{
/*SCL高电平时,SDA由高电平到低电平*/
/*拉高SDA防止使用前已经是低电平*/
iic_sda_out(orgn, 1);
delay_us(2);
iic_scl_out(orgn, 1);
delay_us(1);
/*拉低SDA*/
iic_sda_out(orgn, 0);
delay_us(1);
/*拉低SCL准备数据 */
iic_scl_out(orgn, 0);
delay_us(1);
}
/**
* @brief: 产生IIC停止信号
* @param[in] orgn: IIC句柄指针
* @param[out] None
* @retval: None
*/
void iic_stop(const iic_handle *orgn)
{
/*SCL高电平时,SDA由低电平到高电平*/
/*改变SDA时保证SCL低电平*/
iic_scl_out(orgn, 0);
delay_us(1);
delay_us(1);
/*拉低数据线 */
iic_sda_out(orgn, 0);
delay_us(1);
/*拉高SCL后再拉高SDA*/
iic_scl_out(orgn, 1);
delay_us(1);
iic_sda_out(orgn, 1);
delay_us(1);
}
/**
* @brief: 产生IIC应答信号
* @param[in] orgn: IIC句柄指针
* @param[out] None
* @retval: None
*/
void iic_ack(const iic_handle *orgn)
{
/*在SCL高电平时读取SDA电压*/
/*准备SDA数据低电平应答*/
iic_sda_out(orgn, 0);
delay_us(1);
iic_scl_out(orgn, 1);
delay_us(1);
iic_scl_out(orgn, 0);
delay_us(1);
}
/**
* @brief: 产生IIC非应答信号
* @param[in] orgn: IIC句柄指针
* @param[out] None
* @retval: None
*/
void iic_nack(const iic_handle *orgn)
{
/*在SCL高电平时读取SDA电压*/
/*准备SDA数据高电平不应答*/
iic_sda_out(orgn, 1);
delay_us(1);
iic_scl_out(orgn, 1);
delay_us(1);
iic_scl_out(orgn, 0);
delay_us(1);
}
/**
* @brief: 接收IIC应答信号
* @param[in] orgn: IIC句柄指针
* @param[out] None
* @retval: 应答状态(0:应答成功,1:无应答)
*/
uint8_t iic_rxack(const iic_handle *orgn)
{
/*接收应答*/
uint8_t i = 5;
/*主机释放SDA由从机控制*/
iic_gpio_INinit(orgn);
/*发送第九个时钟信号读取从机应答*/
iic_scl_out(orgn, 1);
delay_us(1);
delay_us(1);
while (iic_sda_in(orgn))
{
/*读5次防止干扰*/
i--;
delay_us(1);
if (0 == i)
{
/*无应答停止IIC总线*/
iic_gpio_outinit(orgn);
iic_stop(orgn);
return 1; /*非应答*/
}
}
/*没有发送不应答,SDA重新配置输出以参与下次发送*/
iic_gpio_outinit(orgn);
iic_scl_out(orgn, 0);
delay_us(1);
delay_us(1);
return 0; /*应答*/
}
/**
* @brief: IIC发送一个字节数据
* @param[in] orgn: IIC句柄指针
* @param[in] data: 要发送的数据字节
* @param[out] None
* @retval: None
*/
void icc_sendbyte(const iic_handle *orgn, uint8_t data)
{
uint8_t i = 8;
while (i--)
{
/*发送数据在时钟低电平时准备数据*/
iic_scl_out(orgn, 0);
delay_us(1);
delay_us(1);
/*对比最高位*/
iic_sda_out(orgn, data & 0x80);
delay_us(1);
/*左移 */
data = data << 1;
/*SCL上升沿读取数据*/
iic_scl_out(orgn, 1);
delay_us(1);
}
/*SCL拉低准备数据*/
iic_scl_out(orgn, 0);
delay_us(1);
}
/**
* @brief: IIC接收一个字节数据
* @param[in] orgn: IIC句柄指针
* @param[out] None
* @retval: 接收到的数据字节
*/
uint8_t icc_receivebyte(const iic_handle *orgn)
{
uint8_t i = 8;
uint8_t data = 0;
/*输入模式*/
iic_gpio_INinit(orgn);
while (i--)
{
/*拉低SCL从机准备数据*/
iic_scl_out(orgn, 0);
delay_us(1);
/*主机该读取数据了*/
iic_scl_out(orgn, 1);
delay_us(1);
data |= iic_sda_in(orgn);
delay_us(1);
/*读一位左移填满这个字节*/
data = data << 1;
}
/*接收完设置输出*/
iic_gpio_outinit(orgn);
/*拉低SCL准备数据*/
iic_scl_out(orgn, 0);
delay_us(1);
return data;
}
/**
* @brief: IIC发送一个字节数据到指定寄存器
*发送字节流程:
*1.主机起始信号
*2.发送从机地址:0 == 7位地址:写操作
*3.接收应答
*4.有应答发送寄存器地址
*5.接收应答
*6.发送数据
*7.接收应答
*8.发送停止位
* @param[in] orgn: IIC句柄指针
* @param[in] address: 从机地址
* @param[in] reg: 寄存器地址
* @param[in] data: 要发送的数据字节
* @param[out] None
* @retval: 操作状态(0:成功,1:失败)
*/
uint8_t icc_transmit_onebyte(const iic_handle *orgn, uint8_t address, uint8_t reg, uint8_t data)
{
iic_start(orgn);
icc_sendbyte(orgn, address);
if (1 == iic_rxack(orgn))
{
iic_stop(orgn);
return 1;
}
icc_sendbyte(orgn, reg);
iic_rxack(orgn);
icc_sendbyte(orgn, data);
iic_rxack(orgn);
iic_stop(orgn);
delay_us(1);
return 0;
}
/**
* @brief: IIC从指定寄存器接收一个字节数据
*接收数据流程:
*1.主机起始信号
*2.发送从机地址:0 == 7位地址:写操作
*3.接收应答
*4.有应答发送寄存器地址
*5.接收应答
*6.再次发送起始信号
*7.发送从机地址:1 == 7位地址:读操作
*8.接收应答
*9.读取数据
*10.主机发送非应答
*11.停止IIC
* @param[in] orgn: IIC句柄指针
* @param[in] address: 从机地址
* @param[in] reg: 寄存器地址
* @param[out] None
* @retval: 接收到的数据字节(如果失败返回1)
*/
uint8_t icc_receive_onebyte(const iic_handle *orgn, uint8_t address, uint8_t reg)
{
uint8_t data = 0;
iic_start(orgn);
icc_sendbyte(orgn, address << 1);
if (1 == iic_rxack(orgn))
{
iic_stop(orgn);
return 1;
}
icc_sendbyte(orgn, reg);
iic_rxack(orgn);
iic_start(orgn);
/*+1目的是|1,最低位写1接收*/
icc_sendbyte(orgn, (address << 1) + 1);
iic_rxack(orgn);
data = icc_receivebyte(orgn);
iic_nack(orgn);
iic_stop(orgn);
return data;
}
/**
* @brief: IIC发送多个字节数据到指定寄存器
* @param[in] orgn: IIC句柄指针
* @param[in] address: 从机地址
* @param[in] reg: 寄存器起始地址
* @param[in] data: 要发送的数据缓冲区指针
* @param[in] length: 要发送的数据长度
* @param[out] None
* @retval: 操作状态(0:成功,1:失败)
*/
uint8_t icc_transmit_morebyte(const iic_handle *orgn, uint8_t address, uint8_t reg, uint8_t *data, uint16_t length)
{
uint16_t i = 0;
iic_start(orgn);
icc_sendbyte(orgn, address);
if (1 == iic_rxack(orgn))
{
iic_stop(orgn);
return 1;
}
icc_sendbyte(orgn, reg);
iic_rxack(orgn);
while (i < length)
{
i++;
icc_sendbyte(orgn, data[i]);
iic_rxack(orgn);
}
iic_stop(orgn);
delay_us(1);
return 0;
}
/**
* @brief: IIC从指定寄存器接收多个字节数据
* @param[in] orgn: IIC句柄指针
* @param[in] address: 从机地址
* @param[in] reg: 寄存器起始地址
* @param[out] data: 接收数据的缓冲区指针
* @param[in] length: 要接收的数据长度
* @retval: 操作状态(0:成功,1:失败)
*/
uint8_t icc_receive_morebyte(const iic_handle *orgn, uint8_t address, uint8_t reg, uint8_t *data, uint16_t length)
{
uint16_t i = 0;
iic_start(orgn);
icc_sendbyte(orgn, address << 1);
if (1 == iic_rxack(orgn))
{
iic_stop(orgn);
return 1;
}
icc_sendbyte(orgn, reg);
iic_rxack(orgn);
iic_start(orgn);
icc_sendbyte(orgn, (address << 1) + 1);
iic_rxack(orgn);
while (i < length)
{
data[i] = icc_receivebyte(orgn);
if (i != length - 1)
{
iic_ack(orgn);
}
}
iic_nack(orgn);
iic_stop(orgn);
return 0;
}
/**
* @brief: IIC初始化函数
* @param[in] orgn: IIC句柄指针
* @param[out] None
* @retval: None
*/
void iic_init(const iic_handle *orgn)
{
cstb168t_gpio_init(orgn);
}
/******************* IIC_H *************************/
#ifndef __IIC_H
#define __IIC_H
#include "stm32f411xe.h"
typedef struct
{
GPIO_TypeDef *iic_SDA;
GPIO_TypeDef *iic_SCL;
uint16_t iic_SDA_PIN;
uint16_t iic_SCL_PIN;
}iic_handle;
typedef enum
{
CST816T,
iic_even_num
} IIC_even;
extern const iic_handle item_i2c[iic_even_num];
void iic_init (const iic_handle *orgn);
uint8_t icc_transmit_onebyte(const iic_handle *orgn, uint8_t address, uint8_t reg, uint8_t data);
uint8_t icc_receive_onebyte(const iic_handle *orgn, uint8_t address, uint8_t reg);
uint8_t icc_transmit_morebyte(const iic_handle *orgn, uint8_t address, uint8_t reg, uint8_t *data, uint16_t length);
uint8_t icc_receive_morebyte(const iic_handle *orgn, uint8_t address, uint8_t reg, uint8_t *data, uint16_t length);
#endif
/******************* IIC_H *************************/
浙公网安备 33010602011771号