软件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 *************************/

posted on 2025-12-16 14:06  li5920o  阅读(9)  评论(0)    收藏  举报

导航