浅谈软件是如何控制硬件工作的

声明:以下知识仅限于本人对于软硬件的理解和整理并作为内部分享,因个人知识水平所限,可能存在一些遗漏和不足甚至错误的地方,如有发现可以留言指出。配合此视频看效果更佳哦~

概述

我们都知道软件是服务于硬件的,因为单纯的软件如果不跑到具体的硬件上面将是没有任何价值的。如果单纯的去谈软件是没有任何价值的,软件的开发往往依附于所运行的硬件环境。关于这个话题涉及的知识比较多,而且比较深奥,这个话题其实是《微机原理》这门课程所要解决的问题,这篇文章不打算以晦涩难懂比较深奥的知识揭开这个问题的本质,而是想基于作者(水寒)的知识积累和实践,通过一些简单的电路知识和计算机软硬件知识来了解软件和硬件是怎么交织在一起的。

数字电路

对于我们物联网而言,一般所讨论的硬件其实可以认为是数字电路相关的一套硬件电路。而数字电路和模拟电路有何区别呢?要搞清数字电路模拟电路,首先要搞清什么是数字信号什么是模拟信号。

模拟量转数字量采样过程

如上图所示,模拟信号是在时间上取值都是连续的,自然界的信号可以说都是模拟信号。但是模拟信号利于观察但是不利于数据交互传递和表示,所以通常我们在计算机中需要将大部分的模拟信号转换为数字信号,方便实现数字电路和软硬件数据交互。

数字电路或数字集成电路是由许多**逻辑门**组成的复杂电路,与模拟电路相比,它主要进行数字信号的处理(即信号以0与1两个状态表示),因此**抗干扰能力较强**。

看到这里你也许还比较迷糊,似懂非懂的感觉,那就对啦!接下来我们以一个小实验来说明一下。

步进电机

电机也就是我们通常所说的马达,但是你可能不知道电机的种类是很多的,从大类上分为交流电机直流电机,而直流电机中有一种步进电机,定义如下:

步进电机实物图

步进电机是将电脉冲信号转变为角位移或线位移的开环控制电机,是现代数字程序控制系统中的主要执行元件,应用极为广泛。在非超载的情况下,电机的转速、停止的位置只取决于脉冲信号的频率和脉冲数,而不受负载变化的影响

说简单就是当电机接受一个脉冲信号,就会驱动电机按设定的方向转动一个固定的角度(步进角),所以我们可以通过控制脉冲信号的频率脉冲宽度来控制步进电机的速度。

脉冲信号

那么脉冲信号是怎么产生的呢?

震荡电路

脉冲信号一般都是利用自激震荡的原理产生的,自激震荡电路是一个正反馈电路,它的输入信号由滤波电路产生。LC 电路,也称为谐振电路、槽路或调谐电路,是包含一个电感(用字母 L 表示)和一个电容(用字母 C 表示)连接在一起的电路。

LC 电路理想化模型

上图是一个 LC 电路的理想化模型,因为它假定有没有因电阻耗散的能量。任何一个 LC 电路的实际实现中都会包含组件和连接导线的尽管小却非零的电阻导致的损耗。LC 电路的目的通常是以最小的阻尼振荡,因此电阻做得尽可能小。

这个电路中有两个比较重要的元器件,电容和电感,接下来我们看看他们的特点。

电容:电容是指容纳电荷的能力,电容上下两级产生电压的原因是因为电荷失衡,电容隔直流通交流。

电感:电感是闭合回路的一种属性,即当通过闭合回路的电流改变时,会出现电动势来抵抗电流的改变,所以通过电感的电流不能突变,电感隔交流通直流。

示波器显示

如图所示震荡电路就会产生一个震荡波,接下来再通过滤波电路,通过滤波电路得到我们想要得到的脉冲频率,然后再经过一次正反馈放大最终得到一个与脉冲信号频率相同的正弦波,这个正弦波通过整形就可以达到所需要的脉冲信号。

脉冲信号的产生过程

看到这里我大概提一下,你已经可以基于这个原理来自己做一个玩具小车玩玩了,而且可以控制左右转、倒车以及车速了,如果你想让这个小车更加智能,可以继续往下看,加上单片机和一些传感器做成一个遥控或者自动导航的小车。

