用于科研的-Arduino-教程-二-

2,757 阅读1小时+

用于科研的 Arduino 教程(二)

原文:Arduino in Science

协议:CC BY-NC-SA 4.0

五、数字信号概念和数字信号输出

用于进行生物、化学或物理测量的大多数传感器产生连续可变的模拟电输出,而计算机和大规模集成电路使用高或低的电能水平来表示它们可以处理的二进制数字信号。监控和数据采集程序必须经常充当双向模数电子信号转换器。本章将开始开发二进制编码和数字电子学的应用,利用标准的 0 和+5 伏信号电平作为二进制 1 和 0 的表示。在许多表面贴装技术(SMT)器件中,逻辑电平为 0 和 3.3 V,无意中施加 5 V 信号常常会损坏 SMT 集成电路。

LabJack U12 人机界面(HMI)用户手册指出,U12 设备上提供了 20 条数字信号线,可设置为接收或输出 5 V 电信号。四条线通过 LabJack 上主螺丝端子板上的 I/O 0–I/O 3 连接提供,其余 16 条线通过机箱顶端的 DB-25 连接器提供。用户指南还建议实验者,主端子连接器上的四条 I/O 线由内部限流电阻保护,而 DB-25 连接器上的四条 I/O 线配有跳线引脚,以便在需要时绕过 1.5kω保护电阻。

可以通过几种方法物理访问 DB-25 行。LabJack 制造商可提供带有各线路连接端子的电缆和电路板。带焊接端子的 DB-25 连接器可从大多数电子供应商处购买。可以从旧的 DB-25 打印机电缆中创建一个便宜的接口,去掉不兼容的端连接器,并将单个线端镀锡以插入数字原型试验板。(参见第章 1 ,图 1-1 ,图 5-1 中的 1、3 项,HMI U12)。)

为了强调有关所用硬件的注意事项,请记住 LabJack 制造商为 DB-25 连接提供的电路板包含预安装的负载限制电阻,而从当地供应商处单独购买的 DB-25 连接器或使用从旧打印机拆下的电缆制造的连接器不包含负载限制电阻。在现场实验和 HMI 之间使用独立供电的缓冲连接(如 CMOS CD4050 hex 同相缓冲芯片)的理念消除了对 HMI 硬件瞬时损坏的担忧。

实验的

本练习将使用与之前练习相同的屏幕控制 led 照明程序,但此处扩展至 8 位,以演示基本的数字信号概念。

五金器具

LabJack Corporation 的 CB25 端子板(项目 2,39 美元)包括 DB-25 电缆(项目 3),用于将 U12 接口的附加终端数字 I/O 线连接到原型板上的 LED 阵列(项目 1)。

图 5-1 中的第 4 项是到显示图 5-3 中所示 DAQFactory 控制面板的主机的 USB 连接。连接设备顶部 LabJack DB-25 连接器的 DB-25 电缆提供了对 16 条数字 I/O 线的访问,其中前 8 条可用于本练习。

img/503603_1_En_5_Fig1_HTML.jpg

图 5-1

LabJack U12、CB25 端子板和 8 位 LED 阵列

如果由于易发生瞬变的电源而需要额外的硬件保护,八条数字信号线可以使用两个 CD4050 hex 缓冲/隔离芯片、八个 led 和限流电阻,如图 5-2 所示。

手边的部件应根据以下电路原理图进行组装。作者用旧的 DB-25 打印机电缆组装了一个初始原型,并将来自 U12 的隔离和识别的 D0–D7 数字 I/O 线直接插入原型板,以激活 CLR LED 阵列位。

img/503603_1_En_5_Fig2_HTML.jpg

图 5-2

8 位字节 LED 显示器原理图

软件

创建一个八按钮面板,每个按钮的标签如图 5-3 所示。本练习演示了使用 8 位字节的现场实验和主 SCADA 屏幕之间的单个数字线路连接的配置。

img/503603_1_En_5_Fig3_HTML.jpg

图 5-3

8 位字节 LED 显示控制面板

创建的每个按钮都被贴上标签,连接到其通道,然后设置为在 0 到 5 伏之间切换,如之前在第 1 ,图 1-9 到 1-11 中所做的那样。同时按下 Ctrl 键和单击鼠标左键允许实验者在单个屏幕组件的集合周围画一个框,这些组件可以通过编辑下拉菜单中的选择形成一个组。在组装更大更复杂的 GUI 屏幕时,可以根据需要使用鼠标、Ctrl 键和编辑菜单对组件进行分组和取消分组。

研究者也不应试图改变背景板上的成分。组件应该根据需要进行排列和配置、分组,然后根据需要通过使用 Ctrl 键和布局菜单中的顺序条目由背景面板支持。

计算被照亮位的十进制和的 DAQFactory 序列程序如清单 5-1 所示。

如图 1-10 所示,对于每个 DigOut_n 通道,代表 8 位的按钮链接到按钮组件动作选项卡中的“切换”选项。

观察

当二极管、DAQFactory 和屏幕配置正确时,单击任何一个按钮都会点亮或关闭代表一个字节数字数据的 8 位二极管组中的相应二极管。

图 5-3 描绘了点击评估按钮后,D1 (2 1 = 2)和 D2 (2 2 = 4)发光二极管亮起时的面板显示。要清除十进制和显示,请关闭所有二极管,然后单击评估按钮。

讨论

不从 HMI 设备或计算机电源为实验装置供电的总体原则与使用 LabJack 接口的无保护数字 I/O 线路特别相关。如第一章练习中所述,CD4050 缓冲器提供了一个虚拟零电流或“仅电压”感测电路,其中流入或流出数字线路的电流几乎为零,因为缓冲 IC 芯片的 CMOS 栅极电阻非常高。

这个练习演示了数字表示的基本原理,即能够以二进制格式直观地表示 0 到 255 之间的任何十进制值。从右边开始的字节发光二极管代表 2 0 或 1,2 1 或 2,2 2 或 4,2 3 或 8,以此类推直到 2 7 或 128。因此,通过手动点亮 1 和 2 或最右边的一对二极管中的 led 来表示十进制值 3,0000011 表示 2 0 和 2 1 。零表示没有发光二极管点亮,255 表示所有发光二极管都点亮。

为了与更大、更复杂的数据收集现场实验的装配的适当实验开发程序保持一致,在进行下一个使用 8 位和更大 led 组的练习之前,请确认所有 8 位都由按钮控制。

8 位字节可用于表示高达 255 的数值,当进行适当的软件调整时,阵列中每增加一个 LED 将使灯组所能显示的数值范围增加一倍。10 位系统可以表示 1024 个值,而 12 位系统可以显示 4096 个数值。

在处理模数转换时,理解二进制和十进制数值域的重要性变得显而易见。大量机电传感器是与数字数值处理系统不兼容的模拟信号发生器,它们的模拟输出需要被数字化,然后才能实现数字信号处理(DSP)的精选。

带微控制器 LED 演示阵列的 DAQFactory 数字输出练习

实验的

图 5-3 中描述的 DAQFactory SCADA 软件面板,经过一些修改,可以耦合到 Arduino 微控制器,以提供一个廉价的显示器。用图 5-4 的电路和清单 5-3 的 Arduino 代码可以实现 8 位、单字节、二进制、LED 照明的数值显示。

img/503603_1_En_5_Fig4_HTML.jpg

图 5-4

微控制器上 8 位字节 LED 照明逐位数字显示的连接

在图 5-4 中,标称 Arduino 数字引脚(ADPs 3–10)是连接到原型板的跳线,对于典型的 10 mm LED 具有 220ω限流电阻,以表示字节显示的各个位。

观察

代表 1 + 4 + 16 + 64 或 85 的 D0、D2、D4 和 D6 按钮的典型点击如图 5-5 所示。

img/503603_1_En_5_Fig5_HTML.jpg

图 5-5

用于微控制器 LED 照明逐位显示的 DAQFactory 8 位字节键盘

讨论

在数字可视化练习的实现中,微控制器用于点亮适当的二极管,只需要创建代码来通过串行端口激活正确的二极管。在 DAQFactory 侧,可以使用类似于清单 5-2 中的快速序列码,并针对每个单独的 D0–D7 按钮动作进行调整。该代码为数字求和程序(列表 5-1 )设置 DigOut_n 的加权包含标志变量,并发送所需的二极管编号,其数值等于二极管及其 CLR 在 Arduino 上连接的数字引脚编号。

图 5-3 和 5-5 的 DAQFactory 控制面板的不同之处在于,标有“清除字节”的额外按钮向微控制器发送数值“12”,微控制器进而触发代码将所有数字引脚返回到低电平状态,从而关闭 Arduino 上的所有二极管。该按钮激活 DAQFactory 快速序列,重置控制面板上的所有数字按钮,并将“12”传输到微控制器,如清单 5-5 中所述。

树莓派

在 Python 中,可以使用 RPi 的 GPIO 数组的前八个引脚来配置 8 位二进制显示表示。清单 5-4 提供了点亮 LED 二进制显示器的代码,并将点亮的 LED 转换成等效的十进制数值。图 5-6 展示了使用 tkinter 库创建图形用户界面的 Python 程序的输出。

img/503603_1_En_5_Fig6_HTML.jpg

图 5-6

程序输出和 8 位字节 LED 显示控制面板

图 5-6 显示点击评估 LED 按钮产生的输出,在 8 位二进制 LED 显示屏中,代表 1、4、16、64 和 128 的 LED 点亮。

在试验板上组装 8 位 LED 显示屏时,使用 330 或 470ω限流电阻来限制 RPi 电源的电流消耗,或者使用辅助电源并缓冲阵列输出。

通过使用“新文件”创建中运行菜单中的“运行模块 F5”选项来管理面板显示的控制。Python 程序在交互式解释器模式下打开,通过选择新文件选项,创建一个新文件,通过运行菜单中的“运行模块 F5”选项,可从该文件中定位、加载和运行 8 位 LED 显示程序。

图 5-6 的 GUI 将出现,当 RPi 启动时,GPIO 管脚上施加的杂散值所照亮的任何 led 将被清单 5-4 中的内部回路重置为 0。然后,GUI 按钮可用于点亮阵列中所需的位 led。单击“评估 led”按钮将切换到交互式 Python 显示模式,并打印“评估”和“十进制和=”以及由所选发光二进制位表示的数值总和的十进制值。

要重置程序,使用交互显示右上角的取消按钮(X ),并在弹出对话框中选择是/确定,返回程序代码列表,重新运行演示。

代码列表

//ClearByteDisplay
//Nov.14/09
//This sequence just re-zeros the 8 bit byte display
//
DigOut = 0
DigOut_1 = 0
DigOut_2 = 0
DigOut_3 = 0
DigOut_4 = 0
DigOut_5 = 0
DigOut_6 = 0
DigOut_7 = 0

Listing 5-5DAQFactory Regular Sequence to Clear Byte Display

# Event handlers join a widget to a type of event and a desired
# resulting action. Command is the method used to detect mouse 
# "<Button-1>" events (clicks on the left mouse button) When a
# button is left clicked with the mouse, the self.buttonClick() 
# method is invoked to initiate a LED illumination by setting
# the pin to high.
#
import tkinter          # lower case t for current python installation
import RPi.GPIO as GPIO
from time import *
#
# the array of LEDs representing the 8 bit binary number must
# be cleared or re-set to low
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
for i in range(2, 18):
    GPIO.setup(i, GPIO.OUT)
    GPIO.output(i, GPIO.LOW)
#
# define the myWindow class in which to create the GUI window
class myWindow:
    def __init__(self):

        self.mw = tkinter.Tk()
        self.mw.title("The Scientyst's Ayde")
        self.mw.option_add("*font",("Arial", 15, "normal"))
        self.mw.geometry("+250+200")
# GUI function title
        self.lab_1 = tkinter.Label(self.mw, text = "Eight Bit Binary - Decimal Interconversions")
        self.lab_1.pack()  # place button widget/image mid window

#
# add eight buttons to the ui
        self.btn_0 = tkinter.Button(self.mw, text = "DO", command = self.btn_0_OnClick)
        self.btn_0.pack()
        self.btn_1 = tkinter.Button(self.mw, text = "D1", command = self.btn_1_OnClick)
        self.btn_1.pack()
        self.btn_2 = tkinter.Button(self.mw, text = "D2", command = self.btn_2_OnClick)
        self.btn_2.pack()
        self.btn_3 = tkinter.Button(self.mw, text = "D3", command = self.btn_3_OnClick)
        self.btn_3.pack()
        self.btn_4 = tkinter.Button(self.mw, text = "D4", command = self.btn_4_OnClick)
        self.btn_4.pack()
        self.btn_5 = tkinter.Button(self.mw, text = "D5", command = self.btn_5_OnClick)
        self.btn_5.pack()
        self.btn_6 = tkinter.Button(self.mw, text = "D6", command = self.btn_6_OnClick)
        self.btn_6.pack()
        self.btn_7 = tkinter.Button(self.mw, text = "D7", command = self.btn_7_OnClick)
        self.btn_7.pack()
