記錄

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