stm32 模拟I2C主机 读写操作通用

一、i2c从机读写时序图(一般通用)

1、i2c write

在这里插入图片描述
S: 开始信号;
W: 表示写;(一般器件地址为7位,所以u8中的第0位表示读(1)写(0)位);
A: 响应(对于主机,则需要设置等待响应);
P: 停止信号;

2、i2c read

在这里插入图片描述
S: 开始信号;
W: 表示写;(一般器件地址为7位,所以u8中的第0位表示读(1)写(0)位);
R:表示读;
A: 响应(对于主机,则需要设置等待响应);
P: 停止信号;

二、模拟I2C主机通用代码

1、i2c.h

/*********************************************************************************************************
* 模块名称: i2c.h
* 摘    要: IIC实验
* 当前版本: 1.0.0
* 作    者: 杨
* 完成日期: 2019年4月16日
* 内    容: 
* 注    意:                                                                  
**********************************************************************************************************
* 取代版本: 
* 作    者:
* 完成日期: 
* 修改内容: 
* 修改文件: 
*********************************************************************************************************/
#ifndef _IIC_H_
#define _IIC_H_

/*********************************************************************************************************
*                                              包含头文件
*********************************************************************************************************/
#include "sys.h" 

/*********************************************************************************************************
*                                              宏定义
*********************************************************************************************************/
//设置PB9上拉/下拉输入
#define SDA_IN()  {GPIOB->CRH &= 0xFFFFFF0F; GPIOB->CRH |= (u32)8<<4;} 

//设置PB9推挽输出
#define SDA_OUT() {GPIOB->CRH &= 0xFFFFFF0F; GPIOB->CRH |= (u32)3<<4;}

#define IIC_SCL PBout(8)   //SCL
#define IIC_SDA PBout(9)   //SDA
#define READ_SDA PBin(9)   //输入SDA
/*********************************************************************************************************
*                                              枚举结构体定义
*********************************************************************************************************/

/*********************************************************************************************************
*                                              API函数声明
*********************************************************************************************************/
void i2c_init(void);         //初始化IIC
void I2C_Start(void);       //起始信号
void I2C_Stop(void);        //停止信号
u8 I2C_Wait_Ack(void);      //等待Ack信号
void I2C_Ack(void);         //发送Ack信号
void I2C_Nack(void);        //不发送Ack信号
void I2C_Send_Byte(u8 data);//发送一个字节
u8 I2C_Read_Byte(u8 ack);   //读取一个字节

void I2C_WriteOneByte(u8 address, u8 reg, u8 val);
u8 I2C_ReadOneByte(u8 address, u8 reg);
void I2C_Write(u8 address, u8 reg, u8 *pBuff, u16 numToWrite);
void I2C_Read(u8 address, u8 reg, u8 *pBuff, u16 numToRead);
#endif

2、i2c.c

/*********************************************************************************************************
* 模块名称: i2c.c
* 摘    要: IIC实验
* 当前版本: 1.0.0
* 作    者: 杨
* 完成日期: 2019年4月16日
* 注    意:                                                               
**********************************************************************************************************
* 取代版本: 
* 作    者:
* 完成日期: 
* 修改内容:
* 修改文件: 
*********************************************************************************************************/

/*********************************************************************************************************
*                                              包含头文件
*********************************************************************************************************/
#include "i2c.h"
#include "delay.h"

/*********************************************************************************************************
*                                              宏定义
*********************************************************************************************************/

/*********************************************************************************************************
*                                              内部变量
*********************************************************************************************************/
  
/*********************************************************************************************************
*                                              内部函数声明
*********************************************************************************************************/

/*********************************************************************************************************
*                                              内部函数实现
*********************************************************************************************************/
/*********************************************************************************************************
* 函数名称:  
* 函数功能: 
* 输入参数: 
* 输出参数: 
* 返 回 值: 
* 创建日期:  
* 注 意:   
*********************************************************************************************************/ 

/*********************************************************************************************************
*                                              API函数实现
*********************************************************************************************************/
/*********************************************************************************************************
* 函数名称: i2c_init
* 函数功能: 初始化IIC
* 输入参数: void
* 输出参数: void
* 返 回 值: void
* 创建日期: 2019年4月16日 
* 注    意: 
*********************************************************************************************************/ 
void i2c_init(void)
{
  GPIO_InitTypeDef GPIO_InitStruct;
  
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
  
  GPIO_InitStruct.GPIO_Pin   = GPIO_Pin_8 | GPIO_Pin_9;
  GPIO_InitStruct.GPIO_Mode  = GPIO_Mode_Out_PP;     //设置为推挽输出
  GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(GPIOB, &GPIO_InitStruct);  
  GPIO_SetBits(GPIOB, GPIO_Pin_8 | GPIO_Pin_9);
}