# Create the evaluation button
        self.btn_8 = tkinter.Button(self.mw, text = "Evaluate LEDs", command = self.btn_8_OnClick)
        self.btn_8.pack()
#
        self.mw.mainloop()
#
    def btn_0_OnClick(self): # specify action desired on button click

        GPIO.output(2, GPIO.HIGH)
#
    def btn_1_OnClick(self):
        GPIO.output(3, GPIO.HIGH)
#
    def btn_2_OnClick(self):
        GPIO.output(4, GPIO.HIGH)
#
    def btn_3_OnClick(self):
        GPIO.output(5, GPIO.HIGH)
#
    def btn_4_OnClick(self):
        GPIO.output(6, GPIO.HIGH)
#
    def btn_5_OnClick(self):
        GPIO.output(7, GPIO.HIGH)
#
    def btn_6_OnClick(self):
        GPIO.output(8, GPIO.HIGH)
#
    def btn_7_OnClick(self):
        GPIO.output(9, GPIO.HIGH)
#
    def btn_8_OnClick(self):
        print("Evaluating") # advise of action occurring 
        dcml_sum = 0 # define and initialize summing variable

        if (GPIO.input(2)) == True: # test array bit status and add appropriate value to sum
            dcml_sum = dcml_sum + 1
        if (GPIO.input(3)) == True:
            dcml_sum = dcml_sum + 2
        if (GPIO.input(4)) == True:
            dcml_sum = dcml_sum + 4
        if (GPIO.input(5)) == True:
            dcml_sum = dcml_sum + 8
        if (GPIO.input(6)) == True:
            dcml_sum = dcml_sum + 16
        if (GPIO.input(7)) == True:
            dcml_sum = dcml_sum + 32
        if (GPIO.input(8)) == True:
            dcml_sum = dcml_sum + 64
        if (GPIO.input(9)) == True:
            dcml_sum = dcml_sum + 128
#
        print("Decimal sum = ", dcml_sum) # display result.
#
#
if __name__ == "__main__":
    app = myWindow()

Listing 5-4Raspberry Pi Python Code for an 8-Bit Binary LED Display

// DAQFactory - Arduino LED Illuminated Digital Bits in Byte
// Register DAQFtry screen bttns D0 to D7 light LEDs in digital
// array. Total value of illuminated bits calculated and
// register cleared with buttons. DAQFtr uses scripting to
// evaluate digital bits and serial port transmissions to
// illuminate LEDs after selection by case statement.
//
// digital pins in use 3,4,5,6,7,8,9, and 10
int pv_one = 3;
int pv_two = 4;
int pv_four = 5;
int pv_eight = 6;
int pv_steen = 7;
int pv_threetwo = 8;
int pv_sixfour = 9;
int pv_onetwoeight = 10;
int diod_num;
String inString = "";
//
void setup() {
  Serial.begin(9600);
//
}
//
void loop() {
  while (Serial.available() > 0 ){    // read serial input
 int inChar = Serial.read();
    if(isDigit(inChar)){
      // cnvrt incoming byte to char and add to string
      inString += (char)inChar;
    }
    // if nuline convert accmlated to integer

    if (inChar == '\n') {
 diod_num = (inString.toInt());
      Serial.println(diod_num);
      inString = "";
     }
  }
     switch(diod_num)
    {
  case 3:
  pinMode(pv_one, OUTPUT);             // units value 2 exp 0
  digitalWrite(pv_one, HIGH);
  Serial.println("Ones");
  break;
  //
  case 4:
  pinMode(pv_two, OUTPUT);             // 2 exp 1 = 2
  digitalWrite(pv_two, HIGH);
  break;
  //
  case 5:
  pinMode(pv_four, OUTPUT);            // 2 exp 2 = 4
  digitalWrite(pv_four, HIGH);
  break;
  //
  case 6:
  pinMode(pv_eight, OUTPUT);           // 2 exp 3 = 8
  digitalWrite(pv_eight, HIGH);
  break;
  //
  case 7:
  pinMode(pv_steen, OUTPUT);           // 2 exp 4 = 16
  digitalWrite(pv_steen, HIGH);
  break;
  //
  case 8:
  pinMode(pv_threetwo, OUTPUT);        // 2 exp 5 = 32
  digitalWrite(pv_threetwo, HIGH);
  break;
  //
  case 9:
  pinMode(pv_sixfour, OUTPUT);         // 2 exp 6 = 64

  digitalWrite(pv_sixfour, HIGH);
  break;
  //
  case 10:
  pinMode(pv_onetwoeight, OUTPUT);     // 2 exp 7 = 128
  digitalWrite(pv_onetwoeight, HIGH);
  break;
  //
  case 12:        // special case to clear array
  pinMode(pv_one, OUTPUT);
  digitalWrite(pv_one, LOW);
  //
  pinMode(pv_two, OUTPUT);
  digitalWrite(pv_two, LOW);
  //
    pinMode(pv_four, OUTPUT);
  digitalWrite(pv_four, LOW);
  //
  pinMode(pv_eight, OUTPUT);
  digitalWrite(pv_eight, LOW);
  //
  pinMode(pv_steen, OUTPUT);
  digitalWrite(pv_steen, LOW);
  //
  pinMode(pv_threetwo, OUTPUT);
  digitalWrite(pv_threetwo, LOW);
  //
  pinMode(pv_sixfour, OUTPUT);

  digitalWrite(pv_sixfour, LOW);
  //
  pinMode(pv_onetwoeight, OUTPUT);
  digitalWrite(pv_onetwoeight, LOW);
  break;
    }
 }

Listing 5-3Arduino Code for 8-Bit Binary Byte Display

// activation code for D0
global DigOut
device.ardyRb.Write('3' + Chr(10))   // light 1's digit
DigOut = 1                           // add 1 to sum

Listing 5-2DAQFactory Quick Sequence Code for a Microcontroller LED Byte Display

DAQFactory Sequence Code for dcml_sum
// dcml_sum sums the binary values of the diodes illuminated
global dcml_sum = 0
//
// Examine each of the 8 bits represented by the buttons on the
// digital input panel
// D0 button action toggles the DigOut channel between value 0 or 1
if (DigOut == 1)
   dcml_sum = dcml_sum + 1 // if the channel is active 20 = 1 is added to dcml_sum
   endif
if (DigOut_1 == 1) // Activation of D1  toggles the channel between 0 and 1
   dcml_sum = dcml_sum + 2 // if the channel is active 21 = 2 is added to dcml_sum
   endif
if (DigOut_2 == 1) // Activation of D2 toggles the channel between 0 and 1
   dcml_sum = dcml_sum + 4 // if the channel is active 22 = 4 is added to dcml_sum
   endif

if (DigOut_3 == 1)
   dcml_sum = dcml_sum + 8 // if the channel is active 23 = 8 is added to dcml_sum
   endif
if (DigOut_4 == 1)
   dcml_sum = dcml_sum + 16 // if the channel is active 24 = 16 is added to dcml_sum
   endif
if (DigOut_5 == 1)
   dcml_sum = dcml_sum + 32 // if the channel is active 25 = 32 is added to dcml_sum
   endif
if (DigOut_6 == 1)
   dcml_sum = dcml_sum + 64 // if the channel is active 26 = 64 is added to dcml_sum
   endif
if (DigOut_7 == 1)
   dcml_sum = dcml_sum + 128 // if the channel is active 27 = 128 is added to dcml_sum
   endif

Listing 5-1DAQFactory Sequence Code to Sum Active Binary Digit Values

摘要

  • 由比特和字节组成的数字数值的概念被直观地示出。

  • 利用商业和低成本 SCADA 系统创建数字视觉演示。

  • 在准备第六章讨论模拟和数字转换时,已经介绍了数字概念。

六、输入和输出的模拟或数字转换

在前一章中,开发了激活 8 位或二进制字节 LED 显示器的单个元件并查看由发光二极管表示的数字的十进制数字等价物的能力。DAQFactory 软件中的显示用 LabJack 硬件可视化。在本练习中,由屏幕按钮和数据输入编辑框激活的一系列 DAQFactory 序列显示输入编辑框的十进制值的二进制等效值。

在本练习中,将一个小于 255 的十进制值输入到主控制屏幕上的编辑框中,该编辑框位于一组组件面板中,这些组件控制转换和显示选项,如各个按钮上的标签所示。如图 6-2 所示,面板包含上下调节二进制值的功能和 LED 显示清除功能。实际的数值转换是通过调用基于标准数值分析的转换算法的脚本序列来完成的。顺序在章节代码清单的清单 6-1 中。

在本练习和之前的练习中,数值已经在由 2 n 和 10 n 组成的两个不同基数编号系统之间进行了转换。编号系统有不同的基础,并产生不同的数字序列来表示手头相同数量的单位或项目。改变所需数字的类型和数量是数学中的一个练习,它总是产生整数,这些数字代表两个基数中任何一个的整数单位的相同数量。

模拟和数字电信号值之间的转换通常不会产生完全相同的结果。理论上,当模拟信号从一个值变化到另一个值时,它平滑而连续地变化。模拟值的电子、数字表示必须将模拟信号的变化范围分成有限数量的间隔,该间隔等于数字显示器中可用的二进制基本位数。8 位二进制数字显示器可以表示 0 到 255 之间的十进制数。如果我们希望用以前开发的 8 位数字光显示器来表示从 0 到 5 伏变化的电信号,那么可用的 256 个二进制数字中的每一个必须表示 5.0/256 = 0.0195 V 或大约 19.5 mV。

如果二进制阵列中的 LED 数量从八个增加到十个,那么 10 位 LED 显示器可以表示 2 个 10 个或 1024 个十进制数值。10 位阵列能够将 5.0 V 信号分为 5.0/1024 = 0.004882812 伏或约 4.88 mV。

类似地,将阵列扩展至 12 位可以表示约 1.22mV/位的 5.0 V 信号。

可用位数通常称为转换器或转换分辨率。

需要在模拟和数字格式之间转换的实验必须仔细设计和组装,以补偿这些不精确的转换所引入的误差。

ADI 公司提供涵盖模数转换发展史的优秀参考书籍的硬拷贝版本或可下载的 pdf 章节系列(Walt Kester, Analog-Digital Conversion ,ADI 公司,2004 年,ISBN 0-916550-27-3)。ADI 公司提供两个出色的教程 MT-015 和 MT-016,它们解释了数模转换(DAC)的基础知识和更高级的主题,并附有大量可供进一步研究的参考资料。(参见“讨论”)

在数字表示中,最右边的位称为最低有效位(LSB),而最左边的位是最高有效位(MSB)。(基数的指数幂随着左边数字位置的增加而增加。)

许多模数转换器(ADC)集成电路器件可用于电子信号的转换。目前使用的转换机制有多种,如电平转换器或 flash 转换器、逐次逼近型寄存器、σ-δ型转换器,以及电子文献中详细讨论其优势和局限性的其它工艺。 1 (另见前面提到的 ADI 公司。)根据图 6-1 中的电路 A–D,用于降低电信号电压电平的电阻分压器电路也可用于将电压电平分成 n 个部分。从 A 到 D 越来越复杂的电路也被称为开尔文分压器,可以追溯到 19 世纪中期。

img/503603_1_En_6_Fig1_HTML.jpg

图 6-1

ADC 和 DAC 电阻网络

在图 6-1 的电路 A 中,如果电阻的值相等,分压电路将输入电压减半,如 Vout= Vin*(R/R+R)。

在图 6-1 的电路 B 中,输出电压为输入的三分之一,为 Vout= Vin*(R/R+R+R)。电路 C 和 D 中所示的四个和五个等值电阻分别将分压降低到输入电压的四分之一和五分之一。

一般来说,可以看出,输入电压和地之间的 n 个串联电阻将提供一系列连接点。输入电压为 n 时,每个电阻的压降是输入电压的 1/n。一串串联电阻和降压结是“flash”型模数转换器(集成电路)背后的机电基础。

从本质上讲,将数字信号转换成模拟信号是 ADC 过程的逆过程。与能够将输入划分为 256 个离散电压电平的二进制 8 位 ADC 一样,二进制 8 位数模转换(DAC)的反向过程也提供 2 8 或 256 个离散输出电压电平。DAC 不产生真正的模拟信号,而是产生模拟波形的阶跃电压近似值。

一种称为 R-2R“梯形”网络的高效转换架构已经开发出来,它仅使用同名的 R 和 2R 两个电阻值。从图 6-1 中的电路 E 可以看出,位 0 相对于地处于最低电压,而位 7 处于最高电压。随着电阻堆栈中位置的增加,位值的重要性或“权重”从最低到最高增加。

模拟和数字格式之间的信号转换可以用相对便宜的 IC 器件实现,如单通道、8 位 ADC0804 或 8 通道、10 位 MCP3008。ADC0804 可以与 5v 电池组一起使用,直接驱动 8 个 LED 显示屏,并提供简单、廉价的 ADC 演示。(一个 ADC0804 芯片成本 6 加元。)

