单片机——通信协议(FPGA+c语言应用之iic篇)

一.I2C的功能特点

(1)功能包括:

1.只需要两条总线;

2.没有严格的波特率要求,例如使用RS232,主设备生成总线时钟;

3.所有组件之间都存在简单的主/从关系,连接到总线的每个设备均可通过唯一地址进行软件寻址;

4.I²C是真正的多主设备总线,可提供仲裁和冲突检测;

(2) 传输速度

  • 标准模式:Standard Mode = 100 Kbps

  • 快速模式:Fast Mode = 400 Kbps

  • 高速模式:High speed mode = 3.4 Mbps

  • 超快速模式:Ultra fast mode = 5 Mbps

(3)能挂载的iic设备数目

1.最大主设备数:无限制;

2.最大从机数:理论上是127;

二.数据传输

主设备和从设备进行数据传输时遵循以下协议格式。数据通过一条SDA数据线在主设备和从设备之间传输0和1的串行数据。串行数据序列的结构可以分为:

三.协议解析

(1)开始位和停止位

开始位

1.SDA线由高电平切换成低电平;

2.SCL线由高电平切换成低电平;

开始位 c代码实现:

cs 复制代码
// 起始信号
void IIC_start(void)
{
    // 1.首先把数据线设置为输出模式
    // 总线空闲, SCL和SDA输出高
    SCL = 1;  
    SDA = 1;
    delay_us(5);
    
    // SDA由高变低
    SDA = 0;
    delay_us(5);
    
    // 拉低SCL开始传输数据
    SCL = 0;
}

停止位

1.将SDA线从低电压电平切换到高电压电平;

2.再将SCL线从高电平拉到低电平;

停止位c代码实现:

cs 复制代码
/ 停止信号
void IIC_stop(void)
{
    // 1.首先把数据线设置为输出模式
    
    // 拉高时钟线
    SDA = 0;
    delay_us(5);
    SCL = 1;
    delay_us(5);
    
    // SDA由低变高
    SDA = 1;
}

(2)地址位+读写命令位

地址位支持7bit、10bit,主设备如果需要向从机发送/接收数据,首先要发送对应从机的地址,然后会匹配总线上挂载的从机的地址,故地址为主要用来辨识不同设备。

地址位由主机发送,从设备负责接受并识别该地址是否位自己地址。

读写位由主机发送;1表示读操作,0表示写操作。

(3)应答位

应答信号: 出现在1个字节传输完成之后,即第9个SCL时钟周期内,此时主机需要释放SDA总线,把总线控制权交给从机,由于上拉电阻的作用,此时总线为高电平,如果从机正确的收到了主机发来的数据,会把SDA拉低,表示应答响应。

**非应答信号:**当第9个SCL时钟周期时,SDA保持高电平,表示非应答信号。

非应答信号可能是主机产生也可能是从机产生,产生非应答信号的情况主要有以下几种:

  • I2C总线上没有主机所指定地址的从机设备;

  • 从机正在执行一些操作,处于忙状态,还没有准备好与主机通讯;

  • 主机发送的一些控制命令,从机不支持;

  • 主机接收从机数据时,主机产生非应答信号,通知从机数据传输结束,不要再发数据了;

(4)数据位

I2C数据总线传输要保证在SCL为高电平时,SDA数据稳定,所以SDA上数据变化只能在SCL为低电平时

一次传输的数据总共有8位,由发送方设置,它需要将数据位传输到接收方。发送之后会紧跟一个ACK / NACK位,如果接收器成功接收到数据,则从机发送ACK。否则,从机发送NACK。

数据可以重复发送多个,直到接收到停止位为止。

写数据等待应答c代码

cs 复制代码
// 等待ACK   1-无效    0-有效
u8 IIC_wait_ack(void)
{
    u8 ack = 0;
    
    // 数据线设置为输入
    
    // 拉高时钟线
    SCL = 1;
    delay_us(5);
    // 获取数据线的电平
    if(SDA)
    {   // 无效应答
        ack = 1;
        IIC_stop();
    }
    else
    {   // 有效应答
        ack = 0;
        // 拉低SCL开始传输数据
        SCL = 0;
        delay_us(5);
    }
    
    return ack;
}

读数据等待应答 c代码

cs 复制代码
void IIC_ack(u8 ack)
{
    // 数据线设置为输出
    
    SCL = 0;
    delay_us(5);
    
    if(ack)
        SDA = 1; // 无效应答
    else
        SDA = 0; // 有效应答      
    delay_us(5);
    SCL = 1;
    // 保持数据稳定
    delay_us(5);
    // 拉低SCL开始传输数据
    SCL = 0;
}

三.FPGA实现

(1)test_ctrl模块状态机设计

(2) 模块设计

(3)代码实现

(4)测试代码实现

(5)仿真结果

读的前仿真结果

(6)后仿真结果

四.封装iic的IP核并通过linux驱动的方式驱动

1.先生成一个带axi总线的IP核;

2.把要控制的信号通过例化的方式连接寄存器;

3.生成镜像文件;

4.写C语言驱动,并控制寄存器

5.测试,完成

步骤有点复杂,有空再完成

相关推荐
Lee川7 小时前
优雅进化的JavaScript:从ES6+新特性看现代前端开发范式
javascript·面试
Lee川10 小时前
从异步迷雾到优雅流程:JavaScript异步编程与内存管理的现代化之旅
javascript·面试
晴殇i12 小时前
揭秘JavaScript中那些“不冒泡”的DOM事件
前端·javascript·面试
绝无仅有12 小时前
Redis过期删除与内存淘汰策略详解
后端·面试·架构
绝无仅有12 小时前
Redis大Key问题排查与解决方案全解析
后端·面试·架构
AAA梅狸猫13 小时前
Looper.loop() 循环机制
面试
AAA梅狸猫13 小时前
Handler基本概念
面试
Wect14 小时前
浏览器缓存机制
前端·面试·浏览器
掘金安东尼15 小时前
Fun with TypeScript Generics:玩转 TS 泛型
前端·javascript·面试
掘金安东尼15 小时前
Next.js 企业级落地
前端·javascript·面试