/*********************************************************************************************************
* 函数名称: I2C_Start
* 函数功能: 产生起始信号
* 输入参数: void
* 输出参数: void
* 返 回 值: void
* 创建日期: 2019年4月16日 
* 注    意: 
*********************************************************************************************************/
void I2C_Start(void)
{
  SDA_OUT();      //设置为输出
  IIC_SDA = 1;
  IIC_SCL = 1;
  delay_us(4);
  IIC_SDA = 0;    //当SCL高的时候SDA由高变低
  delay_us(4);
  IIC_SCL = 0;    //钳住SCL,准备发送或接收数据
}

/*********************************************************************************************************
* 函数名称: I2C_Stop
* 函数功能: 产生停止信号
* 输入参数: void
* 输出参数: void
* 返 回 值: void
* 创建日期: 2019年4月16日 
* 注    意: 
*********************************************************************************************************/
void I2C_Stop(void)
{
  SDA_OUT();      //设置为输出
  IIC_SDA = 0;
  IIC_SCL = 0;
  delay_us(4);
  IIC_SCL = 1;
  IIC_SDA = 1;    //当SCL高的时候SDA由低变高
  delay_us(4);
}

/*********************************************************************************************************
* 函数名称: I2C_Wait_Ack
* 函数功能: 等待Ack信号
* 输入参数: void
* 输出参数: void
* 返 回 值: 0:接收到ack;1:没接收到ack
* 创建日期: 2019年4月16日 
* 注    意: 
*********************************************************************************************************/
u8 I2C_Wait_Ack(void)
{
  u8 waitTime = 0;
  SDA_IN();     //SDA设置输入
  IIC_SDA = 1;
  delay_us(1);
  IIC_SCL = 1;
  delay_us(1);
  //等待接收ack
  while(READ_SDA)
  {
    waitTime++;
    if(waitTime > 250)
    {
      I2C_Stop();
      return 1;
    }
  }
  IIC_SCL = 0;
  return 0;
}

/*********************************************************************************************************
* 函数名称: I2C_Ack
* 函数功能: 发送Ack信号
* 输入参数: void
* 输出参数: void
* 返 回 值: void
* 创建日期: 2019年4月17日 
* 注    意: 
*********************************************************************************************************/
void I2C_Ack(void)
{
  IIC_SCL = 0;
  SDA_OUT();     //SDA设置为输出
  IIC_SDA = 0;
  delay_us(2);
  //在SCL一个脉冲内SDA一直为低
  IIC_SCL = 1;
  delay_us(2);
  IIC_SCL = 0;
}

/*********************************************************************************************************
* 函数名称: I2C_Nack
* 函数功能: 不发送Ack信号
* 输入参数: void
* 输出参数: void
* 返 回 值: void
* 创建日期: 2019年4月17日 
* 注    意: 
*********************************************************************************************************/
void I2C_Nack(void)
{
  IIC_SCL = 0;
  SDA_OUT();  //SDA设置为输出
  IIC_SDA = 1;
  delay_us(2);
  //在SCL一个脉冲内SDA一直为高
  IIC_SCL = 1;
  delay_us(2);
  IIC_SCL = 0;
}

/*********************************************************************************************************
* 函数名称: I2C_Send_Byte
* 函数功能: 发送一个字节
* 输入参数: data
* 输出参数: void
* 返 回 值: void
* 创建日期: 2019年4月17日 
* 注    意: 
*********************************************************************************************************/
void I2C_Send_Byte(u8 data)
{
  u8 i;
  SDA_OUT();    //SDA设置为输出
  IIC_SCL = 0;  //SCL为低,准备接收数据
  for(i = 0; i < 8; i++)
  {
    if((data & 0x80) >> 7)
    {
      IIC_SDA = 1;
    }
    else
    {
      IIC_SDA = 0;
    }
    data <<= 1;  //将下一位移至第八位
    delay_us(2);
    IIC_SCL = 1;
    delay_us(2);
    IIC_SCL = 0;
    delay_us(2);
  }
}

/*********************************************************************************************************
* 函数名称: I2C_Read_Byte
* 函数功能: 读取一个字节
* 输入参数: ack: 1:发送Ack; 0:发送NAck
* 输出参数: void
* 返 回 值: u8:receive
* 创建日期: 2019年4月17日 
* 注    意: 
*********************************************************************************************************/
u8 I2C_Read_Byte(u8 ack)
{
  u8 receive = 0;
  u8 i;
  SDA_IN();     //SDA设置输入
  IIC_SDA = 1;
  for(i = 0; i < 8; i++)
  {
    IIC_SCL = 0;
    delay_us(2);
    IIC_SCL = 1;
    
    receive <<= 1;
    if(READ_SDA)
    {
      receive++;
    } 
    delay_us(1);
  }
  if(ack)
  {
    I2C_Ack();
  }
  else
  {
    I2C_Nack();
  }
  return receive;
}

