学习笔记——STM32软件I2C配置

📢声明:参考的是江科大的代码,图片截于江科大PPT。

 一、I2C硬件电路:

二、I2C通信的时序。

        1、起始条件:SCL高电平期间,SDA从高电平切换到低电平。

 

        2、终止条件:SCL高电平期间,SDA从低电平切换到高电平。

        3、发送一个字节:SCL低电平期间,主机将数据位依次放到SDA线上(高位先行),然后释放SCL,从机将在SCL高电平期间读取数据位,所以SCL高电平期间SDA不允许有数据变化,依次循环上述过程8次,即可发送一个字节。

        4、接收一个字节:SCL低电平期间,从机将数据位依次放到SDA线上(高位先行),然后释放SCL,主机将在SCL高电平期间读取数据位,所以SCL高电平期间SDA不允许有数据变化,依次循环上述过程8次,即可接收一个字节(主机在接收之前,需要释放SDA)

        5、发送应答:主机在接收完一个字节之后,在下一个时钟发送一位数据,数据0表示应答,数据1表示非应答。

        6、接收应答:主机在发送完一个字节之后,在下一个时钟接收一位数据,判断从机是否应答,数据0表示应答,数据1表示非应答(主机在接收之前,需要释放SDA)

三、软件I2C程序编写步骤:

  1、在Keil中新建MyI2C.c和MyI2C.h文件。

  2、编写引脚配置层函数。

#include "stm32f10x.h"                  // Device header
#include "Delay.h"

#define  MyI2C_GPIO_RCC      RCC_APB2Periph_GPIOB
#define  MyI2C_GPIO          GPIOB
#define  MyI2C_SCL           GPIO_Pin_3
#define  MyI2C_SDA           GPIO_Pin_4

/**
  * 函数功能:I2C时钟线写
  * 入口参数:BitVal:控制引脚0或1
  * 返 回 值:无
  */
void MyI2C_W_SCL(BitAction BitVal)
{
    GPIO_WriteBit(MyI2C_GPIO, MyI2C_SCL, BitVal);
    Delay_us(10);
}

/**
  * 函数功能:I2C数据线写
  * 入口参数:BitVal:控制引脚0或1
  * 返 回 值:无
  */
void MyI2C_W_SDA(BitAction BitVal)
{
    GPIO_WriteBit(MyI2C_GPIO, MyI2C_SDA, BitVal);
    Delay_us(10);
}

/**
  * 函数功能:I2C数据线读
  * 入口参数:无
  * 返 回 值:读取数据线引脚的状态
  */
uint8_t MyI2C_R_SDA(void)
{
    uint8_t i;
    i = GPIO_ReadInputDataBit(MyI2C_GPIO, MyI2C_SDA);
    Delay_us(10);
    return i;
}


3、编写I2C初始化函数。

/**
*** 函数功能:软件I2C初始化
*** 入口参数:无
*** 返 回 值:无
***/
void MyI2c_Init(void)
{
    /*开启GPIOB时钟*/
    RCC_APB2PeriphClockCmd(MyI2C_GPIO_RCC, ENABLE);
    
    /*开启AFIO时钟*/
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
    
    /*JTAG/SWD复用功能重映射*/
    GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE); //因为我这里使用了GPIOB_Pin_3和Pin_4
                                                             //所以才需要调用这个库函数
    
    
    /*初始化引脚*/
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;      //开漏输出模式
    GPIO_InitStructure.GPIO_Pin = MyI2C_SCL | MyI2C_SDA;  //GPIOB_Pin_3 | GPIOB_Pin_4
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(MyI2C_GPIO, &GPIO_InitStructure); 
    
    MyI2C_W_SCL(1);   //时钟线默认高电平
    MyI2C_W_SDA(1);   //数据线默认高电平
}

4、编写I2C起始条件函数。

/**
  * 函数功能:I2C起始
  * 入口参数:无
  * 返 回 值:无
  */
void MyI2C_Start(void)
{  
    MyI2C_W_SDA(1);    //释放数据线
    MyI2C_W_SCL(1);    //释放时钟线
    MyI2C_W_SDA(0);    //下拉数据线
    MyI2C_W_SCL(0);    //下拉时钟线
}    

5、编写I2C终止条件函数。

/**
  * 函数功能:I2C终止
  * 入口参数:无
  * 返 回 值:无
  */
void MyI2C_Stop(void)
{
    MyI2C_W_SDA(0);    //下拉数据线
    MyI2C_W_SCL(1);    //释放时钟线
    MyI2C_W_SDA(1);    //释放数据线
}

6、编写I2C发送1个字节函数。

/**
  * 函数功能:I2C发送一个字节
  * 入口参数:Byte: 要发送的一个字节数据
  * 返 回 值:无
  */
void MyI2C_SendByte(uint8_t Byte)
{
    uint8_t i;
    
    for (i = 0; i < 8; i++)             //循环发送8次,完成一个字节的发送
    {
        MyI2C_W_SDA(Byte & (0x80 >> i));//从高位到地位一次发送
        MyI2C_W_SCL(1);                 //释放时钟线
        MyI2C_W_SCL(0);                 //下拉时钟线
    }
}

6、编写I2C接收1个字节函数。

/**
  * 函数功能:I2C接收一个字节
  * 入口参数:无
  * 返 回 值:接收到的字节数据
  */
uint8_t MyI2C_ReceiveByte(void)
{
    uint8_t i;
    uint8_t Byte = 0x00;        //定义接收的数据
    
    MyI2C_W_SDA(1);             //释放数据线
    for (i = 0; i < 8; i++)     //重复接收8次, 完成接收一个字节
    {
        MyI2C_W_SCL(1);         //释放时钟线
        if (MyI2C_R_SDA() == 1) //读取数据线的状态,1就保存数据, 0就不作处理
        {
            Byte |= (0x80 >> i); 
        }
        MyI2C_W_SCL(0);          //下拉时钟线
    }
    
    return Byte;                 //返回接收到的数据
}
    

7、编写I2C发送应答位函数。(0表示应答,1表示非应答)

/**
  * 函数功能:I2C发送应答
  * 入口参数:AckBit:要发送的应答。0表示应答,1表示非应答。
  * 返 回 值:无
  */
void MyI2C_SendAck(uint8_t AckBit)
{
    MyI2C_W_SDA(AckBit);
    MyI2C_W_SCL(1);          //释放时钟线
    MyI2C_W_SCL(0);          //下拉时钟线
}

8、编写I2C接收应答位函数。(0表示应答,1表示非应答)

/**
  * 函数功能:I2C接收应答位
  * 入口参数:无
  * 返 回 值:接收到的应答位。0表示应答,1表示非应答。
  */
uint8_t MyI2C_ReceiveAck(void)
{
    uint8_t AckBit;             //定义应答位变量
    MyI2C_W_SDA(1);             //释放数据线
    MyI2C_W_SCL(1);             //释放时钟线
    AckBit = MyI2C_R_SDA();     //接收应答
    MyI2C_W_SCL(0);             //下拉时钟线
    
    return AckBit;              //返回应答
}

9、MyI2C.h文件内容。

#ifndef __MYI2C_H
#define __MYI2C_H



void MyI2c_Init(void);
void MyI2C_Start(void);
void MyI2C_Stop(void);
void MyI2C_SendByte(uint8_t Byte);
uint8_t MyI2C_ReceiveByte(void);
void MyI2C_SendAck(uint8_t AckBit);
uint8_t MyI2C_ReceiveAck(void);



#endif

  • 4
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值