除了 8 位 LED 阵列之外,使用 LabJack HMI 系列器件和 DAQFactory 软件监控模拟信号的便利性也通过 U12 系列中 10 位模数转换器的+/-10 伏输入限制和 U3 器件中 12 位转换器的 3.6 伏输入电压限制得到了证明。(参见第章 1 ,图 1-1 ,第 1 项。大多数表面贴装技术(SMT)集成电路在 3.5 伏下工作。)

使用一个简单的电阻分压器将实验范围缩小到转换器可接受的范围,就可以实现比 ADC 制造商指定的电压范围更大的电压范围测量。(见图 6-1 。)然后,研究者可以选择使用输入到第二章图 2-6 和图 6-10 和 6-11 中的变量值配置窗口的表达式框中的数学公式中的校正系数,来显示实验电压的当前值。如图 6-11 和 6-12 所示,如果研究人员需要,可以将第二个变量值显示添加到 GUI 中,用于监控施加到 ADC 输入端的实验电压和降低的电压。

数模转换

正如“练习路线图”和之前所指出的,数模转换(DAC)不会也不能再现真正的模拟电子信号。所产生的“模拟”信号在 DAC 上被分解成固定数量的离散数字值,并且从离散数量的数字值产生的模拟信号是阶梯波形,其形状类似于原始平滑且连续的模拟信号。

将数字信号转换为模拟输出有两种基本方法。一种方法使用二进制加权电阻值,其中各个数字位信号施加于电阻,电阻比与二进制幂级数成比例。构建这种类型的 DAC 经常需要非标准电阻值。DAC 的另一种方法更容易实现,如图 6-1 的电路 E 所示。R-2R 梯形电阻产生一个输出信号,该信号由梯形电阻体内的数字输入之和构成。第二种方法有几个优点,因为只需要两个电阻值。梯形电路可扩展至所需的位数,输出阻抗始终恒定,等于梯形电路中使用的较小电阻值。

实验:LabJack-DAQFactory 十进制到二进制的转换

五金器具

在前一章的练习中组装和测试的按钮控制、缓冲、8 位字节 led 显示器将作为转换后的十进制值的单个位显示或输出寄存器。

软件

  1. A panel grouping consisting of the components depicted is assembled on the main screen.

    img/503603_1_En_6_Fig2_HTML.jpg

    图 6-2

    十进制到二进制数转换器的 DAQFactory 面板

    面板由两个文本组件配置而成,显示在面板的顶部两行。编辑框组件接收要处理的数值,并将该值输入所需的变量。第四行按钮组件激活转换序列,底部一行按钮执行标题上显示的操作。

  2. 必需的脚本

    图 6-2 的分组“十进制到二进制转换器”面板需要四个脚本来激活转换器位显示,将二进制显示增加一,将数值减少一,转换输入的十进制数,然后显示二进制值,并清除显示。

本章末尾的清单 6-1 至 6-4 中提供了各个序列代码。

模数转换

为了演示利用 DAQFactory 软件和 LabJack HMI 实现模数转换的简易性,配置了如图 6-3 所示的 ADC 面板。该面板由三部分组成,一个作为标题的文本条目,一个显示通道[0]或感兴趣通道的当前值的变量值读数,以及灰色面板背景。

img/503603_1_En_6_Fig3_HTML.jpg

图 6-3

ADC 面板

模数转换电路如图 6-4 所示,其中电位计的两端连接在+5 V 和 U12 的接地端子之间,游标连接到 AI 0,模拟输入零点,螺丝端子。

img/503603_1_En_6_Fig4_HTML.png

图 6-4

可调模拟信号源

如前所述,通过使用基于电阻的分压器来降低施加于转换器的信号强度,可以使用 ADC 来跟踪超出 ADC 电子设备安全工作限值的电压波动。降低的电压 V out 可以通过以下分压器等式计算:

Vout= Vin*(R1/(R1+R2))

其中 R 1 和 R 2 是连接在 V in 和地之间的一对串联电阻的电阻值,V out 是在 R 1 与 R 2 的连接点和地之间观察到的电压。(参见图 6-1 中的电路 A)。)

实现 ADC LED 阵列照明二进制显示器的成本较低但更复杂,可以用德州仪器(ti)成熟的 ADC0804 芯片组装。(一份 57 页的 pdf 文档可从 www.ti.com/lit/ds/symlink/adc0804-n.pdf 获得)。)

pdf 数据表注明了以下内容:

  • 无需接口逻辑,可作为完整的独立器件工作,访问时间为 135 ns,差分电压输入,MOS 和 TTL 电压电平兼容,能够使用 2.5 基准电压源、片内时钟、0–5v 输入范围和 5v 电源,无需调零,标准 20 引脚 DIP 封装,转换时间为 100 us

img/503603_1_En_6_Fig5_HTML.jpg

图 6-5

8 位 LED ADC 显示器

图 6-5 描述了作者使用德州仪器 ADC0804 8 位逐次逼近型模数转换器开发 ADC 硬件演示所用的电路。为了在原型板上实现,作者使用 3 mm 红色 led 和 1kω限流电阻作为显示器,使用 4 节 AA 电池镍金属氢化物电池组作为电源,并连接到 5kω电位计的游标引线,该电位计连接在标称 5v 电源和地之间,类似于图 6-4 中所示的电路。当电位计上的轴旋转时,游标电压提供变化的模拟电压信号,用于转换成数字格式来驱动二进制 led。

图 6-5 中描述的数字地全部连接到公共连接,然后接地到电源的负端。作者在原型板上实现的电路中包含一个开/关开关,但它并不是启动电路动作所必需的,因为当系统通电时,转换会立即开始。要转换的电压施加于 IC 的引脚 6。

观察

DAQ factory–lab jack HMI 模数基数转换

在编辑框中输入一个十进制值并点击输入脚本按钮,对应于输入的十进制数字值的二极管将会亮起。输入数值 25 时,应点亮 2 个 0 (1)、2 个 3 (8,即 2 × 2 × 2)和 2 个 4 (16,即 2 × 2 × 2 × 2)二极管的单元,以显示 25 的二进制等效值(即 1 + 8 + 16)。

单击增加或减少按钮应该将显示的二进制值增加或减少 1,而清除按钮应该清除显示。

模数电子信号转换

如果没有机械限制或不连续性,在 10kω电位计两端连接一个标称 5 V 信号,理论上应能产生一个平滑变化的模拟游标电压,范围为 0 至 5V。

安装在 U12 中的 10 位 ADC 理论上能够将 5 V 模拟信号分成 1024 个 0.0048828 伏特或 4.883 mV 的单元。变量值显示器被配置为读取如图 6-4 所示接线的 10kω电位计的游标上的电压。当旋转电位计轴时,当变量值显示设置为显示 AO 0、模拟输出零、通道上的数据至三位小数时,DAQFactory GUI 屏幕上显示 0.010 V 至 4.219 V 的值。下电压值显示从 0.005 波动到 0.020,上电压值显示从 4.209 波动到 4.365。

ADC0804: 8 位二进制 LED 显示器

图 6-6 是图 6-5 中电路的电池供电工作示例照片,装配在试验板上,用于直观演示 ADC。仔细检查视野右上角的二极管,会发现 4 位、8 位和 64 位指示灯亮起,指示总值为 76。电压源是视野底部中央可见的 5kω电位计的游标引线。

当图 6-5 的电路通电时,代表数字化游标电压电位的二进制等值的单个 led 立即亮起。将电位计的轴从一个极限位置旋转到另一个极限位置,显示二极管照明序列,其中二进制数从 0 增加到 255 或相反。通过缓慢旋转轴,可以在二进制显示中跟踪单个计数。如前所述,充满电后,电池组产生标称 5 V 电压,施加于电位计两端。

img/503603_1_En_6_Fig6_HTML.jpg

图 6-6

8 位 LED ADC 显示器照片

施加的电压和二进制显示之间的相关性是通过测量然后比较施加到输入引脚#6 的实际电压和由 8 位显示阵列的发光二极管显示的二进制值来建立的。

检查图 6-7 的列表数据和 ADC0804 数据手册发现,施加的电压与产生的数字值之间并不存在 1:1 的对应关系,因为施加的电压为 5.25 时产生的输出仅为 253。利用基准电压输入引脚(引脚#9)可以校正 ADC 差异,如 IC 数据手册所述。(参见“讨论”)

img/503603_1_En_6_Fig7_HTML.jpg

图 6-7

ADC0804 线性度

讨论

ADI 公司出版物模数转换第一章的图 1.1 有助于理解 ADC 和 DAC 的概念。模拟。com/media/en/training-研讨会/设计-手册/数据转换-手册/第一章。pdf 。该图的标题为“18 世纪早期二进制加权水计量系统”,包含十九世纪在土耳其伊斯坦布尔实施的水计量系统的一系列侧视图和俯视图。这些图表记录了 DAC 在重力驱动、水力配水和“加权平均”计量系统方面的实施情况。

模拟电子信号值和数字数值表示之间的相互转换很少是完全等价的。ADC0804 等传统 ADC 使用 8 条信号线的并行输出,每条信号线代表 2 的幂。并行输出有助于组装图 6-6 的电池供电的可视 LED 显示器。然而,LabJack 器件中使用的新技术不使用 ADC 的“并行”输出配置,而是依靠更简单的方式来实现串行数据输出。串行数据输出协议的速度足以监控多种类型的传感器,但高速仪器通常需要使用并行转换器来跟上数据生成速率。

应用分压器时必须小心,因为所选电阻值的比值必须将信号电压降至所需水平,但单个电阻值应尽可能低,以允许足够的电流通过,从而驱动“下游”器件或 ADC。

ADC 产生的数字由并行信号输出组成,以驱动“下游”器件的逻辑,如微处理器、七段 LED 数字显示器,或者在本初级练习中的 8 位二进制 LED 显示器,但其能够安全提供的电流输出通常有限。在一些高电流需求显示器中,可能需要缓冲 ADC 输出。

在使用 DAQFactory 软件的 LabJack HMI 和 ADC0804 8 位 LED 显示器的装配或显示器与 RPi 的接口之间,实现 ADC 和 DAC 演示所需的时间和精力有很大的不同。

ADC0804 是一款单通道器件,需要一个调整至 0–5v 范围的可变电压源输入。IC 有一个参考电压引脚#9,可用于调整 255 位电平的步长。默认设置为每数字增量 19.5 mV,因此整个 5 V 输入范围将产生 0–255 二进制数字输出。(有关使用步长调整的更多信息,请参见德州仪器 ADC0804 数据手册。)需要一个时钟来运行转换逻辑,为简单起见,使用内部时钟需要一个串联电阻和电容(RC)网络。所需的 RC 组合连接在时钟输入和时钟 R 引脚(引脚#4 和#19)之间。RC 时间常数最终决定 IC 对引脚#6 上的电压进行采样的频率,以便在输出引脚上产生转换结果。

除了时钟和输入布线之外,ADC0804 演示练习还需要一个 5 V 电源和八个 LEDS 及其限流电阻。

正如在前面的练习中所提到的,在系统组装时,研究人员应该尽可能地测试每个组件。每个 LED 和限流电阻都可以通过在将连接到 ADC0804 的电阻端施加 5 V 电压来测试。

在创建按钮代码的过程中,演示了使用以前编写的脚本作为函数的能力。如前一练习所述,较大数值的数值转换需要增加适当数量的数字输出线路、通道和二极管,并修改脚本代码。

一个 8 位字节提供 1/28或 1/256 的分辨率。图 6-2 中的十进制到二进制转换器面板包含表示一位数分辨率的增加和减少按钮。如果实验设置可能产生 0 至 10 伏的变化 DC 信号,则 8 位转换能够解析出 10/256 = 0.0390625 或 39.1 mV。在 LED 显示库中增加两个以上的位和相应的软件变化将允许 10 V 信号范围扩展到 1024 个二进制数字,提供 1024 或毫伏灵敏度或分辨率中的一部分的近似划分。将数字能力提高到 12 位将提供 4096 分之一或 0.0244% (244 ppm,百万分之一)的灵敏度或分辨率。

GUI 数字显示除了其当前值之外,不传达关于被监控电压值的任何附加信息。除非数字值有明显的稳定增加或减少的趋势,否则无法从监控变量值的数字显示中获得额外的信息。然而,在生产过程或实验测量被监控并且过程变量或测量结果的恒定性是 SCADA 系统的主要目标的许多情况下,诸如定时记录的不同形式的数据呈现可能具有更大的价值。

利用微控制器进行模数转换

如前五个练习中所述,更紧凑、更便宜的 SMT 设备能够在 DAQFactory SCADA 软件和实验传感器或过程管理硬件之间实现接口,并以微控制器的形式出现。(参见第九章。)

Arduino 微控制器是易于获得、易于使用的紧凑型设备,内置 10 位逐次逼近型 SMT 模数转换器,具有 6 个输入通道。ADC 芯片能够在其 16 MHz 时钟的 25 个周期内将输入电压转换为数字。每次转换 400 微秒)。

Arduino 之类的微控制器是一种串行设备,为了在 DAQFactory 控制屏幕和微控制器 LED 阵列之间来回传递信息,控制屏幕和控制器都必须像前面的练习一样读取和写入串行端口。

串行通信基于 1 和 0 的 ASCII 位模式,允许传输数字和字母控制字符,如换行和回车。虽然 ADC 硬件可以产生一位数或多位数的整数位计数,但串行端口的每一端都必须有一定数量的字符识别和解释逻辑软件,以便创建一个正常工作的通信系统。

实验的

通过 DAQFactory 控制面板和 Arduino 控制的二进制阵列之间的串行连接实现十进制到二进制显示可以从图 6-8 中描述的 DAQFactory 面板的创建开始。

img/503603_1_En_6_Fig8_HTML.jpg

图 6-8

用于串行控制 Arduino 二进制 LED 显示器的 DAQFactory 控制面板

图 6-8 中使用了一个文本组件、一个编辑框和四个按钮。

图 6-9 显示了编辑框配置窗口,该窗口为创建框标题和选择各种选项和动作提供了空间。

img/503603_1_En_6_Fig9_HTML.jpg

图 6-9

编辑框配置窗口

本章末尾的清单 6-5 到 6-9 中提供了实现串行面板连接到微控制器的支持 DAQFactory 脚本和 Arduino 草图代码。

为了将微控制器板上的 ADC 用作串行连接的传感器读数设备,可以如图 6-10 所示配置一对在 DAQFactory 屏幕上分组为一个面板的变量值显示组件。使用 SCADA 软件的通道功能,可以同时显示 ADC 的整数计数和与计数值相对应的计算电压值。(这里只粗略介绍了在两个系统之间提供数据流所需的更复杂的设置。更多细节在第十一章中提供。)

img/503603_1_En_6_Fig10_HTML.jpg

图 6-10

整数 ADC 计数和计算的 ADC 电压的可变值元件显示

如图 6-10 所示,DAQFactory 页面上有两个变量值显示。

图 6-11 和 6-12 显示了显示原始计数的整数 ADC 计数显示和使用表达式计算 ADC 即时电压值的 ADC 电压值显示的配置窗口。

img/503603_1_En_6_Fig12_HTML.jpg

图 6-12

计算出的 ADC 电压的变量值配置页面

img/503603_1_En_6_Fig11_HTML.jpg

图 6-11

串行传输的整数 ADC 计数的变量值配置页面

图 6-13 记录了建立串行微控制器 SCADA 软件通信所遵循的表格、窗口和条目的顺序。

img/503603_1_En_6_Fig13_HTML.png

图 6-13

一种实现 DAQFactory 串行通信的配置序列

图 6-13 显示了从微控制器 ADC 读取串行“数据流”到 DAQFactory 显示组件所需的主要程序动作的标题概要。(详见第十一章。)第 1 项标记了正在使用的 DAQFactory 程序的页面列表,在该页面上,图 6-10 的面板由所需部件组装而成。第 2 项表示通道列表,其中 ArduinoStream 通道由作者创建,用于接收从微控制器输出到串行端口的 ADC 数据(另见图 2-3 )。第 3 项和第 4 项是串行端口配置窗口和串行设备命名和配置窗口,将在第十一章中详细介绍(参见图 11-5 、 11-6 和 11-7 )。

要安装和使用清单 6-10 中的代码,点击快速➤设备配置并选择适当的设备,在作者的演示案例中是 Comm4。在“以太网/串行设备”窗口中,找到所需的设备并选中旁边的框(图中的 Comm4 ),然后单击“协议配置”按钮,调出“I/O 类型和功能”窗口。选择“接收时”功能,然后将清单 6-10 的代码复制并粘贴到空白处。(参见 11 章节中的图 11-7 。)

为了给本练习演示提供可变信号模拟,可以将电位计的两端连接在+5 V 电源和微控制器地之间,以及连接到 Arduino ADC A0 输入的游标引线之间。(参见图 6-4 的类似电路图,用于 LabJack HMI。)

根据从多个经过测试且功能正常的组件构建复杂系统的理念,我们可以从加载并启动清单 6-11 中的微控制器草图代码开始。草图运行后,可以从工具菜单打开 Arduino 串行监视器,在串行监视器视野的左侧应该可以看到 ADC 计数流。确认数据流生成后,串行监视器关闭,微控制器 IDE 最小化。

包含变量值面板的 DAQFactory 程序启动,如果所有配置正确,图 6-10 的屏幕组件应能响应系统噪音和电位计刮水器控制轴的任何重新定位。

观察

启动用于 ADC 读取和串行打印到所用端口的微控制器草图后,应该可以在微控制器 ide 的串行监视器窗口的视野左侧看到一串数值,其值介于 0 和 1024 之间。

微控制器在后台运行时,微控制器原型板上的电位计轴旋转一整圈,电压的整数显示从 0 到 1024 和 0 到 5.000 伏,如图 6-11 和 6-12 的配置窗口中的设置所定义。

讨论

无响应显示器的诊断

如果变量值面板没有响应输入数据流,展开通道表并确认数据被通道捕获,如图 6-14 所示。

img/503603_1_En_6_Fig14_HTML.png

图 6-14

一个活动信道时间戳数据列表

如果通道没有接收到 ADC 数据,则可以访问 DAQFactory 程序的串行端口监视器,以确认数据正在到达显示程序的串行端口。串行端口监视器通过快速➤设备配置菜单和设备选择列表面板进入以太网/串行设备窗口,如图 6-13 的第 4 项所示。点击配置按钮正下方的监视器按钮将调出 DAQFactory 串行监视器,如图 6-15 所示。

img/503603_1_En_6_Fig15_HTML.png

图 6-15

DAQFactory 串行监视器显示通过正在使用的端口的数据

如果数据正在到达 DAQFactory 串行端口,但没有被传输到正确的通道,可以通过确保在协议列表中选择了正确的协议,并且正确的解析代码(列表 6-10 )已经输入到协议配置窗口的“接收时”I/O 类型和功能条目中,来检查端口串行协议。 2

系统开发和编程

虽然建立 SCADA-实验串行连接的微控制器方法比使用市场上可买到的 DAQ 系统要便宜得多,但是所需的实验开发时间和精力是相当大的,并且该系统缺乏商业产品中的鲁棒性。

利用 Raspberry Pi 实现输入和输出的模拟和数字转换

由于之前提到的可用功率限制,可以使用 RPi 及其通用输入/输出引脚阵列创建电子数字编号的 LED 可视化。可以使用 Raspberry Pi Foundation 提供的两个 Python 库演示二进制和十进制之间的数字转换以及 ADC。RPi。GPIO 库允许对 40 针阵列的低级访问,而 gpiozero 库代码提供对许多硬件设备的访问。每个库的文档都可以从 RPi Foundation 网站上获得,两个库版本之间的差异将在接下来的几个练习中进一步阐述。

二进制-十进制转换

作为对前面练习中介绍的 RPi 编程和硬件使用的补充,在本练习的最初部分,我们组装了一个 12 位十进制到二进制转换 LED 可视显示器。转换器的代码在本章末尾的清单 6-12 中,转换的输出如图 6-16 所示。

img/503603_1_En_6_Fig16_HTML.jpg

图 6-16

十进制值的 RPi 12 位二进制显示

12 个 led 的银行组装和测试,以提供几个 Python 和 ADC 程序的视觉输出。十进制到二进制数字转换器、10 位 ADC 和 12 位 ADC 可以共用同一硬件,以图形方式直观显示这些类似程序的各种输出。

带树莓 Pi 的 ADC

如前所述,RPI 需要外部器件来对模拟信号进行数字化处理,RPi 基金会选择 MCP3008 和 MCP3201 ICs 作为 10 位和 12 位数字转换的合适器件。IC 通过串行外设接口(SPI)串行协议与 RPi 通信。ADC 数据以连续的位序列输出到 RPi,RPi 接收并解释 10 位转换值。MCP3008 输出可以格式化为 0 至 1.0 的浮点归一化值,与采样电压和施加于基准引脚的电压之差成比例,也可以格式化为 1 至 1024 的整数值。当 ADC 芯片以 RPi 的 3.3 电源为基准时,归一化输出必须乘以施加的标称电压,或者为了精确起见,乘以 VOM 测量的基准电压,以获得实际采样电压。MCP3008 的整数输出到采样电压值的转换包括将输出值除以 1024 并乘以参考值电压。

表示模拟转换的浮点归一化值不容易用于照亮 10 位二进制 LED 可视显示器。数字整数输出更容易与二进制 LED 显示器接口。

实验的

为了将清单 6-12 和 6-13 的代码用于十进制到 10 或 12 位二进制 LED 可视显示器和本练习中列出的 MCP 芯片,RPi 必须配置为使用串行外设接口(SPI)协议,如图 6-21 和 6-22 所示。

来自偏置在 RPi GPIO 阵列的 3.3 V 和地之间的 10kω电位计的游标的连续可变电压用于产生 MCP3008 ADC 集成电路的测试电压。RPi 从 IC 读取串行输出,解释流数据,并产生调整后的 10 位整数输出,随后用于激活 10 单元 led 显示器。

图 6-17 是用于实现显示的电路的半示意图。游标电压施加于 IC,IC 将信号从模拟格式转换为数字格式,并将数据以串行外设接口(SPI)形式输出至 RPi GPIO 引脚。RPi 接收流数据,解释转换后的数据,并解析整数输出,以驱动转换后的游标电压信号的适当二极管表示。

img/503603_1_En_6_Fig17_HTML.jpg

图 6-17

RPi-MCP3008 电路,用于电位计游标电压的 10 位二进制 LED 显示

图 6-17 的左边是控制和接收 IC 数据的 Raspberry Pi GPIO 引脚连接,右边是 RPi GPIO 二极管阵列连接。

图 6-18 显示了在模拟实验设置期间 RPi 的屏幕输出,其中诊断打印语句已被插入到代码中,以验证系统的运行。电位计游标已经旋转,以产生尽可能接近序列 123 的数字输出。

img/503603_1_En_6_Fig18_HTML.jpg

图 6-18

ADC 期间的 RPi 屏幕输出

观察

图 6-18 显示了 Python 代码的连续输出,该代码解析数字化、转换后的游标电压值,以驱动输出值的 10 位 LED 二进制表示的各个元素。对输出和正在处理的实际代码进行更仔细的检查将会确认,只有当余数变量“rem”具有正值或高值时,程序才会打印诊断输出。将电位计轴从一个极端旋转到另一个极端会使显示从 1 或 0 变化到 1023。从图 6-18 的数据变化中可以看出,系统在雨刷输出值中包含了一定量的噪声。

图 6-19 描述了 RPi GPIO 阵列与原型试验板上的 12 位 LED 显示器的接口。发光二极管对应于二进制位模式 2 + 4 + 8 + 16 + 32 或十进制 62。

img/503603_1_En_6_Fig19_HTML.jpg

图 6-19

十进制值 62 的 12 位二进制 LED 显示

讨论

图 6-19 描绘了一组 12 个 3mm led,可用于 10 位或 12 位转换演示。MCP3201 是一款 12 位转换 IC,可以设置为二进制可视化显示器。小型 3 mm 二极管和 1kω限流电阻用于最大限度地降低视觉显示器中有大量 led 的计算机的电流消耗。

RPi 电路、编程和布线的数字和照片反映了使用非常便宜的系统所需的复杂性。从图 6-19 的照片中可以看出,调查人员需要注意 RPi GPIO 线的跳线连接以及控制 MCP3008 或 MCP3201 转换功能所需的跳线连接。激活引脚阵列输出的 10 或 12 位二进制 LED 显示所需的 RPi GPIO 线连接可以在装配期间用清单 6-14 进行测试。当每个引脚名称出现在交互式屏幕上时,连接到标称引脚的相应 LED 应点亮 3 秒钟。图 6-20 描绘了引脚和 LED 测试的测试程序输出显示。

img/503603_1_En_6_Fig20_HTML.jpg

图 6-20

LED 阵列测试输出

列表 6-15 可用于将 GPIO 阵列电压值重置为零。

前面 ADC0804 所展示的并行 ADC 集成电路在一定程度上已被众多串行通信协议所取代。使用两根或少量导线进行长距离串行通信,比使用 8、10、12 或更多并行导线来传输高频数字数据位要实用得多。防止“串扰”的屏蔽、物理尺寸和费用只是在密集的平行线路上进行高速数据传输时会遇到的一些问题。

model 3 Raspberry Pi 可以配置为使用多种串行通信系统中的一种。图 6-21 和 6-22 显示进入首选项➤配置窗口,该窗口允许执行所需的协议。

img/503603_1_En_6_Fig22_HTML.jpg

图 6-22

接口选择窗口

img/503603_1_En_6_Fig21_HTML.jpg

图 6-21

RPi 首选项选择菜单

选择串行外设接口(SPI)协议允许 RPi 与以连续高低位脉冲流“流出”数据的器件通信。ADC 就是这样一种数据流设备。SPI 协议基于主从概念,三个或四个电气连接在主机和一个或多个从机之间形成一条电子总线。时钟同步数据传输。SPI 配置中的四条线路是主机输出从机输入(MOSI)、主机输入从机输出(MISO)、时钟线(SCLK)和芯片从机选择(CSS)。

