您的位置:首页 > 其它

STM32模拟I2C程序

2016-06-27 10:43 344 查看
修改自cleanflight

/*******************************************************************************
测试平台: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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: