嵌入式硬件通信接口协议-IIC(二)分层架构设计模拟接口

文章首发于同名微信公众号:DigCore

欢迎关注同名微信公众号:DigCore,及时获取最新技术博文。

原文链接:https://mp.weixin.qq.com/s/jFxic0iOet_rIlWi3is8eQ

 

 

关于分层设计的思想,在之前的一篇文章中《嵌入式硬件通信接口协议-SPI(二)分层架构设计模拟接口》介绍SPI接口设计时,已经做了详细的设计过程讲解,在此就不赘述了。

 

现在参考SPI的BSP层设计思路,用同样的方法来设计IIC接口的BSP层代码模块。

 

本文将要讲解和实现的内容主要分为两个部分:代码实现IIC接口管理、代码实现IIC时序

 

  • IIC接口管理


接口管理的目的是想在后期扩展时,一个工程里可使用多个IIC接口。

 

这里暂不考虑使用复杂的数据结构,仅仅采用简单的宏定义,放在头文件中,省去麻烦的内存申请、分配这一些操作。

 

以IIC接口序号“1”开始向后排,新增IIC接口时,直接参考当前示例来定义后续的IIC接口序号和管脚即可:

 

#define IIC_1                    1

#define IIC1_PORT_SCL    PORTB

#define IIC1_PIN_SCL       6

#define IIC1_PORT_SDA   PORTA

#define IIC1_PIN_SDA      2

 

此处要实现的,依然是位于BSP层的IIC模块代码,这个层介于芯片驱动(寄存器)和应用库之间,要考虑到在后期的移植开发,此IIC模块可能由IO模拟,也可能由芯片厂商提供的驱动demo实现,所以这里所封装出来的BSP层接口,一定要考虑到后期的扩展。

 

所以这里的做法是把参数都放在函数中传递,并且均设计成带有uint8_t类型的函数返回值。这里如此设计的原因和习惯问题,可以参考《【嵌入式编程】函数返回类型设计》一文。

 

打开STM32CubeMX工具可以看到,在配置IIC接口时,参数可配置内容如下截图:

 

 

参考以上,暂且在结构体中定义:地址位宽、时钟速率,来定义一个IIC接口对象。如下头文件中的bsp_iic_obj_t结构体类型。

 

 

  • IIC时序


从上一篇《嵌入式硬件通信接口协议-IIC(一)协议基础》中,我们知道IIC的时序中有这几种信号特征,现在就根据这几个信号特征,用代码逐一实现。

 

实际上在互联网上已经有很多关于IIC时序模拟的实现代码,最简单的可以从github开源社区、百度百科、各类技术网站,具体到很多的技术论坛都有IIC应用实例,都能找到IIC接口的源码。

 

因此IIC时序的模拟已经大同小异了,然而在这里再“造轮子”的目的是,集成、优化、完善自有项目BSP层的代码,提高项目的扩展性和应用,对屡清代码的整体框架也有很大帮助!

 

说白了也是想把这篇文章写详细些。废话少说,立即上码:

  • 起始标志:

 

 

 

这段起始标志的代码,思路很简单,首先确保SDA所使用的IO引脚为输出,在本BSP层的IIC模块中使用了iic_set_io(iic_n, 0);函数,将指定IIC接口序号的SDA管脚设为输出,之后的电平设置,就是完成信号时序的过程。

 

  • 结束标志

 

思路类似于上,略。

 

  • 数据输出

 

如上示例发送一个16进制数据0xDC的时序示意图,最重要的原则是:SCL为低电平时,才可以改变SDA输出数据;SCL为高电平时,必须SDA不抖动不改变。

 

 

代码实现的过程,类似于SPI模拟时类似,数据位“踩着”时钟逐bit被输出,每输出一bit就要对数据进行移位“buf <<= 1;”,这样在下一个SCL低电平时候输出下一个bit。

 

完成输出后立即对SDA的IO管脚设为输入模式,即调用iic_set_io(iic_n, 1);函数来实现。

 

  • 数据采样

类似于数据发送,逐bit踩着SCL接收。这里的数据采样,就是IIC主机接收来自外设器件发来的数据,最重要的原则是:SCL为低电平时,做延时等待保证SDA数据稳定;SCL为高电平时,读取SDA的IO管脚电平。

 

 

  • 应答ACK/NACK

 

 

从时序图可以看到,应答位的ACK和NACK区别在于,第9个SCL高电平期间,SDA所呈现的电平状态不同。

 

从上篇文章我们可以知道,IIC总线的电路连接,一般地SCL和SDA都有上拉电阻Rp,也就是说如果IIC从机设备,由于不存在(硬件未焊接)、出故障(烧坏)或者其他原因,导致没有信号产生的时候,此时SDA会处于NACK的状态,也就是IO管脚电平被上拉电阻拉高了,可以理解为“默认”电平,没有“回应”。

 

应答的目的,就是“接收方”告知“发送方”,我已正常收到刚刚发来的数据。

 

  • 等待应答ACK

 

既然是应答,就有两向性:IIC从机应答IIC主机;IIC主机应答IIC从机。

 

上图的应答ACK/NACK都是IIC主机主动输出的,是用来告知从机“我主机已正常收到”。

 

而IIC从机告知主机的应答ACK,这里要用等待ACK的概念,主机通过读取SDA管脚电平来检测ACK信号。

 

 

以上是利用GPIO管脚模拟实现的时序,封装成DigCore_Embed嵌入式软件架构的BSP层接口,对上层提供IIC硬件接口,向下操作GPIO和时序的模拟。移植过程中可以根据目标平台,在上述这些已经封装好的接口内,做适当调整。

 

比如采用官方Demo程序代替GPIO模拟方案,只需要修改这以上接口中的代码即可,对于上层应用库,不论是温湿度传感器SHT20,还是EEPROM存储芯片AT24C1024B,甚至是BS81163-A的触摸键盘芯片,这几个使用了BSP层的IIC接口,这些代码都无需改动。

 

这就是嵌入式软件的分层设计思想的优势。

 

以上函数内部所调用的接口,都是当前BSP层里IIC模块源码中的静态函数:

 

 

总结,IIC时序的模拟,主要思路是根据IIC时序特点,在对应的信号后面做对应的时延,以达到时序的展现!难点之处就是把IIC时序拆解成多个信号特征进行模拟时,如果对信号时序图了解不深,在对比代码时比较绕,需要静下心仔细核对!

 

以上代码仅仅完成初步的编写和整理,未在具体外设上验证。此BPS层的IIC模块最终源码,敬请期待下回分享出来!

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值