如果有许多从机,SPI 可能会变得难以实现,第二种流行的协议是集成电路间(I 2 C 或 I2C)协议。I2C 是双线式实现,固定速度较慢,使用可寻址位置,比 SPI 功耗更高,噪声更低。I2C 是唯一确认数据传输的协议。

在图 6-22 中,有第三个通信接口,称为串行接口,实现通用异步接收和传输(UART)协议。异步通信只在两个设备之间进行,不需要外部时钟,但在两端使用一致同意的数据传输和接收速率。双线总线的每一端都有一个 IC,用于在并行和串行数据流之间进行转换。在 UART 传输中,定义的格式用开始和停止标记指定数据的开始和结束。串行协议广泛用于微处理器通信。

有关这三个协议的更多细节,请参见发明者实用电子学??

代码列表

 /*
  AnalogReadSerial
  Reads an analog input on pin A0, prints the result to the serial monitor.
  Attach the center pin of a potentiometer to pin A0, and the outside pins to +5V and ground.
 */

// the setup routine runs once when you press reset:
void setup() {
  // initialize serial communication at 9600 bits per second:
  Serial.begin(9600);
}

// the loop routine runs over and over again forever:
void loop() {
  // read the input on analog pin 0:
  int sensorValue = analogRead(A0);
  // print out the value you read:
  Serial.println(sensorValue);
  delay(50);        // delay in between reads for stability
}

Listing 6-11Arduino Sketch Code to Read A0 ADC Channel and Write Data to Serial Port on 50 ms Intervals

if (strIn == Chr(13))
   private string datain = ReadUntil(13)
   Channel.AddValue(strDevice, 0, "Input", 0, StrToDouble(DataIn))
   Endif

Listing 6-10DAQFactory “On Receive” Code for the ArduinoStream Channel

// DAQFactory - Arduino LED Illuminated Digital Bits in Byte
// Register DAQFtry screen bttns D0 to D7 light LEDs in digtal
// array. Total value of illuminated bits calculated and
// register cleared with buttons. DAQFtr uses scripting to
// evaluate digital bits and serial port transmisons to
// illuminate LEDs after selectn by case statement.
//
// digital pins in use 3,4,5,6,7,8,9, and 10
int pv_one = 3;
int pv_two = 4;
int pv_four = 5;
int pv_eight = 6;
int pv_steen = 7;
int pv_threetwo = 8;
int pv_sixfour = 9;
int pv_onetwoeight = 10;
int diod_num;
String inString = "";
//
void setup() {
  Serial.begin(9600);
//
}
//
void loop() {
  while (Serial.available() > 0 ){       // read serial input
 int inChar = Serial.read();
    if (inChar == '3') {
    pinMode(pv_one, OUTPUT);             // units value 2 exp 0
    digitalWrite(pv_one, HIGH);
  }
    if (inChar == '4') {
      pinMode(pv_two, OUTPUT);             // 2 exp 1 = 2
      digitalWrite(pv_two, HIGH);
  }
    if (inChar == '5') {
      pinMode(pv_four, OUTPUT);            // 2 exp 2 = 4
      digitalWrite(pv_four, HIGH);
  }
    if (inChar == '6') {
      pinMode(pv_eight, OUTPUT);           // 2 exp 3 = 8
      digitalWrite(pv_eight, HIGH);
  }
    if (inChar == '7') {
      pinMode(pv_steen, OUTPUT);           // 2 exp 4 = 16

      digitalWrite(pv_steen, HIGH);
  }
    if (inChar == '8') {
      pinMode(pv_threetwo, OUTPUT);        // 2 exp 5 = 32
      digitalWrite(pv_threetwo, HIGH);
  }
    if (inChar == '9') {
      pinMode(pv_sixfour, OUTPUT);         // 2 exp 6 = 64
      digitalWrite(pv_sixfour, HIGH);
  }
    if (inChar == 'a') {
      pinMode(pv_onetwoeight, OUTPUT);     // 2 exp 7 = 128
      digitalWrite(pv_onetwoeight, HIGH);
  }
    if (inChar == 'z') {
      // special case to clear array
  pinMode(pv_one, OUTPUT);
  digitalWrite(pv_one, LOW);
  //
  pinMode(pv_two, OUTPUT);
  digitalWrite(pv_two, LOW);
  //
    pinMode(pv_four, OUTPUT);
  digitalWrite(pv_four, LOW);
  //
  pinMode(pv_eight, OUTPUT);
  digitalWrite(pv_eight, LOW);
  //
  pinMode(pv_steen, OUTPUT);

  digitalWrite(pv_steen, LOW);
  //
  pinMode(pv_threetwo, OUTPUT);
  digitalWrite(pv_threetwo, LOW);
  //
  pinMode(pv_sixfour, OUTPUT);
  digitalWrite(pv_sixfour, LOW);
  //
  pinMode(pv_onetwoeight, OUTPUT);
  digitalWrite(pv_onetwoeight, LOW);
   }
 }
}

Listing 6-9Arduino Sketch Code for Diode Array Illumination

/ClearByteDisplay
//Nov.14/09
//This sequence just re-zeros the 8 bit byte display
device.ardyRb.Write('z' + Chr(10))

Listing 6-8DAQFactory Sequence Code for Clearing the Display

//DecBinDisplay
//Nov.14/09
//This sequence decreases the screen entered global variable
//Number_To_Convert that was converted and displayed in
//sequence ConvertDecToBinary and runs the decreased value back 
//through the original sequence.
//In the original conversion sequence the Edit Box value, 
//variable, Number_To_Convert is iteratively divided by two till 
//it vanishes so the entered number is saved in Orgnl_N_To_Cnvrt
//
global Orgnl_N_To_Cnvrt
//clear the register of any residual data
ClearByteDisplay()
//re-initialize the working variable to the desired value to be converted
Number_to_Convert = Orgnl_N_To_Cnvrt - 1
//convert and display the bit pattern
DecimalToBinaryCnvrsnRvn1()

Listing 6-7DAQFactory Sequence Code for Decreasing the Converted Value

//IncBinDisplay
//Nov.14/09
//This sequence increases the screen entered global variable
//Number_To_Convert that was converted and displayed in sequence
//ConvertDecToBinary. The value of the original variable was 
//iteratively reduced to zero by the conversion code but was
//preserved in the global variable Orgnl_N_To_Cnvrt.
//The preserved number is augmented in value and passed back
//through the original sequence.
//
global Orgnl_N_To_Cnvrt
//
//any residual values on the byte register are cleared
ClearByteDisplay()
//
// the original value is augmented
Number_to_Convert = Orgnl_N_To_Cnvrt + 1
//
//the augmented value is converted and displayed
DecimalToBinaryCnvrsnRvn1()

Listing 6-6DAQFactory Sequence Code for Increasing the Converted Value

//Decimal to Binary Conversion
//Oct 14-16, Nov 14/2009, serial port display Jun7/19
//Program Algorithm
//8 LEDs are connected to the  digital output channels D0 (#4) 
//to D7 (#11) on the DB25 output of the LabJack. Each line is 
//buffered/driven with a 4050 buffer.
//An EDIT box accepts the Number_To_Convert and the modulo of
// the value with respect to base 2 is determined for each bit
// of a byte. The bit values are then displayed on the LEDs. In
// this version a quick sequence writes the number of the
// digital pin on the Arduino connected to the diode to be
// illuminated on the serial port.
//A for loop executes 8 times to evaluate each bit of the 
//binary digit
// On the control screen the researcher has the option to
// increase/decrease the conversion value and clear the byte
// register.
//
// Declarations
//
global Number_To_Convert
//Preserve original decimal value entered from the control screen

global Orgnl_N_To_Cnvrt = Number_To_Convert
//
global Converted_Number[0] = 0
global Converted_Number[1] = 0
global Converted_Number[2] = 0
global Converted_Number[3] = 0
global Converted_Number[4] = 0
global Converted_Number[5] = 0
global Converted_Number[6] = 0
global Converted_Number[7] = 0
//
//
//
//
for ( Private.Counter = 0, Counter < 8, Counter++)
      Converted_Number[Counter] = Number_To_Convert %2
      Number_To_Convert = Number_To_Convert/2
      Number_To_Convert = Floor(Number_To_Convert)
   endfor
//
   if (Converted_Number[0] == 1)
//
//      DigOut = 1
device.ardyRb.Write('3' + Chr(10))
   endif
//
   if (Converted_Number[1] == 1)
//
//      DigOut_1 = 1
device.ardyRb.Write('4' + Chr(10))
   endif
//
   if (Converted_Number[2] == 1)
//
//      DigOut_2 = 1
device.ardyRb.Write('5' + Chr(10))
   endif
//
   if (Converted_Number[3] == 1)
//
//      DigOut_3 = 1

device.ardyRb.Write('6' + Chr(10))
   endif
//
   if (Converted_Number[4] == 1)
//
//      DigOut_4 = 1
device.ardyRb.Write('7' + Chr(10))
   endif
//
   if (Converted_Number[5] == 1)
//
//      DigOut_5 = 1
device.ardyRb.Write('8' + Chr(10))
   endif
//
   if (Converted_Number[6] == 1)
//
//      DigOut_6 = 1
device.ardyRb.Write('9' + Chr(10))
   endif
//
   if (Converted_Number[7] == 1)
//
//      DigOut_7 = 1
device.ardyRb.Write('a' + Chr(10))
   endif

Listing 6-5DAQFactory Code for Decimal-to-Binary Conversion via Serial Connection

//ClearByteDisplay
//Nov.14/09
//This sequence just re-zeros the 8 bit byte display
//
DigOut = 0
DigOut_1 = 0
DigOut_2 = 0
DigOut_3 = 0
DigOut_4 = 0
DigOut_5 = 0
DigOut_6 = 0
DigOut_7 = 0

Listing 6-4DAQFactory Script Code to Clear Display

//DecBinDisplay
//Nov.14/09
//This sequence decreases the screen entered global variable
//Number_To_Convert that was converted and displayed in
//sequence ConvertDecToBinary and runs the decreased value back
//through the original sequence.
//In the original conversion sequence the Edit Box value, 
//variable, Number_To_Convert is iteratively divided by two till
//it vanishes so the entered number is saved in Orgnl_N_To_Cnvrt
//
global Orgnl_N_To_Cnvrt
//clear the register of any residual data
ClearByteDisplay()
//re-initialize the working variable to the desired value to be converted
Number_to_Convert = Orgnl_N_To_Cnvrt - 1
//convert and display the bit pattern

ConvertDecToBinary()

Listing 6-3DAQFactory Script Code to Decrease the Converted Value

//IncBinDisplay
//Nov.14/09
//This sequence increases the screen entered global variable
//Number_To_Convert that was converted and displayed in
//sequence ConvertDecToBinary. The value of the original
//variable was iteratively reduced to zero by the conversion code
//but was preserved in the global variable Orgnl_N_To_Cnvrt.
//The preserved number is augmented in value and passed back through the original sequence.
//
global Orgnl_N_To_Cnvrt
//
//any residual values on the byte register are cleared
ClearByteDisplay()
//
// the original value is augmented

Number_to_Convert = Orgnl_N_To_Cnvrt + 1
//
//the augmented value is converted and displayed
ConvertDecToBinary()

Listing 6-2DAQFactory Script Code to Increase the Converted Value

//Decimal to Binary Conversion
//Oct 14-16, Nov 14/2009
//Program Algorithm
//8 LEDs are connected to the  digital output channels D0 (#4) 
// to D7 (#11) on the DB25 output of the LabJack. Each line is 
// buffered/driven with a 4050 buffer.
//An EDIT box accepts the Number_To_Convert and the modulo of
// the value with respect to base 2 is determined for each bit
// of a byte. The bit values are then displayed on the LEDs
//A for loop executes 8 times to evaluate each bit of the
//binary digit
// On the control screen the researcher has the option to
// increase/decrease the conversion value and clear the byte
// register.
//
// Declarations
//
global Number_To_Convert
//Preserve original decimal value entered from the control screen
global Orgnl_N_To_Cnvrt = Number_To_Convert
//
Private Converted_Number[0] = 0
Private Converted_Number[1] = 0
Private Converted_Number[2] = 0
Private Converted_Number[3] = 0
Private Converted_Number[4] = 0
Private Converted_Number[5] = 0
Private Converted_Number[6] = 0
Private Converted_Number[7] = 0

//
//
for ( Private.Counter = 0, Counter < 8, Counter++)
      Converted_Number[Counter] = Number_To_Convert %2
      Number_To_Convert = Number_To_Convert/2
      Number_To_Convert = Floor(Number_To_Convert)
   endfor
//
   if (Converted_Number[0] == 1)
//
      DigOut = 1
   endif
//
   if (Converted_Number[1] == 1)
//
      DigOut_1 = 1
   endif
//
   if (Converted_Number[2] == 1)
//
      DigOut_2 = 1
   endif
//
   if (Converted_Number[3] == 1)
//
      DigOut_3 = 1
   endif
//
   if (Converted_Number[4] == 1)
//
      DigOut_4 = 1
   endif
//
   if (Converted_Number[5] == 1)
//
      DigOut_5 = 1
   endif
//
   if (Converted_Number[6] == 1)