电磁感应

1831 年**法拉第**发现了磁与电之间的相互联系和转化关系,只要穿过闭合电路的磁通量发生变化,闭合电路中就会产生感应电流。

电磁感应现象的产生条件有两点(缺一不可):

  • 闭合电路。
  • 穿过闭合电路的磁通量发生变化。

电感线圈是利用电磁感应的原理进行工作的器件。当有电流流过一根导线时,就会在这根导线的周围产生一定的电磁场,对产生电磁场的导线本身发生的作用,叫做 自感,即导线自己产生的变化电流产生变化磁场,这个磁场又进一步影响了导线中的电流。对处在这个电磁场范围的其他导线产生的作用,叫做 互感

有了上面关于电磁感应的物理知识,这样我们就能很容易的分析出来 LC 震荡电路的工作原理了。

第一步:电容放电,电势差开始逐渐降低,电流也逐渐降低。 第二步:电感中通过电流产生电磁场,电磁场影响导线本身形成 自感。 第三步:电感线圈的自感造成电磁感应现象,产生流向电容另一端的反向电流。

于是 LC 震荡回路中电压和电流如下:

LC 震荡回路中的电压和电流

我们上面提到的电机也是一个电磁感应装置,它的工作原理就是基于电磁感应原理的。

电机的工作示意动画

导线周围会产生磁场,叫做电流的磁效应,聪明的你是否还记得高中物理中学过的左手定则,通过电磁感应我们可以将电能转换为动能,也可以将动能或势能转换为电能(发电机)。

左手定则

晶振振荡器

晶体振荡器是指从一块石英晶体上按一定方位角切下薄片(简称为晶片),石英晶体谐振器,在封装内部添加 LC 组成振荡电路的晶体元件称为晶体振荡器。

电子线路中的晶体振荡器也分为无源晶振有源晶振两种类型。

无源晶振需要用 CPU 内的振荡器。无源晶振只有两个引脚,无源晶振没有电源电压,其信号电平是根据起振电路来决定的,是可变的,同样的晶振可以适用于多种电压,可适应于不同电压要求的 CPU。通常,无源晶振的价格比较较低,在民用的产品当中为了降低成本大部分都是应用无源晶振。

无源晶振实物图

有源晶振是一个完整的振荡器,里面有石英晶体、晶体管和阻容元件。有源晶振的封装如下图所示,有4个引脚。分别为VCC(电源)、GND(地)、OUT(时钟信号输出)、NC(空脚)。

有源晶振实物图

硬件的手表

你们有没有考虑过一个问题,所有硬件工作都有时钟频率,他们的时间是从哪里来的?或者说 CPU 的时间是从哪里来的?

事实上晶振就是这些处理器的手表,用于决定 CPU 内部的取指频率,以及其他相关的通信和数据交互频率等。

下面我们以单片机为例简单说明一下,开始前我们先看看计算机硬件由那几部分组成。

计算机组成

一台计算机由五部分组成:运算器、控制器、存储器、输入设备和输出(I/O)设备。转载请说明出处:https://dp2px.com

单片机又称单片微控制器,它不是完成某一个逻辑功能的芯片,而是把一个计算机系统集成到一个芯片上。相当于一个微型的计算机,和计算机相比,单片机只缺少了 I/O 设备。

单片机虽然是一个智能化的集成芯片,但是其本质上还是电路中的一个电子元件。既然是电子元件,那么就必须在一定的电路中才能运行起来,才能实现它的功能。这就像一个电阻一样,如果把一个电阻独立放着,是没有任何意义的,只有将它连接到电路中才能实现它的功能。

单片机里虽然集成了很多电路,但仍不能独立运行,必须要外连一些电路,才能使单片机运行。这种使单片机工作的最简电路我们称之为单片机最小系统。单片机最小系统中都有哪些电路呢?

单片机的最小系统电路原理图

可以看到图中的 18 和 19 引脚处接了一个时钟电路,他就是我们上面说过的震荡电路,这个就是单片机的手表。

单片机最小系统硬件实物图

单片机原理

