单片机代码怎么读懂_启士 | 蓝桥杯零基础单片机教程10 I2C介绍(下)及ADC”

bb8ba0d6ccd82e73acfce7458b3699d6.gif 72f1c42a0d92d7cfba5f84019f15de03.png

这是 北航士谔书院 的第 942 篇推送

I²C 总线在 51 单片机上的应用实例(含ADC)

上一篇推送中,我们就 I²C 总线协议做了介绍(点此跳转);

在本文,我们将以 PCF8591 和蓝桥杯 CT107D 开发板为例,看看如何使用 I²C 总线通信。

代码

该芯片的示例程序已经打包至附件,供同学们下载使用。在手机上阅读文章的同学也可以单击下面的链接,快速查看代码文件(ex10.c 和 i2c.c)。下文内容的行号均以网页中的行号为准。

    10.PCF8591_ADC实验

    查看 ex10.c

    查看 i2c.c

PCF8591 简介

PCF8591 是一个采用 I²C 接口的模数转换芯片(Analog to Digital Converter,ADC),用于将模拟信号(analog signal,如电压大小)转换为数字信号(digital signal,由具体二进制表示的数字),相当于一个电压表(将电压转换为具体的读数)。

PCF8591 也带有数模转换(DAC)功能,但在开发板上没有作用,因此略去不表。

在 CT107D 开发板上,这个芯片连接了一个电位器(可调电阻)、一个光敏电阻和一个运算放大器,可以让单片机分别从这三者读取信号。光敏电阻可以感知周围光线亮度;电位器可以让用户通过旋钮控制单片机;而运算放大器的输入来自外部,可以感知外部差分信号的大小。

fe12a5ba4ce6b0ad29a499cbd2365fb8.png

CT107D 开发板上的 PCF8591

芯片的 VDD(电源)脚连接到了开发板电源总线,并额外增加了两个退耦电容(C21 和 C22),减少电源噪声对采样带来的影响。AGND(模拟地)和 VSS(电源地)连接到 GND 网络。ADC 芯片需要振荡器产生时钟信号来驱动器工作,EXT 脚(内 / 外振荡器选择)接到 GND,表示芯片使用内部振荡器,因此 OSC(外置振荡器输入)悬空,不连接振荡器。

芯片地址选择脚(A0 – A2)全部连接到 GND,表示芯片地址的对应位全为 0,故此时芯片地址为 1001000。

AIN0 – 3 连接到了 4 组输入,上文已经描述。在电路图上查找相应网络名称,即可知道每个输入的具体功能。

例程:主程序

在示例程序(ex10.c)中,我们使用 PCF8591 读取电位器中心触点的电压值,并通过数码管显示这个电压。

ex10.c:31 – 36 (行号)首先配置定时器,并为定时器设置一个中断处理函数(ex10.c:isr_timer_0()),用于定时将采样数据显示到数码管。在中断函数中,我们可以看到重载定时器的代码(ex10.c:57 – 58),操作数码管显示采样数据的代码(ex10.c:display()),这些代码请到对应的教程中查看它们的具体含义,在此不再赘述。

ex10.c:38 初始化 PCF8591 芯片,这部分内容在下文讲述。

定时器中断每触发一次,ex10.c:59 – 63 就会递增一个计数器(intr),并在其满 50 时将 adc_flag 变量设置为 1。主函数中,ex10.c:42 一直等待 adc_flag 变为 1,并在其为 1 时进行一次采样(ex10.c:45),并将采样结果放入 dspbuf 中(ex10.c:46 – 49)。

例程:I²C

读取采样值

采样用到的函数 adc_pcf8591() 位于 i2c.c:250 处。

采样开始时,单片机首先产生起始条件(i2c.c:254)。产生起始条件的代码非常简单:先释放 SDA 和 SCL(i2c.c:33 – 34),经过短暂的延迟后,拉低 SDA(此时 SCL 处于高电平状态),即产生一个起始条件;再经过延迟后,拉低 SCL,为后续传输作好准备。

起始条件完成后,使用 i2c_sendbyte() 发送设备地址(1001000)及数据方向位(i2c.c:255)。在此我们需要从芯片读取数据,因此数据方向位为 1(WRITE),完整的一帧数据为二进制 10010001(16 进制:0x91)。i2c_sendbyte() 函数的具体实现与上述“帧”一节中的描述相同,同学们可以自己对照查看。

一帧传送完后,使用 i2c_waitack() 函数读取从设备的 ACK 信号(i2c.c:256)。这个函数有返回值,返回 0 表示设备发送了 ACK,返回 1 表示 NACK,即设备没有发送 ACK。理论上讲应该判断这个返回值,为 1 表示通信失败,但例程中假设传输始终成功,没有判断这个值。

紧接着单片机从 PCF8591 中读取一帧数据(i2c.c:257),表示采样值。读取完成后,我们发送一个 ACK 信号(按照 I²C 标准,这个 ACK 可以省略,因为这是最后一帧数据),然后产生停止条件,完成一次通信。读取到的采样值(temp)即作为函数的返回值。

初始化

上文略去的 init_pcf8591() 函数位于 i2c.c:232,它向 PCF8591 发送了一个字节,以控制芯片的行为。它的具体过程和上述采样过程类似,有所不同的是,此时我们向设备写入数据,因此数据方向位应为 0(READ),第一帧即为 0x90。第二帧数据就是实际的控制数据,写入 0x03 表示使用第三个 ADC 通道,这一值的具体含义可以参见 PCF8591 Datasheet 的 8.2 Control byte 节。

官方提供的 I²C 函数库

在竞赛时,同学们无需记住 I²C 通信的细节,而只需能够使用主办方给出的函数库即可。官方提供的函数库如下:

    iic

函数库中定义了 IIC_Start,IIC_Stop,IIC_Ack,IIC_WaitAck,IIC_SendByte,IIC_RecByte 这 6 个函数,同学们应当了解每个函数的具体功能,并能够读懂函数内容的含义。其中,somenop; 用于短暂延时,而 IIC_Ack 函数的参数用于确定是发送 ACK 还是 NACK,其余内容与上文所述基本相同。

结语

至此,同学们应对 I²C 协议的基本概念有了一些认知,并能够使用 I²C 总线与外围芯片通信。如对文章内容有疑问,请点击阅读原文后,在下方留言,作者会及时回复。

图文|田韵豪

排版|李亦龙

出品|士谔书院X大班

3a7ed6a98e56b47e4b2802edf626f9cd.png
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值