//
      DigOut_6 = 1
   endif
//
   if (Converted_Number[7] == 1)
//
      DigOut_7 = 1

   Endif

Listing 6-1DAQFactory–LabJack U12 Decimal-to-Binary Sequence Codes

Raspberry Pi 代码清单

# Utility program to reset the GPIO pin values to 0
import RPi.GPIO as GPIO
# set the pin identity mode
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
# Reset the array pins to off/false/0
chan_list = (2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20)
GPIO.setup(chan_list, GPIO.OUT)
GPIO.output(chan_list, GPIO.LOW)delay)

Listing 6-15Utility Program to Reset the GPIO Pin Values to Zero

# Test the LED Array on the GPIO pins
#
import RPi.GPIO as GPIO
import time
# set the pin identity mode
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
# Reset the array pins to on for 3 sec then turn off
for i in range(2, 21):
    GPIO.setup(i, GPIO.OUT)
    GPIO.output(i, GPIO.HIGH)
    print("Testing pin ",i)
    time.sleep(3)
    GPIO.output(i, GPIO.LOW)

Listing 6-14RPi Code for Testing LEDs on GPIO Pin Array

# An SPI based program to read an MCP3008 10 Bit ADC
# the referenced voltage range is divided into an integer from
# 0 to 1023 sampled voltage is ADC/1023 * 3.3 volts. A blend of
# GPIO and SPI code is used to run a 10 bit LED display of the
# ADC value.
#
# import the RPi.GPIO low level pin control library
import RPi.GPIO as GPIO
import spidev
import time
# setup the pin identification scheme
GPIO.setmode(GPIO.BCM)
# turn off the array use warnings
GPIO.setwarnings(False)
# ensure all the LED driver outputs are set to output and are zero
for i in range(2, 7):
    GPIO.setup(i, GPIO.OUT)
    GPIO.output(i, GPIO.LOW)
for i in range(13, 18):
    GPIO.setup(i, GPIO.OUT)
    GPIO.output(i, GPIO.LOW)
# create required variables
# the delay time
delay = 0.5   # the value of time variable delay is defined
# the channel to use
pot_chnnl = 0
# create a spidev object of the device connected to the 

# channel in use
spi = spidev.SpiDev()
spi.open(0, 0)
# create the readadc function that checks for the correct channel assignment
# if the channel assignment is correct the adc value is read
# the function returns -1 a channel error or the adc value
def readadc(pot_chnnl):
    # check channel
    if pot_chnnl  > 7 or pot_chnnl < 0:
        return -1
    r = spi.xfer2([1,  8 + pot_chnnl << 4, 0])
    data = ((r[1] & 3) << 8) + r[2]
    return data
#
# the while loop, print out and time delay
while True:
    wpr_vlu = int(readadc(pot_chnnl))
    print("--------------------------------")
    print("Pot wiper value = ", wpr_vlu)
    # The LED Display Code
    # Although initially set to low each binary bit
    # determination must be reset to low as the code cycles in
    # the while loop.
    #
    # first or least significant bit of 2**0 or 1s

    Q1 = wpr_vlu // 2
    rem1 = wpr_vlu % 2
    GPIO.output(2, GPIO.LOW)
    if rem1 == 1:
        print("Q1 = ", Q1, "rem1 = ", rem1)
        GPIO.output(2, GPIO.HIGH)
    # second significant bit of 2**1 or 2s
    Q2 = Q1 // 2
    rem1 = Q1 % 2
    GPIO.output(3, GPIO.LOW)
    if rem1 == 1:
        print("Q2 = ", Q2, "rem1 = ", rem1)
        GPIO.output(2, GPIO.HIGH)
    # third significant bit of 2**2 or 4s
    Q3 = Q2 // 2
    rem1 = Q2 % 2
    GPIO.output(3, GPIO.LOW)
    if rem1 == 1:
        print("Q3 = ", Q3, "rem1 = ", rem1)
        GPIO.output(3, GPIO.HIGH)
    # fourth significant bit of 2**3 or 8s
    Q4 = Q3 // 2
    rem1 = Q3 % 2
    GPIO.output(4, GPIO.LOW)
    if rem1 == 1:
        print("Q4 = ", Q4, "rem1 = ", rem1)
        GPIO.output(4, GPIO.HIGH)
    # fifth significant bit of 2**4 or 16s
    Q5 = Q4 // 2
    rem1 = Q4 % 2
    GPIO.output(5, GPIO.LOW)
    if rem1 == 1:
        print("Q5 = ", Q5, "rem1 = ", rem1)
        GPIO.output(5, GPIO.HIGH)
    # sixth significant bit of 2**5 or 32s
    Q6 = Q5 // 2
    rem1 = Q5 % 2
    GPIO.output(6, GPIO.LOW)
    if rem1 == 1:
        print("Q6 = ", Q6, "rem1 = ", rem1)
        GPIO.output(6, GPIO.HIGH)
    # seventh significant bit of 2**6 or 64s
    Q7 = Q6 // 2
    rem1 = Q6 % 2
    GPIO.output(13, GPIO.LOW)
    if rem1 == 1:
        print("Q7 = ", Q7, "rem1 = ", rem1)
        GPIO.output(13, GPIO.HIGH)
    # eighth significant bit of 2**7 or 128s

    Q8 = Q7 // 2
    rem1 = Q7 % 2
    GPIO.output(14, GPIO.LOW)
    if rem1 == 1:
        print("Q8 = ", Q8, "rem1 = ", rem1)
        GPIO.output(14, GPIO.HIGH)
   # ninth significant bit of 2**8 or 256s
    Q9 = Q8 // 2
    rem1 = Q8 % 2
    GPIO.output(15, GPIO.LOW)
    if rem1 == 1:
        print("Q9 = ", Q9, "rem1 = ", rem1)
        GPIO.output(15, GPIO.HIGH)
    # tenth or most significant bit of 2**9 or 512s
    Q10 = Q9 // 2
    rem1 = Q9 % 2

    GPIO.output(16, GPIO.LOW)
    if rem1 == 1:
        print("Q10 = ", Q10, "rem1 = ", rem1)
        GPIO.output(16, GPIO.HIGH)
    # timing delay
    time.sleep(delay)

Listing 6-13SPI-Based Program to Read an MCP3008 10-Bit ADC

# Decimal to 12 Bit Binary LED Visual Display
#
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
# Ensure all LEDS are OFF and set to output mode
for i in range(2, 15):
    GPIO.setup(i, GPIO.OUT)
    GPIO.output(i, GPIO.LOW)
#
# input dec number to process
#
input_str = input("Decimal to convert to a 12 bit binary display ",)
dec = int(input_str)
print()
# print out screen display headings
print("Quotient and remainder listing for conversion and display illumination.")
print()
# first binary digit of 2**0 or 1s
Q1 = dec // 2
rem1 = dec % 2

if rem1 == 1:
    GPIO.output(2, GPIO.HIGH)
print("For LED 1 Q = ", Q1, "and rem = ", rem1)
#
# second binary digit of 2**1 or 2s
Q2 = Q1 // 2
rem2 = Q1 % 2
if rem2 == 1:
    GPIO.output(3, GPIO.HIGH)
print("For LED 2 Q = ", Q2, "and rem = ", rem2)
#
# third binary digit of 2**2 or 4s
Q3 = Q2 // 2
rem3 = Q2 % 2
if rem3 == 1:
    GPIO.output(4, GPIO.HIGH)
print("For LED 3 Q = ",Q3, "and rem = ", rem3)
#
# fourth binary digit of 2**3 or 8s
Q4 = Q3 // 2
rem4 = Q3 % 2
if rem4 == 1:
    GPIO.output(5, GPIO.HIGH)
print("For LED 4 Q = ",Q4, "and rem = ", rem4)
#
# fifth binary digit of 2**4 or 16s#
Q5 = Q4 // 2
rem5 = Q4 % 2
if rem5 == 1:
    GPIO.output(6, GPIO.HIGH)
print("For LED 5 Q = ",Q5, "and rem = ", rem5)
#
# sixth binary digit of 2**5 or 32s
Q6 = Q5 // 2
rem6 = Q5 % 2
if rem6 == 1:
    GPIO.output(7, GPIO.HIGH)
print("For LED 6 Q = ",Q6, "and rem = ", rem6)
#
# seventh binary digit of 2**6 or 64s
Q7 = Q6 // 2
rem7 = Q6 % 2
if rem7 == 1:
    GPIO.output(8, GPIO.HIGH)
print("For LED 7 Q = ",Q7, "and rem = ", rem7)
#
# eighth binary digit of 2**7 or 128s

Q8 = Q7 // 2
rem8 = Q7 % 2
if rem8 == 1:
    GPIO.output(9, GPIO.HIGH)
print("For LED 8 Q = ",Q8, "and rem = ", rem8)
#
# ninth binary digit of 2**8 or 256s
Q9 = Q8 // 2
rem9 = Q8 % 2
if rem9 == 1:
    GPIO.output(10, GPIO.HIGH)
print("For LED 9 Q = ",Q9, "and rem = ", rem9)
#
# tenth binary digit of 2**9 or 512s
Q10 = Q9 // 2
rem10 = Q9 % 2
if rem10 == 1:
    GPIO.output(11, GPIO.HIGH)
print("For LED 10 Q = ",Q10, "and rem = ", rem10)
#
# eleventh binary digit of 2**10 or 1024s
Q11 = Q10 // 2
rem11 = Q10 % 2
if rem11 == 1:
    GPIO.output(12, GPIO.HIGH)
print("For LED 11 Q = ",Q11, "and rem = ", rem11)
#
# twelfth binary digit of 2**11 or 2048s

Q12 = Q11 // 2
rem12 = Q11 % 2
if rem12 == 1:
    GPIO.output(13, GPIO.HIGH)
print("For LED 12 Q = ",Q12, "and rem = ", rem12)

Listing 6-12RPi Python Code for Decimal to 12-Bit Binary LED Visual Display

摘要

  • 已经介绍了 ADC 和 DAC 的局限性以及整数和浮点(包含十进制的数字)之间的差异。

  • 串行和并行信号转换以及各种串行传输协议被引入商用和较便宜的组件组装系统。

  • 第七章介绍了数模转换的一个重要应用,涉及可变亮度和功率控制。

Footnotes 1
  1. 建筑科学仪器第四版。,摩尔,戴维斯和科普兰,剑桥大学出版社,ISBN 978-0-521-87858-6 精装本

  2. 电子艺术第二版 Edn。,Horowitz 和 Hill,剑桥大学出版社,ISBN -13 978 -0-521-37095-0 精装本

  3. 发明家实用电子学第三版 Edn。,谐谑曲与蒙克,麦格劳希尔,ISBN 978-0-07-177133-7

  2

https://www.azeotech.com/dl/serialguide.pdf

  3

发明家实用电子学第三版 Edn。,Schertz 和 Monk,McGraw Hill,ISBN 978-0-07-177133-7

 

七、可变强度和功率控制

从显示屏上任意改变或调整实验设置或过程控制设置的能力是 SCADA 系统的一个组成部分。DAQFactory 软件提供可变控制图标,如旋钮或可移动滑块。旋钮或滑块页面组件可以耦合到模拟输出通道,其值将与控制旋钮的旋转位置或滑块索引标记的线性位置成比例。

通过适当的设计,页面组件控件可用于调节大量电压和电流,进而激活机电设备。

在 GUI 控制屏幕上对图像的操作必须在某一点上被转换成电信号,以在手头的实验或过程中提供期望的机电动作。如前所述,数字系统在二进制领域中运行,其中所需的系统动作以开或关的信号形式产生。然而,有许多系统需要不断调整所需动作量的能力,因此属于模拟领域。控制风扇、泵或混合器、加热元件、照明强度和旋转定位的电机速度是可能需要实验者或过程操作者调整的一些操作。

本练习演示了通过电压控制和脉冲宽度调制(PWM)技术对过程或实验设置进行可变控制的两种方法。

馈送到诸如电机、加热器或光源的设备的功率的 DC 电压的增加通常与通过负载的额外电流成比例地增加速度、产生的热量(温度增加)或亮度。已经说过,PWM 是一种通过数字方式向负载输送部分功率的方法。实质上,PWM 控制应用将电源的全部电压以可调宽度、较高频率(通常为数百 Hz)的矩形脉冲流的形式施加在负载上。然后,通过修改脉冲波形的全导通和全截止时间的宽度来确定对负载所施加和使用的功率的控制。导通时间和矩形脉冲宽度之间的比值称为占空比(参见第十章中的图 10-5 )。施加于负载的矩形、全开或全关波形的占空比变化是 PWM 功率控制的本质。

PWM 技术可以用软件实现,也可以用集成电路实现,如后面的电流控制练习中所述。对于许多需要精确控制和平滑功率转换的应用,基于硬件的 PWM 更受青睐。

在本练习中,PWM 以最简单的方式介绍,完全由软件实现。将 PWM 过程限制为基于代码的程序限制了可用于直观演示该过程的技术,本练习的以下部分将对此进行详细说明。