现如今,我们生活中的许多电器都使用了单片机。例如:手机、电视机、冰箱、洗衣机、以及按下开关,LED就闪烁的儿童玩具。那么,单片机在这些电器中究竟做了些什么呢?

单片机是由 CPU、内存、外围功能等部分组成的。如果将单片机比作人,那么 CPU 是负责思考的,内存是负责记忆的,外围功能相当于视觉的感官系统及控制手脚动作的神经系统。

单片机的构成要素

尽管我们说 CPU 相当于人的大脑,但是它却不能像人的大脑一样,能有意识的、自发的思考。CPU 只能依次读取并执行事先存储在内存中的指令组合(程序)。当然 CPU 执行的指令并不是“走路”、“讲话”等高难度命令,而是一些非常简单的指令,象从内存的某个地方“读取数据”或把某个数据“写入”内存的某个地方,或做加法、乘法和逻辑运算等等。然而这些简单指令的组合,却能实现许多复杂的功能。

通过一个简单的电路来理解一下纯硬件电路和通过单片机控制的区别。

纯硬件控制的 LED 电路

这个时候如我我们有一些需求,比如按下开关后过 5 秒再关灯,再比如,连续按两下 LED 灯开始闪烁,这些需求显而易见不容易使用纯硬件来实现,此时单片机就很容易实现这些功能。

单片机控制的 LED 电路

单片机为什么能实现这些功能呢?那就是因为单片机存在存储器,可以存储我们预执行的程序(逻辑),然后可以通过 CPU 来读取指令,最后通过指令解码电路(属于数字电路的一部分)控制各个引脚的逻辑电平信号。这就是软件操控硬件的一个典型实例。

事实上我们的计算机也是如此,原理基本相同,唯一不同就在于计算机中有操作系统,事实上操作系统就是软件,只不过为了方便我们编写应用程序和安全考虑,不直接暴露硬件给外部,而是由操作系统代理控制而已。

串口通信

在硬件通信包括计算机中有两种方式:并行通信和串行通信。

并行 是指多比特数据同时通过并行线进行传送,这样数据传送速度大大提高,但并行传送的线路长度受到限制,因为长度增加,干扰就会增加,数据也就容易出错。因为我们现在都是用的是集成电路,所以大部分要求速度的地方都是用的是并行通信(相同频率下并行通信效率高),例如我们电脑的硬盘、打印机等。目前比较流行的并行通信接口有 PATA 和 PCI ,如果哥们你拆过电脑,一定见过这样的接口,其实它就是 PATA 接口。

主板上连接硬盘的 PATA 接口

当然我相信你肯定见过插 内存条显卡 的接口,一般都是 PCI 接口。

并行通信示意图

实际上并行通信存在着不少问题,例如通信频率不能太高,否则就会产生干扰,还有就是存在线路不齐导致的数据同步问题。

串行 通信中则不用一一连线,理论上只需要连接一条数据线就可以通信。串行通信又可分为同步通信异步通信两种方式。由于串行的成本低,体积小等特点,电脑中不少地方使用的是串行通信。其实某些机械硬盘的接口是串行的,用的是 SATA 接口。

电脑中硬盘 SATA 接口

串行通信示意图

并行通信作为了解,接下来我们来看一下串行通信。通信协议一般分为物理层和协议层。

物理层:规定通讯系统中具有机械、电子功能部分的特性,确保原始数据在物理媒体的传输。

协议层:规定通讯逻辑,统一收发双方的数据打包、解包标准。

RS-232 标准

RS-232 标准主要规定了信号用途、通讯接口和信号电平标准。如下图为常见的设备间串口通讯结构图。

RS-232 结构串口通讯结构图

如上图所示,每个设备都有一个 DB9 接口,通过 DB9 接口连接 RS-232 标准的串口线进行数据传输。由于通过RS-232 标准传输的电平信号到达设备后,不能直接被识别,所以会通过电平转换芯片(例如 MAX3232、SP3232 芯片等)转换成能识别的 TTL 电平信号,实现通讯。

DB9标准的公头、母头接法(接线口以针式引出信号线为公头,以孔式引出信号线为母头)如下图:

DB9标准的串口公母头引脚

RXD:用于接收 DCE(接收数据的设备)发来的数据信号,即输入。

