記錄
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 *************************/
本文章為轉載內容,我們尊重原作者對文章享有的著作權。如有內容錯誤或侵權問題,歡迎原作者聯繫我們進行內容更正或刪除文章。