为 PWM 产生矩形波形的频率必须大大高于负载的响应时间。根据经验,频率应该是器件 RC 时间常数倒数的两倍,或者是控制系统频率的十倍。简而言之,PWM 频率应该足够高,以免与负载的 RC 时间常数发生谐振。(参见参考文献中的电阻-电容时间常数。 1

PWM 是一种广泛用于功率控制、数模转换、放大器设计和通信的技术,但需要复杂的电路,并可能产生射频干扰、电压尖峰和 EMI 噪声。(参见参考文献 1 和章节 10 中的 triac 控制。)

实验的

可变电压控制

五金器具

2N3904 NPN 晶体管、限制晶体管基极电流的 10kω电阻和带有适当限流电阻的 LED 组装在试验板上,配置如图 7-1 所示。

img/503603_1_En_7_Fig1_HTML.jpg

图 7-1

NPN 晶体管的 LabJack 模拟输出 0 控制

软件

从如图 7-2 所示的右键弹出菜单中选择旋钮控制。

img/503603_1_En_7_Fig2_HTML.jpg

图 7-2

DAQFactory 屏幕组件控制选择菜单

在显示屏的一页上定位控制图标并确定其尺寸后,选择属性选项以访问旋钮配置屏幕。

下面描述的缺省值未配置屏幕图标的视觉外观可以通过主选项卡中显示的框中的适当条目进行更改。与所有屏幕图标一样,相应的帮助文件可以显示在被操作的屏幕对象下方。“属性”窗口的“主”选项卡中显示的一些视觉效果选项仅在图标的较大显示图像上才明显。

旋钮控制指示器图像默认为显示的点,但是通过指示器子面板右侧的单选按钮,可以更改为选择三角形或传统的线索引来标记控制旋转的角度。通过左键单击图 7-3 中的颜色框,从可用的调色板中选择所需的颜色,可以更改默认的蓝色指示器图像。

img/503603_1_En_7_Fig3_HTML.jpg

图 7-3

DAQFactory 屏幕组件配置窗口

图 7-4 描绘了通过选择图 7-3 中的“刻度”选项卡打开的窗口。在 Ticks 窗口中,调查者可以选择圆形标尺的标称方面,并确定显示的分辨率及其在最终窗口中的外观。

img/503603_1_En_7_Fig4_HTML.jpg

图 7-4

旋钮刻度配置窗口

作者屏幕组件的最终配置如图 7-5 所示。

img/503603_1_En_7_Fig5_HTML.jpg

图 7-5

带指示面板的基础电流和 LED 亮度旋转控制旋钮

不需要编写脚本。滑块或旋钮根据旋钮或滑块的位置自动提供可变输出。在“属性”窗口的“主”选项卡的“设置通道”框中指定的通道被设置为,并输出所需的比例信号。

观察

如 DAQFactory 手册中所述,旋钮或滑块可设置为多种配置,以控制所选通道的激活。因为本练习中的控制设置为控制 LED 的电源,所以激活 LED 所需的最小电压会产生一定量的“死区”。

讨论

通过将起始位置配置在旋转的 225 o 处并将起始电压分配给所使用的 LED 的击穿电压,可以实现对施加到晶体管基极的电压以及最终由半导体输送的功率的更精细程度的控制。LED 中的正向电压降可以从红外线的 1.2 伏变化到蓝色和白色设备的 4 或 5 伏。作者的设置使用了绿色 LED,因此根据屏幕图标的预期用途,刻度盘可以配置为从 3 伏或 0 伏开始。如果要估计开启电压本身,可以使用 0-5 伏范围并进行校准,或者可以将刻度盘设置为 3.0-5.0 伏,以再现二极管强度/施加的功率设置。

实验的

电压的脉宽调制

介绍

通常,演示 PWM 基本原理的软件程序的实施使用一个具有高频可变占空比波形的 LED,如第十章所述。在本练习中,通过一个电子电气系统演示了 PWM 的基本概念和方法,该系统具有一个非常简单的软件信号发生器和一个由白炽灯泡组成的响应相对较慢的负载。

为了与使用 DAQFactory 软件创建序列的简单介绍保持一致,本章末尾的清单 7-1 中给出了一个基本程序序列,该序列粗略地改变了通过 12 伏电池供电的 DC 汽车灯的电流。

代码已经减少到生成典型矩形波形所需的最少语句数。占空比值必须由实验人员手动输入或更改,作为 DAQFactory 序列中两个延迟语句中的数值。代码清单中的默认设置是 0.005 和 0.095,这两个值组合在一起给出了 0.1 秒的总矩形脉冲宽度。

图 7-6 描述了用于为 PWM 演示提供慢响应负载的电路。

img/503603_1_En_7_Fig6_HTML.jpg

图 7-6

用于 PWM 演示的白炽灯负载

观察

图 7-7 、 7-8 、 7-9 和 7-10 描绘了白炽灯泡亮度的变化强度以及相应的高低占空比 PWM 波形。

img/503603_1_En_7_Fig10_HTML.png

图 7-10

白炽灯负载的高 PWM DC 波形

img/503603_1_En_7_Fig9_HTML.jpg

图 7-9

高 DC 功率下 PWM 的白炽灯泡负载

img/503603_1_En_7_Fig8_HTML.png

图 7-8

白炽灯负载的低 PWM DC 波形

img/503603_1_En_7_Fig7_HTML.png

图 7-7

低 DC 功率下 PWM 的白炽灯泡负载

如果脉冲代码与 LED 一起使用,则可以看到 5 ms 和 95 ms 时间段的闪烁速率不同,但是眼睛很难看到两种明显闪烁的功率设置之间的照明差异。然而,如图 7-7 和 7-9 所示,白炽灯对不同功率水平的可见响应要大得多。

讨论

在本练习的 PWM 介绍中,提出了一个要点,即承载功率的矩形波的频率需要大大高于施加功率脉冲的系统的时间常数。简而言之,可以说 PWM 频率必须高于负载的响应时间。白炽灯和电池的响应时间很慢,足以直观地说明一个非常简单、基本的 DAQFactory 序列在创建图形可视化 PWM 演示时的功率控制能力。本演示的 PWM 信号由 DAQFactory 序列生成,只有 6 行代码。图 7-8 和 7-10 的示波器记录对应的频率略低于 2 Hz。虽然频率不是那么高,但是对于灯丝加热并达到热和照明稳定性所需的时间来说,双循环 PWM 照明控制技术足以产生期望的结果。使用软件程序(如代码清单中的第一个条目)来改变信号开启和关闭的时间通常被称为“位碰撞”PWM。

PWM 技术是许多数字电子和机电系统中非常重要的一部分,在许多情况下,通过硬件设备来实现,在接下来的几个使用 Arduino 微控制器的练习中将会遇到这种情况。

几乎所有在之前练习中作为 DAQ 系统廉价替代品使用的微控制器板都配备了数字引脚输出,能够输出硬件实现的 PWM 信号(参见第十章)。

树莓 Pi 可变强度控制

介绍

RPi 的物理计算只能通过通用输入和输出引脚阵列来实现,在第一章的图 1-16 中,RPi 电路板上部有双排 13 或 20 个公引脚。阵列上可编程引脚的数字特性允许从实验者编写的代码或从包含各种形式的 PWM 操作的库中实现软件 PWM 操作。

强度变化屏幕控制图标或组件可从可从在线资源获得的 tkinter 图形图像库中获得,如 Raspberry Pi 和 Python 基金会在线提供的文档中所讨论的。 2

为了适应物理计算和“物联网”不断增长的兴趣和发展,RPi 基金会批准了三个开源 Python 库,以促进 GPIO 阵列在连接外部世界中的使用。最初的库版本是一个更基础或更低级的代码,导入名称为 RPi。GPIO,而后来更复杂的代码可以通过导入 gpiozero 和 pigpio 库来访问。RPi。GPIO 包含使用轮询方法或中断来检测机械运动(如按钮或开关触点闭合)、“去抖动”这些事件以及使用触点动作来启动 GPIO 引脚阵列上的电气活动)的机械设备所需的代码。据 RPi 文档报道,gpiozero 库是建立在 RPi 之上的。GPIO 库,包含许多非常易于使用的对象的元素,这些元素来自于使用非常好解释的、面向对象的编程代码。图书馆使用和可用对象的详细列表可以在网上找到。研究人员和教育工作者会发现 gpiozero 库中创建的对象列表非常广泛,并且详细描述它们的实现和连接的文档非常详细,以至于打印出的档案可能会对进一步的工作有很大帮助。

第三个也是最近发布的物理计算库,作为 pigpio 导入,与前两个工具有很大不同,因为它是用 C 编写的,可以在几种操作系统上实现。为了在 RPi 的 Linux 操作系统上使用,必须运行一个接口程序,以便 Python 解释器访问 pigpio 库。这个程序也称为守护程序,它是从 Linux 终端用 sudo pigpiod 命令启动的。

pigpio 设施拥有丰富的文档,包括详细的代码语法、众多可用的测试和可视化实用程序,以及各种简单和非常复杂的代码,可与各种传感器和硬件接口。该库还为一些更流行的通信协议提供了代码。

c 代码以其非常快的执行速度而闻名,pigpio 库使用软件和硬件为其 PWM 和矩形波形生成以及电压转换检测操作提供单位数微秒的时间分辨率。

PWM 应用程序可通过所有库获得,本章末尾提供了三个库中的几个 RPi 代码清单,以展示使用三种不同工具的软件 PWM 功率控制的各个方面。

实验的

使用 RPi 物理计算库的软件 PWM 信号生成和应用在一系列六个程序中介绍。通过使用空闲屏幕菜单中的运行模块访问和处理存储的程序代码,可以观察到所需的 PWM 效果。使用 Ctrl+C 组合键可以暂停程序执行。

除了演示程序,还提供了一个非常简短的实用程序来帮助开发和测试 pigpio 物理计算代码。

带 RPi 的 PWM 信号。GPIO 库

列表 7-2 可用于演示图 7-11 电路产生 PWM 波形的基本原理。

img/503603_1_En_7_Fig11_HTML.png

图 7-11

LED–GPIO 引脚连接示意图

在以前的演习中已经注意到。GPIO 阵列的电流有限,无法安全地提供给与引脚相连的任何外设。图 7-11 描述了显示正在研究和开发的程序所产生的效果所需的一般连接。留给实验者的是安全地配置电子组件,使得从使用中的 GPIO 引脚和阵列接地汲取的功率安全地处于计算机和 LED 的操作限制内。

程序代码 PWM_tst1 在 3.3 和 0 伏之间升高然后降低 GPIO 阵列的#6 引脚。开关脉冲的宽度或其占空比(DC)由研究者定义并作为变量 prcnt_on 输入程序代码。实际的 PWM 波形由两个环路产生,一个是由“while”语句控制的连续外部环路,该语句将#6 引脚设置为高值,另一个是内部“if 环路”,该环路在将引脚复位至 0 伏之前,计算 prcnt_on 变量中的单位数。

将 prcnt_on 变量设置为 5、50 和 95 可用于演示 LED 照明强度的变化。

用 RPi 编写的清单 7-3 给出了 PWM 信号的频率对观察到的 LED 照度的影响的演示。GPIO 库。在开发 RPi 时。GPIO PWM 频率效果演示程序,当使用五个不同的阵列引脚-LED 通道来演示 PWM 频率对观察到的 LED 照明的效果时,获得了合适的视觉效果。演示程序将占空比设置为 95%的恒定值,仅改变 PWM 功率信号的频率。

在加载和运行 PWM 频率效果代码之前,五个 led 和限流电阻必须连接到 GPIO 阵列,如图 7-11 所示。可以使用在物理位置找到的 GPIO 管脚 3、4、5、6 和 7(参见章节 1 ,图 1-16 ) 5、7、29、31 和 26 的 40 管脚阵列。

带 gpiozero 库的 PWM 信号