TXD:用于发送 DTE(发送数据的设备)的信号,即输出。公头和母头的 RXD 和 TXD 应交叉连接。

GND:用于平衡设备双方的地电位,即共地。

你是不是有个疑问,既然串口通信只用到三个引脚,为什么 DB9 标准有 9 个引脚呢?这其实是一个历史遗留问题,因为在两个设备间进行数据传输,有些设备处理速度比较快,有些数据比较慢。为了保证数据能正常传输,在RX,TX 的基础上,还增加了几个控制引脚,本来好端端就 R,T,G,三根线,凑着就凑齐了 9 个引脚。

串口通讯协议层

协议层规定了数据包的内容,内容包含了起始位主体数据校验位停止位,双方需要约定一致的数据包格式才能正常收发数据。如下图为数据包的基本组成。

串口通信协议层数据包的基本组成

串口异步通讯中由于没有时钟信号,所以通讯双方需要约定好波特率,即每个码元的长度,以便对信号进行解码。常见的波特率有 4800、9600、115200 等。

如下图,RS-232 因为发送和接收分别是由不同的线处理的,也就是能同时发送数据和接收数据,这就是所谓的全双工

RS-232 通信连接示意图

RS-485 标准

看似 RS-232 标准没有什么缺陷,但是缺有个比较麻烦的事情,那就是 RS-232 的通信距离不是很长,所以有了 RS-485 标准来解决距离问题。(为什么传输远是因为有极强的抗共模干扰的能力)

在 RS-485 标准中没有 RX 和 TX 的概念,只需要两根线 A 线和 B 线,这种通信方式是一种总线的方式,所以就不是全双工的方式了,而是一种半双工的方式,因此在通信效率是没有 RS-232 高。

RS-485 通信连接示意图

需要注意的是 RS-232 和 RS-485 这些标准都是物理层的标准,所以涉及到的硬件接口完全不同,如果你的硬件设备只支持 RS-232 标准的时候需要使用转接器,上图就是 RS-232 转 RS-485 的转接器。

RS-422 标准

RS-422 的电气性能与 RS-485 近似一样,主要的区别在于 RS-422 有 4 根信号线,其中两根发送(Y、Z)、两根接收(A、B)这样就可以实现全双工通信了。看似 RS-422 似乎是最完美的,它既可以远距离传输又可以实现全双工,但是实际工作中我们采用的反而比较少,因为实际工作中全双工的优势并没有那么明显,而且很多时候我们对通信距离要求也不高,所以干嘛接 4 根线呢,不是自己给自己找麻烦吗?

同步和异步

在我们日常工作中一般使用的是同步通信的方式,也就是发送方和接收方的传输频率(波特率)一致。除了这种方式外,还存在一种异步的通信方式(波特率不一致),这种方式一般用于字符(8 bit)传输,因为一个字符中的比特位长度有限,所以需要的接收时钟和发送时钟只要相近就可以。例如我们使用的键盘就是异步通信的方式。

单片机烧写

说到这里我想结合上面提到的单片机和串口通信聊一聊如何将程序烧录到单片机中,这样你就可以写一个好玩的小程序烧写单片机玩起来了,美不美?嗨不嗨?先放一段我之前公众号里面做的一个最简单的单片机控制流水灯视频吧。

怎么样,是不是勾起了你对美好事物的探索欲望呢?不急,我们接下来不仅仅会实现它,而且会让你明白为什么。

直接上电路原理图,不用怕,超简单:

单片机实现流水的电路原理图

不要意思这张图有点小,时间太长了,原图我也找不到了,不过我找到了一个比较清晰的管脚实物对比图。

先建立实物的直观印象,我们坚决不纸上谈兵,哈哈,继续看看二极管怎么接的,二极管加了一个 100欧 的电阻来分压,不然怕烧坏二极管。

接下来才是重头戏,写代码并烧写到单片机内,为了让这个程序看起来足够的简单,我这里直接贴上让一个发光二极管闪烁的代码:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <reg51.h>	   //此文件中定义了51的一些特殊功能寄存器

void Delay10ms(unsigned int);   //误差 0us

