• STM32 I2C学习


    IIC总线协议介绍

    IIC:Inter Integrated Circuit,集成电路总线,是一种同步、串行、半双工通信总线。

    同步:需要时钟线
    串行:数据一位一位地发送
    半双工:同一时间只能接受或发送,不能同时发送或接收

    总线就是传输数据的通道
    协议就是传输数据的规则

    IIC总线结构图

    在这里插入图片描述
    SDA:数据线——空闲处于高电平(接上拉电阻)
    SCL:时钟线——空闲处于高电平(接上拉电阻)

    总线支持多设备连接,允许多主机存在,每个设备都有一个唯一的地址

    连接到总线上的数目受总线的最大电容400pf限制

    数据传输速率:标准模式100k bit/s 快速模式400k bit/s 高速模式3.4M bit/s

    IIC协议

    三个信号:起始信号、停止信号、应答信号
    在这里插入图片描述
    两个注意:数据有效性、数据传输顺序
    一个状态:空闲状态

    在这里插入图片描述
    起始信号:SCL高电平时,SDA从高电平变为低电平
    停止信号:SCL为高电平时,SDA从低电平变为高电平

    在这里插入图片描述
    应答信号:上拉电阻影响下SDA默认为高,而从机拉低SDA就是确认收到数据即ACK,否则NACK。

    数据先发送高位(MSB),以字节传输,数据在SCL高电平稳定

    发送完后,注意释放SDA,从机应答

    空闲状态:两根线都是高电平

    void iic_start(void)
    {
    	IIC_SDA(1);
    	IIC_SCL(1);
    	iic_delay();
    	IIC_SDA(0);
    	iic_delay();
    	//钳住总线,准备发送or接收数据
    	IIC_SCL(0);
    	iic_delay();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    void iic_stop(void)
    {
    	IIC_SDA(0);
    	iic_delay();
    	IIC_SCL(1);
    	iic_delay();
    	IIC_SDA(1);//发送总线停止信号
    	iic_delay();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    检测应答信号
    uint8_t iic_wait_ack(void)
    {
    	IIC_SDA(1);
    	iic_delay();
    	IIC_SCL(1);
    	iic_delay();
    	if(IIC_READ_SDA)//SDA为高电平NACK
    	{
    		iic_stop();
    		return 1;
    	}
    	IIC_SCL(0);//SCL拉低结束ACK检查
    	iic_delay();
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    void iic_ack(void)
    {
    	IIC_SCL(0);
    	iic_delay();
    	IIC_SDA(0);
    	iic_delay();
    	IIC_SCL(1);
    	iic_delay();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    void iic_nack(void)
    {
    	IIC_SCL(0);
    	iic_delay();
    	IIC_SDA(1);
    	iic_delay();
    	IIC_SCL(1);
    	iic_delay();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    发送一字节数据

    void iic_send_byte(uint8_t data)
    {
    	for(uint8_t i=0; i<8; i++)
    	{
    		IIC_SDA((data & 0x80) >> 7);
    		iic_delay();
    		IIC_SCL(1);
    		iic_delay();
    		IIC_SCL(0);
    		data <<= 1;
    	}
    	IIC_SDA(1); //发送完成主机释放SDA线
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    //1:ack;0:nack
    uint8_t iic_read_byte(uint8_t ack)
    {
    	uint8_t receive;
    	for(uint8_t i; i<8; i++)
    	{
    		receive <<= 1;
    		IIC_SCL(1);
    		iic_delay();
    		if(IIC_READ_SDA)
    			receive++;
    		IIC_SCL(0);
    		iic_delay();
    	}
    	if(!ack)
    		iic_nack();
    	else
    		iic_ack();
    	return receive;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    AT24C02

    EEPROM是一种掉电后数据不丢失的存储器,常用来存储一些配置信息,在系统重新上电时就可以加载。

    与之相比的是,后备域需要额外电源供电才能防止丢失。

    AT24C02是一个2K bit的EEPROM存储器,使用IIC通信方式。

    在这里插入图片描述
    A0/1/2:设备地址决定引脚
    WP:写保护引脚,如果接高电平,就只能读取,不能写入
    SCL、SDA接上拉电阻

    在这里插入图片描述
    24C02由32页组成,每页8Byte
    在这里插入图片描述

    AT24C02通讯地址

    在这里插入图片描述

    • 不可编程部分:1010
    • 可编程部分:由硬件管脚A0/A1/A2决定
    • 数据传输方向:读数据‘1’,还是写数据‘0’

    写操作地址:0xA0,读操作地址:0xA1
    在这里插入图片描述
    支持的写操作:页写、字节写

    AT24C02读写时序

    写操作:支持字节写模式和页写模式

    字节写模式就是一个地址一个数据进行写入。
    页写模式就是连续写入数据。只需要写一个地址,连续写入数据时地址会自增。但存在页的限制。超出一页时,超出数据覆盖原先写入的数据。但读会自动翻页。

    读模式:支持当前地址读模式、随机地址读模式和顺序读模式

    当前读模式是基于上一次读/写操作的最后位置继续读出数据。
    随机地址读模式是指定地址读出数据。
    顺序读模式是连续读出数据。

    硬件和软件IICC对比

    • 硬件IIC:比较复杂,速度快,较稳定,需使用特定管脚
    • 软件IIC:操作过程比较清晰,速度较慢,稳定,任意管脚,比较灵活

    IIC配置步骤

    1. 使能SCL和SDA对应时钟:__HAL_RCC_GPIOB_CLK_ENABLE()
    2. 设置GPIO工作模式:SDA开漏/SCL推挽输出模式,使用HAL_GPIO_Init初始化
    3. 编写基本信号:起始信号、停止信号、应答信号,主机:send_ack、sen_nack、wait ack
    4. 编写读和写函数:iic_read_byte、iic_send_byte,发送完成,主机释放SDA

    为什么IIC总线SDA建议用开漏模式?

    IIC的SDA引脚既要做为输出,又要作为输入,用开漏输出模式,很好地实现输出输入共用,避免IO模式频繁切换带来的麻烦。

    输出时:主机(MCU)输出0,可以拉低信号,来实现低电平发送,主机输出1(实际不起作用),由外部上拉电阻上拉,实现高电平发送。

    输入时:主机(MCU)设置输出1状态,此时由于MCU无法输出1,相当于释放MCU,此时外部器件可以主动拉低SDA引脚/释放SDA引脚,实现SDA脚的高低电平变化。

    由于开漏输出模式下,MCU还是可以读取IDR状态寄存器,来获取引脚高低电平,即可获得SDA脚的高低电平状态,从而实现输入检测。

  • 相关阅读:
    Ajax复习(62nd)
    kubectl按pod创建时间排序获取列表
    竞赛选题 疫情数据分析与3D可视化 - python 大数据
    【SpringBoot AOP Redis实现延时双删功能实战】
    【Python报错】train epoch数据读取for i, batch in enumerate(train_loader)失败?卡住?
    Python的安装与测试(windows为例)
    【C++ 科学计算】C++ 预测算法之多项式曲线拟合
    操作系统基本概念
    [附源码]Python计算机毕业设计Django病人跟踪治疗信息管理系统
    dify接入文心一言出错
  • 原文地址:https://blog.csdn.net/Caramel_biscuit/article/details/136307092