gpiozero 文档中的清单 7-4 是一个非常简单的单 LED PWM 照明变化程序,演示了 gpiozero 库可用的高级接口。脉冲 LED PWM 程序改变施加到 LED 的功率,从而改变其输出的强度或亮度,该程序由五行代码组成,其中两行是 import 语句。演示软件 PWM 的电路配置如图 7-11 所示。作者使用 5 mm LED 和 220ω限流电阻,并将电路连接到 GPIO 引脚 21(物理引脚#40)和地(物理引脚#34)。为了查看该技术可能实现的控制,将程序代码加载到 Python 空闲编辑器屏幕中,并使用运行菜单来启动或处理代码。

gpiozero 库包含许多用于连接 RPi 输出阵列和 MCP3008、8 通道、10 位 ADC 的对象,如第六章、图 6-17 的电路图所示,可用于使用 RGB LED 的 PWM 演示。

清单 7-5 和 7-6 使用偏置在正 RPi 电源输出和地之间的三个电位计,向 MCP ADC 的前三个通道提供三个信号,这三个信号又充当三个 PWM 信号,以改变 LED 的各个红色、绿色和蓝色输出的强度。这些程序的不同之处在于用于实现 PWM 功能的代码。理论上,任何想要的光的颜色都可以通过三电位器颜色控制电路配置产生,如图 7-12 所示。

img/503603_1_En_7_Fig12_HTML.jpg

图 7-12

PWM 三电位计 RGB LED 颜色控制电路

虽然 MCP3008 的前三个通道使用 220ω电阻来限制通过二极管的电流,但绿色 LED 的典型输出强度可能是红色和蓝色器件的五倍。为了“平衡”或均衡绿色通道的灵敏度,实验者可能需要更高的电阻值。

pigpio 库的 PWM 信号

要在操作系统映像或操作系统代码安装上加载、激活和访问 pigpio 库(代码中没有包含该库),必须在终端输入大量命令。(Raspbian Jessie 2016-05-10 或更新版本预装 pigpio C 库。)

作者的 RPi 已经使用了好几年,新的库必须在终端加载,如下所述:

  1. 在终端提示符下输入–wget abyz.co.uk/rpi/pigpio/pigpio.zip

  2. 猪小妹. zip

  3. pipipipo CD

  4. 制造

  5. 进行安装

前两行下载压缩文件并解压缩 Python 代码,以便在 home / pi 目录中快速创建文件 PIGPIO。“make”和“make install”可能需要一分钟左右的时间来处理,这取决于安装库的 Pi 的速度。在/home / pi / PIGPIO 文件中创建了三个程序:“pigpio.py”是一个解释 Python pigpio 模块的文档程序,它有一百多页,定义并解释了所有的模块函数和变量,并提供了简短的典型编码应用程序。除了文档之外,还有“setup.py”和“x_pigpio.py”,前者是 pigpio 守护进程的 RPi 访问模块,后者是 pigpio 库中所有可用库函数的 15-20 页的完整测试程序代码。

清单 7-7 是一个演示 pigpio 基本操作的简单程序,通过运行界面(pigpiod)访问 pigpio 库,打开和关闭 LED,然后通过四步 PWM 照明强度增加和减少来改变亮度。清单 7-8 是一个 pigpio 测试实用程序,它打印出数组中 gpio 管脚的状态。

观察

PWM_tst1

当将三个模拟占空比值输入程序并运行代码时,可以很容易地看出低、中和高实验之间的 LED 照明强度变化。在三个照明周期期间,代码似乎循环得足够快,以产生不能立即察觉的闪烁速率。

图 7-13 是 RPi 的输出。GPIO PWM 频率效果演示程序。

img/503603_1_En_7_Fig13_HTML.jpg

图 7-13

RPi 对 PWM 频率变化的影响。GPIO 库代码

LED 能够在兆赫兹范围内开关;正如预期的那样,2、5 和 8 Hz PWM 信号闪烁不定,闪烁明显,而 11 和 14 Hz 信号相当稳定,闪烁或“抖动”极小。(抖动描述和来源见“讨论”。)

RGB LED 输出的 PWM 控制

可以看出,随着可变电阻器上的轴分别从关闭位置转到全开位置,各种二极管颜色主导了器件输出。尽管图 7-12 的电路具有三个相等的电阻值,允许绿色主导 LED 输出,但二极管输出强度的明显零星和不规则变化在视觉上是可辨别的。

当 LED 通电时,以及在四步增加和减少二极管照明强度的过程中,pigpio 库程序产生明亮稳定的照明。(参见“讨论”)

代码清单中包括测试 RPi GPIO 阵列前 32 个引脚状态的实用程序,并以表格形式打印出它们的状态,如图 7-14 所示。

img/503603_1_En_7_Fig14_HTML.jpg

图 7-14

GPIO 引脚的测试状态

测试程序不仅打印出阵列中 32 个引脚的状态,还确认了 Python 解释器与 C 代码库的 Linux 守护程序接口的操作。

在使用第六章的“将数组重置为零”实用程序清除 RPi 数组(在第六章中列出了 6-15 )后,运行前面的列表。引脚 1、2 和 29 是阵列的电源引脚。

讨论

RPi 的一部分。GPIO 库致力于实现底层设备的接口,比如机械开关到 RPi 的 GPIO 管脚阵列。该库具有用于确定任何引脚的当前状态是高还是低(+5 或 3.3 V 的系统逻辑电压电平或 0 V 的系统地电位)的功能,检测引脚状态的变化,以及用于确定何时或如何监控或检测转换。

RPi 使用基于 Linux 的多任务操作系统,该操作系统可能会暂时从较低优先级的输入/输出操作中夺走控制权。在鼠标或键盘操作中遇到的正常时间范围内,I/O 操作可能不会受到延迟的显著影响;但是对于较短时间尺度上的高精度操作,例如图形显示,它可能变得非常明显。在本练习中,不规则时序的视觉效果可以被视为 LED 亮度的闪烁,或者有时被称为“抖动”

当使用 RPi 的改变频率功能时。GPIO 库,为每个新频率使用不同的引脚阵列 LED 通道比尝试使用同一通道并改变其频率五次要容易得多。

在三个 GPIO 物理计算库的可能应用中,能力和灵活性的显著提高是显而易见的。pigpio 使用起来更复杂,但是比简单的库更强大。如前所述,基于 C 的库能够使用 Linux 操作系统和系统硬件在许多库操作上实现一位数微秒时间分辨率。本练习中使用的简单演示程序完全没有闪烁或抖动。

除了简单的 LED 照明功能程序之外,在代码清单的末尾还包括一个非常简短但有用的实用程序,它可以打印输出从 0 到 31 的每个 GPIO 引脚的状态。控制台的打印输出将所有引脚及其当前高/低值列为 1 或 0。除了显示单个引脚的高/低电压电平,该实用程序还确认 Python pigpio 接口守护程序的功能。

pigpio 库函数和功能的大部分将在后面 RPi 物理计算中处理高级 PWM 应用的高级练习中按要求遇到、演示和讨论;传感器启动或监控;串行、I2C 和 SPI 通信;和电机或伺服控制。

代码列表

# PWM Control of RGB Led Diode Pgm 2
# PWM Control of RGB Led Diode
from gpiozero import RGBLED, MCP3008
from signal import pause
#
led = RGBLED(2, 3, 4)
#
red_pot = MCP3008(channel=0)
green_pot = MCP3008(channel=1)
blue_pot = MCP3008(channel=2)
#
led.source = zip(red_pot.values, green_pot.values, blue_pot.values)
#
pause()

Listing 7-6PWM Control of RGB LED with Three ADC Channels and Pause()

# PWM Control of RGB Led Diode Pgm 1
from gpiozero import RGBLED, MCP3008
#
led = RGBLED(red=2, green=3, blue=4)
#
red_pot = MCP3008(channel=0)
green_pot = MCP3008(channel=1)
blue_pot = MCP3008(channel=2)
#
while True:
    led.red = red_pot.value
    led.green = green_pot.value
    led.blue = blue_pot.value

Listing 7-5Control of a RGB LED with gpiozero PWM Library and Three Potentiometers

from gpiozero import PWMLED
from signal import pause

led = PWMLED(21)

led.pulse()

pause()

Listing 7-4Single-LED PWM with the gpiozero Library

# RPi PWM Frequency Demonstration with the RPi.GPIO Library
# 5 LEDs are used to illustrate the effects of the frequency of the carrier wave on PWM techniques. Different carrier
# frequencies are used at a constant duty cycle to illustrate
# the effects of frequency om PWM
import RPi.GPIO as GPIO
import time
# Array set up
GPIO.setmode(GPIO.BCM) # Use BCM pin reference
GPIO.setwarnings(False) # turn off the array use warnings
GPIO.setup(3, GPIO.OUT) # set pin #3 for output
#
pwm = GPIO.PWM(3, 2) # a PWM instance on pin 3 to operate at 2 Hz is setup
print("PWM carrier frequency set to 2 Hz")
print(" ")# print a blank line in the output
dc = 95 # the duty cycle is set close to full on
pwm.start(dc)# start the application of PWM power
time.sleep(5)# Keep the LED illuminated for 5 seconds
pwm.stop()# stop the power application
#
# carrier frequency increased to 5 Hz
print("PWM carrier frequency set to 5 Hz")
print(" ")
GPIO.setup(4, GPIO.OUT) # set pin #4 for output
pwm = GPIO.PWM(4, 5) # a PWM instance on pin 4 to operate at 5 Hz is setup
dc = 95 # the duty cycle is set close to full on
pwm.start(dc)
time.sleep(5)
#
# carrier frequency increased to 8 Hz
print("PWM carrier frequency set to 8 Hz")
print(" ")
GPIO.setup(5, GPIO.OUT) # set pin #5 for output
pwm = GPIO.PWM(5, 8) # a PWM instance on pin 5 to operate at 8 Hz is setup
dc = 95 # the duty cycle is set close to full on
pwm.start(dc)
time.sleep(5)
pwm.stop()
#
# carrier frequency increased to 11 Hz
print("PWM carrier frequency set to 11 Hz")
print(" ")
GPIO.setup(6, GPIO.OUT) # set pin #6 for output

pwm = GPIO.PWM(6, 11) # a PWM instance on pin 6 to operate at 11 Hz is setup
dc = 95 # the duty cycle is set close to full on
pwm.start(dc)
time.sleep(5)
pwm.stop()
#
# carrier frequency increased to 14 Hz
print("PWM carrier frequency set to 14 Hz")
print(" ")
GPIO.setup(7, GPIO.OUT) # set pin #7 for output
pwm = GPIO.PWM(7, 14) # a PWM instance on pin 7 to operate at 14 Hz is setup
dc = 95 # the duty cycle is set close to full on
pwm.start(dc)
time.sleep(5)
pwm.stop()

Listing 7-3RPI.GPIO PWM Frequency Effect Demonstration

Python Code for Raspberry Pi PWM_tst1
# A software PWM demonstration on GPIO - 6
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
GPIO.setup(6, GPIO.OUT)
#
# set the duty cycle
prcnt_on = 10
#
# the outer loop to provide the continuous application of the modulated power signal
while True:
    # start the duty cycle loop and set the output pin to ON
    GPIO.output(6, 1)
    for i in range(1, 100):
        if i == prcnt_on:
            GPIO.output(6, 0)

Listing 7-2RPi Python PWM_tst1

while(1)
   sftwr_pwm = 5
   delay(0.095)
   sftwr_pwm = 0
   delay(0.005)
endwhile

Listing 7-1DAQFactory Sequence Program for PWM

# A simple demonstration of some basic pigpio capabilities.
# The PIGPIO library must be d/l, installed and available on the RPi in use.
# The requirements for use of the library code must be met and the interface
# often called a daemon must be running to provide an interface between the pigpio library written in C and the
# Python interpreter. (see PIGPIO documentation)
#
import pigpio
import time
#
pi = pigpio.pi()# create a instance of the pigpio class
#
# Simple LED illumination
pi.set_mode(4, pigpio.OUTPUT) #set gpio 4 for output
pi.write(4,1) # set gpio pin 4 high
time.sleep(0.5)# delay for 1/2 sec
pi.write(4,0) # turn LED off
#
time.sleep(2) # delay for 2 sec between displays
#
# simple PWM controlled variable brightness scaled from 0 – off to 255 – full on
pi.set_PWM_dutycycle(4,  0)  #PWM off
time.sleep(0.5)# delay for 1/2 sec
pi.set_PWM_dutycycle(4, 64) # PWM power at 1/4 on
time.sleep(0.5)
pi.set_PWM_dutycycle(4,128) # PWM power at 1/2 on
time.sleep(0.5)
pi.set_PWM_dutycycle(4,192) # PWM power 3/4 on
time.sleep(0.5)
pi.set_PWM_dutycycle(4, 255) # PWM power full on
time.sleep(0.5)
pi.set_PWM_dutycycle(4,192) # PWM power 3/4 on
time.sleep(0.5)
pi.set_PWM_dutycycle(4,128) # PWM power 1/2 on
time.sleep(0.5)
pi.set_PWM_dutycycle(4, 64) #  PWM power 1/4 on
time.sleep(0.5)
pi.set_PWM_dutycycle(4, 0) # PWM power off

#
pi.stop()

Listing 7-7pigpio Basic Operations Program

# pigpio pin status and test utility
# ensure that the pigpio daemon is running and run the following code from the run menu in the Python 3 IDLE facility.
#
import pigpio
pi = pigpio.pi() # create an instance of the library
for g in range(0, 32):  # recall range must be the required number of iterations + 1
    print("gpio {} is {}".format(g, pigio.read(g))) # print out a tabulated status report
pigpio.stop()

Listing 7-8pigpio Test Utility

摘要

  • 商业软件中的可变强度控制用于在软件中实现 PWM 方法,以演示该技术如何工作。

  • 介绍了几种利用廉价的 RPi 计算平台实现 PWM 技术的方法。

  • 在第八章中,介绍了 SCADA 系统中主机计算机外部发生的事件的检测以及如何测量多个事件之间的时间。

Footnotes 1

发明家实用电子学第三版 Edn。,Schertz 和 Monk,McGraw Hill,ISBN 978-0-07-177133-7

  2

docs/python.org/3/library/tk.html

  3

http://gpiozero.readthedocs.org/https://sourceforge.net/p/raspberry-gpio-python/wiki/Examples