void main()     //主函数
{ 
	while(1)
	{
		P2  = 0x00;    	//置P0口为低电平
		Delay10ms(50); 	//调用延时程序

		P2  = 0xff;    	//置P0口为高电平
		Delay10ms(50); 	// 调用延时程序
	}

}

void Delay10ms(unsigned int c)   //误差 0us
{
    unsigned char a,b;
    for(;c>0;c--)
        for(b=38;b>0;b--)
            for(a=130;a>0;a--);
}

你可能有一些疑问,关于 C 语言语法的这里就不提了,重点来看一下这个 P2 是什么,打开开发工具(哦,对了,忘给大家介绍了,我使用的是 Keil 这个开发工具)的安装目录,例如我的在 C:\Keil\C51\INC\REG51.H 打开这个头文件就会看到如下部分代码:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#ifndef __REG51_H__

#define __REG51_H__

/*  BYTE Register  */

sfr P0   = 0x80;

sfr P1   = 0x90;

sfr P2   = 0xA0;

sfr P3   = 0xB0;

sfr PSW  = 0xD0;

sfr ACC  = 0xE0;

sfr B    = 0xF0;

sfr SP   = 0x81;

sfr DPL  = 0x82;

sfr DPH  = 0x83;

//此处省略........

#endif

这个头文件其实是针对此系列单片机做的一个定义,sfr P2 = 0xA0 意思就是给单片机内部地址为 0xA0 的寄存器起名为 P2 (对,就是指针啦!),事实上 P0, P1, P2 分别对应 8 个引脚,看上面那张我找的大图你就明白了。

然后你可能比较好奇的是这个延时程序 Delay10ms() 怎么这么抽象,感觉好像在做无用功。哈哈,这里又可以复习一个知识点了,看看我的伏笔埋得怎么样?

单片机工作和人一样有心跳的,这个心跳我们称为时钟周期,如果外接晶振那么这个时钟周期就是这个晶振频率的倒数(如12MHZ的晶振,它的时钟周期就是1/12us),它是单片机中的最小时间单位。我们让单片机没执行一个程序指令就需要消耗一个机器周期(对应多个时钟周期)这样就会延时。

万事俱备,只需烧写程序了,激不激动。不要太激动,你的电脑可能没有串口,哈哈,找了一遍只有 USB 接口, 惊喜不!在探索的路上到处是绊脚石,不足为奇,就看你的兴趣有多强烈了,哈哈。

事实上这里存在两个问题,一个是 USB 转串口,另一个问题就是 USB 接口的电压是 12v 而单片机的 TTL 一般为 5v, 这个就需要我们手动做一个转换器了,但是鉴于现在我们具备的知识和焦急程度,还是推荐一个神器吧。

其实它并不神奇,它只是做了一件很简单的事情。它里面最核心的就是USB转UART模块,功能是把RS-232电平(PC机输出一般12v)和TTL电平(单片机输出一般5v)相互转换。我们就可以利用这个模块来方便的实现烧录了,连接示意图如下:

然后我们可以看到连接图中 TXD 和 RXD 两个管脚,TXD 发送数据 Transmit(tx) Data 的缩写,RXD 接收数据Receive(rx) Data 的简写。所以注意这两个接口连接需要互换。将 USB 一头插到 PC 机上安装驱动后使用 STC 单片机烧写工具擦除之前程序写入新的程序。

如果不出意外,目前你的第一个发光二极管在闪烁了。有句俗话“麻雀虽小,五脏俱全”,你不要小看这个小程序,只要你跑通它,你已经成功的迈入单片机世界了。同样的道理,如果你能理解整个过程,你就可以依次洞察出其他型号单片机甚至计算机的工作原理了(当然,前提是你足够聪明)。

机器如何识别代码

上面我们虽然成功的将一段代码写入了单片机,但是整个过程我们还是一脸懵逼啊!不急,答案马上揭晓。

事实上我们的 IDE 会将我们的代码编译成机器码文件,当然如果你学过 C 语言就会知道 C 和汇编之间的关系,这里不讨论汇编。计算机的世界里只认识两个东西,一个是开,一个是关,用电路来说就是高电平和底电平,用机器码来说就是 1 和 0. 所以我们的代码最终会编译器(IDE内置)编译成只有 0 和 1 的二进制数据。

