/*******************************************************************************
測試平臺:STM32F103ZET6最小系統
*******************************************************************************/
static void i2cDelay()
{
volatile int i = 7;
while (i)
i--;
}
// SCL高電平期間,SDA出現下降沿為起始信號
static bool i2cStart()
{
SDA_OUT;
SCL_H;
SDA_H;
i2cDelay();
if (!sdaRead) // 如果SDA為低電平,則總線忙,退出
return false;
SDA_L;
if (sdaRead) // 如果SDA為高電平,則總線忙,退出
return false;
SDA_L;
return true;
}
// SCL高電平期間,SDA出現上升沿為停止信號
static void i2cStop(void)
{
SDA_OUT;
SCL_L;
SDA_L;
i2cDelay(); // STOP:when CLK is high DATA from low to high
SCL_H;
SDA_H;
i2cDelay();
}
static void i2cAck(void)
{
SDA_OUT;
SCL_L;
i2cDelay();
SDA_L;
i2cDelay();
SCL_H;
i2cDelay();
SCL_L;
}
static void i2cNoAck(void)
{
SDA_OUT;
SCL_L;
i2cDelay();
SDA_H;
i2cDelay();
SCL_H;
i2cDelay();
SCL_L;
}
// SCL高電平期間,SDA電平被從設備拉低表示應答
static bool i2cWaitAck(void)
{
uint8_t errTimes = 0;
SDA_IN;
SDA_H;
i2cDelay();
SCL_H;
i2cDelay();
while (sdaRead) {
if (errTimes++ > 20) {
SCL_L;
return false;
}
i2cDelay();
}
SCL_L;
return true;
}
// 發送數據,數據從高位到低位傳輸
static void i2cSendByte(uint8_t byte)
{
uint8_t i = 8;
SDA_OUT;
while (i--) {
SCL_L; // 時鐘信號為低電平期間,允許數據線電平變化
i2cDelay();
if (byte & 0x80)
SDA_H;
else
SDA_L;
byte <<= 1;
i2cDelay();
SCL_H;
i2cDelay();
}
SCL_L;
}
static uint8_t i2cReceiveByte()
{
uint8_t i = 8;
uint8_t byte = 0;
SDA_IN;
SDA_H;
while (i--) {
byte <<= 1;
SCL_H;
i2cDelay();
if (sdaRead) {
byte |= 0x01;
}
SCL_L;
i2cDelay();
}
SCL_L;
return byte;
}
void i2cInit()
{
GPIO_InitTypeDef GPIO_InitStructure;
/* Enable GPIOB clock */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
/* Configure GPIOB.6 & GPIOB.7 as open-drain output */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
}
/**
* 通過I2C總線寫一字節數據
* @param[in] dev:設備I2C地址
* @param[in] reg:寄存器地址
* @param[in] data:要寫入的數據
*/
bool i2cWriteOneByte(uint8_t dev, uint8_t reg, uint8_t data)
{
if (!i2cStart())
return false;
i2cSendByte(dev << 1); // 從機地址由高7位+讀寫位構成
if (!i2cWaitAck()) {
i2cStop();
return false;
}
i2cSendByte(reg);
i2cWaitAck();
i2cSendByte(data);
i2cWaitAck();
return true;
}
/**
*
* @param[in] dev:設備I2C地址
* @param[in] reg:寄存器地址
* @param[in] len:字節數
* @param[in] data:待寫入的數據
*/
bool i2cWriteBytes(uint8_t dev, uint8_t reg, uint8_t len, uint8_t *data)
{
uint8_t i;
if (!i2cStart())
return false;
i2cSendByte(dev << 1);
if (!i2cWaitAck()) {
i2cStop();
return false;
}
i2cSendByte(dev);
i2cWaitAck();
for (i = 0; i < len; i++) {
i2cSendByte(data[i]);
if (!i2cWaitAck()) {
i2cStop();
return false;
}
}
i2cStop();
return true;
}
/**
* 從I2C設備中讀取數據
* @param[in] dev:設備I2C地址
* @param[in] reg:寄存器地址
* @param[in] len:數據字節數
* @param[out] data:讀出的數據
*/
bool i2cReadBytes(uint8_t dev, uint8_t reg, uint8_t len, uint8_t *data)
{
if (!i2cStart())
return false;
i2cSendByte(dev << 1);
if (!i2cWaitAck()) {
i2cStop();
return false;
}
i2cSendByte(reg);
i2cWaitAck();
i2cStart();
i2cSendByte((dev << 1) | 0x01); // 器件地址+讀命令
i2cWaitAck();
while (len) {
*data = i2cReceiveByte();
if (len == 1)
i2cNoAck(); // 最后一個字節不應答
else
i2cAck();
data++;
len--;
}
i2cStop();
return true;
}
上海意泓電子科技有限責任公司 版權所有 未經授權禁止復制或鏡像
CopyRight 2020-2025 www.wellnspa.com All rights reserved 滬ICP備2021005866號