/*********************************************************************************************************
* 函数名称: I2C_WriteOneByte
* 函数功能: 指定地址写入一个字节
* 输入参数: address:从机器件地址
*           reg:寄存器地址 
*			val:写入的一个字节的数据
* 输出参数: void
* 返 回 值: void
* 创建日期: 2020年5月25日
* 注    意: 
*********************************************************************************************************/ 
void I2C_WriteOneByte(u8 address, u8 reg, u8 val)
{
  I2C_Start();         //开始位
  I2C_Send_Byte((address << 1) | 0); //I2C的器件地址(写操作)
  I2C_Wait_Ack();      //等待Ack
  I2C_Send_Byte(reg % 256); 
  I2C_Wait_Ack();      //等待Ack
  I2C_Send_Byte(val);  //发送一个字节的数据
  I2C_Wait_Ack();      //等待Ack
  I2C_Stop();          //停止位
}

/*********************************************************************************************************
* 函数名称: I2C_ReadOneByte
* 函数功能: 指定地址读取一个字节
* 输入参数: address:从机器件地址
*           reg:寄存器地址
* 输出参数: void
* 返 回 值: u8,读取的一个字节的数据
* 创建日期: 2020年5月25日
* 注    意: 
*********************************************************************************************************/ 
u8 I2C_ReadOneByte(u8 address, u8 reg)
{
  u8 temp;
  I2C_Start();         //开始位
  I2C_Send_Byte((address << 1) | 0); //写操作
  I2C_Wait_Ack();      //等待Ack
  I2C_Send_Byte(reg % 256); 
  I2C_Wait_Ack();      //等待Ack
  I2C_Start();         //开始位
  I2C_Send_Byte((address << 1) | 1); //读操作
  I2C_Wait_Ack();      //等待Ack
  temp = I2C_Read_Byte(0);    //读取一个字节数据,无Ack
  I2C_Stop();          //停止位
  return temp;
}

/*********************************************************************************************************
* 函数名称: I2C_Write
* 函数功能: 指定地址写入数据
* 输入参数: address:从机器件地址
*           reg:寄存器地址
*           pBuff:所需要写入数据存放的地址
*           numToWrite:写入数据的字节长度
* 输出参数: void
* 返 回 值: void
* 创建日期: 2020年5月25日
* 注    意: 
*********************************************************************************************************/ 
void I2C_Write(u8 address, u8 reg, u8 *pBuff, u16 numToWrite)
{
  u16 i;
  for(i = 0; i < numToWrite; i++)
  {
    I2C_WriteOneByte(address, reg, *(pBuff+i));
    reg++;
  }
}

/*********************************************************************************************************
* 函数名称:I2C_Read
* 函数功能: 指定地址写入数据
* 输入参数: address:从机器件地址
            reg:寄存器地址;
            pBuff:读取数据后存放的首地址地址;
            numToWrite:读取数据的字节长度
* 输出参数: void
* 返 回 值: void
* 创建日期: 2020年5月25日
* 注    意: 
*********************************************************************************************************/ 
void I2C_Read(u8 address, u8 reg, u8 *pBuff, u16 numToRead)
{
  u16 i;
  for(i = 0; i < numToRead; i++)
  {
    *(pBuff+i) = I2C_ReadOneByte(address, reg);
    reg++;
  }
}


  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
STM32模拟I2C主机是一种利用STM32单片机的GPIO端口和软件编程实现的I2C主机通信协议的方法。 I2C主机是指在I2C总线上拥有主动发送和接收数据能力的设备。要实现STM32模拟I2C主机,首先需要确定使用哪两个GPIO端口作为SDA(串行数据线)和SCL(串行时钟线),然后进行相应的配置。 在STM32的设置中,需要将这两个GPIO端口设置为开漏输出模式,并设置速度适当,以便与其他I2C设备进行通信。然后,通过STM32的GPIO输入输出控制寄存器进行相应的操作,模拟I2C主机的发送和接收功能。 在发送数据时,首先需要拉低SDA线,然后通过GPIO控制寄存器设置SCL线为高电平。接下来,发送一个字节的数据,从高位到低位,通过逐位设置SDA线的电平,并在每位设置后将SCL线拉高,为下一位的传输做准备。最后,在最后一个位传输结束后,保持SCL线为高电平,将SDA线拉高,形成停止条件。 在接收数据时,首先需要将SDA线拉高,并迅速取SCL线的电平。然后,通过从高位到低位,依次取SDA线上的数据,并在每次取后将SCL线拉高,以便于下一位的传输。最后,在最后一位取结束后,拉低SCL线,形成停止条件。 通过以上步骤,就可以通过STM32模拟I2C主机进行数据的发送和接收。在具体的应用中,可以根据需要进行相应的数据处理和协议解析,实现与其他I2C从机设备的通信和数据交换。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值