话不多说,我费了好大力气找了一张图,太直观了,感谢这位作者。

机器识别代码的过程

当我们的数据状态通过处理器读入寄存器后,寄存器就可以控制电平,这里的寄存器可以理解为一种电容整列,通过充放电来改变电容两端的高低电平。

传感器

通过上面的分析我们已经知道可以通过程序来控制单片机的引脚电平发生变化,事实上我们还可以通过读引脚的电平高低来采集外部传感器的数据,先举一个大家都听过而且比较简单的例子,红外对管传感器。

红外对管 是红外线发射管与光敏接收管,或者红外线接收管,或者红外线接收头配合在一起使用时候的总称。

红外对管传感器

有一个发生信号,另一个接受信号,当我们在它们中间放置一个隔档板,就会接收不到信号,这样就会发生状态变化,就能检测到时候中间有物体遮挡。

事实上,靠上面两个二极管是不能形成传感器效果的,需要接入到红外对管电路中(这里就不详细讨论了),还有我们可以自己买已近封装好的对管套装,或者红外光栅电路套装。

红外光栅套件

假设我们将光栅的接收端接到了单片机的 P0.0 (P0 的第一个引脚),此时只需要在程序中根据实际场景不断读取 P0.0 的电平变化进行判断即可,如果发生变化则说明光栅被遮挡了。

这个例子很容易理解,我们的自动售货柜和垃圾回收站中都有用到不同种类的类似原理光栅。

事实上像这样的传感器很多,例如超声波测距、温度等,都可以通过类似的原理获得数据。

看到这里你应该明白了,软件和硬件之间的通信是双向的,我们有时候需要获得硬件的传感器状态来作为我们软件逻辑的一部分,软件又可以控制单片机实现引脚的电平变化来实现控制部分硬件,或者显示数据到 LED 显示器上。

说到这里,我顺便提一下,基于这些知识你现在完全可以做一个自动避障的智能小车了,不要惊讶哦~

另外偷偷的告诉你,你可以将视频中的红外对管传感器换成超声波测距传感器更好玩哦。说道这里我再顺口提一句,我们千万不要做装配工,淘宝买一大堆现成零件拼装就认为自己会了,我建议你自己制作电路或者学习电路原理,然后自己摸索着去写控制程序(程序很简单的),相信你会深层次的理解其原理并融汇贯通。

软件是什么

说了这么多,其实就扯了一小段代码,其他都是硬件和通信的知识。咳咳!其实知识量应该很多了,再多我就 hold 不住了,下面就简单提一下软件。

软件从功能和作用上来讲,本质上是在做几个事情,用户交互(俗称 UI),计算处理,数据存储,通信协议的实现。而从计算机系统方面来说软件本质上只做两件事情,管理进程和操作内存。

其实这个世界上很多复杂的事情都是有最最简单的单元组成,例如我们都知道 CPU 很强大,事实上 CPU 一直在做简单重复的工作,只不过它的速度足够快而已。软件也是如此,无论是什么语言,除了语法糖,它的语法本质其实并不复杂,例如软件中的逻辑控制就三个 while 循环, if, for 循环。

因此,软件的重点不在语法糖上面,而在于正确理解和整理需求然后通过逻辑思维梳理并形成软件工程的设计思维,实现一个软件工程的过程本质上就是将你的思维表达出来,和画家用笔表达,音乐家用乐器表达类似。表达的是否优雅就看个人修行了。

总结

扯了这么多不知道你是否明白这个中间的过程,本身软硬件中的一门都有很多细分的枝叶,所以要说清楚这件事情并不容易,而我恰恰选了一个避重就轻的路,再结合一些看得到摸得着,工作中经常遇到的实例来加以说明,当然你要听清楚可能也不容易,但是这个分享如果能给你留下一个大致印象,日后你在工作中遇到某些问题可以拾起来一部分那就达到了分享的目的了。

进入和了解一个行业难就难在知识点环环相扣,不是一根线,而可能是一个网,你处于网的一个节点中,你要看清这张网,你必须先具备对大部分节点的认知,来能连起来。