MicroPython物联网教程全绝不原创的飞龙

这本书旨在成为一个指南,帮助您了解物联网,并开始构建您可以用来了解更多关于物联网的解决方案。因为这是一本初学者的书,我们将从检查编程语言和环境开始,然后详细看一下硬件。我们还将学习电子学的基本知识,然后探索几个项目来帮助我们理解如何使用该软件。最终项目将把所有方面结合在一起,以帮助理解什么是物联网,甚至如何编写定制软件来构建物联网解决方案。最重要的是,我们使用最容易使用的编程语言之一和易于使用的开源微控制器板。

那么,这个物联网是什么,也就是IOT?1我们先来解释一下它不是什么。IOT不是一个新的设备或专有软件或一些新的硬件,也不是一个新的营销计划,通过重命名和发音为“新的和改进的”来卖给你更多你已经拥有的东西2虽然IOT确实采用了已经存在的技术和技巧,但它们的使用方式,加上从世界任何地方访问解决方案的能力,使得IOT成为一个令人兴奋的探索概念。现在让我们讨论什么是IOT。

你可以想象,如果我们将我们周围的每一个设备都连接到互联网,并为这些设备提供传感数据,很明显,IOT设备的数量有可能超过地球上的人口数量,生成的数据也有可能迅速超过除最复杂的数据库系统之外的所有数据库系统的能力。这些概念通常被称为可寻址性和大数据,是IOT最活跃和最具争议的两个话题。

然而,IOT是关于理解我们周围的世界。也就是说,我们可以利用数据让我们的世界和我们对它的理解变得更好。

我们如何观察周围的世界?人体是巧妙的感觉器官的奇迹,它允许我们看、听、尝,甚至通过触摸我们遇到的任何东西。甚至我们的大脑也可以存储视觉和听觉事件,并随意回忆它们。IOT解决方案模仿了许多这样的感觉能力,因此可以成为我们自身能力的延伸。虽然这听起来有点浮夸(确实如此),但IOT解决方案可以记录来自一个或多个传感器的数据形式的观察结果,并通过互联网供任何人在任何地方查看。

一个更复杂的例子是使用一系列传感器来记录大气数据,如温度、湿度、气压、风速、环境光、降雨量等。,以监控天气,使我们能够对数据进行分析,以预测天气趋势。也就是说,我们可以在合理的确定性范围内预测该地区有降水。

现在,添加不仅实时(当数据出现时)而且从世界任何地方远程查看数据的能力,解决方案就不仅仅是一个简单的气象站了。它成为一种从世界任何地方观察一个地方天气的方法。这个例子可能看起来有点普通,因为你可以收听任何数量的电视、网络和广播,收听世界任何地方的天气预报。但是,请考虑在您的家中构建这样一个解决方案的意义。现在你可以在自己家里看到关于天气的数据!

以同样的方式,但也许在更小的范围内,我们可以建立监测植物的解决方案,以帮助我们了解它们需要水和其他养分的频率。或者,我们可以在外出工作时监控我们的宠物。此外,我们可以记录我们所在地区的野生动物数据,以更好地了解我们对自然的影响。

如果一个设备连接到互联网,这是否使其成为IOT解决方案?那取决于你问谁。一些人认为答案是肯定的。然而,其他人(比如我自己)认为答案是否定的,除非这样做有好处。例如,如果你把你的烤面包机连接到互联网,这样做有什么好处?如果你的烤面包机给你的手机发短信说你的烤面包准备好了,这是毫无意义的(或者至少是极端古怪的)。所以,在这种情况下,答案是否定的。

对我来说,如果数据没有任何用处,无论是实时查看的数据还是存储起来供以后处理的数据,那么简单地将其连接到互联网并不能使其成为IOT的解决方案。使用这种设备肯定会有好处。因此,接入互联网并不能让某些东西成为IOT。相反,IOT解决方案必须是那些能提供一些意义的东西——无论多小,只要对某人或其他设备或服务有益。

更重要的是,无论我们构建IOT解决方案来做什么,它们都允许我们感知我们周围的世界,并从这些观察中学习。真正棘手的部分在于数据是如何收集、存储和呈现的。我们将在后面的章节中通过例子看到这些。请看侧栏中一个有争议的IOT设备的例子——一个普通的家用电器。

但是,IOT解决方案通常可以利用提供服务的公司,这些服务可以帮助增强或提供您可以在IOT解决方案中使用的功能。这些功能通常被称为IOT服务,范围从存储和演示到托管等基础设施服务。

Internet-EnabledAppliances:IOTorMarketingHype

一个似乎变得流行的想法或概念是将主要的家用电器连接到互联网。虽然制造商可能希望你相信这是一个新的和令人兴奋的IOT设备,但事实是,它既不是一个新的想法,也不是一个改变世界的IOT解决方案。

我有幸参加了20世纪90年代末在微软校园举行的设计研讨会。在我们参观校园的过程中,我们看到了世界上第一台能够上网的冰箱(也称为智能冰箱或简称为互联网冰箱)。3货架上有传感器来检测食物的重量。有人建议,只要有点独创性,就可以利用传感器在你的牛奶供应不足时通知你的杂货商,这将使人们不仅可以在线购物,而且可以自动购物。

现在,20年后,我们看到制造商们正在制造连接互联网的冰箱。然而,与第一台智能冰箱不同,这些新设备被定位为家庭的社交媒体焦点。许多人不提供关于冰箱内容的任何有意义的数据,除了小工具一样的不开门就能看到内容的视频图像的功能,这可以通过安装玻璃门来解决。

让我们用我对IOT的定义来评价互联网冰箱:它通过向你提供关于你周围世界的信息来改善你的生活吗?好吧,如果你需要在离家3000英里之外查看你有多少牛奶,那么我想这可能是有益的,但对于我们大多数人来说,我们宁愿在去商店之前打开门看看,这可能不是一个IOT设备。

可悲的是,有些公司吹嘘拥有IOT的产品和服务只不过是营销炒作——就像一些公司所做的那样,在名称前加上“云”或附加“为了云”。幸运的是,有一些好的产品和服务是专为IOT打造的。这些范围从数据存储和托管到专门的硬件。

那么,IOT有哪些服务呢?下面列出了最近几年出现的一些。随着IOT解决方案和服务的成熟,可能会提供更多的服务。

现在,我们对IOT有了更多的了解,让我们来看几个IOT解决方案的例子,以便更好地了解IOT解决方案能做什么以及如何使用它们。

IOT解决方案就是一组设计用于产生、消费或呈现关于某个事件或一系列事件或观察结果的数据的设备。这可以包括生成数据的设备(如传感器)、组合数据以推断某些东西的设备、设计用于制表和存储数据的设备或服务,以及设计用于呈现数据的设备或系统。任何这些都可以连接到互联网。

无论是将IOT解决方案整合到网络摄像头等单一设备中,还是整合到气象站等传感器包和监控单元中,或者整合到由专用传感器、聚合器、数据存储和演示等设备组成的复杂系统中,如完整的家庭自动化系统中,这些解决方案都可能具备上述多种特性。图1-1展示了一幅无处不在的连接到互联网的所有设备的未来图景,这些设备可以是数据库、数据收集器或集成器、显示服务,甚至是其他设备。

图1-1。

ThefutureofIOT–alldevices,everywhere5

让我们看一些IOT解决方案的例子。本节中描述的IOT解决方案是多种解决方案的组合,您应该对IOT解决方案的规模和复杂性有所了解。我还指出了其中一些解决方案如何利用IOT供应商的服务。

传感器网络是最常见的IOT解决方案之一。简单地说,传感器网络让你可以观察你周围的世界并理解它。传感器网络可以采取池塘监控系统的形式,提醒您水位、水纯度(污染)、水温,检测捕食者,甚至自动打开功能,如照明或给花园池塘中的鱼喂食。

因此,传感器网络采用一个或多个传感器,这些传感器对事件或状态进行测量(观察),并将该数据传送给网络中的另一个组件或节点,然后以某种形式呈现该数据以供分析。让我们看一个重要的医疗IOT解决方案的例子。

糖尿病是一种影响全球数百万人的疾病。有几种形式:最严重的是1型(diabetes.org/diabetes-basics/type-1/loc=db-slabnav)。由于遗传缺陷、先天缺陷或胰腺损伤,1型糖尿病患者不能产生足够的(或任何)胰岛素。胰岛素是一种激素,身体用来从血液中提取一种简单的糖,称为葡萄糖,由糖和淀粉产生,供细胞使用。未能监测您的血糖可能会导致危险的低血糖或高血糖水平,这两种情况都可能危及生命,如果不加以控制,可能会对内脏器官、神经和其他部位造成长期损害。这是最严重的情况。

AthletesandDiabetes

一个突出的例子是RyanReed,他是NASCARXfinity赛车的赛车手,也是16号LilyDiabetesFord的司机。2011年,里德被诊断患有1型糖尿病,并被告知他将永远不会再参加比赛。从那时起,里德通过仔细监测自己的状况克服了障碍,重返赛场。

里德不仅回到了他热爱的运动,他还在代托纳国际赛道赢得了不止一次而是两次的赛季开幕系列赛冠军。里德证明了教育、警惕和技术可以让我们的生活变得更好。

1型糖尿病患者必须监测他们的血糖,以确保他们正确使用药物(主要是胰岛素),并与健康的生活方式和饮食保持平衡。如果他们的血糖水平降得过低或过高,他们可能会出现一系列症状。更糟糕的是,极低的血糖水平非常危险,可能是致命的。

图1-2。

DexcomContinuousGlucoseMonitorwithSensor

一项名为DexcomShare的功能允许患者通过手机上的应用向他人提供他们的数据。也就是说,患者的手机将数据传输到Dexcom云服务器,然后这些数据将被发送给任何拥有DexcomShare应用并被授予查看数据权限的人。图1-3显示了来自DexcomShareiOS应用的DexcomShareCGM报告示例,它允许您轻松快速地检查朋友或亲人的血糖。

图1-3。

DexcomShareAppReport

该应用不仅允许数据可视化,还可以传递低血糖或高血糖水平的警报,这对患有其他疾病或糖尿病并发症的患者具有深远的影响。例如,如果患者在独自一人、无行为能力或无法接受治疗时血糖水平下降,使用DexcomShare应用的亲人可以通过检查患者做出反应,并可能避免严重的糖尿病事件。

虽然这种解决方案是通过专有应用连接到互联网的单个传感器,但它是医疗IOT设备的一个极好的例子,不仅可以改善患者的生活,还可以改善护理他们的每个人的生活。

图1-4。

DexcomStudioWhatAboutBloodGlucoseTesters–Glucometers

在像DexcomCGM这样的解决方案出现之前,糖尿病患者必须使用手动测试仪。传统的血糖测试仪是一次性使用的,需要患者刺破手指或手臂,并在测试条上抽取少量血液。虽然这种设备已经使用了很多年,但直到最近,制造商才开始制造具有记忆功能,甚至可以连接到笔记本电脑或手机等其他设备的血糖测试仪。这些设备的最终发展是像Dexcom这样的解决方案,它已经成为一种医疗IOT设备,可以提高糖尿病患者的生活质量。

结合可编程警报,您和您所爱的人可以帮助管理糖尿病的影响。如果你有一个患有糖尿病的爱人,CGM值得每一分钱来让你安心。这是IOT的真正力量,体现在一个潜在的救命解决方案中。

另一个个人IOT解决方案是使用互联网连接的汽车功能。最古老的产品之一叫做安吉星(onstar.com),通用汽车公司(GM)的最新款和新款汽车上都有这种产品。虽然OnStar是一种基于卫星的服务,有几个级别和许多收费选项,但它结合了互联网,允许与车主通信。事实上,最新的通用汽车配备了内置的WiFi接入点!更好的是,在我看来,有一些基本功能是免费提供给GM所有者的,非常有价值。

图1-5。

OnStarAppKeyFobFeature

OnStar应用通过连接到云中的OnStar服务,请求通过OnStar卫星网络发送到车辆的功能(例如,解锁)。因此,这是IOT解决方案如何使用多种通信协议的绝佳范例。

我最喜欢的功能是维护报告。您将收到一封电子邮件,其中概述了您车辆的维护状态。该报告包括机油寿命、轮胎压力、发动机和变速器警告、排放、安全气囊等内容。图1-6显示了您将收到的一封典型电子邮件的摘录。

图1-6。

OnStarMaintenanceReport

请注意显示的信息。实际数据从您的车辆传输到OnStar。例如,里程表读数和轮胎压力数据直接取自车辆的车载数据存储器。也就是说,来自传感器的数据被读取、解释并为您生成报告。该功能展示了IOT解决方案中的自动数据编辑如何帮助我们保持车辆处于良好的机械状态,并在需要维护时发出预警。这为我们提供了最好的服务,帮助我们保持我们的车辆处于最佳状态,从而处于高转售价值的状态。

我应该指出,通用汽车并不是唯一提供此类服务的汽车制造商。许多其他人正在开发他们自己的解决方案,从类似OnStar的功能集到专注于娱乐和连接的解决方案。

车队管理系统不仅仅是为了路由。事实上,车队管理系统还允许企业监控每个单元进行诊断。例如,可以知道每辆卡车中有多少燃料,上次维护是什么时候进行的,或者更重要的是,下次维护是什么时候,等等。车辆地理跟踪和诊断的结合被称为远程信息处理。图1-7为车队管理系统图。

图1-7。

FleetManagementExample7

在图中,您将看到GPS系统在跟踪位置方面的应用,以及卫星通信在传输诊断、有效负载状态等附加数据方面的应用。所有这些最终都会通过互联网,业务分析师可以访问这些数据。

你可能认为船队管理系统只适用于大型航运公司,但随着GPS模块甚至微控制器市场的激增,任何人都可以创建船队管理系统。也就是说,它们不需要花费数百万美元来开发。

CameraDronesandTheIOT

IOT的一个可能用途是让无人机产生的数据在互联网上可用。有些人可能觉得无人机侵犯了隐私,我同意无人机被滥用或违反既定法律的情况。幸运的是,绝大多数无人机所有者遵守当地法律、法规和业主的意愿。8

然而,无人机有许多合法用途,无论是陆基、空基还是海基。例如,我可以想象家庭监控解决方案,您可以通过查看固定摄像头的数据和移动无人机的数据来远程检查您的家。就我个人而言,我希望看到一种解决方案,允许我编程一个预先确定的哨兵飞行路径,用飞行的无人机监控我的财产。

最近一连串的大规模数据泄露事件证明,基本的安全性还不够好。我们已经看到了从直接盗窃到利用从Target等非常知名的企业(超过4000万个信用卡号码可能已被泄露)和美国人事管理办公室等政府机构(超过2000万个社会安全号码被泄露)窃取的数据的各种情况。

IOT解决方案也不能幸免于安全威胁。事实上,随着IOT解决方案越来越多地融入我们的生活,我们的个人数据也将越来越多。因此,必须非常重视安全性,并从一开始就将其纳入解决方案中。

这包括我们自己开发的解决方案。更具体地说,如果您设计一个供自己使用的气象站,您应该采取合理的措施来确保数据不会被意外或故意利用。您可能认为天气数据没有高风险,但是考虑一下这样一种情况,您为您的传感器包括GPS坐标(一个合理的功能),以便人们可以看到天气在哪里被观察到。如果有人可以看到这些信息,并确定该解决方案使用了互联网连接,他们就有可能获得对互联网设备的物理访问权,并可能利用它来进一步渗透和利用您的系统。因此,安全性不仅仅与数据有关;它应该涵盖解决方案的所有方面,从数据到软件到硬件到物理访问。

您可能需要考虑在以下四个方面花费额外的精力,以确保您的IOT解决方案受到良好的安全保护。正如您将看到的,这包括您应该为现有基础设施、计算机甚至安全计算习惯考虑的几件事情。通过利用这些领域,您将构建一个分层的安全方法:通常称为深度防御方法。

DoIReallyNeedToWorryAboutSecurity

如果您想知道为什么我在一本关于IOT和Python的初学者书籍中包含了这一部分,请考虑一下您最终想用从这本书中学到的知识做什么。如果您只对学习如何使用新的MicroPython板感兴趣,并且没有进一步开发的愿望,那么您可能想浏览这些部分。但是,如果您的目标包括制作您部署的MicroPythonIOT解决方案——特别是如果您计划将其连接到互联网——您将需要考虑解决方案的安全性。无论哪种方式,我强烈建议阅读并遵循这些提示来保护您的IOT解决方案。

在将IOT解决方案引入您的家庭网络之前,您应该考虑采取预防措施,以确保家庭网络上的机器受到保护。这一点很重要,因为如果有人进入您的家庭网络,他们就可以进行各种各样的恶意活动。

最常见的错误是没有保护家庭WiFi网络。这不仅意味着你的邻居可以跳到你的网络上占用你的带宽,还意味着他们可以离开你的IOT设备、电脑、电器等进入你家庭网络的系统。,容易受到攻击。

幸运的是,有一些保护家庭网络的最佳实践可以帮助降低这些风险。其中包括以下内容。密码:这似乎是一件简单的事情,但是一定要确保在你所有的电脑和设备上使用密码。此外,采用良好的密码习惯,例如要求较长的字符串、混合大小写、数字和符号,以确保密码不容易被猜到。9

其中一些你可能知道如何做,但其他的可能需要一个更了解设备和网络的朋友的帮助。例如,如果你不知道什么是防火墙,请别人帮助你。一点额外的安全是值得努力学习如何设置防火墙的基础知识的。

如上所述,您的IOT设备也需要得到保护。要考虑的一些实践包括以下内容。

这是一个经常被忽视的领域。虽然该选项通常仅用于传输机密数据的解决方案,如商用IOT设备,但如果您计划发送您认为敏感的数据,如果您在存储数据时加密数据,并在传输数据时加密通信机制,则可以进一步保护您自己和您的数据。如果你加密了你的数据,即使有人获得了存储设备的物理访问权,这些数据也是无用的,因为他们不容易破译加密。像处理计算机密码一样小心处理加密密钥和密码。

将IOT设备连接到云服务需要考虑很多因素。事实上,微软和其他公司已经使得在你的IOT解决方案中使用can服务变得非常容易。但是,对于安全性和您的IOT数据,有两个重要的注意事项。

既然我们已经知道了应该如何在我们的项目中包含安全性,那么让我们简单地看一下我们将在本书中使用的编程语言——Python。

Python是一种高级的、解释性的、面向对象的脚本语言。Python的最大特点之一是拥有一个清晰、易于理解的语法,读起来尽可能接近英语。也就是说,即使你没有学过Python,你也应该能够阅读Python脚本并理解它。Python也比其他语言有更少的标点符号(特殊符号)和更少的语法机制。

以下是Python的一些关键特性。

Python由吉多·范·罗苏姆于20世纪80年代末至90年代初在荷兰国家数学和计算机科学研究所开发,并由该研究所的核心开发团队维护。它源自许多语言并受其影响,包括Modula-3、C、C++,甚至Unixshell脚本语言。

关于Python的一个有趣的事实是,它是以BBC节目“蒙蒂Python的飞行马戏团”命名的,与同名的爬行动物没有任何关系。在源代码文档中引用MontyPython(甚至是对错误消息的幽默转移)是非常常见的,虽然一些专业开发人员可能会对这种暗示感到畏缩,但Pythonstas11认为这是展示您的Python街头信誉。如果你喜欢MontyPython,我鼓励你在代码中使用节目片段。我喜欢玩的一个地方是打印信息。我最喜欢的是这样的:12

>DUPLICATEFILEERROR:Hesaysthey'vealreadygotone!有些人可能想知道像Python这样的语言怎么可能有助于编写IOT解决方案。答案是一个叫做MicroPython的很酷的产品。简而言之,MicroPython是一个压缩的、优化的Python3代码,已经加载到硬件中。这意味着,MicroPython芯片可以直接在硬件上运行Python代码,而不是必须在操作系统上运行解释器来执行Python代码。不需要操作系统。事实上,MicroPython内置了基本的文件I/O。

模拟器有几个示例脚本(Python程序称为脚本),您可以试用。有脚本来打开发光二极管,打印到液晶显示器,甚至移动伺服。模拟器允许您选择一个脚本,并将其提交到队列中运行。如果队列中没有其他脚本,您将看到您选择的脚本几乎立即运行。图1-8显示了一个打开LED的简单脚本示例。在这种情况下,是电路板上的LED。

图1-8。

MicroPythonSimulator-LEDon(courtesyofmicropython.org)

请注意,在图像中,我们看到几个部分或面板。从左上方顺时针方向,我们可以看到当前代码(当前代码)和板上运行的代码的当前输出(当前输出),运行中的板的视频馈送,显示您执行的代码的脚本输出(使用print()函数)的区域(我的输出),以及允许您滚动可用示例脚本并执行它们的面板(我的代码)。以下按钮允许您控制脚本。

模拟器最酷的一点是,你可以使用“我的代码”面板编写自己的代码!只需单击clear按钮,将光标放在第2行(在import语句下面),然后开始输入。当你准备好了,点击运行!按钮。图1-9显示了一个脚本的例子,它打印了两行代码,显示了我编写的在板上运行的代码。

图1-9。

MicroPythonSimulator-Customcode(courtesyofmicropython.org)

图1-10和1-11显示了另外两个示例脚本。

图1-11。

MicroPythonSimulator–UARTCalculations(courtesyofmicropython.org)

图1-10。

MicroPythonSimulator–LCD(courtesyofmicropython.org)

在本章中,我们发现了什么是IOT,并看到了一些著名的IOT解决方案的例子。我们还发现了微软如何通过RaspberryPi硬件将其Windows10操作系统扩展到IOT,从而为Windows用户打开大门。对于那些不想学习基于Linux的操作系统的细微差别的人来说,这是一个非常令人兴奋的机会,他们可以从一个熟悉的、充分理解的平台探索硬件和IOT的世界。

在下一章,我们将发现更多关于MicroPython的内容,包括如何在MicroPython中编程。正如你将看到的,这并不困难。然后,我们将在第三章中更详细地探讨我们将用于运行MicroPython的硬件,以完成我们的IOTMicroPython入门之旅。

Footnotes1

2

例如,一切似乎都是云——这,云——那时候什么都没有改变。

3

4

5

6

7

埃里克狩猎——通过ccby-sa3.0(“”)。

8

9

您还需要在密码的复杂性和您记忆密码的能力之间取得平衡。如果你一定要写下来,你刚刚打败了你自己的安全!你可能会惊讶地发现,猜测别人密码的第一条规则是看他们的键盘下面。那是大多数人放便利贴和密码的地方。不要那样做。

10

11

Pythonistas是Python开发专家,是所有Python事物的倡导者。

12

现在,我们已经了解了更多关于物联网的知识,并看到了一些MicroPython的演示,是时候了解更多关于MicroPython的知识了——我们如何开始,它如何工作,以及您可以使用自己的MicroPython板做什么的示例。

在这一章中,我们将学习更多关于MicroPython的知识,包括如何开始使用最流行的主板之一的概述。如果你还没有冲浪板,也不用担心;本章中的例子旨在让你了解你能做什么,而不是一个详细的教程。也就是说,我们将会看到本章中使用的主板以及第三章中其他主板的详细教程。我们还将在第四章中更详细地探讨编程Python。

Tip

我将本机运行MicroPython或可以加载MicroPython二进制文件的微处理器板称为“MicroPython兼容板”或“MicroPython板”。

我们先来看看什么是MicroPython,包括为什么创建它,如何入门。

然而,这需要构建特殊的库来与硬件通信。这些库旨在与通用输入输出(GPIO)引脚接口。GPIO引脚通常出现在板上的一排或多排公引脚中。一些电路板使用母头引脚。

虽然这些电路板使那些想要开发电子项目的人成为可能,但它要求用户购买电路板以及键盘、鼠标和显示器等外围设备。不仅如此,用户还必须学习操作系统。对于那些不习惯Linux的人来说,这本身就是一个挑战。

你可能想知道微控制器,如广受欢迎的Arduino(arduino.cc)或Espressif,也称为ESP板(espressif.com)。对于那些板卡,你必须用一种类C语言1来编程,这可能是有些人不愿意学的。

MicroPython的愿景是将学习Python的简单性与微控制器板的低成本和易用性结合起来,这将允许更多的人在艺术和科学项目中使用电子产品。初学者不必学习新的操作系统或学习更复杂的编程语言。答案是MicroPython。图2-1显示了来自Adafruit的技能徽章2形式的MicroPython标志。

图2-1。

MicroPythonLogoSkillBadge(courtesyofadafruit.com)

MicroPython3由DamienP.George、PaulSokolovsky和其他贡献者创建和维护。它被设计成Python3语言的精简、高效版本,并安装在一个小型微控制器上。由于Python是一种解释语言,因此(一般来说)比编译语言慢,所以MicroPython被设计得尽可能高效,以便它可以在通常比典型的个人计算机慢得多且内存少得多的微控制器上运行。

CompiledVS.Interpreted

编译语言使用称为编译器的程序将源代码从人类可读的形式转换为二进制可执行的形式。这种转换涉及几个步骤,但一般来说,我们获取源代码并将其编译成二进制形式。由于它是二进制形式,处理器可以直接执行生成的语句,而不需要任何额外的步骤(同样,一般情况下)。

另一方面,解释语言不是编译的,而是用一个叫做解释器的程序动态地转换成二进制形式(或中间二进制形式)。Python3提供了一个Python可执行文件,它既是解释器又是控制台,允许您在输入代码时运行代码。Python程序一次运行一行代码,从文件的顶部开始。

因此,编译语言比解释语言更快,因为代码是为执行而准备的,并且不需要中间的实时步骤来在执行之前处理代码。

另一方面,Arduino等微控制器板需要一个编译步骤,您必须在电脑上执行该步骤,并首先将二进制可执行文件加载到板上。相比之下,由于MicroPython的解释器直接在硬件上运行,我们不需要中间步骤来准备代码;我们可以直接在硬件上运行解释语言!

这使得硬件制造商可以制造小型、廉价的主板,在与微处理器相同的芯片上包含MicroPython(通常情况下)。这使您能够连接到电路板,编写代码,并执行它,而无需任何额外的工作。

您可能会想,将Python3缩减到适合内存有限的小芯片的大小,这种语言被剥离了,缺少了一些特性。这不可能比事实更进一步。事实上,MicroPython是Python3核心特性的完整实现,包括紧凑的运行时和交互式解释器。它支持读写文件、加载模块、与GPIO引脚等硬件交互、错误处理等等。最重要的是,Python3代码的优化允许它被编译成需要大约256K内存来存储二进制文件的二进制文件,并且运行时只需要16k的RAM。

然而,有一些事情MicroPython没有从Python3语言中实现。下面几节将向您介绍使用MicroPython能做什么,不能做什么。

MicroPython最大的特点当然是运行Python。这允许你创建简单的、有效的、易于理解的程序。我认为,这是它相对于Arduino等其他主板的最大优势。下面列出了MicroPython支持的一些特性。我们将在本书中更详细地看到这些特性。

回答你的问题,“我能用MicroPython做什么?,“答案还挺多的!您可以控制连接到MicroPython板上的硬件,编写代码模块以扩展您的程序的功能,并将它们存储在SD卡上以供以后检索(就像您在PC上使用Python一样),等等。您可以连接的硬件包括打开和关闭led,驱动伺服系统,读取传感器,甚至在LCD上显示文本。一些主板还以WiFi无线电的形式提供网络支持。几乎任何你可以用其他微控制器板做的事情,你都可以用MicroPython板来做。

然而,在芯片上运行MicroPython有一些限制。

MicroPython最大的限制是易用性。Python的易用性意味着代码是动态解释的。尽管MicroPython得到了高度优化,但对解释器来说还是有损失的。这意味着需要高精度的项目,如高速数据采样或通过连接(USB、硬件接口等)进行通信。)可能跑得不够快。对于这些领域,我们可以通过用处理低级通信的优化库来扩展MicroPython语言来克服这个问题。

MicroPython使用的内存也比Arduino等其他微控制器平台多一点。通常,这不是一个问题,但是如果你的程序开始变大,你应该考虑一下。使用大量库的大型程序消耗的内存可能会超出您的预期。这又一次与Python的易用性有关——这是另一个要付出的代价。

最后,如前所述,MicroPython没有实现所有Python3库的所有特性。但是,您应该会发现它拥有构建IOT项目所需的一切(甚至更多)。

AreMyPythonSkillsApplicableToMicropython

如果你已经学会了如何用Python编程,你可能会期望看到一些与众不同的东西,甚至是关于MicroPython的奇怪的东西。好消息是,使用MicroPython只需要掌握Python技能。的确,MicroPython和Python使用相同的语法;没有什么新东西要学。正如您将在接下来的几章中看到的,MicroPython实现了Python库的一个子集,但仍然是非常Python化的。

由于MicroPython越来越受欢迎,运行MicroPython的主板有了更多的选择。其中一部分来自开发人员构建特定于处理器和平台的MicroPython编译版本,您可以下载并安装到主板上。这是增长最快的类别。

有两类板可以用来运行MicroPython。首先是从工厂加载了MicroPython并且只运行MicroPython的主板。其中包括Pyboard(最初的MicroPython板)和WiPy。接下来是有可用固件选项在板上安装MicroPython的板,包括ESP8266、Teensy等。我们将在下一章看到更多关于这些板的内容。

接下来,让我们在下一节中从我们的PC上探索Python,让您了解这种语言是什么样的,并有机会在不需要MicroPython板的情况下亲自尝试一下。

由于MicroPython是Python(只是为了优化的目的稍微缩小了一点),您可以在PC上运行Python并试验这种语言。我建议在你的PC上加载Python,即使你已经有一个MicroPython板。你可能会发现用你的电脑来尝试更方便,因为你可以更好地控制环境。然而,您的PC将无法与电子元件或硬件(如MicroPython板)通信,因此虽然您可以在PC上做更多的事情,但您无法测试与硬件通信的代码。但是您可以测试基本的构造,比如函数调用、打印消息等等。

所以,何必呢?简单地说,在MicroPython板上尝试之前,使用您的PC调试Python代码将允许您完成项目的大部分工作。更具体地说,通过在您的PC上开发普通的东西,您消除了许多在MicroPython板上调试代码的潜在问题。这是新手程序员犯的头号错误——编写完整的解决方案而不测试较小的部分。从小处着手,一次只测试一小部分代码,只添加那些已经测试并证明可以正常工作的部分,这样总是更好。

Caution

Python有两个版本——Python2和Python3。因为MicroPython是基于Python3的,所以您需要安装Python3版,而不是Python2版。

但是首先,检查您的系统,看看是否已经安装了Python。打开终端窗口(命令提示符)并键入以下命令。

python--version如果安装了Python,您应该会看到如下所示的内容。

$python--versionPython3.6.0如果您看到了类似Python2.7.3的版本,那么您的机器上仍然有机会安装Python3。有些系统同时安装了Python2和Python3。要运行Python3,请使用以下命令。

下载Python后,就可以启动安装程序了。例如,在我的Windows10机器上,我在名为最新Python3版本——Python3.6.0的链接下下载了该文件。如果你向下滚动,你可以找到你想要的安装程序。例如,我点击了Windows64位机器的安装程序。这下载了一个名为python-3.6.0-amd64.exe的文件,我将它放在我的Downloads文件夹中,并通过双击该文件来执行。

像大多数Windowsinstaller安装一样,您可以通过各种屏幕来同意许可,指定您要安装它的位置,并最终启动安装。图2-2显示了安装程序运行的示例。

图2-2。

InstallingPythononWindows10Tip

安装完成后,您可以尝试上一节中的测试来验证安装。如果不修改路径变量,可能需要使用开始菜单上的Python控制台快捷方式来启动控制台。

下载Python后,就可以启动安装程序了。例如,在我的iMac上,我在名为最新Python3版本——Python3.6.0的链接下下载了最新的Python3文件。如果你向下滚动,你可以找到你想要的安装程序。例如,我点击了64位机器的安装程序。这下载了一个名为python-3.6.0-macosx10.6.pkg的文件,我将它放在我的下载文件夹中并执行。

像大多数安装程序一样,您可以一步一步地通过各种屏幕,同意许可,指定您想要安装它的位置,最后开始安装。图2-3显示了安装程序运行的示例。

Note

根据您运行的macOS版本以及您的安全设置,您可能需要更改它们来运行安装程序,因为它不是由指定的开发人员签名的。请查看“系统偏好设置”中的“安全性与隐私”面板。

图2-3。

InstallingPythononmacOS

安装完成后,您可以尝试上一节中的测试来验证安装。

如果您使用的是Linux,安装Python的方式会因平台而异。例如,Ubuntu使用apt-get命令,而其他发行版有不同的包管理器。使用您平台的默认包管理器安装Python3.6(或更高版本)。

例如,在Debian或Ubuntu上,我们使用以下命令安装Python3.6包。第一个命令更新包,以确保我们拥有最新的包引用。第二个命令启动必要文件的下载并安装Python。

sudoapt-getupdatesudoapt-getinstallpython3.6Tip

在16.10之前的Ubuntu版本上,您可能需要在运行update命令之前添加apt存储库。使用命令sudoadd-apt-repositoryppa:jonathonf/python-3.6添加存储库并重新运行sudoapt-getupdate命令,然后安装Python3.6。其他平台可能有类似的解决方案。

图2-4展示了一个在Kubuntu(Ubuntu的一个变种)上安装的例子。您的平台输出可能略有不同。

图2-4。

InstallingPythononKubuntu(Linux)

注意,在这次安装中,我已经安装了Python2.7和Python3.4。一旦我安装了Python3.6,我就可以简单地通过使用正确的解释器来运行这三个版本:2.7版使用python,3.4版使用python3,3.6版使用python3.6。如果安装了以前版本的Python,您的平台可能会有类似的约束。

现在让我们在电脑上运行一些测试。回想一下,我们可以通过打开一个终端窗口(命令提示符)并输入命令python(或python3或python3.6,这取决于您的安装)来打开Python控制台。看到提示后,在提示处输入下面的代码(>>>)。这段代码将在屏幕上打印一条消息。结尾的--n是一个特殊的非打印字符,它发出回车(类似于按Enter)来移动到新的一行。

print("Hello,World!")当你输入这段代码时,你会马上看到结果。回想一下,解释器的工作方式是每次执行一行代码——每次按回车键。但是,与运行存储在文件中的程序不同,您在控制台中输入的代码不会被保存。图2-5显示了一个在macOS上运行Python控制台的例子。注意,我输入了一个简单的程序——典型的“你好,世界!”例子。

图2-5。

Hello,World!

要退出控制台,输入quit()代码,如上图所示。

虽然这演示了如何在PC上运行Python,但并不有趣。让我们看一些更复杂的东西。

假设您的项目要求您将数据保存到文件中,或者可能从文件中读取数据。我们可以在我们的PC上对文件进行实验,而不是试图找出如何在MicroPython板上做到这一点!

在下一个例子中,我将数据写入文件,然后读取数据并打印出来。不要太担心理解代码——通读一下就好——它非常直观。清单2-1显示了这个例子的代码。我使用了文本编辑器,并将文件保存为file_io.py。

#Examplecodetodemonstratewritingandreadingdatato/fromfiles#Step1:Createafileandwritesomedatanew_file=open("log.txt","w")#use"write"modenew_file.write("1,apples,2.5--n")#writesomedatanew_file.write("2,oranges,1--n")#writesomedatanew_file.write("3,peaches,3--n")#writesomedatanew_file.write("4,grapes,21--n")#writesomedatanew_file.close()#closethefile#Step2:Openafileandreaddataold_file=open("log.txt","r")#use"read"mode#Usealooptoreadallrowsinthefileforrowinold_file.readlines():columns=row.strip("--n").split(",")#splitrowbycommasprint(":".join(columns))#printtherowwithcolonseparatorold_file.close()Listing2-1.FileIOExample我将代码保存到一个文件中,向您展示如何使用Python解释器使用以下命令执行Python脚本。如果使用Windows,可能需要修改类似“python.exefile_io.py”的命令。

python./file_io.py清单2-2显示了运行脚本的结果。

既然我们已经在PC上试验了Python,那么让我们看看如何在典型的MicroPython板上使用MicroPython。

回想一下,MicroPython设计用于小型微控制器平台。这些微控制器平台中的一些使用包含MicroPython二进制文件(库、基本磁盘IO、引导等)的特殊芯片。)以及微控制器、存储器和支持组件。

像大多数微控制器一样,当您使用MicroPython板时,您必须首先编写代码并将其加载到板上。大多数MicroPython主板都有一个USB闪存驱动器,当您使用USB电缆将它连接到您的计算机时,它就会安装。这个闪存驱动器存储了几个文件,您可以通过修改来改变它的行为。您也可以将您的程序(脚本文件)复制到这个驱动器,以便在引导时执行。我们将在后面的章节中看到如何做到这一点。

您还可以使用MicroPython控制台,它非常类似于我们在上一节中看到的Python控制台。MicroPython控制台被称为运行、评估、打印循环或REPL控制台。每次开发板通电时,在将程序加载到开发板上执行之前,控制台使启动和调试程序(排除错误)变得非常容易。

如果您使用过Arduino之类的微控制器板,您可能会熟悉以下一些内容。但是如果您没有使用过这样的程序或者没有使用过终端程序,我提供了您在三个主要平台上需要的所有步骤:Windows、macOS和Linux。以下部分将带您完成首次连接到电路板的过程。

我在这些例子中使用Pyboard。您可以使用默认加载了MicroPython的任何其他板,但是在第一次开始使用该板之前,一定要查看供应商的文档。某些主板可能需要在首次使用前加载固件。

要开始使用REPL控制台,请使用USB转microUSB电缆(通常)将该板连接到您的计算机,该电缆通过USB供电并连接控制台。一旦主板启动(有些主板第一次启动可能需要1-2分钟),您就可以使用终端程序连接到主板。从那里,我们可以像使用Python控制台一样使用REPL控制台。

当主板完成启动时,您可以使用电脑浏览主板上的驱动器。使用USB电缆连接Pyboard后,您应该会看到USB驱动器安装。例如,在Windows10上,您可以使用文件资源管理器查看驱动器上的文件。图2-6显示了Pyboard上的文件示例。

图2-6。

USBDrive(Pyboard)

注意有两个文件的扩展名为.py:boot.py,在引导时执行(因此得名);和main.py,如果你想独立使用该板,你可以用你自己的程序替换它。同样,我们将在后面的章节中看到这一点。还有一些附加文件,如README.txt,其中包含一些使用电路板的说明;还有pybcdc.inf,这是一个Windows的设备驱动安装程序。

要安装PuTTY,请选择适当的.msi文件(32位或64位),下载它,然后双击该文件启动安装程序。按照提示完成安装。比如我下载了名为putty-64bit-0.68-installer.msi的文件。

现在您已经安装了PuTTY,您必须知道要使用的正确端口。打开设备管理器,沿树向下导航,直到找到端口(COM&LPT)条目,然后单击将其打开。请注意,Pyboard必须连接才能工作。您应该在子树中看到一个或多个条目,指示连接到PC的COM端口(和打印机端口)。Pyboard将被简单地列为USB串行设备(COMn),其中n是类似COM1、COM2等的数字。比如在我的PC上,它被列为COM3。图2-7显示了一个来自我的电脑的例子。

图2-7。

FindingtheCOMPortonWindows10

现在我们可以打开PuTTY并连接到Pyboard。使用开始菜单上的快捷方式启动PuTTY,或者在搜索框中键入PuTTY,当Cortana找到该条目时单击它。当PuTTY打开时,您将看到一个对话框,您可以使用它通过网络上的终端进行连接。因为Pyboard是通过COM端口连接的,所以我们必须单击标有Serial的小单选按钮。然后,我们可以在串行线文本框中输入COM端口,并将速度设置为115200。图2-8显示了一个正确配置的PuTTY,用于连接到COM3上的Pyboard(如设备管理器所示)。

图2-8。

ConnectingtoPyboardUsingPuTTY

准备就绪后,单击“打开”按钮。这将打开一个新的终端,启动REPL控制台,如图2-9所示。我输入了一个简单的语句来演示控制台正在工作。

图2-9。

TheREPLConsole(Windows10)Tip

如果你不喜欢黑底白字的配色方案,你可以通过点击树控件中的颜色来改变它们。小心行事,因为您必须单独设置这些值(没有方案概念)。

要使用macOS或Linux进行连接,您可以使用以下命令。您唯一需要做的就是找到正确的设备。我用列出我的macOS系统上的设备的第一个命令来演示这一点。请在连接到MicroPython板(Pyboard)后执行此操作。

$ls/dev/tty.usb*/dev/tty.usbmodem1422$screen/dev/tty.usbmodem1422继续插入您的主板,然后按照上面的说明打开一个控制台。控制台打开后,输入如下所示的代码。图2-10显示了在Pyboard上运行的REPL控制台的示例。

图2-10。

REPLConsole(Pyboard)

REPL游戏机有一个奇怪之处。quit()不工作了。要退出某些板的控制台,您需要重置板或切断连接。虽然这看起来很奇怪,但我确信它在未来会得到改进,回想一下,我们通常不使用REPL控制台来运行我们的项目;相反,我们用它来测试代码,所以退出时的一点小问题不是大问题。

您应该避免简单地拔掉您的MicroPython板。有些主板,如Pyboard,将它们的基本文件系统作为一个可挂载的USB驱动器。未弹出板就断开连接可能会导致数据丢失。

现在是时候来看看我们能用MicroPython做些什么了。下一节使用几个示例项目向您展示如何使用MicroPython板。我再一次用最少的硬件解释和细节来介绍这些例子。我们将在下一章学到更多关于硬件的知识。

图2-11。

PyboardwithHeaders

电路板的右侧是微型USB连接器,上方是微型SD读卡器。如果您查看这些连接器之间,您会看到四个小led,如方形框所示。指示灯的左侧是一个标有USR的按钮。这些是我们将在以下示例中与之交互的组件。

此处显示的Pyboard具有从MicroPython.org预焊的GPIO接头(板周围的插座排)。如果您订购Pyboard,我建议您购买这个版本,尤其是如果您不知道如何或不想自己焊接接头的话。

我最喜欢这个板的地方是它有一个发光二极管(led)阵列和一个按钮,你可以用它来试验编写MicroPython项目。这使得Pyboard成为初学者的绝佳首选。

但是,如果你还没有冲浪板,也不用担心。同样,我包括这一部分是为了帮助你通过例子了解更多的可能性。一旦我们讨论了流行的板的细节以及如何在MicroPython中编程,我们将深入到更复杂的项目中,您可以在学习的过程中进行实验。

不幸的是,Pyboard不提供任何形式的网络,因此它在IOT项目中的使用可能相当有限。幸运的是,有很多方法可以将你的Pyboard连接到互联网。

您可以使用的兼容MicroPython的主板越来越多。我选择Pyboard来演示MicroPython,因为Pyboard是最容易使用的板,而且相对便宜。我们将在第三章中了解更多关于其他选择的信息。如果你想买一个Pyboard来运行这些例子,你可以,但是你可能需要一个不同的板或者一个网络模块来用于连接到互联网的更高级的项目。

虽然下面的例子不需要任何额外的电子元件,但我想介绍几个你在本书后面会用到的关键元件。如果您没有这些组件,现在订购它们是一个好主意,这样当您到达示例项目时,您将拥有您所需要的。

除了MicroPython板之外,我认为这些组件是任何想要学习如何使用电子学和MicroPython的人的必备物品。这些包括一个基本的电子工具包,其中包含学习电子技术时需要的最常见的组件、试验板和跳线。我将在下面的章节中描述每一个。

本书中的示例项目使用了几种常见的电子元件,如发光二极管、开关、按钮、电阻等。在爱好层面学习使用电子产品时,最大的挑战之一是买什么。我曾和一些人交谈过,他们多次去当地的电子商店购买他们需要的东西,似乎无论他们买什么都没有合适的组件。

幸运的是,电子产品零售商已经意识到了这个问题,现在他们提供了一个基本的电子套件,其中包含了许多更常见的组件。Adafruit(adafruit.com/products/2975)和Sparkfun(sparkfun.com/products/13973)都提供这样的套件。虽然这两种套件都不会出错,但我最喜欢Adafruit套件,因为它有更多的组件(例如,更多的led)。

AdafruitPartsPal封装在一个小型塑料外壳中,带有大量电子元件。图2-12显示了零件Pal套件。

图2-12。

AdafruitPartsPal(courtesyofadafruit.com)

该套件包括以下组件:原型制作工具、led、电容器、电阻器、一些基本传感器等。事实上,这个工具包里的组件比你做很多实验所需的都要多。更好的是,该套件的价格仅为19.95美元,非常划算(而且这个箱子是一个巨大的奖励)。

试验板是一种特殊的工具,它允许您插入电气元件,并提供各列之间的互连,以便您可以将两个元件的引线插入同一列,从而实现连接。电路板分为两排,便于在电路板中央使用IC。电线(称为跳线或简称跳线)可用于将试验板上的电路连接到MicroPython板上。在本章的后面你会看到一个这样的例子。

幸运的是,AdafruitPartsPal配备了如图2-13所示的试验板。这是Adafruit公司的半块面包板。这种试验板被称为半板,因为它是标准试验板正常长度的一半。最重要的是,它适合零件Pal盒。

图2-13。

Half-sizedBreadboard(courtesyofadafruit.com)

如果已经有了一些组件,或者决定购买一个不附带试验板的不同的基本电子套件,您可以从Adafruit(adafruit.com/products/64)单独购买试验板。

如果您的MicroPython板有公头引脚而不是母头引脚,您将需要一套不同的跳线。再说一次,Adafruit有你需要的东西。如果您需要公/母跳线,请订购优质母/公扩展跳线–20x6(adafruit.com/products/1954)。图2-14显示了一组公/母跳线。

图2-14。

Male/FemaleJumperWires(courtesyofadafruit.com)

现在,让我们来看看一些硬件的运行情况!

在本例中,我们将编写代码来打开电路板上的一个led。如果您按照图2-11所示的方向放置电路板,四个led从左到右排列为不同的颜色,分别为红色、绿色、黄色(橙色)和蓝色。如果你像我一样是右撇子,你可能会调整电路板的方向,使USB连接器在左边。在这种情况下,蓝色LED位于最左侧。

让我们写一些代码来打开蓝色LED。与其简单地打开它,不如让我们使用一个称为循环的结构来每隔250毫秒打开和关闭它。因此,它会快速闪烁。在我解释代码之前,让我们看一下完整的代码。清单2-3展示了代码的样子。不用担心;我将在清单之后解释每一行代码。

##MicroPythonfortheIOT##Example1##TurnontheblueLED(4=Blue)##Dr.CharlesBell#importpyb#ImportthePyboardlibraryled=pyb.LED(4)#GettheLEDinstanceled.off()#Makesureit'sofffirstforiinrange(0,20):#Runtheindentedcode20timesled.on()#TurnLEDonpyb.delay(250)#Waitfor250millesecondsled.off()#TurnLEDoffpyb.delay(250)#Waitfor250millesecondsled.off()#TurntheLEDoffattheendprint("Done!")#Goodbye!Listing2-3.BlinktheBlueLED代码的第一行是注释行。这些都被MicroPython忽略了,是一种向他人传达你的程序正在做什么的方式。在REPL控制台中输入代码时,可以随意跳过注释行。

接下来是一行用于导入Pyboard硬件库的代码(pyb)。该库专用于Pyboard,并提供板上的所有元件。接下来的两行代码通过使用Pyboard库(pyb)初始化一个变量(led)来获得第四个LED(蓝色的那个)。这就创建了一个我们可以使用的对象的实例。在这种情况下,我们立即通过调用led.off()关闭LED。

接下来是代码的主要部分——一个循环!在这种情况下,它是一个for循环,设计用来运行它下面的代码块,如缩进所指示的那样运行20次。for循环使用计数器i和由range(0,20)函数返回的0到19的值。在循环体(缩进部分)中,我们首先用led.on()打开LED,使用Pyboarddelay()方法等待250毫秒,然后再次关闭LED,再等待250毫秒。最后,我们关闭LED并打印一条消息,说明我们完成了。

您可以在REPL控制台中逐行输入该代码。#开头的可以跳过。一旦您输入了for循环语句,您将得到一个没有>>>提示的行。这很正常。使用两个空格键入下一行(用于缩进,为循环建立块)。第二次delay()调用后,在空白处像结束缩进块一样按回车键。现在看一下Pyboard。蓝色LED应该在闪烁。请记住,REPL控制台与Python控制台一样,在您输入代码时运行代码。图2-15显示了代码运行的一个例子(我在蓝色LED亮着的时候捕捉到的)。如果你想让它闪烁得更慢,只需调整delay()调用,将数值增加到500甚至1000。

图2-15。

RunningExample1Note

在某些平台上,如macOS和Linux,您可以使用文本编辑器输入代码,然后将其复制并粘贴到REPL控制台。然而,这并不适用于所有平台或终端程序。你自己试试。

如果您想再次运行代码或出现错误,您必须首先关闭PuTTY窗口,然后弹出USB驱动器。一旦弹出,按下重置按钮(板上标有RST)重新初始化REPL控制台。

现在,让我们使用不同循环(while循环)中的计数变量按顺序打开和关闭led。在这种情况下,我们必须一次打开一个led,然后在短暂的延迟后关闭。因此,它就像前面的例子一样,但是,正如你将看到的,它展示了更多的复杂性。因为它更复杂,所以在展示完整的代码之前,我将分几部分浏览代码。

像Pyboard的所有程序一样,我们从导入Pyboard硬件库开始。

importpyb#ImportthePyboardlibrary这个例子使用了两个循环。首先,我们循环关闭所有的led。下面显示了如何做到这一点。请注意,我使用了1到4范围内的计数变量。在循环体中,我使用Pyboard硬件库中的计数变量获取LED,并将其保存在名为led(led=pyb.LED(j))的变量中,然后用led.off()将其关闭。在开始时关闭led是一个好习惯,它将处理任何让代码运行或中断代码运行的事件,以便一个或多个led保持打开。您也可以通过重置电路板来解决这个问题,但这种方法是首选的(也是一种好的做法)。

forjinrange(1,5):#TurnoffalloftheLEDsled=pyb.LED(j)#GettheLEDled.off()#TurntheLEDoff接下来,我们使用另一个初始化为1的计数变量。然后,我们用一个无限条件开始while循环。也就是说,while后面的表达式始终为真。在循环体中,我做了与上一个循环类似的事情,从Pyboard硬件库中获取LED,打开它,等待500毫秒,关闭它,再等待500毫秒。在循环体的末尾,我增加了计数变量(而循环不像for循环那样增加计数变量)。如果计数器计数到5,我从1开始计数。检查以下代码以查看这些元素。

whileTrue:#Loopforeverled=pyb.LED(i)#GetnextLEDled.on()#TurnLEDonpyb.delay(500)#Waitfor1/2secondled.off()#TurnLEDoffpyb.delay(500)#Waitfor1/2secondi=i+1#IncrementtheLEDcounterifi>4:#If>4,startoverat1i=1清单2-4显示了完整的代码。通读几遍,直到你确信它可以工作。

##MicroPythonfortheIOT##Example2##TurnonthefourLEDsontheboardinorder##1=Red#2=Green#3=Orange#4=Blue##Dr.CharlesBell#importpyb#ImportthePyboardlibraryforjinrange(1,5):#TurnoffalloftheLEDsled=pyb.LED(j)#GettheLEDled.off()#TurntheLEDoffi=1#LEDcounterwhileTrue:#Loopforeverled=pyb.LED(i)#GetnextLEDled.on()#TurnLEDonpyb.delay(500)#Waitfor1/2secondled.off()#TurnLEDoffpyb.delay(500)#Waitfor1/2secondi=i+1#IncrementtheLEDcounterifi>4:#If>4,startoverat1i=1Listing2-4.Example2:BlinkingtheLEDs当您运行代码时,您将看到led依次打开,首先是红色,然后是绿色、黄色(橙色)和蓝色。由于循环没有结束,它将一直闪烁led,直到您重置板(记住首先弹出驱动器)。参见图2-16。

图2-16。

RunningExample2

这个例子演示了如何使用板上的按钮。它还演示了如何使用中断(称为回调函数)。也就是说,我们在代码中创建一个函数,然后告诉MicroPython在发生中断时执行该函数——在本例中,就是当按钮被按下时。由于这个例子也很复杂,我将带您浏览一下代码。

首先,我们导入Pyboard硬件库,为绿色LED(列表中的第二个)设置一个变量,并关闭它。

importpyb#ImportthePyboardlibraryled=pyb.LED(2)#GetLEDinstance(2=green)led.off()#MakesuretheLEDifoff接下来,我们定义一个函数。这相当容易。我们只是使用def指令并给函数一个名字。姑且称之为flash_led吧。在这个函数中,我们让LED快速闪烁(100毫秒延迟)25次。我们已经在前面的例子中看到了这样做的代码。

defflash_led():foriinrange(0,25):led.on()pyb.delay(100)led.off()pyb.delay(100)接下来,我们通过获取用户按钮(在库中称为开关)来创建另一个变量。然后,我们使用方法callback()并传入我们创建的函数的名称。这两个语句将建立连接,以便在按钮被按下时运行flash_led()函数。

button=pyb.Switch()#Getthebutton(switch)button.callback(flash_led)#Registerthecallback(ISR)最后,我们打印一条消息,说明代码已经可以测试了。

print("Readyfortesting!")清单2-5显示了完整的代码。

##MicroPythonfortheIOT##Example3##FlashthegreenLEDwhenbuttonispushed##Dr.CharlesBell#importpyb#ImportthePyboardlibraryled=pyb.LED(2)#GetLEDinstance(2=green)led.off()#MakesuretheLEDifoff#Setupacallbackfunctiontohandlebuttonpressed#usinganinterruptserviceroutinedefflash_led():foriinrange(0,25):led.on()pyb.delay(100)led.off()pyb.delay(100)button=pyb.Switch()#Getthebutton(switch)button.callback(flash_led)#Registerthecallback(ISR)print("Readyfortesting!")Listing2-5.Example3:UsingaButton一旦你看到,准备测试!在REPL控制台中,您可以测试它。如果你胆小或有异常高的静电倾向,使用非导电探针并按下标有USR的按钮。图2-17显示了一个按钮按下调用flash_led()方法的例子。尝试几次,直到你满意为止。

图2-17。

RunningExample3

拔下或重置Pyboard之前,不要忘记弹出驱动器。

MicroPython是微控制器世界中一个非常令人激动的新成员。第一次,初学者不需要学习新的操作系统或复杂的编程语言如C或C++来编程微控制器。MicroPython允许有一些甚至没有编程经验的人试验电子产品并构建有趣的项目。因此,MicroPython为更多的业余爱好者和爱好者提供了机会,他们只想在没有陡峭的学习曲线的情况下完成他们的项目。

在本章中,我们发现了MicroPython的主要特性。我们还发现MicroPython是基于我们在个人电脑上发现的Python。我们甚至在PC上测试Python来展示相似之处。最重要的是,我们亲眼看到了MicroPython如何在微控制器板上工作。在这种情况下,我们使用原始的MicroPython板Pyboard来演示为在Pyboard上运行组件而编写的三个Python代码示例。

在下一章中,我们将发现一系列可以用来运行MicroPython和构建我们的IOT项目的硬件。正如您将看到的,有许多选项,从已经加载了MicroPython的板(允许您无需额外设置即可构建项目)到您可以自己加载MicroPython的普通板。

有些人可能会说C++,我想这是有一定道理的,但它们更像是通用的、基本的C语言。

是的,我有一个。

本章还包括如何开始使用所讨论的每种板,包括如何连接板、加载固件等。您应该通读整个章节,因为虽然许多概念是相同的,但程序可能会因主板不同而略有不同。此外,本章的重点是支持MicroPython的主板。虽然我简要讨论了您可以使用的替代板,但这些部分中的信息对于使用本章中未列出的板是有用的。

在我们开始查看可用的主板之前,让我们讨论一些使用MicroPython主板的最佳实践和其他实用建议。这些适用于本章中的所有主板,也可能适用于任何新兴的主板,因此在选择主板时,你应该将这些考虑在内。

虽然你可以买一个这样的主板,然后直接进入你的IOT项目,但是在使用你的主板时,有一些事情你应该考虑和记住。具体来说,有些主板可能需要更新,有些可能需要组装硬件(焊接),而其他的可能有局限性要考虑。我将在本节中讨论这些以及更多内容。我还包括一些在你的电脑上使用主板的技巧。

那些在芯片上包含MicroPython的主板可能需要固件更新。固件1是用来描述芯片上软件的术语。大多数主板都有特殊的芯片,允许您自己更新MicroPython(和其他方面),使您能够跟上供应商、MicroPython等的变化。

当您第一次收到主板时,或者当您发现无法访问某些库函数、操作失败或发布新硬件(附加主板)时,您应该考虑更新固件。但是,您应该避免过于频繁地更新固件。

我的理念很简单:我只在主板是新的时候更新一次固件,并且只在某些东西不再工作的时候更新。如果您的项目正在运行,并且没有遇到任何问题,就没有必要更新它。过于频繁地更新固件的一个风险是,如果固件中发生了一些变化,如旧的库或硬件不再受支持,对库的更改破坏了您的代码,以及其他恼人的问题,您可能会使您的项目变得无用。我对这个规则的唯一例外是,如果供应商已经修复了一个错误或改善了用户体验,在这种情况下,我会更新固件。底线是,如果有用,就不要乱来!

当您的主板是新的时,只在以后需要时更新您的固件。

特别要提到的是那些必须自己加载MicroPython的板。其中一些主板可能需要您更新系统的其他部分,如引导机制、在非易失性内存中加载MicroPython等。如果您选择使用必须加载MicroPython的主板,请务必查看供应商的文档,了解关于更新主板上软件的建议(可能不仅限于固件)。最后,有些主板是新的,因此它们的固件可能不是测试版或候选版本,也不是产品质量。在这些情况下,我喜欢更频繁地更新固件,直到发布生产版本。

如果您的主板具有联网功能,您在学习如何使用主板时应该格外小心。具体来说,请按照供应商的说明设置网络并将您的主板连接到网络。例如,某些主板具有非常特殊的机制来连接到WiFi网络。未能正确配置您的网络连接将导致很多挫折,尤其是如果您的项目旨在生成通过网络访问的数据。

这也适用于将主板连接到您的PC。对于那些允许您将板载存储器作为文件系统进行访问的主板,这可能不是问题,但对于其他需要通过特殊软件通过USB进行连接的主板,您应该确保在尝试编写第一个Python程序之前可以连接到主板。

新手常犯的另一个错误是坐下来一次写完所有代码,而没有提前测试任何东西。这就造成了这样一种情况:如果某件事不成功,它可能会被一大堆问题掩盖。例如,如果有一些逻辑错误或产生的数据不正确,它可能会导致项目的其他部分失败或产生不正确的结果。当项目根本不工作时,情况会变得更糟——有太多的部分需要尝试和诊断出了什么问题。这往往会让初学者陷入困惑和沮丧的绝望境地。你们这些学生完全知道我在说什么。

这可以通过一步一步地构建项目来轻松避免。也就是说,一次构建一个方面的项目。例如,如果你用发光二极管发出信号,首先让那部分工作。同样,如果你从一个传感器读取数据,在把它们连接在一起并希望它们都能正常工作之前,确保你能独立正确地完成这项工作。即使是非常有经验的人也可能犯这种错误,但是如果出现问题,他们更有能力解决(他们知道得更多,但是这是一种照我说的做而不是照我做的情况)。我们将一步一步地构建本书中的示例。有些很小,可能只有一个步骤,但是这种实践是你从事任何项目都应该注意的。

一些微控制器供应商提供软件开发(编程)工具。可以说最成功的一个是Arduino集成开发环境(IDE)。ArduinoIDE提供了操作(编程)Arduino所需的所有工具,从编写代码到编译,再到将其安装到电路板上。

Atom、Sublime、VisualStudioCode和PyCharm的PyMakr插件仍在开发中。目的是用PyMakr桌面应用来替换它们。目前,建议用户使用FileZilla等FTP客户端将代码/项目上传到他们的设备。

我最喜欢的编辑器是KomodoEdit和PyCharm。两者都有Python语法高亮显示——文本的颜色会改变以指示语法、字符串等。,还有一些可以完成你的语句,甚至可以根据你使用的构造自动缩进。

两者都是编写Python的绝佳选择。KomodoEdit是一个简单的编辑器,但它的工作做得非常好。PyCharm是一个PythonIDE,它能做更多的事情,包括交互式调试。虽然您不能使用MicroPython板的一些功能,但是如果您想在PC上使用Python,您应该考虑使用IDE(或类似的工具)。图3-1显示了使用KomodoEdit编辑下一章中的Python示例的例子。虽然您看不到突出显示的彩色文本,但是请注意,编辑器提供了链接编号、用于编辑多个文件的选项卡等等。

图3-1。

KomodoEditExample

一些供应商,如Adafruit和GeorgeRoboticsLimited/micropython.org(pyboard的原始制造商)提供焊接和不焊接接头的电路板。不焊接接头节省了生产成本,在某些情况下还节省了运输成本,使电路板更便宜。如果你知道如何焊接(或者知道谁知道),你可以用不带接头的电路板来节省一点。

您可能需要不带接头的电路板的另一个原因是,如果您想将电路板安装在工程外壳或其他形式的嵌入式安装中。在这种情况下,焊接头部可能会占用更多的空间,或者使整个项目变得更大。

您还可能会遇到一些附加板、分线板或其他不与接头(或连接器)焊接的分立元件。如果您想使用这些,您可能需要自己焊接接头或连接器。例如,Adafruit(adafruit.com)和Sparkfun(sparkfun.com)的大多数分线板都没有焊接接头。

在上一章中,我们了解了一些通用输入输出(GPIO)引脚。各种板的区别之一是GPIO引脚的排列方式,甚至是引脚的数量。虽然大多数板支持一系列引脚,包括模拟和数字引脚,但有些板提供的引脚比其他板少。图3-2显示了WiPy上可用的GPIO引脚。您可以从主板制造商或供应商处找到类似的图纸(也称为数据手册、映射或引脚排列)。

图3-2。

WiPyGPIOPins(courtesyofpycom.io)

如果您的项目需要几个模拟或数字引脚,您应该计划选择一个能够支持所需引脚数量的电路板。幸运的是,大多数会;然而,一些可以加载MicroPython的较新的主板可能不能。例如,无处不在的ESP82663(一种低成本的WiFi芯片)的一些版本可能只支持几个引脚,这对于有许多组件的项目来说不太理想。

本节包括几个使用MicroPython板时可能遇到的问题的提示。把这些建议当作你在实验前或实验过程中应该做的事情。让我们从基础开始。

您应该做的第一件事(甚至在购买主板之前)是访问您选择的主板的社区论坛。许多供应商主持和管理一个在线消息论坛,供人们提出问题,社区中的人们提供他们的见解、答案、建议,甚至帮助那些陷入困境的人。

除了阅读这本书,访问社区论坛是绝对必要的。事实上,你应该考虑在任何时候对你的董事会有疑问或问题的时候访问论坛。你很可能会遇到一个人,他曾经遇到过同样的(或非常相似的)问题,以及他们(和其他人)对如何解决这个问题的建议。

下面列出了更流行的MicroPython板的论坛。如果你在这里没有看到你的公告板,下次你上网的时候谷歌一下;然后,如果你喜欢这个论坛,把它加入书签以便更快地访问。

我在第十二章中提供了更多与社区论坛互动的技巧。

您应该将MicroPython板视为一种非常敏感的设备,容易受到静电放电(ESD)的影响。除非您将您的主板放在箱子里,否则您应该小心处理您的主板,在通电之前,请始终将它放在不导电的表面上。ESD可能是由许多事情引起的(回想一下你小时候在地毯上穿着运动鞋的时候)。这种放电会损坏电路板。请务必处理好您的主板,以便控制ESD并将其降至最低。

图3-3显示了供应商装运的保护箱中的Pyboard示例。这种蛤壳式外壳仅比主板大一点点,当它在您的工具包底部发出嘎嘎声时,可以通过卡扣关闭,以确保主板的安全。

图3-3。

ThePyboardv1.1withHeadersinitsProtectiveCase

您也不应该在主板通电时移动它。为什么呢?MicroPython板上焊接有元件,两侧有许多裸露的引脚。如果任何两个或两个以上的引脚接触到导电的东西,您可能会损坏电路板。

此外,请务必将您的主板存放在ESD安全容器中——专门用于存放电子产品的容器。应该避免使用普通、日常、廉价的塑料盒。但是,如果您没有为电子产品制作的容器,您可以使用防静电袋来存放电路板。您购买的许多主板和组件都采用这种包装。所以,不要扔掉!

您应该注意确保您的身体、工作区和项目接地,以避免静电放电(ESD)。避免这种情况的最佳方法是使用接地带,环绕在手腕上,并连接到像这些uline.com/BL_7403/Anti-Static-Table-Mats的防静电垫上。

最后,将USB电缆连接到主板时要格外小心。大多数主板都配有微型USB连接器,这种连接器容易损坏(比其他连接器更容易损坏)。在大多数情况下,不是电缆坏了,而是电路板上的连接器坏了。发生这种情况时,可能很难修复(或者可能无法修复)。也有可能电缆本身会停止工作,或者只有当您将电缆固定到位时才能工作。如果发生这种情况,请尝试使用新的电缆,如果这样可以解决问题,请扔掉旧的电缆。如果不能解决问题,可能是主板上的连接器有问题。幸运的是,插拔电缆时格外小心可以避免这些问题。例如,始终首先插入微型USB端,然后使用全尺寸USB端插入和拔出您的PC。使用microUSB连接器的次数越少,损坏的几率就越小。

当人们第一次使用带有微型SD卡/驱动器的主板时,最常遇到的问题之一是操作系统无法识别板载USB驱动器。如果您的主板带有USB就绪驱动器(内置或外置),而您在文件浏览器(或finder)中看不到它,您可以做几件事情来解决这个问题。首先,如果主板有一个可移动的microSD驱动器,请确保它被正确插入并且被格式化为FAT。如果你提供了自己的微型SD卡,这通常是一个问题。把它重新格式化成FAT,应该就可以了。

另一方面,如果主板有一个可移动的microSD驱动器和一个板载驱动器,请取出microSD卡,然后再次尝试将主板连接到您的PC。有时,外部microSD卡优先于板载驱动器。

如果您的主板根本不显示,或者您通过USB连接到它有问题,有几种可能的原因。首先,确保你的USB线是供应商推荐的。如果你像我一样,已经积累了一个名副其实的USB电缆坑,很可能有一条或多条你“最喜欢”的电缆是充电电缆,而不是数据线。也就是说,电缆可以用来给设备充电,但用于传输数据的引脚(导线)缺失或未连接。先检查你的电缆。

下一种可能的情况是你的电脑没有安装正确的驱动程序。请务必查看供应商网站,了解您需要安装哪些驱动程序。有些需要特定操作系统的特殊驱动程序。例如,如果您使用Windows10,您将需要大多数主板的驱动程序。

另一个可能的问题是电路板需要外部电源。我在一些早期的原型板上见过这种情况,在某些情况下也在生产板上见过这种情况(但本章没有列出)。在这种情况下,您需要先打开主板电源,然后再将其连接到PC。

使用带有跳线(设计用于完成电路的小型塑料连接器)的电路板时,可能会出现一个或多个跳线丢失的情况。跳线用于启用或禁用某些功能。图3-4显示了WiPy扩展板上跳线的引脚排列示例。

图3-4。

JumpersontheWiPyExpansionBoard

跳线非常小,很容易丢失或放错地方。如果您丢失了跳线并需要更换,您通常可以从您所在地区的计算机维修店获得一些跳线。如果你所在的地区没有任何电脑维修店,如果你找到一个自己组装电脑的PC爱好者,你应该可以从他们那里获得几个跳线。为什么呢?因为这些人通常手头都有很多。当我管理一家电脑公司时,我不能放弃这些东西。我还有几百个在某个地方。底线是你不应该买它们——我敢肯定,你身边有人有一些备用的。

如果一个或多个跳线脱落,您可以拧紧它们,使它们更难移除。要拧紧跳线,使用一对尖嘴钳,并轻轻(我提到轻轻?)压缩母插座。做那件事有一点技巧。您也可以在引脚顶部轻轻向外弯曲跳线引脚,使跳线更加贴合。当然,如果它仍然太松或者你损坏了它,你可以找到那个电脑爱好者并得到一个新的。

有些板卡,比如WiPy扩展板,4有几个跳线,拆下来不影响操作。例如,如果你没有使用锂聚合物5电池,通过USB连接等。,那么如果移除一些跳线,您就可以使用未使用的跳线来代替丢失的跳线。

现在我们已经了解了开始使用MicroPython板的一些注意事项,让我们开始浏览可用的板,从那些已经加载并准备使用MicroPython的板开始。每个部分都包括对该板的简要概述,以及关于如何开始使用该板以及在哪里可以购买该板的说明。

我们将探讨的第一类主板是那些安装了MicroPython并随时可以使用的主板。这些主板不需要安装任何软件就可以使用(尽管您可能需要定期更新固件或在PC上安装驱动程序)。因此,对于那些刚接触MicroPython和电子产品的人来说,这些主板是最好的选择。然而,这并不意味着主板不强大——它们是强大的!事实上,本书中的项目是使用这些板演示的,您会发现它们对于大多数中小型IOT项目来说绰绰有余。

在撰写本文时,支持MicroPython的板是Pyboard和WiPy。两者都是不错的选择,但是正如我们将看到的,对于IOT项目来说,其中一个更容易使用。

PyboardMicroPython板是第一批用于托管MicroPython的板之一。在某些方面,它为MicroPython板应该如何配置和如何操作设定了标准。它由DamienGeorge创建,于2013年作为Kickstarter活动开始,旨在实现片上Python以在微控制器上运行。Pyboard及其附件板由乔治机器人有限公司(micropython.org)生产和销售。

该板最显著的特点是尺寸小。该板尺寸约为40毫米x40mm毫米,有两个分离式“耳”用于安装该板。没有耳朵,板子大约是32毫米乘40毫米。也就是说,如果你不想安装板,你可以打破耳朵,减少尺寸更大。电路板的三面都有放置接头的空间。一侧包含一个微型USB电缆连接器,用于连接到您的PC(或为主板供电)以及微型SD驱动器。图3-5显示了Pyboardv1.1的特写视图。

图3-5。

ThePyboardv1.1withoutHeaders(courtesyofadafruit.com)

注意棋盘左上角和右下角的小耳朵。这些都是穿孔的,便于拆卸。到目前为止,他们并没有碍事;因此,除非你有一个更小的,紧配合的情况下,你可以让他们重视。

你还可以在微型USB连接器附近的板上看到两个小按钮。一个是用户自定义按钮,您可以编程(USR),另一个是复位按钮(RST),用于复位电路板。主板的中心是ARM处理器芯片。

最后,在microSD卡插槽旁边的板上有四个led。这些是用来交流错误,通电,并可以打开或关闭你的代码!

现在,让我们了解更多关于硬件的知识,更具体地说,一些您可能不知道但可能方便知道的细节和规格。

当您使用插入了microSD卡的主板时(并且该卡被格式化为FAT),主板将使用该驱动器而不是内部驱动器进行引导,并且当您将Pyboard连接到PC时,它会显示出来。但是,您将看不到内部驱动器。这是许多人困惑的根源。如果您想使用内部驱动器进行引导,您必须在microSD上创建一个名为flash的文件夹,并在该文件夹中创建一个名为SKIPSD的空文件。这样做,然后断开并重新连接您的板。之后,您可以从您的脚本访问microSD卡。

回想一下引导驱动器是用来保存boot.py和main.py文件的;boot.py文件在启动时执行,一旦开发板运行,就会调用main.py。默认情况下,更改这些选项以添加您的自定义程序就是您让电路板引导到您的项目中的方式。

然而,这两个驱动器都可以从Python中访问,不管哪一个用于引导。内部驱动器在文件夹/flash下,microSD卡(当SKIPSDtrick发出时)在文件夹/sd下(分别使用0:/和1:/的旧版本板)。在Python代码中使用这些路径来访问正确的驱动器。

该板还支持其他引导模式,可通过USR按钮启动。要更改模式,请在插入(或打开)主板时按住USR按钮。按住按钮时,板上的led将按如下方式点亮。当电路板循环到您想要的模式时,释放USR按钮。

最后一种模式是非常有用的,如果你设法砖板。更具体地说,如果您的主板变得不可用或无法正确启动,请先尝试此模式,看看它是否能解决问题。

led的另一个用途是指示存在Python错误。如果红色和绿色指示灯闪烁,则表明从main.py调用的Python脚本中存在错误。如果所有指示灯都循环亮起,则表明可能存在硬件故障。尝试关闭主板电源并重置文件系统。如果那不起作用,你的板可能被损坏。

Pyboard由几个主要组件组成。我在这里列出它们是为了让那些有兴趣了解支持哪些功能的人知道。我从微控制器和内存规格开始。

如果您有兴趣了解其中一些器件的更多信息,以下是主要器件的附加数据和数据表链接。

如前所述,Pyboard有多种版本,包括焊接和不焊接接头的版本,以及速度稍慢、硬件功能较少的早期版本(1.0版)。我建议您的所有项目都使用1.1版的开发板。

What,NoInternet

Pyboard中可能缺少您期望找到的一个特性。没有联网功能。虽然最新的固件包括使用两个网络硬件(CC3000和WizNet5000)的规定,但您必须购买支持其中一个芯片组/库的模块(分线板)来将您的Pyboard连接到互联网(或您的本地网络)。有些人可能会发现在没有网络的情况下使用Pyboard对大多数项目来说是很好的,但是本书后面的项目将需要连接到网络。毕竟,这是一本IOT的书!因此,如果您打算构建一个IOT项目,您可能需要考虑一个不同的电路板,或者查看下一节中的网络示例,了解如何将Pyboard连接到您的网络。

如果您想使用外部电源或电池为主板供电,您必须确保电源设置为3.6-10V。连接更高的电源会损坏电路板。较低的功率会使电路板不稳定(可能无法正常运行)。您可以将电源(正极)连接到VIN,将接地(负极)连接到GND。图3-6显示了这些引脚位于微型USB连接器附近的特写。

图3-6。

Pinsforconnectingexternalpower(Pyboard)Tip

在拔下驱动器插头或重置主板之前,请始终弹出驱动器。

现在,让我们从连接到我们的PC并运行一个简单的Python程序的简单演练开始,来看看Pyboard的运行情况。

我们在第二章中讨论了REPL控制台,包括如何将主板连接到你的电脑。让我们再看一遍,这样我们就能确保理解它是如何工作的。要连接到主板,请使用USB转microUSB电缆,将一端连接到Pyboard,另一端连接到PC。过一会儿,您应该会看到一个名为PYBFLASH的驱动器被挂载(或者在Windows上,一个新的驱动器盘符出现在文件资源管理器树中)。

然后,您可以打开USB驱动器,通过在驱动器上编辑文件或将文件复制到驱动器来修改文件。例如,如果您想要修改main.py脚本以包含您自己的代码或加载您自己的脚本文件,您可以进行更改,然后弹出驱动器并重置板。一旦你这样做了,你添加的代码或者你设置调用的脚本将会在主板启动时触发。我们将在后面的章节中看到如何做到这一点。

你也可以像我们在第二章看到的那样启动REPL控制台。图3-7显示了连接到Pyboard的REPL控制台示例。在这种情况下,代码只是打印一条语句——现在已经是老生常谈的Hello,World!消息。

图3-7。

TheREPLConsole(Pyboard)

回想一下,我们讨论过定期加载固件的必要性。这适用于所有的主板,不管它们是否准备好了MicroPython。这是因为MicroPython的版本在不断完善,缺陷也在不断修复。因此,为了确保您拥有最新的更新,您应该在获得主板时至少更新一次固件,并且只在以后需要时更新,例如当您发现缺陷或向库中添加新的硬件组件时。在每块板上加载固件略有不同,但我们将从Pyboard开始详细介绍,然后在本章中提及其他板的不同之处。

在开始之前,您应该检查加载的固件版本。您可以使用以下Python语句来实现这一点。在这种情况下,代码在通过REPL控制台连接的Pyboard上运行。

>>>importos>>>os.uname()(sysname='pyboard',nodename='pyboard',release='1.9.1',version='v1.9.1-80-g3e82bedfon2017-06-27',machine='PYBv1.1withSTM32F405RG')这里我们看到固件版本是1.9.1,这是在撰写本文时可用的最新版本。它还显示固件加载的日期以及固件文件的名称。最后,我们还看到了板名。

图3-8。

ExcerptofFirmwareAvailableforthePyboard

注意,这些文件以文件扩展名.dfu命名,代表设备固件更新7——一种特殊的固件二进制格式。你应该下载最新版本的固件。一定要选择和你的板子相匹配的!例如,我选择了标题为适合PYBv1.1板的文件,其中包括CC30000和WIZ820io的网络驱动程序,因为我想将我的Pyboard与网络模块一起使用。您应该选择具有帮助节省空间(内存)所需的最小支持集的固件,但是,到目前为止,这还不是一个问题。

接下来你必须做的是将Pyboard设置为DFU模式。如图3-9所示,在DFU和3.3V引脚之间放置一根跳线即可。3.3V引脚标记在电路板边缘,DFU引脚就在它旁边(未标记,但位于第二行)。在将评估板连接到PC之前,请执行此操作。

图3-9。

DFUModeJumper(Pyboard)Note

首次在DFU模式下将主板连接到PC时,Windows10可能会安装驱动程序。如果驱动程序安装开始,请选择自动选项,并允许Windows搜索驱动程序。该过程完成后,您就可以加载固件了。

现在我们来看看如何使用Windows10更新固件。一旦你下载了你想加载的固件并安装了DFU编程器,你可以启动它,然后点击“更新或验证操作”部分的“选择”按钮(见下文),搜索你下载的文件,然后打开它。读取文件后,单击升级按钮开始更新。该过程将开始更新电路板,并显示如图3-10所示的完整信息。

图3-10。

DFUProgrammer(Windows10)

该过程完成后,单击“退出”关闭DFU编程器,断开主板与PC的连接,并移除跳线。主板现在将使用最新的固件启动。

本节将向您展示如何使您的Pyboard成为支持网络的设备。我们将简要介绍这一点,因为只有拥有Pyboard的用户才需要将这一步作为他们设置和入门的一部分,并且只有在我们使用互联网的示例项目中才会用到。

首先,你必须购买一个网络模块。这是困难的部分,因为迄今为止支持的唯一两个芯片组/库是用于WiFi的CC3000(CC3K)和用于以太网的WIZNET5000(WIZNET5K)。可悲的是,找到一个CC3K模块可能是一个挑战,因为制造它们的零售商已经更新到更新的芯片。

无论你买哪个,确保它有可用的分线针,这样你就可以把它连接到你的Pyboard。查找标记为MISO、MOSI、CLK/SCK、IRQ和VBAT_EN/VBEN的引脚。它们应该在模块上排成一行。即使它和我将要展示给你的不完全一样,它也应该可以工作。

确保您已经加载了具有网络支持的固件。标准固件不包括网络模块。

为了证明您确实可以将Pyboard连接到互联网(您可能会发现一些帖子认为这是不可能的),让我们重新利用Adafruit的CC3000Arduinoshield。是的,这意味着我们可以在没有Arduino的情况下使用Arduino盾!Arduino的许多屏蔽和模块可以与其他微处理器一起使用。您只需要知道如何将引脚连接到Pyboard。别担心,我会告诉你具体怎么做。图3-11显示未安装接头的屏蔽。

图3-11。

AdafruitCC3000ArduinoShield(courtesyofadafruit.com)

Adafruit是如此神奇的资源的原因之一是它们包括所有产品的数据表和操作指南。他们甚至维护停产产品的链接。在简要回顾了他们的文档后,需要将屏蔽和Pyboard一起使用的引脚在屏蔽上和文档中都有标注。

表3-1显示了两块板上的正确引脚。只需使用一根公母跳线将Pyboard上的引脚连接到CC3000屏蔽上的正确引脚。将公端连接到屏蔽上的引脚(通常会插入Arduino),母端连接到Pyboard引脚。你总共需要八根跳线。注意,其他模块可能具有类似的布置。引脚的标签与表中所示的相同,但编号可能不同,或者排列在专用接头中。

表3-1。

MappingPinsfromthePyboardtotheCC3000Shield

图3-12显示了所有连接的连接图,图3-13显示了完成后连接的样子。有点乱,但是很管用。请务必将屏蔽和电路板放在不导电的工作面上。

图3-13。

PyboardwithAdafruitCC3000ArduinoShield

图3-12。

ConnectingtheCC3000tothePyboardNote

如果你仔细检查CC3000屏蔽,你会看到有一个单独的头孔,如果你不想使用Arduino头可以使用。

如果您有Pyboard和CC3000shield,请继续进行连接。首先要确保你的Pyboard没有连接到你的电脑上。完成所有连接后,您就可以将Pyboard连接到PC了。

现在,让我们编写一些代码来测试模块,并将我们的Pyboard连接到互联网。由于这是一个WiFi盾,我们需要知道您的WiFi接入点(路由器)的名称和密码。我们需要使用的代码如清单3-1所示。

继续编辑代码以包含您的路由器和密码,然后以名称CC3K.py将其保存到您的PyboardUSB驱动器。接下来,用REPL控制台连接到您的Pyboard,然后发出以下命令。这将加载模块,然后运行代码并测试连接。

现在,让我们看看您可以在哪里购买我们自己的Pyboard。

您可以购买安装或不安装接头的Pyboard。旧版本的电路板可以以同样的方式购买,有一个版本没有加速度计,这使得它稍微便宜一些。不过我推荐买最新的,1.1版的板。

至于网络模块,最好的办法是等到更多的硬件支持被添加到MicroPython库(并上传固件)或者找到一个旧的AdafruitCC3000模块。查看网上拍卖网站,寻找仍在出售这些物品的卖家或有二手物品出售的人。8

WiPyMicroPython板是第一批支持MicroPython的板中的另一个。顾名思义,WiPy内置了充当主机的WiFi网络(想想路由器或接入点)。事实上,你使用WiPy的默认方式是通过WiFi。因此,您不必使用另一个模块来使您的项目互联网就绪。这个特性使得WiPy成为本书中项目的更好选择。作为奖励,该板还具有蓝牙,使其更容易适应您的项目。

该板最显著的特点是尺寸小。该板尺寸约为40毫米x40mm毫米,有两个。WiPy是一个比一包口香糖大不了多少的小模块,尺寸仅为42毫米x20mm毫米,厚度仅为3.5毫米(不含头部)。

该板有或没有接头(获得一个有接头或自己安装)。您可以在试验板上使用该板,也可以购买像dock一样工作的特殊板。Pycom将其称为扩展板,并提供了一个微型SD驱动器,微型USB连接器,led,复制所有的插头引脚,并包括一个电池连接器。扩展板使WiPy的使用变得相当容易,正如我们将看到的,使用它只有一个技巧。图3-14显示了Pycom的WiPy板。

图3-14。

PycomWiPy(courtesyofpycom.io)

扩展板允许您通过USB连接到WiPy,并使用LIPO电池或通过USB为板供电。我喜欢扩展板,因为它很方便。此外,它在每个角落都有孔,可以将其安装在竖板上,以便更容易地接触到引脚或将其永久安装在机箱或工具架上。它甚至有一个用户可访问的(可编程)按钮和LED。图3-15显示了Pycom扩展板。

图3-15。

PycomExpansionBoard(courtesyofpycom.io)Tip

WiPy的当前版本是2.0版。如果您购买了WiPy并想要扩展板,请确保您还购买了2.0版本的扩展板。

当然,扩展板要大得多,尺寸约为50毫米x65mm毫米,安装的WiPy厚度约为14毫米。仍然很小,但没有WiPy本身小。

微型SD驱动器和微型USB连接器是您在使用WiPy时可能需要的功能。扩展板的另一个特点是,LIPO电池连接器也是一个充电器,因此当您的板插入USB电源时,它可以为LIPO电池充电。

首先,扩展板上的microSD卡(WiPy没有SD驱动器)的工作方式与Pyboard不同。WiPy无法从microSD驱动器启动,但仍然可以存储您的文件并从您的程序中访问它们。我们将在下一节看到更多关于如何使用microSD驱动器的内容。

接下来我们要讨论的是引导模式。您可以像Pyboard一样更改引导模式,这在出现问题时很有帮助,但与Pyboard不同的是,引导模式与配置(固件)更改一起工作,而不是与板的引导方式一起工作。更具体地说,您可以将开发板设置为安全引导,这将跳过boot.py和main.py脚本。安全引导模式包括以下几种。

要激活和选择保存引导模式,请在P12引脚(GPIO20)和3.3V之间放置一根跳线。这将有效地“上拉”引脚,以便固件可以检测到选择。握住主板,使USB连接器位于顶部时,P12引脚是左侧最后一个引脚,3.3V引脚是右侧第三个引脚。图3-16显示了WiPy扩展板上正确安装的跳线。

图3-16。

JumperInstalledforSafeBootSelection(WiPyExpansionBoard)

当您打开主板电源时,LED将变为橙色并开始缓慢闪烁。如果您在3秒钟后将跳线留在原位,LED将开始快速闪烁,主板将使用最新的固件启动。如果您将跳线留在原位超过3秒钟,主板将使用之前的用户更新选择启动。最后,如果您将跳线留在原位3秒钟以上,LED将会更快地闪烁,表示主板将会以出厂设置启动。在此过程中的任何时候移除跳线,以选择所需的安全启动模式。

WiPy板支持WiFi和蓝牙通信机制,是IOT项目的绝佳选择。它采用EspressifESP32芯片组和双处理器。其他功能包括以下内容。

有趣的是,Pycom还制造了其他几种MicroPython板,您可以用它们来进行更高级的项目。每块主板都支持不同的通信机制(WiFi、无线电、蜂窝和蓝牙)和嵌入式解决方案的高级功能。它们都具有与WiPy相同的外形。其中包括以下电路板。有关更多信息,请参见产品描述页面。

最棒的是,Pycom扩展板可以与这些板一起工作。显然,Pycom的业务是向IOT世界提供一系列强大的微处理器——全部运行MicroPython!

如果您想使用外部电源或电池为主板供电,您必须确保电源设置为3.3-5V。连接更高的电源会损坏电路板。较低的功率会使电路板不稳定(程序可能会失败)。您可以将电源(正极)连接到VIN,将接地(负极)连接到GND。图3-17显示了这些引脚位于大LED附近的特写。

图3-17。

Pinsforconnectingexternalpower(WiPy-courtesyofpycom.io)

现在,让我们来看看WiPy的运行情况,从连接到我们的PC并运行一个简单的Python程序开始。

让我们再次从基础开始——REPL控制台。由于WiPy是一种WiFi设备,因此最简单的连接方式是通过WiFi。如果您使用的是扩展板,您只需要用连接到PC的USB电缆或USB电源给板通电。如果您使用不带扩展板的WiPy,您可以如上所示给板通电。

WiPy通电后,它将设置默认为192.168.4.XXX的WiFi网络,WiPy的IP地址为192.168.4.1。此过程可能需要几分钟,在此期间,WiPy上的LED将熄灭。当它开始闪烁蓝色时,您的WiPy网络已准备好连接。

连接到WiPyWiFi网络后,您可以使用telnet连接到REPL控制台,如下所示。

图3-18。

TheREPLConsole(WiPy)

如果使用扩展板,您还可以通过USB连接到WiPy。但是,您必须首先在WiPy上复制UART通信。这是一个常见的疏忽,有些人抱怨他们的WiPy不能通过USB连接。他们没有做到的是(除了阅读在线文档之外)在通过网络连接的WiPy上运行下面的代码。这个代码复制了扩展板上的UART,这样你就可以通过USB连接了。但是,如果您计划通过网络使用WiPy,则不需要这样做。

frommachineimportUARTimportosuart=UART(0,115200)os.dupterm(uart)Note

较新的WiPy板应该已经有这个代码。

如果您的WiPy在boot.py文件中没有这个代码,您应该考虑添加它。

如果您想将WiPy连接到WiFi网络,您需要对boot.py脚本进行一些小的更改。最简单的方法是从WiPy中复制它,修改它,然后将新版本复制到WiPy中。最好的方法是使用文件传输协议(ftp)。大多数操作系统都有ftp客户端,但是如果你的系统没有,你可以找到几个下载选项。使用用户micro和passwordpython进行连接。清单3-2展示了如何连接到WiPy并将boot.py文件复制到你的PC上。

$mkdirwipy_files$cdwipy_files/$ftp192.168.4.1Connectedto192.168.4.1.220MicropythonFTPServerName(192.168.4.1:cbell):microPassword:RemotesystemtypeisUNIX.Usingbinarymodetotransferfiles.ftp>cdflashftp>getboot.pylocal:boot.pyremote:boot.py227(192,168,4,1,7,232)1086.33KiB/s108bytesreceivedin00:00(6.23KiB/s)ftp>getmain.pylocal:main.pyremote:main.py227(192,168,4,1,7,232)342.53KiB/s34bytesreceivedin00:00(2.47KiB/s)ftp>quitMacBook-Pro:wipy_filescbell$lsboot.pymain.pyListing3-2.CopyingFilesFromtheWiPy注意,我在本地PC上创建了一个目录,然后用命令ftp192.168.4.1连接到WiPy。然后,我切换到闪存目录,用get命令复制文件。一旦我复制了文件,我就退出ftp应用,现在文件就在我的本地机器上了。

备份您的原始WiPy文件,以便在需要时可以恢复到出厂设置。

现在我们可以修改boot.py文件来连接到我们的本地网络。我们需要做的是使用网络模块中的WLAN类来配置它,以扫描网络并通过名称(SSID)和密码连接到您的WiFi网络。清单3-3显示了您需要添加到您的boot.py文件中的代码(新行以粗体显示)。在将代码保存到WiPy(以粗体显示)之前,请确保在代码中替换您的SSID和密码。

我建议等到您准备好运行您的IOT项目时再对您的boot.py文件进行这种更改。继续在默认模式下使用WiPy,直到你完善了你的项目。

#boot.py--runonboot-upfrommachineimportUARTfromnetworkimportWLANimportosuart=UART(0,115200)os.dupterm(uart)wlan=WLAN(mode=WLAN.STA)wlan.scan()wlan.connect(ssid='YourNetworkSSID',auth=(WLAN.WPA2,'YourNetworkPassword'))whilenotwlan.isconnected():passprint(wlan.ifconfig())#printsoutlocalIPListing3-3.EnablingWiFiConnectiononBoot(WiPy)注意复制UART的代码也包括在内。另外,请注意末尾的打印。在将文件保存到WiPy之前,您应该使用USB上的REPL控制台测试代码,并粘贴它以确保它能够工作。我们必须使用USB,因为WiFi会在执行过程中重置。下面显示了从REPL控制台运行代码的结果。

>>>fromnetworkimportWLAN>>>wlan=WLAN(mode=WLAN.STA)>>>wlan.scan()[(ssid='SSIDHERE1',bssid=b'\xc9\xd0\x18W\x11',sec=3,channel=1,rssi=-70),(ssid='SSIDHERE2',bssid=b'\x88\x1f\xa16X\x1c',sec=3,channel=6,rssi=-78),(ssid='SSIDHERE3',bssid=b'\xb8\x8d\x12bX\xd3',sec=3,channel=1,rssi=-90)]>>>wlan.connect(ssid="SSIDHERE1",auth=(WLAN.WPA2,"SSIDPASSWORD"))>>>whilenotwlan.isconnected():...pass>>>print(wlan.ifconfig())('10.0.1.128','255.255.255.0','10.0.1.1','10.0.1.1')注意,返回的IP地址(print语句中的第一个)是10.0.1.128。现在,您可以使用telnet连接到您的WiPy,如下所示。

$telnet10.0.1.128Trying10.0.1.128...Connectedto10.0.1.128.Escapecharacteris'^]'.MicroPythonv1.8.6-689-g095792e0on2017-06-27;WiPywithESP32Loginas:microPassword:Loginsucceeded!Type"help()"formoreinformation.一旦您对它的工作感到满意(您有正确的SSID和密码),您就可以进行更改,并将文件复制到您的WiPy中,如清单3-4所示。

$ftp192.168.4.1Connectedto192.168.4.1.220MicropythonFTPServerName(192.168.4.1:cbell):microPassword:RemotesystemtypeisUNIX.Usingbinarymodetotransferfiles.ftp>cdflashftp>putboot.pylocal:boot.pyremote:boot.py227(192,168,4,1,7,232)100%|***********************************|3361.84MiB/s00:00ETA336bytessentin00:00(0.86KiB/s)ftp>quitListing3-4.CopyingFilesTotheWiPy现在你可以重启你的WiPy,等待蓝色LED闪烁;那你应该能在你的WiFi网络上看到。酷吧。

与Pyboard一样,WiPy在与扩展板配合使用时,也有一个微型SD驱动器。您可以使用SD卡来存储数据、脚本等。然而,与Pyboard不同的是,SD驱动器在主板启动时并不使用(您不能从它启动),当通过USB电缆连接到您的PC时也不可安装。

您的电脑上既没有安装内置驱动器,也没有安装SD卡(如果连接到扩展卡,并且插入了一张FAT格式的卡)。您必须使用文件传输协议(FTP)应用来访问您的文件,就像我们在上一节中看到的那样。但是,您可以通过REPL控制台安装SD卡。如果您总是想要访问SD驱动器,可以将此代码添加到闪存驱动器上的boot.py文件中。

我们需要做的是运行一些MicroPython代码来启用SD卡并挂载它。以下显示了如何安装SD卡。

frommachineimportSDtry:sd=SD()os.mount(sd,'/sd')print('Cardmountedat/sd')except:sd=Noneprint('ERROR:Cardnotmounted.')现在,当您访问您的文件时,您会看到SD卡。

如果你打算用WiPy,一定要买扩展板。这是非常值得的。

您只需为您的平台下载升级工具,安装它,然后运行应用。例如,在macOS上,你可以点击链接,下载工具,打开存档,并安装它。

像Pyboard一样,您也必须跳线其中一个引脚。在这种情况下,我们将通过将跳线连接到GND来拉低引脚G23。握住主板,使USB连接器位于顶部时,G23引脚是左上第四个引脚,GND引脚是右上第二个引脚。图3-19显示了WiPy扩展板上正确安装的跳线。

图3-19。

JumperInstalledforFirmwareUpgradeTool(WiPyExpansionBoard)

现在,让我们简单看看Pycom固件升级工具是如何在macOS上运行的。该对话框有四个主要面板:欢迎、设置、通信和结果。您可以单击“继续”按钮前进到每个面板。在设置面板上,会提醒您需要进行的连接以及如何设置跳线。在通信面板上,选择WiPy连接的通信(USB)端口。升级完成后,结果面板会告诉您何时可以断开板的连接。图3-20按顺序显示对话框,从左上顺时针方向。

图3-20。

UpgradingtheFirmware(WiPy)

还有一点是WiPy(和所有Pycom板)所独有的。Pycom还为一些流行的编辑器提供了一个特殊的编辑器插件,允许你在WiPy上连接和处理你的文件。该插件名为PyMakr,目前可用于Atom编辑器(但很快将可用于其他编辑器)。Pycom还为您的移动设备提供了一个名为PyMate的应用,允许您在移动设备上与WiPy进行交互。

PyMakr插件是WiPy体验的一个很好的补充。该插件是Pycom最初发布的原始PyMakr编辑器的替代品,但他们意识到开发一个新的编辑器不如开发一个允许用户使用他们现有的喜爱的编辑器的插件有效率。

该插件允许您在编辑器中打开REPL控制台,移动(同步)文件,打开Python脚本并运行它们,配置控制台以连接到其他网络上的WiPy(设置),并获取有关WiPy的信息,如固件版本、SSID等。图3-21显示了一个在Atom编辑器中运行的插件的例子。

图3-21。

PyMakrPlugin(Atom)

用于移动设备的PyMate应用还允许您与您的WiPy进行交互,类似于使用WiPy的PyMakr插件,但它可以提供一些小部件,您可以使用这些小部件从您的WiPy中读取数据并显示数据。小部件可用于在移动设备上显示脚本中的数据。小部件包括线形图和条形图、控制led的按钮等等。

PyMate的设置需要从苹果或谷歌应用商店下载,并在您的移动设备上进行配置。它还需要向Pycom注册应用。设置WiPy需要首先连接到您的WiFi(或蜂窝)网络以下载正确的文件,然后选择您的设备,最后连接到WiPyWiFi以上传文件。该过程会修改boot.py文件,所以一定要先备份该文件。如果您遇到问题或者无法再访问您的WiPy,您可以引导到一个安全引导模式,并将原始boot.py文件复制到WiPy(或者编辑PyMate为您创建的文件)。一旦在PyMate中设置好设备,就可以连接到它并执行脚本,配置想要与之交互的小部件。

PyMate应用目前非常新,关于如何使用它的文档非常少。出于这个原因,您可能想等到完成本书中的项目后再使用PyMate应用。这主要是由于对boot.py文件的修改,但也因为您必须首先学习如何使用MicroPython访问硬件,这样您才能使用小部件。图3-22显示了PyMate应用。

图3-22。

PyMateApplication(courtesyofpycom.io)

如果您已经决定购买WiPy(和扩展板),我鼓励您查看这些应用。

DeepSleepIssueResolved

Pycom最近宣布了他们的主板关于深度睡眠模式的一个小问题,深度睡眠模式是一种您可以通过编程将主板置于低功耗模式并稍后唤醒的状态。使用深度睡眠模式可以让主板省电,对于使用太阳能或电池供电的项目尤其方便。该问题被发现是一个硬件问题,Pycom正在构建一个特殊的附加板(称为shield),您可以使用它来纠正旧主板的深度睡眠问题。请访问pycom.io了解深度睡眠盾的最新信息。本书中的项目不需要深度睡眠模式,但是你自己的IOT项目可能需要。

您可以购买带或不带接头的电路板。为了在本书中使用,最好安装标题。这允许您将电路板插入试验板。

下一组要探索的硬件是那些没有配备MicroPython的主板,但可以加载MicroPython固件或使用特殊软件执行MicroPython。

这里涉及的板是广受欢迎的BBCmicro:bit板,它在学校的使用趋势越来越明显,来自Adafruit的最新电路板称为CircuitPlaygroundExpress,以及AdafruitFeatherHuzzah。这些板是按照让MicroPython在板上工作所需的复杂程度排列的。

BBCmicro:bit板是专门设计的,非常容易使用。事实上,它旨在帮助教孩子更多关于硬件和软件的知识。在这一点上,BBCmicro:bit是一个巨大的成功。这一成功的部分原因在于该板的易用性——它的外形尺寸只有大约52毫米x42mm毫米,两侧都有元件。

一侧是可编程led阵列和两个按钮。另一侧是包括处理器、微型USB连接器、复位按钮和电池连接器在内的组件。该板的GPIO接头沿底部边缘排列,也是双面的。一组大孔引脚(称为鳄鱼引脚)均匀分布,允许接地、电源(3V)和(3)GPIO引脚。这使得使用带有边缘连接器的板变得简单。图3-23显示了BBCmicro:bit板的正面和背面。

图3-23。

TheBBCmicro:bitBoard(frontandback)

BBCmicro:bit没有联网功能,但有蓝牙,可以用来连接另一台设备,将数据转发到互联网上。因此,它可以用于IOT项目,但不像带有WiFi模块的WiPy或Pyboard那么容易,可能需要一个中间节点,如PC或小型计算机,如RaspberryPi甚至Arduino。

以下列出了BBCmicro:bit板的一些硬件特性的概述。当主板通过USB电缆连接到PC时,您也可以访问板载USB驱动器。

现在我们已经对硬件有了一个简单的了解,让我们看看如何将开发板与MicroPython一起使用。

BBCmicro:bit板是与MicroPython一起使用的最简单的替代板。这要归功于两个软件应用——一个名为Mu的桌面应用,一个名为uFlash的命令行工具。Mu是一个完整的编辑器,你可以在你的PC上使用,当通过USB电缆连接到你的BBCmicro:bit时,可以保存和执行脚本。uFlash工具可用于手动将Python脚本传输到电路板。这两个选项都可以在Windows、macOS和Linux上使用。图3-24显示了一个使用Mu编写一个简短的MicroPython脚本来使用led滚动消息的例子。

图3-24。

TheMuEditorforMicroPythonontheBBCmicro:bit

与我们必须首先安装固件才能使用MicroPython的其他主板不同,BBCmicro:bit可以使用这些工具之一来运行MicroPython脚本。例如,我们可以使用Mu编写我们的MicroPython脚本,然后用该脚本的编译版本(称为十六进制文件)来“刷新”BBCmicro:bit板。是的,这意味着你可以写你的脚本,编译它,并直接闪存(加载十六进制文件)到主板上!我们只需在编辑器中编写代码,然后点击Flash将其加载到板上。最棒的是,该板被编程为每次启动时总是运行脚本。因此,这意味着我们可以直接将自己的代码加载到电路板上,而无需额外的工作。酷。

您仍然可以通过单击REPL按钮,通过管理部门应用使用REPL控制台访问电路板。图3-25显示了在Windows10上运行于Mu的BBCmicro:bit的REPL控制台。

图3-25。

REPLConsoleviaMuonWindows10(BBCmicro:bit)Tip

下一个最容易使用的替代板是Adafruit的CircuitPlaygroundExpress板。实际上,CircuitPlaygroundExpress(开发者版)是一个奇怪的替代板。它的模式是在其他几个Adafruit可穿戴板的基础上设计的,这样它就可以融入到衣服中。9因此,它是圆形的,直径约50毫米。

当前的主板附加了开发人员版的名称,因为它仍处于早期版本。我怀疑将来会有更完整的生产形式的板。

图3-26。

CircuitPlaygroundExpress,DeveloperEdition(courtesyofadafruit.com)

下面列出了CircuitPlaygroundExpress板的一些硬件功能的概述。当主板通过USB电缆连接到PC时,您也可以访问板载USB驱动器。

还有Adafruit的CircuitPlayground经典板。不要把它和游乐场快车混淆。这些板是不一样的;只有Expressboard可以运行MicroPython。

然而,与Pyboard一样,CircuitPlaygroundExpress(开发者版)不具备任何联网功能。因此,您必须使用外部模块连接到您的网络。我发现最好的选择是蓝牙模块,但其他模块如CC3000可能是替代品。

该板也不运行MicroPython。相反,它运行一个名为CircuitPython的特殊版本的MicroPython。CircuitPython是由Adafruit设计和维护的MicroPython的衍生产品,专为CircuitPlaygroundExpress和许多其他电路板而构建。CircuitPython被设计成可以在多种电路板上运行,包括CircuitPlaygroundExpress、Feather和其他流行的电路板。CircuitPython目前与MicroPython版本1.8.4兼容,但会定期更新。

虽然CircuitPlaygroundExpress板没有像BBCmicro:bit那样的花哨应用,但一旦安装了正确的驱动程序,在板上加载CircuitPython二进制文件(固件)就出奇地容易。事实上,你需要做的就是下载当前的二进制文件,并将其复制到主板的驱动器上。所涉及的步骤总结如下。

图3-27。

AdafruitBoardsDriver–InstallationOptions

当你进入那个页面时,你会发现每个板都有两个选项:一个.bin文件和一个.uf2文件。.bin文件与一个名为bossac、11的命令行工具一起使用,但是我们不会使用那个工具,因为UF2格式更容易使用。

现在,您可以将CircuitPlaygroundExpress连接到您的电脑。当u盘挂载(应该命名为CIRCUITPY)时,将旧的名为CURRENT.UF2的UF2文件复制到你的PC上。我们将用它作为备份。接下来,将新的UF2拖到CIRCUITPY文件夹中。文件复制完成后,电路板将重启并运行CircuitPython。就这样!您刚刚加载了CircuitPython!看,这比其他任何一块板都容易,是吧?

您必须保存原始的UF2文件,以便可以反向安装Python。

您现在应该看到驱动器返回,但没有UF2文件。例如,我的板只显示了一个名为boot_out.txt的文件。现在,您可以使用screen或Windows上的PUTTY连接到您的板。但是首先,检查一下主板使用的是哪个COM端口。图3-28显示了在Windows上使用PUTTY运行REPL控制台。

图3-28。

REPLConsoleonWindows(CircuitPlaygroundExpress)

幸运的是,将电路板恢复到默认配置也很容易。您可以通过单击两次重置按钮将主板置于引导加载程序模式来完成此操作。当处于引导模式时,led将变为红色,在此期间,您可以复制我们保存的名为CURRENT的原始文件。UF2到弹出的驱动器(名为CIRCUITPY)。复制完成后,主板将重新启动并运行原始固件。

如果您决定尝试CircuitPlaygroundExpress板,我建议您购买一些鳄鱼夹,这样您就可以将该板与试验板一起使用,或者将其连接到其他组件。请访问Adafruit商店,了解更多将电路板连接到您的组件的想法和附件。

adafruitFeatherhuzzahw/ESP8266WiFi是另一个非常受欢迎的板,但在它上面加载MicroPython仅限于使用命令行工具,在Windows上使用有点奇怪。因此,我认为这是最难使用的MicroPython兼容板。幸运的是,它确实使用了MicroPython,而不是CircuitPlaygroundExpress这样的CircuitPython。

事实上,该板具有许多特性,使其成为MicroPythonIOT项目的绝佳替代板。其中最主要的是它有网络,在WiFi网络上工作得很好,与WiPy不相上下。

该板如此受欢迎的原因之一是因为它基于ESP826612WiFi微控制器,时钟频率为80MHz,并在一个小巧轻便的封装中结合了丰富的功能(因此得名羽毛)。该板也非常小,大约是一包口香糖的大小,尺寸为51毫米x23mm毫米x8毫米,适合放在试验板上,这也使它成为一种优秀的原型制作工具。该板有两行GPIO接口,包括通信(RX、TX)、I2C和SPI协议。图3-29为阿达果羽毛Huzzah板。

图3-29。

AdafruitFeatherHuzzah(courtesyofadafruit.com)

在FeatherHuzzah(或任何ESP8266板)上使用MicroPython的过程需要确保您加载了正确的驱动程序,使用基于Python的串行bootloader实用程序分两步进行,首先擦除闪存,然后写入新的固件。

FeatherHuzzah的一个优点是,它支持在固件上传之前进入引导模式。当我们试图访问引导程序时,该功能会自动检测并将其置于正确的模式。酷!

在其他ESP8266板上加载MicroPython可能需要将板设置为bootloader模式。查看您的文档了解如何做到这一点。

一旦安装了驱动程序,打开控制台(终端)并切换到解压esptool.py实用程序的目录,并且您的主板通过USB电缆连接到您的PC,我们就可以开始使用esptool.py脚本和erase_flash命令擦除主板上的闪存驱动器,如清单3-5所示。

$python./esptool.py--port/dev/tty.SLAB_USBtoUARTerase_flashesptool.pyv2.0.1Connecting........_Detectingchiptype...ESP8266ChipisESP8266Uploadingstub...Runningstub...Stubrunning...Erasingflash(thismaytakeawhile)...Chiperasecompletedsuccessfullyin8.8sHardresetting...Listing3-5.ErasingFirmware(FeatherHuzzah)这个过程只需要几分钟。完成后,我们可以使用清单3-6中所示的esptool.py脚本和write_flash命令上传固件。

图3-30。

REPLConsole(FeatherHuzzah)

我应该指出,我遇到了一些与最新固件的小通信问题,所以在该版本中可能会有一些不稳定。确保使用最新的固件以避免问题。

WhatAboutOtherESP8266Boards

现在,让我们简要讨论一下您可以使用的其他一些电路板。正如你可能会怀疑的,这种类型的板是最难使用的,并不适合所有人。

随着MicroPython越来越受欢迎,您可能会看到更多可用的板。事实上,目前正在努力使MicroPython在几个主板上可用,包括Teensy、Arduino和ESP8266(Espressif)芯片组主板的几个变量。有一些早期的,有限的版本可用,如Teensy3。x版本的板,可以用MicroPython加载,但是这个过程需要交叉编译的经验,因此不适合初学者(但是欢迎您尝试!).十三

然而,请记住,第三方板可能在功能上有些滞后,文档通常最多是不完整的。但是现在您已经阅读了关于生产板的内容,您应该已经掌握了使用新板所需的知识。

我们也开始看到Pyboard的几种变体出现。到目前为止,我已经看到了另外两个来自亚洲的板子,看起来像是Pyboard的克隆版。我试用过其中一个克隆板,虽然GPIO引脚布局不同,但它的行为与Pyboard完全一样。如果您发现您想要在一个大型项目或一个多次完成的项目中使用多个电路板(如在教学环境中),您可能需要考虑克隆电路板,因为它们可以节省大量成本。

现在我们已经看到了一些可用的MicroPython板,让我们深入了解一下您可以用来构建项目的附件。

我们将探讨的最后一点硬件是那些可与MicroPython板一起使用的板。这些可以是特殊的、独立的模块(称为分线板),以及专门设计用于MicroPython板的板(取决于板,称为屏蔽板或面板)。以下部分简要描述了一些分线板、屏蔽/外壳和一些附件,您可以根据选择的板来考虑这些附件。这个清单既不全面,也不是你必须买的东西的清单。在讨论完MicroPython之后,我们将在每个示例章节中看到推荐的硬件。

要在我们的项目中使用分线板,我们只需要知道使用哪个接口以及如何连接。幸运的是,大多数供应商都会提供数据手册和其它文档来帮助您连接电路板。即使供应商只有Arduino的文档,学习如何进行连接仍然是有帮助的。诀窍是学习如何编写MicroPython代码。我们将在第5和6章中了解更多关于MicroPython库和硬件支持的信息。现在,让我们探索一些可用的分线板。同样,这里显示的只是一个非常小的样本。

回想一下前面的讨论,有用于提供网络连接的分线板。此外,回想一下,MicroPython目前支持使用CC3KWiFi芯片组的分线板以及使用WIZNET5K以太网芯片组的分线板。我们之前看到了一种使用ArduinoCC3K屏蔽的有趣方法,但图3-31显示的是AdafruitCC3000WiFi分线板。我给你看这个有两个原因:首先,你可以看到它比Arduino盾小得多;第二,您可以看到一排引脚(目前没有接头)。请注意,这里只有几个引脚(如果不是通过阅读文档,而是根据经验),我们可以看到它支持与屏蔽层相同的SPI协议/接口。14就像重新利用的Arduinoshield一样,我们可以使用这个分线板为不具备该功能的MicroPython板添加网络。

图3-31。

AdafruitCC3000Module(courtesyofadafruit.com)

图3-32。

WeatherBreakoutBoards(courtesyofadafruit.comandsparkfun.com)

下一个分线板本身通常被认为是一个传感器,因为它只执行一个功能,但它仍然是一个分线板。许多传感器以这种方式封装,当它们是分线板时,通常被称为传感器。幸运的是,如果你用错了术语,大多数人会明白你的意思。您可以通过安装传感器的电路板是否包含其他分立元件和一排接头引脚来判断它是否是分线板。

图3-33。

SoilMoistureSensor(courtesyofsparkfun.com)

注意板子的独特形状。两臂或长叉是测量湿度的传感器设备的一部分。请注意,顶部是一组引脚(未安装接头),用于连接您的主板。此分线板不使用特殊接口;相反,传感器产生的电压可以在MicroPython板上的一个模拟引脚上测量。事实上,我们只需要三条线:5V,GND,和信号(连接到我们板上的模拟引脚)。同样,我们将在后面的章节中看到如何使用这个分线板。

图3-34。

BBCmicro:bitEdgeBreakoutBoard(courtesyofsparkfun.com)

MicroPython板供应商,实际上是各种微控制器和类似板的供应商,封装他们的组件,以便他们可以用于称为shields或skins或类似东西的附加板。例如,Beaglebone附加板称为capes,RaspberryPi附加板称为hats。这些板具有匹配的头部,用于插入(或堆叠在)主MicroPython板上以增加功能。许多屏蔽或外壳都有直通或堆叠接头,允许一次添加多个屏蔽。例如,Arduino及其屏蔽格式可以配置为添加两个、三个或更多屏蔽。

在本节中,我们将看到一些可用于Pyboard和WiPyMicroPython板的附加板。如果您决定在本书中的项目中使用另一种板,请向供应商或零售商了解附加板的可用性。因为有几块板相对较新,所以你应该每隔几周左右检查一下,看看是否有新的板被添加进来。

第一个皮肤是一个原型板,允许您在皮肤上构建一个电路,以便您可以将其与Pyboard一起使用。它带有一套完整的标题。我喜欢它,因为虽然它比Pyboard略大,但有足够的空间,如果你想组装一个电路,你可以。此外,它允许您删除皮肤,以便您可以在其他项目中使用您的Pyboard。图3-35显示了来自micropython.org的原型皮肤通孔XY尺寸皮肤

图3-35。

PyboardProtoskinThrough-holeXY-Size

下一个皮肤是一个奇怪而有趣的功能,它为Pyboard添加了音频。它被简单地称为音频皮肤,允许你播放和录制短声音,以及播放某些波形(声音)。我展示这本书是为了激起你对本书以外的项目的兴趣。图3-36显示了来自micropython.org的音频皮肤。

图3-36。

PyboardAudioSkin

下一个皮肤是另一个非常有趣的特性,它允许你以触摸LCD的形式给你的Pyboard添加一个视觉元素。具有电阻式触摸和头部的彩色LCD皮肤增加了使用160x128像素图形LCD显示器和背光以及覆盖整个屏幕的电阻式触摸传感器来添加交互界面的能力。这意味着您可以为您的MicroPython项目构建小型图形界面。酷!图3-37显示了带有电阻式触摸的彩色LCD面板的正面和背面以及来自micropython.org的headers面板。幸运的是,你可以购买这种皮肤作为一个完整的组装套件。

图3-37。

PyboardLCDSkin

图3-38。

PySenseShield(courtesyofpycom.io)

该盾牌的功能列表令人印象深刻,包括以下内容(由pycom.io提供)。显然,这里有很多你可以利用的东西,所以如果你正在考虑使用WiPy,这个盾和下一个盾可能会打破平衡。事实上,我将在后面的章节中向您展示如何使用这个屏蔽来读取天气数据。

图3-39。

PyTrackShield(courtesyofpycom.io)

该盾牌的功能列表令人印象深刻,包括以下内容(由pycom.io提供)。很明显,这里有很多你可以利用的东西,所以如果你考虑使用WiPy,这个盾和之前的盾可能会扭转局势。

我们将讨论的最后一类硬件是本章中讨论的几种主板可用的附件。就像生活中的几乎所有事情一样,我们可以为我们的电路板添加配件,以达到深远(且昂贵)的目的。虽然MicroPython主板可用的附件列表还没有达到RaspberryPi或Arduino的书呆子比例,但仍有一些附件是您应该考虑的。

在这一节中,我将介绍Pyboard、WiPy和BBCmicro:bit的一些我认为必不可少的附件。这并不意味着你应该冲出去买,或者这本书需要它们;相反,我认为如果你打算在完成本书中的例子后继续用这些板进行开发,你应该考虑它们。

例如,我觉得每个项目都应该放在一个盒子里,这样电路板和任何其他元件都不会受到意外触摸、跌落和其他可能损坏电子设备的事件的影响。如果您计划将电路板安装在某个地方进行长期操作,这一点尤其正确。因此,我为每块板列出一个案例。

除了USB线和皮肤等必需品之外,Pyboard没有太多附件。但我发现有一件配饰是Pyboard不可或缺的——来自micropython.org的盒子。

你可以从micropython.org购买一个铝制外壳,这是我见过的最好的外壳之一。其他主板上也有一些类似的,但是它们的价格通常都过高。那根本不适用于这个例子。这款保护套有三种型号:一种是打开的盖子,可以接触到接头;另一种是关闭的盖子,可以安装触摸屏。它们都与带耳板相适应,因此使用这种情况时,您无需将它们折断。图3-40显示了打开盖子的纸板盒。

图3-40。

PyBoardCase

我对这个案子的质量怎么说都不为过。这简直是我见过的最好的。打开和关闭的盖子上有文字,标记了割台上的所有针脚。这个案子你不会失望的。它有点贵,大约35美元,但物有所值。他们经常缺货,所以经常检查新订单。

WiPy的配件清单正在增加。你可以买到USB线等日常必需品,但Pycom也出售天线和各种各样的外壳等物品。

WiPy的外壳有不同的颜色和形状。有尺寸适合WiPy和shield的轻型外壳,也有密封用于户外的外壳,包括一个足以容纳WiPy、shield和LIPO电池的外壳。图3-41显示了用于WiPy的烟色外壳,其可以容纳WiPy和护罩。

图3-41。

WiPyCase(courtesyofpycom.io)

接下来是一个电池盒,带有正确的连接器,可连接到您的主板上。您可以得到一个电池盒,其中包含用于正确电压的正确数量的电池(首先检查您的主板规格)以及带有正确连接器的电池盒。我选择购买一个通用的外壳,可以容纳四节1.5VAA电池,并自己添加了正确的连接器。图3-42显示了我在项目中经常使用的电池盒。我已经在WiPy部分列出了电池盒,但它也可以用于其他板,如BBCmicro:bit。

图3-42。

BatteryCaseCaution

请确保您的电池盒包含适合您的主板的大小和额定功率。

拥有最令人印象深刻的附件列表的板是BBCmicro:bit。我确信这是由于它的流行,但它也有利于我们的努力。您可以找到用于建造机器人、电源配件、箱子等的工具包!

图3-43。

MI:powerBoardfortheBBCmicro:bit

如果你决定使用这种电池板,我强烈推荐它超过外部电池——特别是对于BBCmicro:bit,并且你决定使用外壳,你应该知道大多数外壳不是为支持MI:power板而设计的。然而,我确实找到了至少一个。正如你所猜测的,它是由制造MI:power的同一批人制造的!

BBCmicro:bit提供了许多案例,似乎每天都有另一个案例出现(包括那些可以在3D打印机上打印的案例)。然而,我发现我喜欢的那个和我在其他板上用过的一样。它由丙烯酸制成,使用尼龙螺栓将几层连接在一起。这是一个干净的组件,可以清晰地看到电路板,考虑到BBCmicro:bit有很多led,这很好!图3-44显示了BBCmicro:bit的MI:pro案例。

图3-44。

BBCmicro:bitMI:proCaseKit

图3-45。

PrototypingSystemfortheBBCmicro:bit(courtesyofkitronik.uk.co)

现在,让我们简单地讨论一下,在IOT之旅中,您应该为您的MicroPython购买哪种主板。

所以,你想买一个MicroPython板但是不知道选哪个。幸运的是,本章中的所有电路板都是理想的选择。可能使某些人比其他人更适合某些人的特征包括以下几点。

显然,选择购买哪种主板需要事先考虑。话说回来,如果你是一个真正的发烧友,你可能会决定买几块这样的板,17自己试验一下哪一块最适合你的项目。不管怎样,我觉得最适合IOT学习MicroPython的是那些有网络的板,比如WiPy和FeatherHuzzah。然而,Pyboard和BBCmicro:bit板也是学习MicroPython的很好的板,但是需要一个外部模块来添加网络功能。

ConsiderBuyingaKit

许多主板都附带一个套件,其中包含各种附件,包括一个包含主板和电源适配器的入门套件。其他套件可能包括试验板,通常还有传感器或附加板。例如,您可以为BBCmicro:bit板购买几个套件,包括Sparkfun的两个不错的选项。

其他供应商可能有针对其他主板的附加或类似套件。例如,Kitronik为BBCmicro:bit提供了一个优秀的发明家工具包(如下所示,由kitronik.co.uk提供),里面有许多你需要的部件。

如果您刚刚开始,没有任何主板或组件,入门套件可能是最经济的选择。

哇,信息量真大。如您所见,有几种MicroPython板可用。有些工具,比如Pyboard和WiPy,可以直接使用,除了插入它并编写您的第一个Python程序之外,不需要任何东西。其他人可能要求您首先加载MicroPython,其他人仍然需要一点魔法来使它们工作。然而,这里介绍的所有电路板都是本书实验中使用的绝佳选择。

在本章中,我们探索了一些使用MicroPython板的最佳实践和技巧。我们讨论了可能出错的常见问题,以及在哪里寻找您可能遇到的其他问题的解决方案。最后,我们看了几个流行的插件和分线板,您可以使用它们来开发您的项目,包括本书后面使用的那些。

在下一章,我们将深入学习使用Python和MicroPython的编程教程。这一章在很大程度上是一个闪电之旅,旨在帮助指导你能够写出(并理解)本书中的例子。

版本号可能不会改变,但日期或内部版本号可能会经常改变。

的确是最普遍的芯片!

13

14

注意MOSI和MISO引脚,这是一个SPI接口。

15

注意SDA和SLA引脚,这是一个I2C接口。

16

只是一个名字。每个人都试图成为独一无二的,但我仍然称它们为盾牌——这是我修补Arduino时养成的习惯。

17

是的,我拥有这里列出的董事会(一些多重),以及一个不断增长的,不要脸的其他董事会。

现在我们已经对各种MicroPython板有了基本的了解,我们可以学习更多关于MicroPython编程的知识——这是一种非常健壮和强大的语言,可以用来编写非常强大的应用。掌握MicroPython非常容易,有些人可能认为使用它不需要任何正式的培训。这在很大程度上是正确的,因此您应该只需要一点点语言知识就能够编写MicroPython脚本。

鉴于MicroPython是Python,我们可以先通过我们PC上的例子来学习Python语言的基础。因此,本章介绍了Python编程基础的速成课程,包括对一些最常用语言特性的解释。因此,本章将为您提供理解互联网上的PythonIOT项目示例所需的技能。本章还通过可以在PC或MicroPython板上运行的例子演示了如何用Python编程。所以,让我们开始吧!

在本章中,我使用术语Python来描述同时适用于MicroPython和Python的编程概念。MicroPython特有的概念使用术语MicroPython。

现在让我们学习一些Python编程的基本概念。我们将从语言的构件开始,比如变量、模块和基本语句,然后进入更复杂的流控制和数据结构的概念。虽然这些材料看起来很仓促,但是本Python教程只涵盖了该语言最基本的知识,以及如何在PC和MicroPython板上使用它。它旨在帮助您开始编写PythonIOT应用。

如果你知道Python编程的基础,请随意浏览这一章。但是,我建议您完成本章末尾的示例项目,尤其是如果您没有编写过很多Python应用的话。

下面几节介绍了Python编程的许多基本特性,您需要了解这些特性才能理解本书中的示例项目。

Python是一种高级的、解释性的、面向对象的脚本语言。Python的最大目标之一是拥有一个清晰、易于理解的语法,读起来尽可能接近英语。也就是说,即使你没有学过Python语言,你也应该能够阅读和理解Python脚本。Python也比其他语言有更少的标点符号(特殊符号)和更少的语法机制。下面列出了Python的一些关键特性。

Python可以在你可能遇到或使用的几乎所有平台上下载(python.org/downloads)——甚至是Windows!Python是一种非常容易学习的语言,它的结构非常少,甚至有点难学。与其抛出一个示例应用,不如让我们以类似Python的方式来学习Python的基础知识:一步一步来。

如果你没有MicroPython板,也没有在你的PC上安装Python,你应该现在就安装,这样你就可以运行本章中的例子。

你应该学习的第一件事是Python不像其他语言那样使用用符号划分的代码块。更具体地说,对于诸如函数、条件或循环之类的构造来说,局部的代码是使用缩进来指定的。因此,下面的行是缩进的(通过空格或制表符),以便起始字符与结构的代码体对齐。

下面展示了这个概念的实际应用。如果缩进不一致,Python解释器会抱怨并产生奇怪的结果。

if(expr1):print("insideexpr1")print("stillinsideexpr1")else:print("insideelse")print("stillinsideelse")print("inouterlevel")这里我们看到一个条件或if语句。注意函数调用print()是缩进的。这向解释器发出信号,表明这些行属于它上面的结构。例如,提到expr1的两个print语句构成了if条件的代码块(当表达式的计算结果为true时执行)。类似地,接下来的两个print语句构成了else条件的代码块。最后,非缩进的行不是条件行的一部分,因此在if或else之后执行,这取决于表达式的计算。

如您所见,缩进是编写Python时需要学习的一个关键概念。尽管这很简单,但是在缩进中出错可能会导致代码意外执行,或者解释器出现更糟糕的错误。

在讨论Python时,我将“程序”和“应用”与“脚本”互换使用。虽然从技术上讲,保存在文件中的Python代码是一个脚本,但我们通常在“程序”或“应用”更合适的上下文中使用它。

任何编程语言中最基本的概念之一是用不可执行的文本注释源代码的能力,这不仅允许您在代码行之间做笔记,还形成了一种记录源代码的方法。

要向源代码添加注释,请使用井号(#)。在行首放置至少一个符号,为该行创建注释,对后续的每一行重复使用#符号。这将创建所谓的块注释,如图所示。注意,我使用了不带任何文本的注释来创建空白。这有助于提高可读性,并且是块注释的常见做法。

##MicroPythonfortheIOT##ExamplePythonapplication.##CreatedbyDr.CharlesBell#您也可以将注释放在源代码所在的同一行。编译器将忽略从井号到行尾的所有内容。例如,下面显示了记录变量的常见样式。

zip=35012#Ziporpostalcodeaddress1="123MainSt."#Storethestreetaddress算术您可以在Python中执行许多数学运算,包括常见的原语以及逻辑运算和用于比较值的运算。与其详细讨论这些,我在表4-1中提供了一个快速参考,显示了操作和如何使用操作的例子。

表4-1。

Arithmetic,Logical,andComparisonOperatorsinPython

按位运算产生对每个位执行的值的结果。逻辑运算符(and、or)产生一个值,该值可为真或为假,通常与表达式或条件一起使用。

我们已经看到了一些如何将消息打印到屏幕上的例子,但是没有对所显示的语句进行任何解释。虽然不太可能为您部署的项目打印MicroPython板的输出,但是当您可以在屏幕上显示消息时,学习Python会容易得多。

正如我们在前面的例子中看到的,你可能想要打印的一些东西是为了传达你的程序内部正在发生的事情。这可以包括简单的消息(字符串),但也可以包括变量、表达式等的值。

正如我们所见,内置的print()函数是显示包含在单引号或双引号中的输出文本的最常见方式。我们还看到了一些使用另一个名为format()的函数的有趣例子。format()函数为每个传递的参数生成一个字符串。这些参数可以是其他字符串、表达式、变量等。该函数与一个特殊字符串一起使用,该字符串包含由花括号{}(calledstringinterpolation1)分隔的替换键。每个替换键包含一个索引(从0开始)或一个命名关键字。这个特殊字符串称为格式字符串。让我们看几个例子来说明这个概念。您可以在您的PC或MicroPython板上运行这些程序。我包括了输出,这样您可以看到每个语句做了什么。

>>>a=42>>>b=1.5>>>c="seventy">>>print("{0}{1}{2}{3}".format(a,b,c,(2+3)))421.5seventy5>>>print("{a_var}{b_var}{c_var}{0}".format((3*3),c_var=c,b_var=b,a_var=a))421.5seventy9请注意,我创建了三个变量(我们将在下一节讨论变量),用等号(=)给它们分配不同的值。然后,我使用带有四个替换键的格式字符串打印了一条消息,这四个替换键使用索引进行标记。请注意打印语句的输出。请注意,我在结尾处包含了一个表达式,以展示format()函数如何计算表达式。

最后一行更有趣。这里,我使用了三个命名参数(a_var、b_var、c_var),并在format()函数中使用了一个特殊的参数选项,在这里我给参数赋值。请注意,我以不同的顺序列出了它们。这是使用命名参数的最大优点;它们可以以任何顺序出现,但被放在格式字符串中指定的位置。

如您所见,这只是用format()函数中的键替换{}键的一个例子,format()函数将参数转换为字符串。我们在任何需要包含从多个区域或类型收集的数据的字符串的地方使用这种技术。我们可以在上面的例子中看到这一点。

现在让我们看看如何在我们的程序(脚本)中使用变量。

对于那些已经学会用另一种语言如C或C++编程的人来说,Python允许你用分号(;)终止一个语句;然而,包含它是不必要的,并且被认为是不好的形式。

Python中的变量只是命名的内存位置,可以用来在执行过程中存储值。我们通过使用等号赋值来存储值。Python变量名可以是您想要的任何名称,但是大多数Python开发人员都遵循一些规则和惯例。Python编码标准中列出了这些规则。2

然而,一般的、首要的规则要求变量名是描述性的、在上下文中有意义的并且容易阅读。也就是说,您应该避免使用带有随机字符、强制缩写、首字母缩略词以及类似的晦涩难懂的名称。按照惯例,变量名应该长于一个字符(除了一些可接受的循环计数变量),并且足够短以避免过长的代码行。

WhatisaLongCodeLine

大多数人会说一个代码行不应超过80个字符,但这是从编程的黑暗时代听来的,那时我们使用穿孔卡,每张卡最多允许80个字符,后来的显示设备也有同样的限制。对于现代的宽屏显示器来说,这没什么大不了的,但我仍然建议保持短行以确保更好的可读性。没有人喜欢向下(或向右)滚动阅读!

下面显示了一些简单变量及其动态确定类型的示例。

#floatingpointnumberlength=10.0#integerwidth=4#stringbox_label="Tools"#listcar_makers=['Ford','Chevrolet','Dodge']#tupleporsche_cars=('911','Cayman','Boxster')#dictionaryaddress={"name":"JoeSmith","Street":"123Main","City":"Anytown","State":"NewHappyville"}那么,我们怎么知道变量width是一个整数呢?仅仅因为数字4是一个整数。同样,Python将“工具”解释为字符串。我们将在下一节看到更多关于最后三种类型和Python支持的其他类型的内容。

如前所述,Python不像其他语言那样有正式的类型规范机制。但是,您仍然可以定义变量来存储您想要的任何内容。事实上,Python允许您基于上下文创建和使用变量,并且您可以使用初始化来“设置”变量的数据类型。下面给出了几个例子。

#Numbersfloat_value=9.75integer_value=5#Stringsmy_string="Hesays,he'salreadygotone."print("Floatingnumber:{0}".format(float_value))print("Integernumber:{0}".format(integer_value))print(my_string)对于需要转换类型或希望确保值以某种方式键入的情况,有许多用于转换数据的函数。表4-2显示了一些更常用的类型转换函数。我将在后面的章节中讨论一些数据结构。

表4-2。

TypeConversioninPython

但是,您应该小心使用这些转换函数,以避免数据丢失或舍入。例如,将浮点数转换为整数可能会导致截断。同样,打印浮点数会导致舍入。

现在让我们看看一些常用的数据结构,包括这个叫做字典的奇怪的东西。

列表是Python中组织数据的一种方式。这是一种构建集合的自由形式的方法。也就是说,项目(或元素)不必是相同的数据类型。列表还允许你做一些有趣的操作,比如在末尾、开头或特殊索引处添加内容。下面演示了如何创建列表。

#Listmy_list=["abacab",575,"rex,thewonderdog",24,5,6]my_list.append("end")my_list.insert(0,"begin")foriteminmy_list:print("{0}".format(item))这里我们看到我使用方括号([])创建了列表。列表定义中的项目用逗号分隔。注意,您可以简单地通过设置一个等于[]的变量来创建一个空列表。因为列表和其他数据结构一样,都是对象,所以有几种操作可用于列表,如下所示。

列表就像其他语言中的数组一样,对于构建动态数据集合非常有用。

另一方面,元组是一种限制性更强的集合类型。也就是说,它们是由一组特定的数据构建的,不允许像列表一样进行操作。事实上,您不能更改元组中的元素。因此,我们可以对不应该改变的数据使用元组。下面显示了一个元组的示例以及如何使用它。

#Tuplemy_tuple=(0,1,2,3,4,5,6,7,8,"nine")foriteminmy_tuple:print("{0}".format(item))if7inmy_tuple:print("7isinthelist")这里我们看到我使用括号()创建了元组。元组定义中的各项用逗号分隔。注意,只需将变量设置为()就可以创建一个空元组。因为元组像其他数据结构一样是对象,所以有如下几种可用的操作,包括对诸如包含、定位等序列的操作。

如果你想在内存中存储更多的数据,你可以使用一个叫做字典的特殊结构(对象)。

字典是一种数据结构,允许您存储键、值对,通过键来评估数据。字典是一种非常结构化的数据处理方式,也是我们在收集复杂数据时想要使用的最符合逻辑的形式。下面是一个字典的例子。

按照字典,我们看到在字典上执行的几个操作,包括打印键、打印所有值和只打印值。下面显示了从Python解释器执行该代码片段的输出。

[42,'first_name','last_name','age','my_ip'][(42,'whatisthemeaningoflife'),('first_name','Chuck'),('last_name','Bell'),('age',36),('my_ip',(192,168,1,225))]['whatisthemeaningoflife','Chuck','Bell',36,(192,168,1,225)]'42':whatisthemeaningoflife'first_name':Chuck'last_name':Bell'age':36'my_ip':(192,168,1,225)正如我们在这个例子中看到的,有几个操作(函数或方法)可用于字典,包括如下。这些操作使得字典成为一个非常强大的编程工具。

最重要的是,对象可以放在其他对象中。例如,你可以像我上面做的那样创建一个字典列表,一个包含列表和元组的字典,以及你需要的任何组合。因此,列表、元组和字典是管理程序数据的强大方法。

在下一节中,我们将学习如何控制程序的流程。

现在我们对Python的基础有了更多的了解,我们可以发现一些完成项目所需的更复杂的代码概念,比如条件语句和循环。

我们还看到了一些简单的条件语句:根据一个或多个表达式的计算来改变执行流程的语句。条件语句允许我们根据一个或多个表达式的计算,将程序的执行指向代码段(块)。Python中的条件语句是if语句。

在我们的示例代码中,我们已经看到了if语句的作用。注意,在示例中,我们可以有一个或多个(可选的)else短语,一旦if条件的表达式计算为false,我们就执行这些短语。我们可以链接if/else语句来包含多个条件,其中执行的代码取决于几个条件的评估。下面显示了if语句的一般结构。注意在注释中我是如何解释执行是如何到达每个条件的主体的。

if(expr1):#executeonlyifexpr1istrueelif((expr2)or(expr3)):#executeonlyifexpr1isfalse*and*eitherexpr2orexpr3istrueelse:#executeifbothsetsofifconditionsevaluatetofalse虽然您可以尽可能多地链接语句,但在这里要小心,因为您拥有的elif部分越多,就越难理解、维护和避免表达式中的逻辑错误。

还有另一种形式的条件语句,称为三元运算符。在Python中,三元运算符通常被称为条件表达式。这些操作符基于条件的真或假来评估某些东西。在2.4版本中,它们成为Python的一部分。条件表达式是在赋值语句中使用的if-then-else结构的简写符号,如下所示。

variable=value_if_trueifconditionelsevalue_if_false这里我们看到如果条件被评估为真,则使用if前面的值,但是如果条件被评估为假,则使用else后面的值。下面是一个简短的例子。

>>>numbers=[1,2,3,4]>>>forninnumbers:...x='odd'ifn%2else'even'...print("{0}is{1}.".format(n,x))...1isodd.2iseven.3isodd.4iseven.>>>条件表达式允许您快速测试条件,而不是使用多行条件语句,这有助于使您的代码更容易阅读(也更短)。

循环用于控制代码块的重复执行。有三种形式的循环,它们的行为略有不同。所有循环都使用条件语句来决定是否重复执行。也就是说,只要条件为真,它们就会重复。两种类型的循环是while和for。我用一个例子来解释每一个。

while循环的条件位于代码块的“顶部”或开始处。因此,while循环仅当且仅当条件在第一次通过时评估为true时才执行主体。下面说明了while循环的语法。只有当某些表达式的计算结果为true时,才需要执行代码,此时最好使用这种形式的循环。例如,遍历一个元素个数未知的事物集合(循环,直到集合中的事物用完)。

while(expression):#dosomethinghereFor循环由于其独特的形式,有时也被称为计数循环。For循环允许您定义一个计数变量和一个要迭代的范围或列表。下面说明了for循环的结构。这种形式的循环最适合用于在集合中执行操作。在这种情况下,Python会在每次循环中自动将集合中的每一项放入变量中,直到没有更多项可用为止。

forvariable_nameinlist:#dosomethinghere你也可以做范围循环或计数循环。这使用了一个名为range()的特殊函数,它最多接受三个参数,range([start],stop[,step]),其中start是起始数字(一个整数),stop是序列中的最后一个数字,step是增量。所以,你可以按1,2,3等来数。,通过一系列的数字。下面是一个简单的例子。

这些关键字有一些用途,尤其是break,但它不是终止和控制循环的首选方法。也就是说,专业人士认为条件表达式或错误处理代码应该表现得足够好,不需要这些选项。

最后几组主题是最高级的,包括模块化(代码组织)。正如我们将看到的,我们可以使用函数对代码进行分组,消除重复,并将功能封装到对象中。

Python应用可以从Python环境提供的可重用库构建。它们也可以从您自己创建或从第三方下载的自定义模块或库构建。这些文件通常作为一组Python代码文件分发(例如,文件扩展名为.py的文件)。当我们想使用一个库(函数、类等)时。)包含在一个模块中,我们使用import关键字并列出模块的名称。下面是一些例子。

importosimportsys前两行演示了如何导入Python提供的基本或公共模块。在这种情况下,我们为os和sys模块(操作系统和Python系统函数)使用或导入模块。

习惯上(但不要求)按字母顺序列出您的导入,首先是内置模块,然后是第三方模块,最后是您自己的模块。

Python允许在代码中使用模块化。虽然它通过类的方式支持面向对象编程(对于大多数PythonGPIO示例来说,这是一个不太可能遇到的更高级的特性),但在更基本的层面上,您可以使用函数将代码分成更小的块。

defprint_dictionary(the_dictionary):forkey,valueinthe_dictionary.items():print("'{0}':{1}".format(key,value))#definesomedatamy_dictionary={'name':"Chuck",‘age’:37,}您可能想知道这个奇怪的代码是做什么的。注意,该循环从items()函数的结果中分配了两个值。这是dictionary对象提供的一个特殊函数。3items()函数返回键、值对:因此得名变量。

print_dictionary(my_dictionary)print(my_dictionary['age'])print(my_dictionary['name'])这个示例和上面的代码一起执行时,会生成以下内容。

$python3Python3.6.0(v3.6.0:41df79263a11,Dec222016,17:23:13)[GCC4.2.1(AppleInc.build5666)(dot3)]ondarwinType"help","copyright","credits"or"license"formoreinformation.>>>defprint_dictionary(the_dictionary):...forkey,valueinthe_dictionary.items():...print("'{0}':{1}".format(key,value))...>>>#definesomedata...my_dictionary={...'name':"Chuck",...'age':41,...}>>>print_dictionary(my_dictionary)'name':Chuck'age':41>>>print(my_dictionary['age'])41>>>print(my_dictionary['name'])Chuck现在让我们看看Python中最复杂的概念——面向对象编程。

你可能听说过Python是一种面向对象的编程语言。但这意味着什么呢?简单地说,Python是一种编程语言,它提供了描述对象(事物)以及可以用对象做什么(操作)的工具。对象是数据抽象的一种高级形式,其中数据对调用者是隐藏的,只能由对象提供的操作(方法)来操作。

我们在Python中使用的语法是class语句,您可以使用它来帮助您的项目模块化。所谓模块化,我们的意思是源代码被安排得更容易开发和维护。通常,我们将类放在单独的模块(代码文件)中,这有助于更好地组织代码。虽然这不是必需的,但我建议使用这种将类放在它自己的源文件中的技术。这使得修改类或修复问题(错误)更加容易。

我更喜欢使用语言设计者或开发人员社区已经采用的术语。例如,有些使用“函数”,但有些可能使用“方法”。还有一些可能使用子程序、例行程序、过程等。你使用哪个术语并不重要,但是你应该努力使用一致的术语。一个可能让一些人感到困惑的例子是,我在讨论面向对象的例子时使用了术语方法。也就是说,一个类有方法而没有函数。然而,你可以用函数代替方法,你仍然是正确的(大多数情况下)。

通过使用类(创建实例)和使用点标记来引用数据成员或函数,使用一种或多种方法来访问数据。让我们看一个例子。清单4-1展示了一个完整的类,它描述(模拟)了用于运输的车辆的最基本特征。我创建了一个名为vehicle.py的文件来包含这段代码。

##MicroPythonfortheIOT##ClassExample:Agenericvehicle##Dr.CharlesBell#classVehicle:"""Baseclassfordefiningvehicles"""axles=0doors=0occupants=0def__init__(self,num_axles,num_doors):self.axles=num_axlesself.doors=num_doorsdefget_axles(self):returnself.axlesdefget_doors(self):returnself.doorsdefadd_occupant(self):self.occupants+=1defnum_occupants(self):returnself.occupantsListing4-1.Vehicleclass注意这里的一些事情。首先,有一个名为init()的方法。这是构造函数,在创建类实例时调用。您将所有初始化代码像设置变量一样放在这个方法中。我们也有返回轴、门和居住者数量的方法。我们在这个类中有一个方法:添加居住者。

让我们看看这个类如何被用来定义一个家庭轿车。清单4-2展示了使用这个类的代码。我们可以将这段代码放在一个名为sedan.py的文件中。

##MicroPythonfortheIOT##ClassExample:UsingthegenericVehicleclass##Dr.CharlesBell#fromvehicleimportVehiclesedan=Vehicle(2,4)sedan.add_occupant()sedan.add_occupant()sedan.add_occupant()print("Thecarhas{0}occupants.".format(sedan.num_occupants()))Listing4-2.UsingtheVehicleclass注意,第一行从vehicle模块导入了Vehicle类。注意,我大写了类名,而不是文件名。这是一种非常常见的命名方案。接下来,在代码中,我们创建类的一个实例。注意我把2,4传递给了类名。这将导致在实例化类时调用__init__()方法。变量sedan变成了我们可以操作的类实例变量(对象),我通过添加三个居住者然后使用Vehicle类中的方法打印出居住者的数量来实现。

我们可以使用下面的命令在PC上运行代码。正如我们所看到的,当代码运行时,它告诉我们车上有三个人。不错。

$python./sedan.pyThecarhas3occupants.Object-OrientedProgramming(OOP)Terminology

像任何技术或概念一样,有一定数量的术语,您必须学会这些术语,才能理解技术并与他人交流。下面简要描述了一些您需要了解的术语,以便更好地了解面向对象编程。

属性:类中的数据元素。

类:用于以属性(数据)和对数据进行操作的方法(函数)的形式定义对象的代码构造。Python中的方法和属性可以使用点符号来访问。

类实例变量:用于存储对象实例的变量。它们像其他变量一样使用,与点符号结合,允许我们操作对象。

实例:类的可执行形式,通过将类赋给变量来创建,将代码初始化为对象。

继承:将一个类的属性和方法包含在另一个类中。

实例化:创建一个类的实例。

方法重载:创建两个或多个同名但参数不同的方法。这允许我们创建具有相同名称的方法,但是根据所传递的参数,操作可能不同。

多态性:从基类继承属性和方法,添加额外的方法或覆盖(改变)方法。

还有很多OOP术语,但这些是你最常遇到的。

现在,让我们看看如何使用vehicle类来演示继承。在这种情况下,我们将创建一个名为PickupTruck的新类,它使用了vehicle类,但是向结果类添加了专门化。清单4-3显示了新的类。我将这段代码放在一个名为pickup_truck.py的文件中。如你所见,皮卡是一种交通工具。

接下来,注意__max_occupants变量。按照惯例,在一个类中为一个属性或方法使用两个下划线会使该项成为该类的私有项。4也就是说,它应该只能从类内部访问。该类的调用方(通过类变量/实例)不能访问私有项,从该类派生的任何类也不能访问私有项。隐藏属性(数据)总是一个好的做法。

您可能想知道occupant方法发生了什么变化。他们为什么不在新班级?它们不在那里,因为我们的新类继承了基类的所有行为。不仅如此,还修改了代码,将乘员限制为三人。

我还想指出我添加到该类中的文档。我们使用文档字符串(前后使用三个双引号的字符串)来记录类。您可以将文档放在这里解释该类及其方法。稍后我们会看到它的一个很好的用途。

最后,请注意构造函数中的代码。这演示了如何调用基类方法,我这样做是为了设置轴和门的数量。如果我们想调用基类方法的版本,我们可以在其他方法中做同样的事情。

现在,让我们写一些代码来使用这个类。清单4-4显示了我们用来测试这个类的代码。在这里,我们创建了一个名为pickup.py的文件,该文件创建了一个皮卡实例,添加了乘员和有效载荷,然后打印出卡车的内容。

##MicroPythonfortheIOT##ClassExample:ExercisingthePickupTruckclass.##Dr.CharlesBell#frompickup_truckimportPickupTruckpickup=PickupTruck(500)pickup.add_occupant()pickup.add_occupant()pickup.add_occupant()pickup.add_occupant()pickup.add_payload(100)pickup.add_payload(300)print("Numberofoccupantsintruck={0}.".format(pickup.num_occupants()))print("Weightintruck={0}.".format(pickup.get_payload()))pickup.add_payload(200)pickup.remove_payload(400)pickup.remove_payload(10)Listing4-4.UsingthePickupTruckclass注意,我添加了几个对add_occupant()方法的调用,新类继承并覆盖了它。我还添加了一些调用,这样我们就可以在检查过度占用和最大有效负载能力的方法中测试代码。当我们运行这段代码时,我们将看到如下所示的结果。

$python./pickup.pySorry,only3occupantsarepermittedinthetruck.Numberofoccupantsintruck=3.Weightintruck=400.Overloaded!Nothinginthetruck.我再次在我的PC上运行这段代码,但是我可以在MicroPython板上运行所有这些代码,并且会看到相同的结果。

关于类,我们还应该了解一件事:内置属性。回忆一下__init__()方法。Python自动提供了几个内置属性,每个属性都以__开头,您可以使用它们来了解更多关于对象的信息。下面列出了几个可用于类的运算符。

下面显示了每个属性为上面的PickupTruck类返回的内容。我将这段代码添加到pickup.py文件中。

print("PickupTruck.__doc__:",PickupTruck.__doc__)print("PickupTruck.__name__:",PickupTruck.__name__)print("PickupTruck.__module__:",PickupTruck.__module__)print("PickupTruck.__bases__:",PickupTruck.__bases__)print("PickupTruck.__dict__:",PickupTruck.__dict__)运行这段代码时,我们会看到以下输出。

现在,让我们看几个可以用来练习的Python程序的例子。与前面的例子一样,您可以在PC或MicroPython板上编写和执行这些代码。

学习如何用任何语言编程的最好方法是用例子练习。在这一节中,我将展示几个例子,您可以用它们来练习Python编码。您可以使用MicroPython板或PC来运行这些示例。我通过Python控制台在我的PC上展示了前两个例子,通过REPL控制台使用MicroPython板展示了后两个例子。

我详细解释了每个示例的代码,并展示了执行代码时的示例输出,以及让您自己尝试对每个示例进行一两次修改的挑战。我鼓励你实现这些例子,并在本书后面的项目实践中自己找出挑战。

该示例从要转换的整数元组开始。可以使用for循环遍历元组和列表(按顺序读取值)。回想一下,一个元组是只读的,所以在这种情况下,因为它是输入的,所以它是好的,但在其他情况下,您可能需要更改值,您将需要使用列表。回想一下,元组和列表之间的语法差异是元组使用括号,而列表使用方括号。

这里演示的for循环称为“foreach”循环。注意,我使用了语法“forvalueinvalues,”,它告诉Python遍历名为values的元组,每次遍历元组时,将每个条目提取(存储)到value变量中。

最后,我使用print()和format()函数替换两个占位符{0}和{1},使用方法bin()为二进制、oct()为八进制、hex()为十六进制打印出不同格式的整数。清单4-5展示了将整数转换成不同形式的例子。

##MicroPythonfortheIOT##Example:Convertintegertobinary,hex,andoctal##Dr.CharlesBell##Createatupleofintegervaluesvalues=(12,450,1,89,2017,90125)#Loopthroughthevaluesandconverteachtobinary,hex,andoctalforvalueinvalues:print("{0}inbinaryis{1}".format(value,bin(value)))print("{0}inoctalis{1}".format(value,oct(value)))print("{0}inhexadecimalis{1}".format(value,hex(value)))Listing4-5.ConvertingIntegers执行代码您可以将这段代码保存在PC上一个名为conversions.py的文件中,然后打开一个终端(控制台窗口)并使用命令python./conversions.py运行这段代码(如果您安装了多个版本的python,则使用python3)。清单4-6显示了输出。

$python3./conversions.py12inbinaryis0b110012inoctalis0o1412inhexadecimalis0xc450inbinaryis0b111000010450inoctalis0o702450inhexadecimalis0x1c21inbinaryis0b11inoctalis0o11inhexadecimalis0x189inbinaryis0b101100189inoctalis0o13189inhexadecimalis0x592017inbinaryis0b111111000012017inoctalis0o37412017inhexadecimalis0x7e190125inbinaryis0b1011000000000110190125inoctalis0o26001590125inhexadecimalis0x1600dListing4-6.ConversionsExampleOutput注意元组中所有被转换的值。

为了使这个示例更好,不使用静态元组来包含硬编码的整数,而是重写这个示例,以便从命令行上的参数中读取整数以及格式。例如,代码将按如下方式执行。

importargparse#Setuptheargumentparserparser=argparse.ArgumentParser()#Weneedtwoarguments:integer,andconversionparser.add_argument("original_val")parser.add_argument("conversion")#Gettheargumentsargs=parser.parse_args()当您使用参数解析器(argparse)模块时,参数的值都是字符串,因此您需要在使用bin()、hex()或oct()方法之前将值转换为整数。

您还需要确定所请求的转换。我建议只使用十六进制、二进制和十进制进行转换,并使用一组条件来检查所请求的转换。类似于下面的内容会起作用。

ifargs.conversion=='bin':#doconversiontobinaryelifargs.conversion=='oct':#doconversiontooctalelifargs.conversion=='hex':#doconversiontohexadecimalelse:print("Sorry,Idon'tunderstand,{0}.".format(args.conversion))请注意,最后一个else通知参数未被识别。这有助于管理用户错误。

关于参数解析器,还有一点你应该知道。添加参数时,可以传入一个帮助字符串。参数解析器还免费为您提供帮助参数(-h)。请注意以下事项。注意,我使用help=参数添加了几个字符串。

#Weneedtwoarguments:integer,andconversionparser.add_argument("original_val",help="Valuetoconvert.")parser.add_argument("conversion",help="Conversionoptions:hex,bin,oroct.")现在,当我们完成代码并使用-h选项运行它时,我们会得到下面的输出。酷吧。

$python3./conversions.py-husage:conversions.py[-h]original_valconversionpositionalarguments:original_valValuetoconvert.conversionConversionoptions:hex,bin,oroct.optionalarguments:-h,--helpshowthishelpmessageandexit示例2:使用复杂的数据和文件这个例子演示了如何在Python中使用JavaScript对象符号5(JSON)。简而言之,JSON是一种用于交换数据的标记语言。它不仅可读,还可以直接在应用中使用,在其他应用、服务器甚至MySQL之间存储和检索数据。事实上,程序员对JSON很熟悉,因为它类似于其他标记方案。JSON也非常简单,因为它只支持两种类型的结构:1)包含(名称,值)对的集合,2)有序列表(或数组)。当然,您也可以混合和匹配一个对象中的结构。当我们创建一个JSON对象时,我们称之为JSON文档。

我们试图解决的问题是向/从文件中写入和读取数据。在这种情况下,我们将使用一个名为json的特殊JSON编码器和解码器模块,它允许我们轻松地将文件(或其他流)中的数据与JSON相互转换。正如您将看到的,访问JSON数据很容易,只需使用键名(有时称为字段)来访问数据。因此,这个例子不仅对将来如何使用读写文件有帮助,而且对如何使用JSON文档也有帮助。

此示例存储和检索文件中的数据。这些数据是关于宠物的基本信息,包括名字、年龄、品种和类型。该类型用于确定广泛的类别,如鱼、狗或猫。

我们从导入JSON模块(名为json)开始,该模块内置于MicroPython平台中。接下来,我们通过构建JSON文档并将其存储在Python列表中来准备一些初始数据。我们使用json.loads()方法传入一个JSON格式的字符串。结果是一个JSON文档,我们可以将它添加到我们的列表中。这些例子使用了一种非常简单的JSON文档——一组(名称,值)对。下面显示了一个使用的JSON格式字符串的例子。

JSON方法json.loads()获取JSON格式的字符串,然后分析字符串的有效性并返回一个JSON文档。然后,我们将该文档存储在一个变量中,并将其添加到列表中,如下所示。

parsed_json=json.loads('{"name":"Violet","age":6,"breed":"dachshund","type":"dog"}')pets.append(parsed_json)一旦数据被添加到列表中,我们就把数据写到一个名为my_data.json的文件中。为了处理文件,我们首先用open()函数打开文件,它接受一个文件名(如果您想把文件放在一个目录中,还包括一个路径)和一个访问模式。我们用“r”读,用“w”写。如果你想打开一个文件并添加到末尾,你也可以使用“a”进行追加。请注意,当您写入文件时,“w”访问将会覆盖该文件。如果open()函数成功,您将获得一个file对象,它允许您调用额外的函数来读取或写入数据。如果文件不存在(并且您已经请求了读取权限)或者您没有权限写入文件,那么open()将会失败。

如果你想知道还有哪些访问模式,表4-3显示了open()功能可用的模式列表。

表4-3。

PythonFileAccessModes

文件打开后,我们可以通过遍历列表将JSON文档写入文件。迭代意味着从第一个元素开始,按顺序(它们在列表中出现的顺序)一次访问列表中的一个元素。回想一下,Python中的迭代非常容易。我们简单地说,“对于列表中的每一项”,for循环如下。

forpetinpets://dosomethingwiththepetdata为了将JSON文档写入文件,我们使用了json.dumps()方法,这将产生一个JSON格式的字符串,使用file变量和write()方法将该字符串写入文件。因此,我们现在看到如何从字符串构建JSON文档,然后将它们解码(转储)成一个字符串。

一旦我们将数据写入文件,我们就用close()函数关闭文件,然后重新打开它并从文件中读取数据。在这种情况下,我们使用for循环的另一种特殊实现。我们使用file变量通过readlines()方法读取文件中的所有行,然后用下面的代码遍历它们。

json_file=open("my_data.json","r")forpetinjson_file.readlines()://dosomethingwiththepetstring我们再次使用json.loads()方法读取从文件中读取的JSON格式的字符串,将其转换为JSON文档,并将其添加到另一个列表中。然后我们关闭文件。现在数据已经读回到我们的程序中,我们可以使用它了。最后,我们遍历新列表,并使用键名从JSON文档中打印出数据,以检索我们想要的数据。清单4-7显示了这个例子的完整代码。

那么,文件看起来像什么?下面是使用more实用程序的文件转储,它显示了文件的内容。注意,该文件包含JSON格式的字符串,就像我们在代码中一样。

$moremy_data.json{"age":6,"breed":"dachshund","type":"dog","name":"Violet"}{"age":15,"breed":"poodle","type":"dog","name":"JonJon"}{"age":4,"breed":"siberiankhatru","type":"cat","name":"Mister"}{"age":7,"breed":"koi","type":"fish","name":"Spot"}{"age":6,"breed":"dachshund","type":"dog","name":"Charlie"}现在,让我们看看运行这个脚本会发生什么。

您可以将此代码保存在PC上名为rw_json.py的文件中,然后打开一个终端(控制台窗口)并使用命令python./rw_json.py运行代码(如果您安装了多个版本的python,则使用python3)。下面显示了输出。

$python./rw_json.pyName,AgeViolet,6JonJon,15Charlie,6虽然输出可能不是很令人印象深刻,但是通过完成这个示例,您已经学到了很多关于使用JSON文档处理文件和结构化数据的知识。

有了这个文件后,修改代码,从文件中读取并打印出每只宠物的所有信息,方法是打印键名和值。提示:您将需要使用特殊的代码来打印出键名和值,称为“漂亮打印”例如,下面的代码将以易读的格式打印出JSON文档。注意,我们使用sort_keys选项来打印键(字段),我们可以控制缩进的空格数。

forpetinmy_pets:print(json.dumps(pet,sort_keys=True,indent=4))运行时,输出将如下所示。

{"age":6,"breed":"dachshund","name":"Violet","type":"dog"}{"age":15,"breed":"poodle","name":"JonJon","type":"dog"}示例3:使用函数这个例子演示了如何创建和使用函数。回调函数用于帮助我们的代码更加模块化。函数也是避免代码重复的重要工具。也就是说,我们可以通过将部分代码放在函数中来重复使用它们。函数也用于帮助隔离特殊操作的代码,例如数学公式。

我们在这个例子中探索的问题是如何创建函数来执行计算。我们还将探索一种常见的计算机科学技术,称为递归6,在这种技术中,函数会重复调用自身。我还将向您展示以迭代方式实现的相同功能(通常使用循环)。虽然有些人建议避免递归,但是递归函数写起来更短,但是如果出错的话,调试起来会更困难。我能提供的最好的建议是,几乎每个递归函数都可以写成迭代函数,新手程序员应该坚持迭代解决方案,直到他们对使用函数有了信心。

这个例子是用来计算斐波那契数列的。7斐波纳契数列是以数列中前两个值的和来计算的。该序列从1开始,后跟1(无加1),然后是1+1=2,依此类推。对于这个例子,我们将要求用户输入一个整数,然后计算斐波那契数列中值的个数。如果输入为5,则序列为1、1、2、3、5。

我们将创建两个函数:一个使用迭代计算数列的代码计算斐波那契数列,另一个使用递归函数计算第n个斐波那契数列。我们先来看迭代函数。

为了定义一个函数,我们使用语法deffunc_name():,其中我们提供一个函数名和一个零个或多个参数的列表,后跟一个冒号。这些参数可以在函数内部使用。我们使用参数将数据传递给函数。下面显示了斐波那契数列代码的迭代版本。我们把这个函数命名为fibonacci_iterative。

现在让我们看看函数的递归版本。下面显示了代码。我们将这个函数命名为fibonacci_recursive。

现在,您可能想知道将函数放在代码中的什么位置。我们需要将它们放在代码的顶部。Python将解析函数,并继续执行定义之后的语句。因此,我们将“主”代码放在函数之后。

本例的主要代码从请求斐波那契数列的第n个值开始,然后首先使用递归函数来计算该值。然后,我们询问用户是否想要查看整个系列,如果是,我们使用函数的迭代版本来获取列表并将其打印出来。我们打印出第n个值,并再次给出查看整个系列的选项,以显示使用两个函数的结果是相同的。清单4-8展示了这个例子的完整代码。我们将这个代码命名为fibonacci.py。

现在,让我们看看运行这个脚本会发生什么。回想一下,我们将在我们的MicroPython板上运行这段代码,因此如果您正在跟进,请确保设置好您的板并将其连接到您的PC。

回想一下第三章,当我们想要将代码移动到我们的MicroPython板上时,我们需要创建文件,然后将它复制到MicroPython板上,然后执行它。在这一节中,我将向您展示如何在macOS上做到这一点。在Windows10上如何做到这一点的示例如示例4所示。

当您将MicroPython板插入PC上的USB端口时,闪存盘将出现在您的Finder和桌面上。图4-1显示了macOS上的一个例子。

图4-1。

MicroPythonboardFlashDriveMounted

我们现在需要将fibonacci.py文件复制到闪存驱动器。在macOS上,打开闪存驱动器,然后将文件拖到驱动器上。当你复制完文件后,你应该会看到类似图4-2的东西。

图4-2。

FilesCopiedtotheMicroPythonboardFlashDrive

请注意,我对图像进行了注释以显示文件。注意,我们还看到了MicroPython文件boot.py和main.py。我们不会修改main.py文件来运行我们的例子,因为我们不希望程序在每次启动设备时都运行。相反,我们将从REPL控制台运行代码。

使用终端窗口打开REPL控制台。您应该会看到来自MicroPython的欢迎消息,后面是RELP提示(>>>)。在REPL提示符下,发出以下代码语句。

importfibonnaci这段代码导入我们刚刚复制的fibonnaci.py文件,当它导入时,它执行这段代码。因此,就像我们从Python控制台在我们的PC上运行它一样。继续通过请求斐波纳契数列中的第十二个值来测试程序。您应该会看到如图4-3所示的输出。

图4-3。

OutputofFibonacciExample(MicroPythonboard)

注意,我对查询做出了响应,显示了整个系列。还要注意,我们看到代码已经使用了我们编写的两个版本的函数:迭代和递归。最后,我们看到两个函数的值或输出是相同的数据。

如果您还没有MicroPython板,您可以在PC上使用命令python./fibonacci.py运行代码。您将看到类似的输出,如图所示。

如果再次运行代码,只需按CTRL-D进行软重置,然后再次发出import语句。这将重新运行整个代码。或者,如果您想运行其中一个函数,您可以通过使用下面的代码导入它来再次调用它。图4-4显示了在MicroPython板上执行时的样子。

图4-4。

ExperimentingwiththeFibonacciFunctions

fromfibonacciimportfibonacci_iterativefibonacci_iterative(6)fromfibonacciimportfibonacci_recursivefibonacci_recursive(6)以这种方式导入后,您可以再次运行这些函数。继续尝试使用不同的值来显示它们的行为。回想一下,函数的实现是不同的——迭代版本返回列表,递归版本只返回最后一个或第n个值。

当您完成了示例的实验后,记得在拔下驱动器之前关闭终端并弹出闪存驱动器。

为了让这个例子更有用,修改代码,在斐波那契数列中搜索特定的整数。要求用户提供一个整数,然后确定该值是否是有效的斐波那契值。例如,如果用户输入144,代码应该告诉用户该值是有效的,并且是序列中的第十二个值。虽然这个挑战将要求您为“主要”功能重写大部分代码,但是您必须找出如何以新的方式使用这些功能。

这个例子通过引入面向对象的编程概念:类,大大增加了复杂性。回想一下前面的内容,类是模块化代码的另一种方式。类用于建模数据和数据上的行为。此外,类通常放在它们自己的代码模块(文件)中,进一步模块化代码。如果您需要修改一个类,您可能只需要更改类模块中的代码。

我们在这个例子中探索的问题是如何使用类和代码模块开发解决方案。我们将创建两个文件:一个用于类,另一个用于主代码。

这个例子是用来把罗马数字8转换成整数的。也就是说,我们将输入一个类似VIII的值,即8,并期望看到整数8。为了让事情变得更有趣,我们还将把我们得到的整数转换回罗马数字。罗马数字是用字符I表示1,V表示5,X表示10,L表示50,C表示100,D表示500,M表示1000组成的字符串。其他数字的组合是通过将字符数值加在一起(例如,3=III),或者在另一个字符之前加一个单独的低位字符来表示代表减去该字符(例如,4=IV)。下面展示了一些如何工作的例子。

3=III15=XV12=XII24=XXIV96=LXLVI107=CVII这听起来像是很多额外的工作,但是考虑一下:如果我们可以从一种格式转换到另一种格式,我们应该能够没有错误地转换回来。更具体地说,我们可以使用一个转换的代码来验证另一个转换。如果我们在把它转换回来的时候得到了不同的值,我们知道我们有一个需要解决的问题。

为了解决这个问题,我们将把转换罗马数字的代码放到一个单独的文件(代码模块)中,并构建一个名为Roman_Numerals的类来包含这些方法。在这种情况下,数据是整数到罗马数字的映射。

#Privatedictionaryofromannumerals__roman_dict={'I':1,'IV':4,'V':5,'IX':9,'X':10,'XL':40,'L':50,'XC':90,'C':100,'CD':400,'D':500,'CM':900,'M':1000,}注意字典名称前的两个下划线。这是一种特殊的符号,它将字典标记为类中的私有变量。这是用于信息隐藏的Python方面,是设计对象时推荐使用的技术;总是努力隐藏在类内部使用的数据。

还要注意,我没有使用基本字符及其值,而是使用了其他几个值。我这样做是为了让转换变得更容易(也有一点欺骗)。在本例中,我添加了表示先前转换的一个值的条目,如4(IV)、9(IX)等。这使得转换更容易(也更准确)。

我们还将添加两个方法;convert_to_int(),取一个罗马数字串,转换成整数;和convert_to_roman(),它接受一个整数并将其转换为罗马数字。我没有解释方法中的每一行代码,而是让您阅读代码,看看它是如何工作的。

简单地说,converttointeger方法获取每个字符,并从字典中对这些值求和得到它的值。这里有一个技巧,需要对出现在较高值之前的较低值字符进行特殊处理(例如,IX)。converttoRoman方法稍微容易一些,因为我们只需将该值除以字典中的最高值,直到达到零。清单4-9显示了类模块的代码,它保存在一个名为roman_numerals.py的文件中。

现在让我们看看主要代码。为此,我们只需从代码模块导入新的类,如下所示。这是进口指令的一种稍微不同的形式。在这种情况下,我们告诉Python包含名为Roman_Numerals的文件中的roman_numerals类。

fromroman_numeralsimportRoman_NumeralsNote

如果代码模块在一个子文件夹中,比如说roman,我们将把import语句写成fromromanimportRoman_Numerals,在这里我们使用点符号而不是斜线列出文件夹。

代码的其余部分很简单。我们首先要求用户输入一个有效的罗马数字字符串,然后将其转换为整数,并使用该值转换回罗马数字,打印结果。所以,你可以看到,将类放在一个单独的模块中简化了我们的代码,使它更短,更容易维护。清单4-10显示了保存在一个简单命名为roman.py的文件中的完整主代码。

##MicroPythonfortheIOT##Example:Convertromannumeralsusingaclass##Convertintegerstoromannumerals#Convertromannumeralstointegers##Dr.CharlesBell#fromroman_numeralsimportRoman_Numeralsroman_str=input("Enteravalidromannumeral:")roman_num=Roman_Numerals()#Converttoromannumberalsvalue=roman_num.convert_to_int(roman_str)print("Converttointeger:{0}={1}".format(roman_str,value))#Converttointegernew_str=roman_num.convert_to_roman(value)print("ConverttoRomanNumerals:{0}={1}".format(value,new_str))print("bye!")Listing4-10.ConvertingRomanNumerals如果你按照这一章来做,那么就在你的PC上为这段代码创建一个文件,并把它命名为roman.py。在下一节中,我们将把它复制到我们的MicroPython板上。

在这个例子中,我们将看到如何在Windows10上将代码复制到我们的MicroPython板上。像上一个例子一样,我们将首先在我们的PC上创建文件,连接MicroPython板,复制文件,然后执行它们。

当您在Windows10上连接您的MicroPython板时,该驱动器将显示在文件资源管理器中,如图4-5所示。

图4-5。

MicroPythonboardFlashDriveMounted(Windows10)

如果您还没有创建文件,现在就创建。准备好后,我们会把它们复制到MicroPython板上。我没有使用文件浏览器,而是选择演示如何从控制台(命令提示符)复制文件。打开控制台,然后切换到文件资源管理器中显示的驱动器号。接下来,将文件roman_numerals.py和roman.py复制到驱动器。图4-6显示了一个复制文件的例子。

图4-6。

CopyingtheFiletotheMicroPythonboardFlashDrive(Console)

现在,我们准备好连接到MicroPython板并运行代码。回想一下,连接到电路板的方法之一是在Windows上使用PuTTY。图4-7为油灰控制台。注意,我选择了COM3和串行连接。回想一下,您可以从设备管理器中找到COM端口。准备就绪后,单击打开。

连接完成后,PuTTY将打开REPL控制台。您应该会看到来自MicroPython的欢迎消息,后面是RELP提示符(>>>)。在REPL提示符下,发出以下代码语句。

importroman这段代码导入我们刚刚复制的roman.py文件,当它这样做时,它执行这段代码,如果您还记得的话,这段代码将调用roman_numerals.py代码模块中的代码。同样,发布导入就像我们在PC上从Python控制台运行它一样。

图4-7。

ConnectingwithPuTTy(Windows10)

一旦发出import语句,代码就会执行。去试试吧。从值LXLIV开始,它是罗马数字中的SSS。图4-8显示了输出的样子。

图4-8。

ExecutingtheRomanNumeralsExample

您还可以尝试从终端导入代码并再次执行它,或者只是弹出驱动器,重置板,并重新连接以使用其他值再次运行它。

当您完成执行示例时,记得在拔下驱动器之前关闭终端并弹出闪存驱动器。

除了一些用户友好性(更好使用)之外,这个例子没有太多需要改进的地方。如果您想改进代码或类本身,我建议添加一个名为validate()的新方法,用于验证罗马数字字符串。该方法可以获取一个字符串,并确定它是否包含有效的字符序列。提示:首先,检查字符串是否只包含字典中的字符。

但是,您可以使用该模板构建其他用于转换格式的类。例如,作为练习,您可以创建一个新的类来将整数转换为十六进制甚至八进制。是的,有一些功能可以帮我们做到这一点,但是自己构建它会很有启发性和令人满意。去吧,试一试——创建一个新的类来将整数转换成其他格式。我建议先做一个十六进制到整数的函数,当这个函数工作正常时,创建一个倒数函数来把整数转换成十六进制。

更高级的挑战是重写类以接受构造函数中的字符串(当类变量被创建时),并使用该字符串进行转换,而不是使用convert_to*方法传递字符串或整数。例如,该类可以有一个构造函数和私有成员,如下所示。

__roman_str=""...def__init__(self,name):self.name=name当您创建实例时,您将需要传递该字符串,否则您将会得到一个缺少必需参数的错误。

roman_str=input("Enteravalidromannumeral:")roman_num=Roman_Numerals(roman_str)更多信息如果您需要更深入的Python知识,有几本关于这个主题的优秀书籍。下面我列出了几个我最喜欢的。Python站点上的文档是一个很好的资源:python.org/doc/。

哇哦!那是一次疯狂的旅行,不是吗?我希望这个简短的Python速成课程已经对到目前为止展示的示例程序进行了足够的解释,现在您已经知道它们是如何工作的了。这个速成课程也是理解本书中其他Python例子的基础。

如果您正在学习如何使用IOT项目,但不知道如何使用Python编程,鉴于Python易于理解的语法,学习Python会很有趣。虽然互联网上有很多例子可以使用,但是很少有以这种方式记录的,可以为Python新手提供足够的信息来理解,更不用说开始使用和部署示例了!但至少代码很容易阅读。

本章提供了Python速成课程,涵盖了您在研究大多数较小的示例项目时将会遇到的基本内容。我们发现了Python应用的基本语法和结构,包括构建一个闪烁LED的真实Python应用的演练。通过这个例子,我们学习了如何使用无头应用,包括如何管理一个启动后台应用。

在下一章,我们将深入探究MicroPython编程。我们将看到更多关于在MicroPython板上运行的IOT项目中可用的特殊库。

没错,字典就是对象!元组和列表以及许多其他数据结构也是如此。

现在我们已经很好地掌握了如何用Python和MicroPython编写代码,是时候看看组成固件的支持库了。正如您将看到的,MicroPython中可用的库反映了Python中的库。事实上,固件中的库(有时称为应用编程接口或API或固件API)包含大量Python中的相同库。

对于标准库来说,有一些值得注意的例外,在MicroPython中有一个等价的库,但它已经被重命名,以区别于Python库。在这种情况下,要么通过删除不常用的特性来缩小库的范围,要么通过某些方式进行修改以适应MicroPython平台——所有这些都是为了节省空间(内存)。

还有一些特定于MicroPython的库,以及一些硬件,这些硬件提供的功能在一些通用Python版本中可能有,也可能没有。这些库旨在简化微控制器和硬件的使用。

因此,固件中有三种类型的库:标准的,与Python中的基本相同;专用于MicroPython的;专用于硬件的。还有另一种类型的库,有时称为用户提供的库或简单的自定义库。这些是我们自己创建的库(API),我们可以将它们部署到我们的板上,从而使我们所有的项目都可以使用这些功能。在本章中,我们将会看到所有类型的库的概述。

模块这个词,或者代码模块,有时用来指一个库;然而,模块通常是单个代码文件,而库可能由许多代码文件组成。因此,如果库是一个单独的文件(代码模块),交换名字是可以的。有时用于库的另一个词是包,它意味着多个文件。你可能也会遇到这个术语。

让我们先来看看MicroPython中的那些“标准”Python库。

众所周知,MicroPython是建立在Python之上的。人们做了大量的工作来精简内容,以便大部分Python库可以放在一个芯片上。由此产生的MicroPython固件比你电脑上的Python小得多,但一点也不差。也就是说,MicroPython是Python,因此MicroPython有许多与Python相同的库。

有些人可能称这些库为“内置的”,但更正确的说法是称它们为“标准”库,因为这些库与Python中的库是一样的。更具体地说,它们与Python中的类具有相同的类和相同的功能。因此,你可以在你的PC上写一个脚本并在那里执行它,然后在你的MicroPython板上执行相同的脚本。不错!正如您所猜测的,这在开发一个复杂的项目时非常有帮助。

回想一下,我们在上一章中看到过这种技术的演示。在那里我们看到了开发你的脚本的一部分——那些使用标准库的部分——并在你的PC上调试它们是可能的。也就是说,一旦您让它们正常工作,您就可以进入下一个需要MicroPython库或硬件库的部分。这是因为在我们的PC上开发要容易得多。我们不需要打开主板电源,将它连接到我们的WiFi等。,让它发挥作用。另外,个人电脑的速度要快得多。只是到处都更容易。通过实践这一实践,我们可以通过确保我们项目的“标准”部分正确工作来潜在地为我们自己节省一些挫折。

在这一节中,我们将探索标准的Python库,首先简要概述可用的库,然后详细介绍如何使用一些更常见的库。

MicroPython中的标准库包含一些对象,您可以使用这些对象来执行数学函数、操作编程结构、通过JSON处理可传输的文档(文档存储)、与操作系统和其他系统函数进行交互,甚至按时执行计算。表5-1包含了当前标准MicroPython库的列表。第一列是我们在import语句中使用的名称,第二列是简短的描述,第三列包含指向在线文档的链接。

表5-1。

StandardPythonLibrariesinMicroPython

请注意,这些链接是Pyboard文档的链接,其中大多数也适用于其它电路板。如果有疑问,请访问您的主板的MicroPython文档。

这里介绍的大多数库都是Pyboard和WiPy所共有的。我们还将在下一章看到一些不同之处。

如您所见,有许多库以u开头,表示它们是Python等价库的特殊版本。有趣的是,一些平台可能包含原始的Python库。也就是说,如果您需要访问原始Python版本——如果它存在的话——您仍然可以通过使用原始名称(没有u前缀)来访问它。在这种情况下,MicroPython将尝试通过原始名称查找模块,如果不存在,则默认为MicroPython版本。例如,如果我们想使用原始的io库,我们可以使用importio。但是,如果平台上没有名为io的模块,MicroPython将使用名为uio的MicroPython版本。

import语句的格式允许我们指定目录。所以,如果我们使用importmylibs.io,MicroPython将试图在mylibs文件夹中找到名为io.py的库(代码模块)。这可能会影响到如何使用不带u前缀的模块。如果我们使用了importio并且io.py不是一个代码模块,它将使用io作为一个文件夹的名称,如果它存在,在那个文件夹中查找模块。因此,如果您使用与Python库名称相同的文件夹名称,您可能会遇到麻烦。别这样。

接下来,我们将查看一些更常用的标准库,并查看每个标准库的一些代码示例。但是首先,我们应该讨论两类标准函数。

InteractiveHelpforLibraries

在学习MicroPython中的库时,一个鲜为人知的名为help()的函数会非常有帮助。您可以在REPL会话中使用该函数来获取有关库的信息。下面显示了uos库输出的摘录。

>>>help(uos)objectisoftypemodule__name__--uosuname--chdir--getcwd--listdir--mkdir--请注意,我们看到了所有函数的名称,以及常数(如果有的话)。当学习库和它们包含的内容时,这是一个真正的帮助。试试看!

现在让我们看看一些更常用的标准库的例子。接下来的只是你可以用每个库做什么的一个例子。有关所有功能的完整描述,请参见联机文档。像大多数MicroPython库一样,公共标准库可能是完整Python3(CPython)实现的子集。

本章中的例子旨在运行在MicroPython板上。您可能需要做一些更改才能在您的电脑上运行它。

sys库提供对执行系统的访问,例如常量、变量、命令行选项、流(stdout、stdin、stderr)等等。该库的大多数特性都是常量或列表。可以直接访问这些流,但通常我们使用print()函数,默认情况下它会将数据发送到stdout流。

该库中最常用的函数包括。清单5-1展示了这些变量和exit()函数。

#MicroPythonfortheIOT-Chapter5#Exampleuseofthesyslibraryimportsysprint("Modulesloaded:",sys.modules)sys.path.append("/sd")print("Path:",sys.path)sys.stdout.write("Platform:")sys.stdout.write(sys.platform)sys.stdout.write("\n")sys.stdout.write("Version:")sys.stdout.write(sys.version)sys.stdout.write("\n")sys.exit(1)Listing5-1.Demonstrationofthesyslibraryfeatures注意我们从import语句开始,然后我们可以使用print()函数打印sys库中的常量和变量。我们还将看到如何使用sys.path.append()函数将路径添加到搜索路径中。如果我们在引导驱动器(SD驱动器)上创建自己的目录来放置代码,这将非常有帮助。没有这个添加,import语句将失败,除非代码模块在lib目录中。

在示例的最后,我们将看到如何使用stdout流将内容写入屏幕。注意,您必须提供回车(换行符)命令来将输出推进到新的一行(\n)。print()函数为我们处理了这个问题。下面显示了在MicroPython板上运行这个脚本的输出。

>>>importexamples.sys_exampleModulesloaded:{'examples':,'examples.sys_example':}Path:['','/flash','/flash/lib','/sd']Platform:WiPyVersion:3.4.0请注意,我们看到了预期的数据,并且这个示例运行在一个WiPy模块上。你在import语句中看出了什么奇怪的地方吗?这里,代码被放在一个名为examples的新目录中,然后将代码模块复制到我的引导驱动器上的那个目录中。因此,我们可以使用语句中的目录名来查找代码模块并导入它(examples/sys_examples.py)。如果您想在自己的MicroPython板上运行这段代码,您可以将代码写入一个文件,比如sys_example.py,然后将该文件复制到您的引导驱动器,或者使用ftp来复制该文件。这允许你保持你的引导(闪存)驱动器整洁,并把你的代码放在一个共同的位置。

最后,请注意没有命令行参数。这是因为我们使用了一个import语句。然而,如果我们在PC上运行提供命令行参数的代码,我们会看到它们。下面显示了在PC上运行该脚本的输出。

$python./sys_example.pyModulesloaded:{'builtins':,'sys':,...'/sd']darwinVersion:3.6.0(v3.6.0:41df79263a11,Dec222016,17:23:13)[GCC4.2.1(AppleInc.build5666)(dot3)]奥斯陆大学uio库包含额外的函数来处理流和类似流的对象。有一个名为uio.open()的函数可以用来打开文件(但是大多数人使用名为open()的内置函数)以及用于字节流和字符串流的类。事实上,这些类有类似的文件函数,比如read()、write()、seek()、flush()、close(),以及一个getvalue()函数,它返回包含数据的流缓冲区的内容。让我们看一个例子。

在本例中,我们首先打开一个新的文件进行写入,并将一个字节数组写入该文件。使用的技术是将每个bye的十六进制值传递给write()函数。当您从传感器读取数据时,它们通常是二进制的(一个字节或一串字节)。你用转义符\x表示一个字节,如图所示。

将数据写入文件后,我们通过将1传递给read()函数来一次读取一个字节。然后,我们打印读取的原始for值(从read(1)调用返回的值)、十进制值和十六进制值。清单5-2展示了如何使用uio以二进制模式读取文件。FileIo()类。写入的字节包含一个秘密的字(一个用十六进制值模糊的字)-你能看到它吗?

#MicroPythonfortheIOT-Chapter5#Exampleuseoftheuiolibrary#Note:changeuiotoiotorunthisonyourPC!importuio#Createthebinaryfilefio_out=uio.FileIO('data.bin','wb')fio_out.write("\x5F\x9E\xAE\x09\x3E\x96\x68\x65\x6C\x6C\x6F")fio_out.write("\x00")fio_out.close()#Readthebinaryfileandprintouttheresultsinhexandchar.fio_in=uio.FileIO('data.bin','rb')print("Raw,Dec,Hexfromfile:")byte_val=fio_in.read(1)#readabytewhilebyte_val:print(byte_val,",",ord(byte_val),hex(ord(byte_val)))byte_val=fio_in.read(1)#readabytefio_in.close()Listing5-2.Demonstrationoftheuiolibraryfeatures这就像我们在上一章看到的普通内置函数一样。清单5-3显示了在WiPy上运行时的输出。

>>>importexamples.uio_exampleRaw,Dec,Hexfromfile:b'_',950x5fb'\xc2',1940xc2b'\x9e',1580x9eb'\xc2',1940xc2b'\xae',1740xaeb'\t',90x9b'>',620x3eb'\xc2',1940xc2b'\x96',1500x96b'h',1040x68b'e',1010x65b'l',1080x6cb'l',1080x6cb'o',1110x6fb'\x00',00x0Listing5-3.Demonstrationoftheuiolibraryfeatures(Pyboard)如果您想知道文件是什么样子,您可以使用一个像hexdump这样的工具来打印内容,如下所示。你能看到隐藏的信息吗?

$hexdump-Cdata.bin000000005f9eae093e9668656c6c6f00|_...>.hello.|0000000c乌伊松在IOT项目中处理数据时,ujson库是您可能会经常使用的库之一。它提供了JavaScript对象符号(JSON)文档的编码和解码。这是因为许多可用的IOT服务要么需要要么能够处理JSON文档。因此,您应该考虑养成在JSON中格式化数据的习惯,以便更容易与其他系统集成。该库实现了以下函数,您可以使用这些函数来处理JSON文档。

回想一下,我们在上一章看到了一个JSON文档的简单例子。这个例子是专门为PC编写的,但是做了一点小小的改动就可以在MicroPython板上运行。让我们看一个类似的例子。清单5-4展示了一个使用ujson库的例子。

>>>importexamples.ujson_exampleYearMakeModelColor2015ChevroletSilveradoPullmeoverred2009YamahaR1Blue/Silver1997SeaDooSpeedsterWhite2013TaoJenSicilyBlack终极指标uos库实现了一组用于基本操作系统的函数。如果你为你的电脑写过程序,有些功能你可能会很熟悉。大多数函数允许您处理文件和目录操作。下面列出了几个比较常用的函数。

在这个例子中,我们看到了如何更改工作目录,以便简化我们的导入语句。我们还将看到如何创建一个新目录,重命名它,在新目录中创建一个文件,列出目录,最后清理(删除)更改。清单5-5展示了使用uosl库函数的例子。

您还将看到如何使用更改目录来改进我们使用import语句的方式。由于我们将目录改为examples,importujson_example将首先尝试在当前目录中找到那个模块(库)。这是一个很好的技巧,你可以在你自己的项目中使用,将你的代码部署到你的开发板的一个单独的目录中,这意味着你可以使用它将多个项目部署到你的开发板,将每个项目放在它自己的目录中。

此示例还展示了不同主板的固件差异。这个例子只适用于WiPy和类似的Pycom板。

因为该函数创建了一个24位的随机数,所以我们用24位的最大值除,得到一个介于0和1之间的值。然后我们可以把它乘以一个整数,得到一个范围的值。例如,如果我们想要一个0到6之间的值,我们可以使用get_rand()*6。

现在我们对这段代码的作用有了更多的了解,让我们看看它是如何工作的一个例子。下面显示了在WiPy上运行这段代码的输出。

>>>importexamples.utime_exampleDatetimeValue---------------------------2017-07-1521:32:12014.15202017-07-1521:32:25003.53802017-07-1521:32:28044.82982017-07-1521:32:35099.09812017-07-1521:32:41086.88392017-07-1521:32:47083.83042017-07-1521:32:55083.06702017-07-1521:32:59064.3214Note

如前几章所述,MicroPython有一些元素是特定于单个MicroPython板或硬件的。我们将在下一章讨论这些。

也有不属于任何特定库的内置函数,也有允许我们捕获错误条件的异常。在深入研究一些更常用的标准库之前,让我们先看看这些。

Python附带了许多内置函数:可以直接从脚本中调用而无需导入的函数。有许多类可以用来定义变量、处理数据等等。它们是对象,因此您可以使用它们来包含数据并对数据执行操作(功能)。到目前为止,我们已经在示例中看到了一些。

您应该浏览这个列表,找到您感兴趣的链接,并在开发项目时参考这个列表,以便使用最合适的函数或类。你可能会惊讶有多少是“内置的”但是,请再次检查您选择的MicroPython板的文档,以了解固件中可用的最新功能和类。

表5-2。

MicroPythonBuilt-inFunctionsandClasses

让我们看一个使用其中一个类的例子——字典。下面展示了我们如何使用内置类来创建一个类型为dict()的变量,并在以后使用它。因为该类是内置功能的一部分,所以它可以在Python和MicroPython上工作。

>>>my_addr=dict()>>>print(my_addr){}>>>my_addr['street']='123MainSt'>>>my_addr['city']='Anywhere'>>>my_addr['zip']=90125>>>print(my_addr){'city':'Anywhere','street':'123MainSt','zip':90125}>>>my_addr={'street':'201CherryTreeRoad','city':'Gobye','zip':12345}>>>print(my_addr){'city':'Gobye','street':'201CherryTreeRoad','zip':12345}这里我们看到我们可以使用dictionary类来创建该类型的变量。我们可以在第一个print()调用中看到这一点。回想一下,定义字典的语法是一组花括号。接下来,我们使用访问元素的特殊语法将值添加到字典中。最后,我们使用更熟悉的字典语法给变量重新分配一组新的数据。

现在我们来谈谈一个我们没怎么谈过的话题——异常。异常是Python内置模块的一部分,可能是您想要使用的一项非常重要的编程技术。也许不是马上,但是最终你会体会到在你的代码中使用异常的力量和方便。

Python(和MicroPython)中还有一个强大的机制,我们可以使用它来帮助管理或捕获发生错误时的事件,并针对特定错误执行代码。这种结构称为异常,我们可以捕获的异常(错误)称为异常类。它使用一种称为try语句的特殊语法(也称为子句,因为它需要至少一个其他子句才能形成有效的语句)来帮助我们在错误生成时捕获它们。用raise()函数可以在代码的任何地方生成异常。也就是说,如果出现问题,程序员可以“引发”一个特定的、命名的异常,并且可以使用try语句通过except子句来捕获它。表5-3显示了MicroPython中可用的异常类列表,以及何时(如何)引发异常的简短描述。

表5-3。

MicroPythonExceptionClasses

try语句的语法如下所示。该结构的每个部分称为一个子句。

try_stmt::=try1_stmt|try2_stmttry1_stmt::="try"":"codeblock("except"[expression["as"identifier]]":"codeblock)+["else"":"codeblock]["finally"":"codeblock]try2_stmt::="try"":"codeblock"finally"":"codeblock注意这里有四个子句:try、except、else和finally。try子句是我们放置代码(代码块)的地方——一行或多行代码将包含在异常捕获中。只能有一个try、else和finally,但是可以有任意数量的except子句来命名一个异常类。事实上,except和else一起运行,如果在运行try子句中的任何代码行时检测到异常,它将搜索except子句,当且仅当不满足except子句时,它将执行else子句。finally子句用于在所有异常被处理和执行后执行。还要注意该语句有两个版本:一个包含一个或多个except和可选的一个else和finally,另一个只包含try和finally子句。

让我们看看使用语句来捕获代码中的错误的一种方法。假设您正在从一批传感器中读取数据,如果读取的值超出范围或无效,这些传感器的库(模块)将引发ValueError。如果一个或多个传感器出现故障,您也可能不想要来自任何其他传感器的数据。因此,我们可以使用如下代码“尝试”读取每个传感器,如果有一个ValueError,发出警告并继续,或者如果遇到其他错误,在读取期间将其标记为错误。注意,通常我们不会在这一点上停止程序;相反,我们通常会记录下来并继续下去。研究以下内容,直到你确信例外很酷。

values=[]print("Startsensorread.")try:values.append(read_sensor(pin11))values.append(read_sensor(pin12))values.append(read_sensor(pin13))values.append(read_sensor(pin17))values.append(read_sensor(pin18))exceptValueErroraserr:print("WARNING:Oneormoresensorsvaluedtoreadacorrectvalue.",err)except:print("ERROR:fatalerrorreadingsensors.")finally:print("Sensorreadcomplete.")我们使用异常的另一种方式是当我们想要导入一个模块(库)但不确定它是否存在时。例如,假设有一个名为piano.py的模块,它有一个名为keys()的函数,您希望导入该模块,但是该模块可能在系统上,也可能不在系统上。在这种情况下,我们可以使用其他代码来创建我们自己版本的keys()。为了测试模块是否可以导入,我们可以将导入放在try块中,如下所示。然后,我们可以检测导入是否失败,并采取适当的措施。

#Trytoimportthekeys()functionfrompiano.Ifnotpresent,#useasimulatedversionofthekeys()function.try:frompianoimportkeysexceptImportErroraserr:print("WARNING:",err)defkeys():return(['A','B','C','D','E','F','G'])print("Keys:",keys())如果我们像这样添加代码,而模块不存在,我们不仅可以用警告消息来响应,还可以定义我们自己的函数在模块不存在时使用。

raiseValueError("ERROR:thevaluereadfromthesensor({0})isnotinrange.".format(val_read))然后,您可以使用try语句来捕获这种情况,因为您知道这是可能的,并且您的代码可以绕过它。例如,如果您正在读取数据,您可以选择跳过读取,继续循环。然而,如果在运行您的代码时遇到这个异常,并且没有try语句,您可能会得到一个类似下面的错误,尽管它是致命的,但仍然可以提供信息。

Traceback(mostrecentcalllast):File"",line1,inValueError:ERROR:thevaluereadfromthesensor(-12)isnotinrange.您可以使用这里所示的类似技术来使您的MicroPython代码更加健壮和容错。更好的是,您可以编写代码来预测错误,并以优雅、可控的方式对错误做出反应。

也有专门为MicroPython系统构建的库。这些库旨在帮助在硬件上使用MicroPython。像内置库一样,有一些MicroPython库适用于一种或另一种板,而那些库又因板而异。也就是说,库之间存在细微的差异,这使得它们不能在多个板上工作。有关可用的MicroPython库的完整列表,请始终查阅您的主板固件文档。

MicroPython库提供了特定于Python的MicroPython实现的功能。有些函数库具有直接处理硬件、MicroPython系统和网络的功能。在接下来的章节中,我们将会看到这些库的一些特性的例子。表5-4包含了大多数主板通用的当前MicroPython库的列表。第一列是我们在import语句中使用的名称,第二列是简短的描述,第三列包含指向在线文档的链接。

表5-4。

MicroPython-SpecificLibraries

接下来,我们将查看一些更常见的MicroPython库,并查看每个库的一些代码示例。

)。ThesemodulesarespecifictoPycomdevicesandmaybeslightlydifferentfromothervariantsofMicroPython(forexample,fornon-Pycomdevices).Themodulesincludemodulesthatsupportaccessingtheunderlyinghardware,suchasI2C,SPI,WLAN,Bluetooth,etc.

使用低级机库时要小心,避免改变甚至潜在地损坏主板的性能或配置。

由于机器库是一个低级的硬件抽象,我们在本章中不会深入讨论它。相反,我们将在下一章看到更多的硬件特性。同时,让我们通过向您展示如何通过help函数发现一个库包含什么来探索另一个有趣的MicroPython知识宝库。例如,清单5-8显示了当我们在连接到扩展板的WiPy上发出语句help(machine)时,通过REPL控制台报告的内容的摘录。help()函数将显示库中所有可用的函数和常量。虽然它不能代替详细的解释,甚至不能代替完整的例子,但在第一次遇到一个库时,它会很有用。

>>>importmachine>>>help(machine)objectisoftypemodule__name__--umachinemem8--<8-bitmemory>mem16--<16-bitmemory>mem32--<32-bitmemory>reset--...Pin--UART--SPI--I2C--PWM--ADC--DAC--SD--Timer--RTC--WDT--PWRON_RESET--0HARD_RESET--1WDT_RESET--2...Listing5-8.ThemachineLibraryHelp注意这里有很多信息!这给我们最多的是我们可以用来与硬件交互的类的列表。这里我们看到有UART、SPI、I2C、PWM等类。让我们对比一下Pyboard的相同输出。下面显示了Pyboard类的相同摘录。

Pin--Signal--I2C--SPI--UART--WDT--注意有几个不见了。我们将在下一章探讨这些差异。在你第一次使用的板上检查帮助(机器)的输出总是一个好主意。它可以让你省去很多为不存在的硬件寻找支持的麻烦!

Pyboard上的network库用于安装网络驱动程序(与网络抽象交互的类)和配置设置。虽然讨论的其他库在不同的电路板上略有不同,但是这个库在Pyboard和WiPy(以及其他)电路板上是非常不同的。事实上,WiPy有相同的库,但是包含不同的类。

这主要是因为WiPy内置了WiFi,它有自己的网络工作机制。回想一下,我们在第三章中看到了Pyboard的网络库,我们将在后面的示例章节中再次看到它的使用。也就是说,我们了解到Pyboard(以及类似的)板只有两个网络驱动程序:CC3K和WINNET5K。WiPynetwork库包含三个类:WLAN、Bluetooth和Server。还记得我们在第三章中看到的WLAN类示例。

我们将在下一章看到更多关于网络类和有趣的蓝牙类的内容。

构建自己的定制库似乎是一项艰巨的任务,但事实并非如此。可能有点挑战的是弄清楚你想要这个库做什么,并使这个库抽象(足够)到可以被任何脚本使用。编程的规则和最佳实践在这里发挥了作用,比如数据抽象、API不变性等。

我们在上一章讨论了创建你自己的模块。在这一节中,我们将看看如何将我们的代码模块组织成一个库(包),我们可以将它部署(复制)到我们的MicroPython板上,并在我们所有的程序中使用。这个例子虽然简单,但却是一个完整的例子,如果您决定创建自己的定制库,可以将它用作模板。

对于这个例子,我们将创建一个包含两个模块的库:一个包含为传感器执行值转换的代码,另一个包含我们项目的帮助函数——我们希望重用的通用函数。我们将这个库命名为my_helper。它将包含两个代码模块:sensor_convert.py和helper_functions.py。回想一下,我们还需要一个__init__.py文件来帮助MicroPython正确地导入函数,但是我们稍后会回到这个问题上。让我们看看第一个代码模块。

我们将文件放在名为my_helper(与库名相同)的目录中。这是典型的约定,您可以输入您想要的任何名称,但是您必须记住它,因为我们将在代码中导入库时使用该名称。图5-1显示了文件的布局示例。这张照片是我的Pyboard闪存盘拍的。

图5-1。

Directory/FileLayoutforthemy_helperSampleLibraryonPyboard

请注意,我们将包含这三个文件的目录移动(复制)到了我的Pyboard中。如果您将文件复制到WiPy,您将需要使用清单5-9中的命令来使用ftp。还要注意,我们在连接到WiPy时创建了目录,并且我们位于包含我们想要复制的文件的目录中。

如果您使用Linux,您可能需要为ftp命令添加-p选项(被动)。

#MicroPythonfortheIOT-Chapter5#Examplemoduleforthemy_helperlibrary#Thismodulecontainshelperfunctionsforgeneraluse.try:importpyb_PYBOARD=TrueexceptImportError:importmachine_PYBOARD=False#Getarandomnumberfrom0-1froma22bitrandomvalue#ifrunontheWiPy,return0-1froma23bitrandom#valueifthePyboardisused.defget_rand():if_PYBOARD:returnpyb.rng()/(2**30-1)returnmachine.rng()/(2**24-1)#Formatthetime(epoch)forabetterviewdefformat_time(tm_data):#Useaspecialshortcuttounpacktuple:*tm_datareturn"{0}-{1:0>2}-{2:0>2}{3:0>2}:{4:0>2}:{5:0>2}".format(*tm_data)Listing5-10.Thehelper_functions.pymodule第二个代码模块名为sensor_convert.py,它包含的函数有助于将传感器原始值转换为字符串,以便进行定性比较。例如,函数get_moisture_level()根据原始值的阈值返回一个字符串。传感器的数据手册将定义这些值,除非能够校准传感器,否则应在代码中使用这些值。在这种情况下,如果该值小于下限,则土壤是干燥的;如果大于上限,土壤是湿的。清单5-11显示了模块的完整代码。

#MicroPythonfortheIOT-Chapter5#Examplemoduleforthemy_helperlibrary#Thisfunctionconvertsvaluesreadfromthesensortoa#stringforuseinqualifyingthemoisturelevelread.#Constants-adjustto"tune"yoursensor_UPPER_BOUND=400_LOWER_BOUND=250defget_moisture_level(raw_value):ifraw_value<=_LOWER_BOUND:return("dry")elifraw_value>=_UPPER_BOUND:return("wet")return("ok")Listing5-11.Thesensor_convert.pymodule现在让我们检查一下__init__.py文件。这是一个非常神秘的文件,开发人员经常对此感到困惑。如果您的库目录中没有包含,您应该手动导入您想要使用的内容。也就是用类似import.my_helper.helper_functions的东西。但是有了这个文件,你可以通过一个简单的importmy_helper语句一次性导入所有文件。我们来看一下__init__.py文件。下面显示了该文件的内容。

#Metadata__name__="Chuck'sPythonHelperLibrary"__all__=['format_time','get_rand','get_moisture_level']#Library-levelimportsfrommy_helper.helper_functionsimportformat_time,get_randfrommy_helper.sensor_convertimportget_moisture_level请注意,在第一行,我们使用了一个特殊的常量来设置库的名称。下一个常量限制了import语句的*(all)选项将导入的内容。因为它列出了所有的方法,所以这只是一个练习,但却是一个很好的习惯,特别是当你的库和模块包含许多你不想让其他人使用的内部函数时。最后两行显示了用于从模块导入函数的import语句,使导入库的任何人都可以使用这些函数。下面给出了一个简短的例子,说明如何做到这一点以及如何使用别名。这里,我们用myh作为my_helper的别名。

>>>importmy_helperasmyh>>>myh.get_rand()0.2830396我们现在可以通过别名访问(使用)所有三个函数,如下所示。

r_int=myh.get_rand()*10print(myh.format_time(value))print(myh.get_moisture_level(sensor_raw))如果您想知道,帮助功能也可以在这个自定义库上工作!

>>>importmy_helper>>>help(my_helper)objectisoftypemodule__path__--my_helperhelper_functions--__name__--Chuck'sPythonHelperLibrarysensor_convert--get_rand--format_time--__file__--my_helper/__init__.py__all__--['format_time','get_rand','get_moisture_level']get_moisture_level--一旦您开始尝试MicroPython并完成了几个项目,您就可以开始构建一组不时重用的函数。这些是放入图书馆的完美候选。如果这些函数不是一个更大的类或对象的一部分,那就再好不过了。只要你把它们组织成功能相似的模块,你就不需要担心把它们变成类。另一方面,如果涉及到数据或者函数集作用于一组数据,那么您应该考虑将函数集作为一个类,以便更容易使用和更高质量的代码。

Wait,WhataboutCircuitpython

使用硬件是MicroPython与其他主板最大的不同。这是因为这些板非常不同。有些有网络,有些没有。有些芯片的板载特性比其他芯片更多,有些芯片的内存更少,GPIO引脚甚至更少。因此,当涉及到硬件抽象层时,不同主板的固件会有所不同也就不足为奇了。

在这一章中,我们探讨了一些更常用的内置库和MicroPython库,它们通常适用于所有的主板。在下一章中,我们将更深入地探讨MicroPython中的底层库和硬件支持,包括我们可以使用的特定于主板的库,如Pyboard、WiPy等。

对于所有支持的通用Python语言和许多内置函数,MicroPython固件在最基本的功能上是相同的。然而,MicroPython固件中的一些库在不同的主板上有一些细微的差别。在某些情况下,可用的库或类比其他的多,或者类的组织方式不同,但大多数都以某种形式实现了相同的核心库。在较低级别的硬件抽象层,情况就不一样了。这仅仅是因为一个主板供应商可能实现不同的硬件。在某些情况下,该板具有其它板上不存在的特性。例如,WiPy有WiFi和蓝牙,而Pyboard两者都没有。

在这一章中,我们将看几个MicroPython中低级硬件支持的例子。我们将了解特定于主板的库以及一些低级别的专用库,如蓝牙、SPI、I2C等库。我们还将看到一些简短的代码示例来说明特定于主板的库的功能。其中一些将是简短的代码片段,而不是您可以自己实现的实际项目。

但是,有几个是完整的项目,您可能想探索一下,但是大多数都没有深入的解释,只是作为例子,而不是详细的演练。此外,请记住,它们可能需要特定的分线板和MicroPython板以及其他附件来实现。同样,这些只是为了演示的目的。我们将在后面的章节中看到更完整的、循序渐进的例子,包括如何组装硬件。

为了保持简洁,我们将探索Pyboard和WiPy上不同的板专用库。其他电路板可能会有进一步的不同,但您需要查看供应商文档,以了解它们之间的差异。本章将为你提供发现这些差异的洞察力。我们还将重温使用分线板来演示前几章中讨论的一些库和硬件协议和技术。

让我们先来看一下Pyboard和WiPy的板专用库。

我们已经看到Pyboard和WiPy的机器库中存在差异。但是还有其他的不同:特定于每块板的库,因此只能用于同一块板的另一块板上。这些包括具有用于低级硬件的函数和类的库、特定于电路板的函数和常数等。

第一次使用新的MicroPython板时,您应该记住的一件事是,硬件级别的固件很可能与您使用的上一个MicroPython板不同。当您查看BBCmicro:bit、CircuitPlayground、ESP8266等板的固件端口时,情况尤其如此。

请务必查阅您的主板文档,以获得主板专用库的完整功能、用途和更多示例。

特定于Pyboard的库是独一无二的,因为它们包含对特定于供应商的皮肤的支持。正如我们在第三章中了解到的,Pyboard有几种皮肤可供使用。幸运的是,固件中的Pyboard特定类直接支持所有的皮肤。这包括音频皮肤、LCD等。

下面几节将更详细地介绍这些库,并包括一些常见的功能示例。有关每个库的内容和功能的完整详细信息,请参见指定的文档。

现在让我们看几个简短的例子。前两个展示了复位函数的例子,后两个是杂项函数,最后一个展示了如何使用其中一个类与板上的硬件进行交互。

您可以使用pyb.hard_reset()功能执行硬复位,如下所示。如果您在REPL控制台中输入此语句,板将以与您按下重置按钮相同的方式重置。如果您需要从严重错误或硬件故障中中止,这可能很方便。

MicroPythonv1.9.1-154-g4d55d880on2017-07-11;PYBv1.1withSTM32F405RGType"help()"formoreinformation.>>>importpyb>>>pyb.hard_reset()Note

hard_reset()功能可能会导致您的电脑抱怨SD卡在没有停止文件系统的情况下被弹出,因此请谨慎使用该功能。

pyb.bootloader()功能将板卡置于引导加载模式。回想一下第三章中的,要安装固件,必须先关闭主板电源,安装跳线,然后打开主板电源,才能加载固件。通过此功能,您可以从REPL控制台执行此操作。也就是说,如果你能拿到REPL控制台的话。如果您的主板损坏或固件损坏,您仍然可以执行跳线过程,将主板置于引导加载程序模式以加载新固件。

pyb.info()函数被用作信息转储。它打印出大量关于电路板的底层信息,包括硬件地址等等。除非您正在编写低级驱动程序或类似的东西,否则大多数都没有用,但是您可以将True传递给该函数,并以GC内存布局转储的形式获得更多信息,如下面的摘录所示。如果您对这些数据感到好奇,请参阅在线参考手册中的Pyboard硬件规格部分或forum.micropython.org论坛。

>>>pyb.info(True)...LFSfree:52224bytesGCmemorylayout;from20003e40:00000:h=hhhhhBShh==Sh=hhhh==h==Bh=hBh=hBhThShh=h==hh=BhhhBhBh=hh=hBh=h00400:=hTh==Shhhh==B........h=....................................h===00800:====h===========================================================00c00:==============..................................................(92linesallfree)18000:............................pyb.main(filename)函数是最有用的函数之一。它设置boot.py完成后运行的主脚本的文件名。您可以将该功能与几个可选的main.py代码模块结合使用。如果您想实现一些自动启动和运行的项目,这可能是一个有用的工具。您可以使用这个函数告诉Pyboard从一个替代文件开始,而不是手动进入boot.py并改变它。这样,你就可以有“配置文件”来改变董事会的行为。酷。只需用有效的代码模块路径和名称(作为字符串)调用函数。在您更改之前,此设置一直有效。

您应该只从boot.py内部调用该函数。

pyb库也为支持的硬件主机提供了低级硬件类。注意,我们在机器库中看到了WiPy的一组类似的类。在Pyboard上,它们在pyb库中。表6-1显示了可用硬件类别的列表。如您所见,它支持led、LCD(我们将在后面的章节中看到)、GPIO引脚等等。记住类名是区分大小写的。

表6-1。

PyboardLow-LevelHardwareClasses(pyblibrary)

现在,让我们来看看其中的一个。我们将使用加速度计对电路板进行简单测试。也就是说,我们将编写一些代码,您可以使用这些代码来运行和检测Pyboard何时在三个方向上发生了物理移动。下面显示了可用于Accel类的方法。

现在,让我们看一些代码!下面显示了如何使用加速度计获得X、Y和Z轴的原始值。值的范围从-32到32。只要稍加观察,我们就可以推断出哪些值表示棋盘在每个方向上移动了多远。尝试下面的代码,轻轻地拿起棋盘,通过向不同的方向旋转,在三维空间内移动它。慢慢地做,然后稍微快一点,注意数值是如何变化的。然后,将板放回原来的位置并观察。您可以按CTRL-C停止循环。

importpybfrompybimportAccelacc=Accel()print("PressCTRL-Ctostop.")whileTrue:pyb.delay(500)#Shortdelaybeforesamplingprint("X={0:03}Y={1:03}Z={2:03}".format(acc.x(),acc.y(),acc.z()))UseSoftResettoRefreshImport

如果您像我一样,喜欢在PC上编写MicroPython代码并在那里进行测试,然后将其移动到板上进行更多的开发和测试,那么您可能会感到困惑,因为每次您复制想要包含和测试的代码模块或库的新版本时,都必须重置板。当连接到REPL控制台时,您可以使用CTRL+D键进行软复位,而不是关闭电路板电源或进行硬复位。这将执行软重启,允许您再次运行导入。事实上,您必须再次发出import——它刚刚重启了!最好的部分是,你将不必重新连接你的董事会或REPL控制台!试试看。

下面显示了在REPL控制台中运行时的输出摘录。

X=002Y=000Z=021X=000Y=-01Z=023X=005Y=020Z=000X=-05Y=016Z=-11X=-11Y=-13Z=014X=022Y=-04Z=-05X=-03Y=019Z=012...如果你喜欢挑战,你可以试着写一个脚本来使用加速度计检测电路板何时被颠倒。提示:在实验和编写代码时观察X、Y和Z的原始值,以寻找特定的范围。

在Pyboard上,加速度计使用I2C(1),因此您不能同时使用加速度计和I2C(1)。I2C必须使用不同的引脚才能同时使用加速度计和I2C设备。

这些例子只是这个库中可用内容的一小部分。如果您正在使用Pyboard,您应该首先查看这个库,以满足您所有的低级硬件和特定于电路板的控制需求。我们将在后面的章节中看到一些可用类的例子以及它们的用法。

Pyboard的制造商制作了一个有趣的皮肤,到目前为止,在提供MicroPython板的供应商中是独一无二的。这种皮肤称为lcd160cr因此,LCD是一个触摸感应LCD屏幕,您可以直接将其连接到Pyboard,为您提供一个非常漂亮的触摸屏,您可以用它来制作一个现代化的用户界面。想想看——你可以制作一个MicroPython手表,天气传感器,或者任何需要用户界面的东西。

LCD可以安装在两个位置之一,称为位置X和y。然后在构造函数中使用这些值。图6-1显示了在X和Y位置(从左到右显示)连接LCD和Pyboard的位置。

图6-1。

PositionsforMountingtheLCD(Pyboard)

位置差异指的是液晶屏在主板上的方向。在X位置,LCD安装在X范围的GPIO引脚上,在Y位置,它安装在Y范围的GPIO引脚上。请注意,在Y位置,LCD必须旋转180度,如图所示。

现在,让我们来看一个使用LCD的例子。在这个例子中,我们将创建一个简单的用户界面来检测屏幕四角的触摸。为了让它更有趣,我们还会在每次触摸时打开不同的LED。这将给你一个视觉反馈,告诉你已经触摸了屏幕。

这个例子是本书中较长的例子之一,但不难理解。让我们从代码的高级演练开始。

我们应该做的第一件事是编写import语句,这样我们就可以检测代码何时在Pyboard(或另一个板)上运行。如果它不是Pyboard,我们应该中止,因为其他板没有我们需要的库(lcd160cr)。如果您在自己的代码中采用这种技术,您可以避免奇怪的导入异常和其他可能不清楚程序失败原因的问题。另外,这是很好的编程。下面显示了用于检测所需库是否存在的代码,以及如何在其中一个库无法导入时退出程序。

#First,makesurethisisrunningonaPyboardtry:importpybexceptImportError:print("ERROR:notonaPyboard!")sys.exit(-1)#Next,makesuretheLCDskinlibraryinthefirmwaretry:importlcd160crexceptImportError:print("ERROR:LCD160CRlibrarymissing!")sys.exit(-1)接下来,我们将编写一个函数来打开LED。这是一个如何编写可重用代码的例子。也就是说,我们不想重复的重复同样的代码。在这种情况下,我们可以按颜色打开特定的LED。为了帮助我们做到这一点,我们可以编写一个函数来检索基于颜色的LED(1=红色,2=绿色,等等)。).下面显示了helper函数。

defled_color(num):ifnum==1:return"red"elifnum==2:return"green"elifnum==3:return"orange"else:return"blue"以下显示了打开LED的可重复使用的功能。如您所见,我们首先关闭旧的LED,然后打开新的(选定的)LED。

defturn_on_led(num,led_last):#turnlastLEDoffled=pyb.LED(led_last)led.off()led=pyb.LED(num)led.on()sys.stdout.write("Turningoff")sys.stdout.write(led_color(led_last))sys.stdout.write("-Turningon")sys.stdout.write(led_color(num))sys.stdout.write("\n")接下来,我们可以编写代码来读取LCD上被触摸的位置,并根据触摸发生的位置,打开该角的LED。我们将用红色表示左上角,绿色表示右上角,橙色表示右下角,蓝色表示右下角。

由于pyb.LED()用数字指代发光二极管,因此使用数字来简化代码。精明的读者可能会发现一种通过枚举甚至使用常量来改进代码的方法。如果你看到这些潜在的改进,请随意把这些改进作为练习。清单6-1展示了这个例子的完整代码。

>>>importpyboard_lcdWelcometothetouchscreendemo!TouchthescreeninthecornerstochangetheLEDlit.Touchthecentertoexit.Turningoffred-TurningongreenTurningoffgreen-TurningonredTurningoffred-TurningonredTurningoffred-TurningonorangeTurningofforange-TurningongreenTurningoffgreen-TurningongreenTurningoffgreen-TurningonorangeTurningofforange-TurningonblueTurningoffblue-TurningonredThanksforplaying!Tip

液晶屏上有一层薄薄的保护膜。您需要删除它,并使用手写笔或类似的软指针来测试脚本。如果你的手指很大,触摸指定的小区域可能会有一些困难。

特定于WiPy的库是独一无二的,因为它们支持完整的Pycom板,包括扩展板、PySense和PyTrackshields。

还有一些特定于Pyboard本身的库,以pycom库的形式出现,其中包括支持更改心跳LED,包括更改颜色。AES库包含一个保护数据的有趣特性——AES加密。我们将更详细地探索这个库。此外,回想一下,WiPy固件包含I2C、SPI等底层硬件。与Pyboard相反,pyboard在pyb库中有这些。

下面几节将更详细地介绍这些库,包括一些常见的功能示例。有关每个库的内容和功能的完整详细信息,请参见指定的文档。

pycom库具有控制Pycom设备特定功能的功能,例如心跳RGBLED。事实上,您可以改变LED的颜色,打开或关闭它,并获得LED的当前状态。虽然这看起来非常初级,但您可以使用心跳LED来传达状态信息。例如,您可以更改颜色来指示不同的操作(或状态),如从传感器读取、保存数据、传达错误等。

让我们看一个使用心跳LED设置状态的简短示例。请注意,LED颜色由代表红、绿、蓝(RGB)的24位值定义,其中红色由最高的8位表示,绿色接下来是8位,蓝色是最低的8位。我们通常用十六进制表示这些值。1比如亮白色是0xFFFFFF,0xFFFF00是黄色,0x00FFFF是海绿色。

在本例中,我们将使用一组辅助函数和一个测试循环来处理心跳LED。注意,要打开(使用)心跳LED,必须先用heartbeat(False)关闭心跳内部功能。清单6-2展示了使用心跳LED显示状态的示例代码。

#MicroPythonfortheIOT-Chapter6#ExampleforworkingwiththehearbeatLEDasa#status/stateindicator#importutime#First,makesurethisisrunningonaPyboardtry:importpycomexceptImportError:print("ERROR:notonaWiPy(orPycom)board!")sys.exit(-1)#State/statusenumeration_STATES={'ERROR':0xFF0000,#Brightred'READING':0x00FF00,#Green'WRITING':0x0000FF,#Blue'OK':0xFF33FF,#Pinkish}#Clearthestate(returntonormaloperation)defclear_status():pycom.heartbeat(True)#Showstate/statuswiththeheatbeatLEDdefshow_status(state):pycom.heartbeat(False)pycom.rgbled(state)#Now,demonstratethestatechangesforstatein_STATES.keys():show_status(_STATES[state])utime.sleep(3)#Returnheartbeattonormalclear_status()Listing6-2.UsingtheHeartbeatLEDforStatus/State(WiPy)如果您运行这段代码,您会注意到LED会呈现一些非常明亮的颜色。所以,不要直接盯着领导!你可以尝试使用一些更微妙的颜色值来降低亮度。

WiPy有一个名为crypto的特殊库,它有支持AES(高级加密标准)的AES库,AES是由NIST标准化的对称分组密码。虽然您可能不需要这个特性,但是对于我们这些关心保护敏感数据的人来说,这可能是一个值得考虑的漂亮特性。

例如,您可能希望通过互联网将数据传输到另一个系统。如果您没有用加密来保护数据,那么如果数据以某种方式被利用,解密数据并不太困难。如果您加密数据(并保护密钥!),你可以让人们更难看到数据。

AES库提供了几个常量来控制加密模式和两个函数:一个用来加密,另一个用来解密。您需要提供一个密钥,用于由常量AES.MODE_ECB定义的最简单加密形式的加密算法,该常量表示电子代码簿。其他表单可能需要附加参数。

有一个警告。您加密的数据必须是16字节块的倍数。注意我们是如何使用空格使字符串变成16字节的。因此,如果您要加密从传感器或网络上的其他节点创建或读取的数据,需要确保使用16字节倍数的块进行加密。

让我们看一个例子。在本例中,我们将创建一个包含加密数据的文件,以展示如何保护您的数据,以便保存或发送到另一个节点(计算机)。然后,我们将打开文件并读取解密数据,这样我们就可以展示如何解密加密数据。我们将使用字符串使它更容易,但你也可以加密二进制数据。清单6-3显示了使用AES加密保护数据的示例代码。

当这个程序运行时,它会在WiPy的闪存驱动器上创建一个名为secret_log.txt的文件。如果我们用十六进制转储实用程序检查这个文件,我们可以看到它确实被加密了(我们无法读取数据,因为它被打乱了)。下面显示了文件在十六进制转储中的样子。

$hexdump-Csecret_log.txt00000000c102978774284f4ede838d8d494af893|....t(ON....IJ..|00000010c9e7f800f3bae2f87c6eca41130c0935|........|n.A...5|00000020a683f6fc2cdebaebf63aaffec0b5c6ee|....,....:......|000000307a3b3a3690dadc363d617e3175a3ca96|z;:6...6=a~1u...|00000040该代码还打印出从文件中读取的字符串,以确认其工作正常。如果您通过REPL控制台运行该程序,您应该会看到以下输出。

>>>importwipy_encryption1:apples:2.52:oranges:13:peaches:34:grapes:21既然我们已经看到了几个板专用库的例子,让我们来看看几个直接使用硬件特性的例子。我们在前面的例子中已经看到了一些,但是没有详细解释。下面几节将深入探讨一些使用Pyboard和WiPy的更常见的低级硬件访问。

使用底层硬件(有些人会说是“硬件”或“设备”)是使用MicroPython的所有动作和焦点(以及相对难度)发生的地方。MicroPython和分线板供应商在让事情变得更容易方面做得非常出色,但是在解释方面还有改进的空间。

也就是说,当提供使用低级硬件的例子时,在线文档有点简洁。部分原因是这些例子通常需要额外的特定硬件。例如,要使用I2C接口,您需要一个支持I2C的分线板。因此,在线示例仅提供了最基本的示例和解释。

然而,这并不意味着缺少底层硬件的其他文档。事实上,该文档提供了您可以使用的所有类和函数的极好概述。接下来的挑战是利用这个概述并应用它来解决你的编程需求,这也是本书的目的之一!

除了可能存在的车载传感器或其他组件,如led、RTC、按钮等。大多数低级通信将通过I2C、单线、模拟或数字引脚,甚至SPI接口。I2C和SPI接口是您在使用硬件时可能会遇到最大困难的接口。这是因为您使用的每个设备(分线板)都需要一个非常具体的协议。也就是说,该设备可能需要特殊的序列来触发该设备的不同于其他分支板的传感器或特征。因此,使用I2C或SPI(以及其他一些)类型的设备可能是一个挑战,要弄清楚究竟如何与它们“交谈”。

幸运的是,有一小部分人正在制作帮助我们使用这些设备的类和函数集,但是人数在不断增加。这些称为库或更常见的驱动程序,以一个或多个代码模块的形式出现,您可以下载、复制到您的主板,并将功能导入到您的程序中。驱动程序的开发者已经为你做了所有繁重的工作,让你很容易使用这个设备。

因此,对于大多数刚开始使用MicroPython的人来说,他们希望使用某些传感器、设备、分线板等。,您应该将您计划使用的内容限制在那些您可以找到与之一起工作的驱动程序的范围内。那么,如何为你的设备找到一个驱动程序呢?有几个地方可以看看。

首先,您应该查看MicroPython上的论坛和文档。在这种情况下,不要只局限于那些迎合你的选择的论坛。相反,看看他们所有人!很有可能,您可以找到一个只需稍加修改就能适应的库。除了下载并复制到板上,大多数都可以轻松使用。下面列出了在寻找驱动程序时应该经常访问的论坛和文档。

注意最后一项。如果您搜索MicroPython,您会发现许多精彩的(完整的)教程,包括越来越多的硬件主题。

第二,使用你最喜欢的互联网搜索引擎,搜索硬件的例子。在搜索中使用硬件设备的名称和“MicroPython”。如果设备是新的,你可能找不到任何搜索条件。一定要探索其他搜索词。

一旦你找到了司机,乐趣就开始了!您应该下载驱动程序,并将其复制到您的主板上进行测试。请务必遵循驱动程序附带的示例,以避免以意外的方式使用驱动程序。

让我们看两个低级的例子:使用实时时钟和通过中断回调。我们将从实时时钟(RTC)开始。这些只是可用的一小部分样本,代表了你在本书和大多数小型IOT项目中需要用到的最常见的东西。

Pyboard在机器库中提供了RTC()类,但它与WiPy固件中的略有不同。您可以修改这个示例,作为在Pyboard上使用的练习。

>>>importwipy_ntpConnected!Timebeforesync:(1970,1,1,0,0,36,560190,None)waitingforNTPserver...waitingforNTPserver...waitingforNTPserver...Timeaftersync:(2017,7,13,16,19,51,402976,None)这个例子非常有帮助,在某些情况下,在读取数据以进行后续分析时是必须的。知道数据何时保存或传感器何时被读取通常是至关重要的。您可能希望将此代码标记为以后在您的IOT项目中使用。

我们可以使用具有板载时钟的专用RTC模块,以便在离线操作或板断电期间保持时钟同步。我们将在第八章中看到如何做到这一点。

现在,让我们来看看回调,这是一种可以用来处理硬件中断的编程机制。

如果你想执行一些代码来响应传感器或用户输入,你会怎么做?利用我们到目前为止所学的知识,我们可以编写一个循环程序来轮询传感器或用户可操作的设备(如按钮),并在被触发时执行代码。这种轮询技术是可行的,但是有一种更好的结构叫做回调。

回调的使用允许我们继续执行代码来完成诸如读取传感器、显示数据等工作。,当事件(中断)发生时,MicroPython将执行回调函数,然后返回执行我们的代码。这是通过将回调函数绑定到中断上来实现的。开关类有一个为按钮按压定义的中断。也就是说,当按钮被按下时,回调被触发(执行)。

使用开关回调有一些注意事项。首先,switch回调函数不能带参数,因此您不能定义回调函数并向它传递任何数据。事实上,回调函数不允许创建数据。例如,您不能创建字典、元组等。,在函数内部。虽然回调函数可以访问全局变量,但如果使用状态变量,它们可能会引发异常。最后,您可以关闭(断开)回拨。例如,您可以用switch.callback(none)断开交换机的回拨。

现在,让我们看一个例子。在本例中,我们希望创建一个回调函数来循环显示板上的led。每按一次按钮,另一个LED就会亮起,直到我们循环所有的LED,然后重新开始。这意味着我们需要保存最后点亮的LED或LED的状态。为此,我们可以使用一个具有局部变量的类,我们可以在回调函数中访问这个局部变量。

设置回调很容易。我们只是调用开关的回调函数,并传入函数名。我们通过类的构造函数来实现这一点。也就是说,当我们创建一个类的新实例时,我们传入pyb.Switch对象,然后调用该对象上的回调函数,传入类函数的名称。

让我们看看代码,你会看到这是如何工作的。清单6-5显示了Pyboard回调示例的完整代码。

如果您正在使用Pyboard,请对这个示例进行测试。正如您将看到的,使用回调是非常强大的。

CommunicationViaBluetoothLowEnergy(BLE)

现在,让我们看看如何使用I2C和SPI协议与分线板通信。

我们在第三章简要介绍了分线板,其中我们看到了一个使用Arduino屏蔽将Pyboard连接到无线网络的有趣示例。这只是分线板的一个例子。您还可以找到承载传感器和其他设备的分线板,从而简化您的IOT项目。使用这些分线板的诀窍是找到正确的、有效的驱动程序。

搜索一个驱动程序可能是一项单调乏味的工作,这需要一些耐心,并且可能需要在论坛上使用不同的搜索词进行多次搜索,例如“micropythonBME280”一旦你找到一个驱动程序,你可以通过查看包含的例子快速判断它是否是一个可行的选择。如前所述,如果没有例子或者例子与你在本书或在线文档中看到的不相似,就不要使用它。

让我们来看两个分线板示例:一个使用I2C协议,另一个使用SPI协议。

OnlineExamples

I2C协议可能是你在分组讨论板上看到的最常见的协议。我们在前面的章节中遇到过这个术语几次,因此我们只知道它是一个通信协议。I2C是一种快速数字协议,使用两条线(加上电源和地)从电路(或设备)读取数据。该协议旨在允许多个设备(从设备)与一个主设备(MicroPython板)一起使用。因此,每个I2C分线板都有自己的地址或标识,您将在驱动程序中使用这些地址或标识来连接设备并与之通信。

如果您没有或不想购买AdafruitRGB传感器分线板(虽然不贵),也不用担心。此示例作为使用I2C分线板的教程提供。我们将在本书后面的一个示例项目中使用另一个I2C分线板。图6-2显示了AdafruitRGB传感器。

图6-2。

AdafruitRGBSensor(courtesyofadafruit.com)

配线分线板也非常容易,因为我们只需要电源、接地、SCL和SDA连接。SCL是时钟信号,SDA是数据信号。这些引脚在您的MicroPython板上(或在文档中)以及分线板上有标签。当您连接分线板时,请确保电源要求匹配。也就是说,一些分线板可以采用5V,但许多限于3或3.3V。如果您有任何疑问,请查看供应商的网站。

要连接电线,您可以使用五根公母跳线插入WiPy(或扩展板)和分线板。图6-3显示了您需要进行的连接。请注意,电线被插入标有“GXX”而不是“PinXX”的引脚中在使用电路板时,这可能会引起混淆。最好参考引脚排列图,以确保使用正确的引脚。在这种情况下,我们需要P9和P10用于I2C连接,我们将使用P8用于LED。

图6-3。

WiringtheRBGSensor(WiPy)Tip

$ftp192.168.4.1Connectedto192.168.4.1.220MicropythonFTPServerName(192.168.4.1:cbell):microPassword:RemotesystemtypeisUNIX.Usingbinarymodetotransferfiles.ftp>cdflashftp>puttcs34725.pylocal:tcs34725.pyremote:tcs34725.py227(192,168,4,1,7,232)100%|***********************************|522223.05MiB/s00:00ETA5222bytessentin00:00(6.57KiB/s)ftp>quit既然驱动程序已经复制到我们的板上,我们就可以写代码了。在本例中,我们将建立到分线板的I2C连接,并运行一个循环来从传感器读取值。听起来很简单,但是有一点技巧。我们将放弃对代码的冗长讨论,而是提供一些关键方面,让您自己阅读代码,看看它是如何工作的。

关键组件是设置I2C、传感器、用于控制LED的引脚以及从传感器读取数据。通过将引脚设为高电平(开)或低电平(关),可以打开和关闭板上的LED。首先,I2C电码如下。这里,我们初始化一个对象,然后调用init()函数将总线设置为主机模式。scan()功能打印出总线上的设备。如果你看到一个空的设置显示,你的I2C接线是不正确的。请检查并再次尝试该代码。注意,完成导入后,您可以手动运行这段代码。

i2c=I2C(0,I2C.MASTER)#createandinitasamasteri2c.init(I2C.MASTER,baudrate=20000)#initasamasteri2c.scan()接下来是传感器本身。司机使这变得容易。我们需要做的就是传递I2C构造函数,如图所示。

#Setupthesensorsensor=tcs34725.TCS34725(i2c)设置LED引脚也很容易。我们需要做的就是调用Pin()类构造函数,传入引脚名称(P8)并将其设置为输出模式,如下所示。

$ftp192.168.4.1Connectedto192.168.4.1.220MicropythonFTPServerName(192.168.4.1:cbell):microPassword:RemotesystemtypeisUNIX.Usingbinarymodetotransferfiles.ftp>cdflashftp>putwipy_RGB.pylocal:wipy_RGB.pyremote:wipy_RGB.py227(192,168,4,1,7,232)100%|***********************************|12024.51MiB/s00:00ETA1202bytessentin00:00(2.17KiB/s)ftp>quit剩下的工作就是运行示例并测试它。清单6-7展示了如何在WiPy上运行这个例子以及一个输出示例。如果您在WiPy上运行此示例,您可以将任何想要的对象放在传感器前面,它将读取颜色,并将其作为表示RGB值加上透明值的元组返回,如图所示。

串行外设接口(SPI)设计用于在两个器件之间通过专用线路双向发送和接收数据。也就是说,它使用两条数据线、一个时钟和一个从机选择引脚。因此,它需要六个连接进行双向通信,或者只需要五个连接进行读写。一些SPI器件可能需要第七个引脚,称为复位线。

如果您没有或不想购买Adafruit热电偶放大器MAX31855分线板(虽然不贵),也不用担心。此示例作为使用SPI分线板的教程提供。我们将在本书后面的一个示例项目中使用另一个I2C分线板。图6-4显示了Adafruit的Adafruit热电偶放大器和H型传感器。

图6-4。

AdafruitThermocoupleBreakoutBoardandType-KSensor(courtesyofadafruit.com)

该传感器可用于通过接近或触摸来测量高温。该传感器可以以0.25度的增量读取-200°C至+1350°C范围内的温度输出。这种传感器的一个可能用途是读取3D打印机上喷嘴的温度或任何类似的高热输出。应该注意的是,分线板是未组装的,因此您需要焊接接头和接线柱。

现在,让我们看看如何将分线板连接到我们的Pyboard。我们将只使用五根电线,因为我们只从分线板上的传感器读取数据。这需要连接到电源(地(GND)、主输入(MOSI)、时钟(CLK)和从选择(SS)。图6-5显示了连接。

图6-5。

WiringtheAdafruitThermocoupleModule(Pyboard)

表6-2。

ConnectingtheThermocoupleBreakoutBoard(Pyboard)

现在,让我们看看代码!在这个例子中,我们不打算使用驱动程序;相反,我们将了解如何使用SPI直接从分线板读取数据。为此,我们首先设置SPI接口的对象实例,然后选择一个引脚用于从机选择(也称为芯片或代码选择)。从那里,我们需要做的就是读取数据并解释它。我们将循环读取传感器,并编写一个函数来转换数据。

这是棘手的部分。这个例子向您展示了驱动程序作者必须做些什么来使设备的使用更容易。在这种情况下,我们必须从分线板中读取数据并对其进行解释。我们可以只读取原始数据,但这没有任何意义,因为它是二进制形式的。因此,我们可以从Adafruit借用一些代码来读取原始数据并理解它。

该函数名为normalize_data(),它执行一些位移和算术运算,将原始数据转换为摄氏度值。这些信息来自分线板的数据手册,但是Adafruit的友好人员让我们很容易就知道了。

设置SPI类很容易。我们使用SPI选项中传递的类构造函数来初始化SPI对象。这对于Pyboard是唯一的,可以是值1-使用X位置,或值2-使用Y位置。请注意,在上面的连接中,我们使用Y引脚,因此我们将使用值2作为第一个参数。其他参数告诉SPI类设置为主机,设置波特率、极性和相位(可在数据手册中找到)。接下来,我们只需选择用于读取数据的引脚,然后将引脚设为高电平。下面显示了激活SPI接口所需的代码。

spi=SPI(2,SPI.MASTER,baudrate=5000000,polarity=0,phase=0)cs=machine.Pin("Y5",machine.Pin.OUT)cs.high()现在,让我们看看完整的代码。清单6-8显示了使用Adafruit热电偶放大器分线板的完整代码。

>>>importpyboard_SPIReadingtemperatureeverysecond.PressCTRL-Ctostop.Temperatureis32.0Celsius.Temperatureis31.75Celsius.Temperatureis32.0Celsius.Temperatureis32.5Celsius.Temperatureis33.5Celsius.Temperatureis34.0Celsius.Temperatureis34.25Celsius.Temperatureis34.5Celsius.Temperatureis34.5Celsius....运行该示例后,您应该会看到它产生以摄氏度为单位的值。如果您看到0.00,您可能没有正确连接SPI接口。对照上图检查您的接线。如果您看到数值,但当您将热电偶暴露在高温下时,数值下降,您需要反转导线。确保先关闭主板电源,以免损坏传感器、分线板或您的Pyboard!

通过固件访问底层硬件是使用MicroPython的真正优雅之处,在某些情况下也是复杂性的开始。鉴于可用的主板不同,固件中的低级支持也不同也就不足为奇了。因此,在规划MicroPythonIOT项目时,我们必须考虑我们想要做什么,以及我们的主板(和固件)是否支持它。我们还需要知道我们想要连接到什么分线板和设备,以及是否有我们可以用来访问它们的驱动程序或其他库。在这种情况下,大多数带I2C或SPI接口的分线板都需要某种形式的驱动器。

在本章中,我们探讨了固件中的一些低级支持以及对Pyboard和WiPy的专门支持。正如我们所发现的,这是代码变得非常专门化的地方。正如我们所看到的,有时需要选择不同的库来导入,但是有时类、函数、甚至如何使用函数在不同的板上是不同的。

我们在这一章中也看到了很多代码——比之前的任何一章都多。本章中的例子旨在让你看到事情是如何完成的,而不是你自己去实现的项目(尽管我们欢迎并鼓励你这样做)。在后面的章节中,我们将会看到更多更详细的实践项目。

在下一章中,我们将以电子学的简短教程的形式进行一次简短的探讨。如果你以前从未接触过电子学,下一章将为你提供完成本书中的项目所需的信息,并让你为一个令人兴奋的新爱好做好准备——构建MicroPythonIOT项目!

每当你发现自己在为常用代码编写函数时,是时候考虑将它添加到你最喜欢的函数库中,以使这些代码对你所有的程序都可用,正如我们在第五章中所讨论的。

但是如果你好奇的话,请随意。如果您这样做了,您将会看到一段有趣的代码,它展示了I2C设备的寻址能力。

如果你刚接触硬件,对电子产品很少或没有经验,你可能会好奇如何完成本书中的项目。幸运的是,本书中的项目将指导您如何使用MicroPython板将各种电子器件连接在一起。也就是说,您可以在没有额外技能或经验的情况下完成项目。

然而,如果你想知道组件是做什么的,除了“把这一端插在这里”之外,你还需要更多的信息如果出了问题,尤其如此。此外,如果你想自己创建项目,你需要足够了解组件如何工作以成功完成你的项目——无论是完成本书中的例子还是在互联网上找到的例子。

本章不是试图提供一个全面的电子学教程,这需要几卷,而是为那些想使用IOT项目中常见的电子元件类型的人提供一个电子学概述。我包括一些基础知识的概述、常见组件的描述以及对传感器的介绍。如果你是电子学新手,这一章会给你额外的帮助,帮助你理解本书项目中使用的元件。

如果您有电子爱好者或发烧友级别的经验,或者有电子方面的经验或正式培训,您可能希望浏览本章或阅读您希望复习的主题部分。

让我们先来看看电子学的基础知识。再说一次,这绝不是一个涵盖所有知识的教程,但它将带您了解项目在如何连接和使用组件方面的意义。

本节简要概述了使用电子设备时需要用到的一些最常用的工具和技术。正如您将看到的,您只需要最基本的工具,技能或技术并不难学习。然而,在我们进入这些之前,让我们看看你在IOT项目中需要用到的一些工具。

然而,如果你想买一套完整的电子工具,比如来自sparkfun(sparkfun.com/categories/47)或Adafruit(Adafruit.com/categories/83)的工具,那就错不了。你经常可以在各大品牌电子商店和家装中心找到电子套件。如果你足够幸运,住在一家电器店附近,你可以找到几乎所有制造的电子工具。大多数电子工具包都有你需要的所有手工工具。有些甚至带有万用表,但更多时候你必须单独购买。

列表中的大多数工具不需要任何解释,只是说你应该在预算允许的情况下购买最好的工具。以下段落描述了一些用于特殊任务的工具,例如剥线、焊接以及测量电压和电流。

万用表是构建IOT解决方案时需要的工具之一。你还需要它来对你的电路进行几乎所有的电气维修。有许多不同的万用表,价格从便宜的基本单位;到复杂、功能丰富、价格昂贵的设备。对于大多数IOT项目,包括大多数IOT工具包,一个基本单位是你所需要的。然而,如果你计划建立一个以上的IOT解决方案或想要组装自己的电子产品,你可能要多投资一点,在一个更复杂的万用表。图7-1左边是一个基本的数字万用表(成本约10美元),右边是BKPrecision的专业万用表。

图7-1。

Digitalmultimeters

请注意,更好的血糖仪具有更精细的设置和更多功能。同样,你可能不需要超过基本单位。你至少需要测量电压、电流和电阻。无论你买哪个电表,确保它有测量交流和DC电压、连续性测试(有声音警报)和检查电阻的模式。我将在后面的章节中解释如何使用万用表。

大多数万用表,包括便宜的万用表,都有一个小说明书,告诉你如何测量电压、电阻和其他功能。

为获得最佳结果,选择含铅量在37%-40%范围内的低焊料。如果您使用专业烙铁,请调整温度以匹配焊料的熔点(列在标签上)。

图7-2。

Entry-levelsolderingironDoINeedtoLearntoSolder

图7-3。

Professionalsolderingiron

剥线钳有几种类型。事实上,可能有一打或更多的设计。但是有两种:一种是当你从电线上拉下来的时候,它只能夹住并切断绝缘层;以及抓持、切割和移除绝缘体的那些。第一种类型更常见,经过一些练习后,对于大多数小工作(比如修理断了的电线)来说就很好了;但是第二种类型的工作量更大,比如用裸线(没有预制连接器)连接电子设备,速度更快。可以想象,第一种要便宜得多。图7-4显示了两种类型的剥线钳。两者都是不错的选择。

图7-4。

Wirestrippers

还有一个你可能想要得到的工具,特别是如果你需要做任何焊接的话:它被称为帮助之手或第三手工具。大多数都有一对鳄鱼夹,用来在焊接时夹住电线、印刷电路板或元件。图7-5显示了一个简单的帮助工具的例子。

图7-5。

Helpinghandstool

现在让我们来看看在使用高级IOT项目时可能需要的一些技能。

ESDistheEnemy

您应该注意确保您的身体、工作区和项目接地,以避免静电放电(ESD)。ESD会永久损坏您的电子设备。避免这种情况的最佳方法是使用接地带,环绕在手腕上,并连接到防静电垫上,就像uline.com/BL_7403/Anti-Static-Table-Mats中的这些。

让我们来看看如何使用一个你在学习电子学时可能会用得最多的工具——万用表。

IOT项目所需的电气技能各不相同,从在试验板上插上电线(正如我们迄今为止在项目中看到的那样),到需要将元件焊接在一起或焊接到印刷电路板(PCB)上。不管你是否需要焊接电子元件,你都需要能够使用基本的万用表来测量电阻和检查电压和电流。

对于任何电子爱好者来说,万用表都是非常有用和必不可少的工具,对于任何有价值的发烧友来说,这是绝对需要的。典型的万用表有一个数字显示器【2】(通常是LCD或类似的数字显示器)、一个刻度盘和两个或多个用于插入带有探针端的测试引线的接线柱或端口。大多数万用表都有低电流端口(你最常用的)和大电流端口。测试引线使用红色表示正极,黑色表示负极(接地)。接地端口是插入黑色测试引线的地方,通常标有破折号或COM。您使用的其他端口将取决于您正在测试的内容。

表盘上有一点需要注意,那就是有很多设置(有些值是重复的)或者那些看起来很相似的设置。例如,您会看到一组欧姆值(有时称为标度),一组或两组安培值,以及一组或两组伏特值。带有V形实线和虚线的一组电压值适用于DC,而带有V形波浪线的范围适用于交流。安培范围以同样的方式标记。图7-6显示了一个万用表表盘的特写,上面标有我提到的几组数值。

图7-6。

MultimeterDial(typical)Tip

不使用时,一定要将万用表拨盘转到off或某个电压范围,如果它有单独的off按钮的话。

用万用表可以做很多事情。你可以检查电压,测量电阻,甚至检查连续性。大多数基本的万用表将完成这些功能。然而,有些万用表有更多的功能,如测试电容,测试交流和DC。

让我们看看如何使用万用表来完成IOT项目中最常见的任务:测试连续性、测量DC电路中的电压、测量电阻和测量电流。

我们测试连续性,以确定是否有带电粒子流动的路径:也就是说,我们的电线和组件连接正确。例如,您可能想要检查以确保导线已正确接合。

为了测试连续性,将万用表刻度盘转到标有声音符号、铃或有箭头穿过的三角形的位置。将黑色测试引线插入COM端口,将红色测试引线插入标有HzVΩ或类似标志的端口。现在,您可以一起触摸测试引线的探针端,以听到声音或嘟嘟声。有些万用表没有声音,但可能显示“1”或类似的数字来表示连续性。查看您的手册,了解您的万用表是如何指示连续性的。图7-7显示了如何设置万用表来检查连续性,包括插入测试引线的端口。

请注意,在照片中,我只是将探针接触在一起,以演示如何检查连续性。我喜欢这样做,只是为了确保我的万用表是打开的,并且设置正确。3

图7-7。

Settingsforcheckingcontinuity

我们的IOT项目使用DC。为了测量电路中的电压,我们将使用万用表上的DC量程。注意,DC山脉有几个站点。这是一个音阶选择。选择与您想要测试的电压范围最接近的刻度。例如,对于我们的IOT项目,我们通常会测量3.3-12V,因此我们在表盘上选择20。接下来,将黑色测试引线插入COM端口,将红色测试引线插入标有HzVΩ的端口。

现在我们需要一些东西来衡量!拿起你家里的任何一个电池,用黑色探针接触负极,用红色探针接触正极。您应该会看到显示屏上出现一个接近电池范围的值。例如,如果我们使用1.5V的电池,我们应该看到接近1.5V。如果电池耗尽,它可能不会正好是1.5-1.6V。现在你知道如何测试电池的新鲜度了吧!图7-8显示了如何测量电池电压。

图7-8。

Measuringvoltageofabattery

注意读数显示1.50,这是该AA电池的正确电压。如果我把探针颠倒过来——红色的是负极,黑色的是正极,显示屏上的读数应该是-1.50。这是可以的,因为它表明电流的流动方向与探头的方向相反。

如果在DC电路中测量电压时使用了错误的探针,大多数万用表会将电压显示为负数。用你的电池试试。不会伤到万用表(或者电池)!

我们可以在项目中使用这种技术来测量电压。注意将探针放在适当的位置,尽量不要用一个探针头一次接触多个元件而造成交叉或短路。

电流以安培数(毫安-毫安)来衡量。因此,我们将使用标有A的直线和虚线的范围(不是波浪线,那是AC)。我们串联测量电流。也就是说,我们必须将万用表放在电路中。这可能有点棘手,因为我们必须中断电流,并将电表放在线路上。

如果你熟悉如何使用试验板,你可以跟着做这个实验。然而,如果你没有使用过试验板,你可能想通读这个实验,然后在你读完这一章后再返回。在本实验中,我们将使用试验板电源、LED和电阻。我们将连接电路,这样我们将使用万用表来完成电路。图7-9显示了如何使用万用表在线设置电路。

图7-9。

Measuringcurrent

在接通试验板电源之前,将黑色测试引线插入COM端口,将其他测试引线插入标有mA的端口。有些万用表用同一个端口测量电压和电流。将万用表的旋钮转到200毫安的设定值。然后接通试验板电源,将引线接触到指示的位置。注意只触摸试验板电源上的VCC引脚。一旦电路通电,您应该会在万用表上看到一个值。图7-10显示了如何使用万用表测量电路中的电流

图7-10。

测量电流还有一个棘手的问题。如果您试图测量大于端口最大值的电流(例如,照片中的仪表在一个端口上的最大值为20mA)。如果超过这个值,比如说5A,我可能会烧断万用表的保险丝。这是不可取的,但至少有一个保险丝,我们可以更换,如果我们犯了错误,选择了错误的端口。

电阻以欧姆(ω)为单位测量。我们用来在电路中引入电阻的最常见的元件是电阻器。我们可以用万用表通过电阻测试电荷的电阻。要测试电阻,选择最接近电阻额定值的欧姆表。例如,我要测试一个电阻,我认为它大约为200欧姆,但由于我不确定,我将选择2k设置。

接下来,将黑色测试引线插入COM端口,将红色测试引线插入标有HzVΩ的端口。现在,将一个探针接触电阻器的一侧,另一个探针接触另一侧。无论选择哪一侧,电阻都可以双向工作。注意读数。仪表将读取以下三个值之一:0.00、1或实际电阻值。

这种情况下,电表读数为0.219,意味着该电阻的阻值为220ω。回想一下,我使用2k标度,这意味着1k的电阻读数为1.0。由于该值是一个小数,我可以将小数点向左移动,得到一个整数。

如果万用表显示另一个值,如0或1,这表明标度是错误的,你应该尝试更高的标度。这不是问题。只是说明你需要选择更大的尺度。另一方面,如果显示器显示0或较小的数字,则需要选择较低的刻度。当我在一个未知的元件或电路中测试电阻时,我喜欢按下旋钮。

图7-11显示了一个测量电阻器电阻的例子。注意显示屏上显示的是219。我正在测试一个额定220欧姆的电阻。之所以是219而不是220,是因为我使用的电阻额定值为220+/-5%。因此,该电阻器的可接受范围是209-231欧姆。

图7-11。

Measuringresistanceofaresistor

现在我们知道了如何测试一个电阻来发现它的额定值。正如我们将看到的,电阻体周围的环是我们了解其额定值的主要方式,但如果我们不确定,有人在上面涂了漆(嘿,这种情况时有发生),或者我们懒得去查,我们总是可以测试它。

现在,让我们来讨论使用电子设备时必须理解的最基本概念——为您的项目供电!

电4简单地定义为电荷的流动,当使用时为我们的电子设备提供电力——从普通的灯泡或吊扇到我们的高清电视或我们的新平板电脑。无论你是用电池还是电源给你的电子设备供电,你都是在启动一个电子以特定模式流动的电路。你将使用两种形式的权力。你的家用交流电供电,你的电子设备用直流电供电。

术语交流电(AC)用于描述以特定速率(或周期)周期性改变方向的带电粒子流,使电压与电流反向。因此,交流系统被设计成在特定的周期和电压范围内工作。通常,交流系统比直流系统使用更高的电压。

术语直流电(DC)用于描述不改变方向的带电粒子的流动,因此总是以特定的“方向”流动大多数电子系统由DC电压供电,通常比交流系统的电压低。例如,IOT项目通常在3.3-24V范围内的较低直流(DC)电压下运行。

由于DC是单向流动的,在DC上工作的元件有一个正的和一个负的“面”,电流从正流向负。这些面的方向——一个是正极,一个是负极——叫做极性。有些元件,如电阻,可以在任何一个“方向”上工作,但你应该始终确保按照极性连接你的元件。大多数部件都有明确的标记,但那些没有标记的部件却有着众所周知的排列方式。例如,LED的正极(侧面)是两条腿中较长的一条(称为阳极,而负极或较短的腿称为阴极)。

尽管电压较低,但我们不能认为它们完全无害或安全。电子设备接线错误(极性颠倒)或短路(将正极和负极连接在一起)会损坏您的电子设备,在某些情况下会导致过热,在极端情况下,会导致电子设备着火。

不要认为在3.3或5.5伏电压下工作是“安全的”即使少量电压连接不当也可能导致潜在的灾难性后果。不要认为低DC电压是无害的。

几年前,我就知道这种情况有多真实。我在换烟雾探测器的电池。我把旧电池拿出来,放在口袋里。我忘了在同一个口袋里还有一把小铅笔刀。其中一个电池在刀上短路,在大约十分钟内,电池加热到惊人的温度。它不足以燃烧,但如果我没有注意到这样的东西,它可能会很糟糕。

这是个可怕的想法,不是吗?把它当作一个告诫和警告;即使是低压项目,我们也不应放松安全操作实践。

最后,DC组件通常针对特定的电压范围进行额定。回想一下我们对各种低成本计算板和GPIO接头的讨论,一些板的工作电压为5V,而另一些板的工作电压为3.3V(或更低)。幸运的是,我们有几种方法可以调整在不同电压下工作的元件——通过使用其他元件!

我有意让关于权力的讨论保持简单。电流——甚至DC——远不止我在这里描述的那样。一旦你理解了这些基础知识,你就能使用本书及更多书中的项目。

除了学习如何使用万用表和可能的学习焊接,你还需要知道一些关于电子元件可用于建立你的项目。在这一节中,我将按名称的字母顺序提供一个简短的列表和一些常见组件的描述,您将在构建IOT解决方案时遇到这些组件。我还介绍了分线板和逻辑电路,它们是用一组组件构建的小电路,提供一种功能或解决一个问题。例如,您可以获得用于USB主机连接、以太网模块、逻辑移位器、实时时钟等的分线板。

按钮(有时称为瞬时按钮)是一种按下时产生连接的机制。更具体地说,按钮在被按下时将两个或多个电极连接在一起。按钮的一个常见(也许是过度使用的)例子是家庭门铃。当按下时,它完成一个电路,触发钟声、铃声、音调或音乐播放。有些老式门铃在按下按钮时会继续响。

在IOT项目中,我们将使用按钮来触发事件、开始和停止动作以及类似的操作。按钮是开关的一种简单形式,但与开关不同的是,您必须持续按下按钮才能进行电气连接。大多数按钮至少有两个脚(或引脚),当按钮被按下时,这两个脚连接在一起。一些具有成对连接的两个以上的腿,并且其中一些可以允许多个连接。图7-12显示了几个按钮。

图7-12。

Momentarybuttons

瞬时按钮有一种特殊的变体,称为闩锁瞬时按钮。这个版本使用一个缺口或棘爪来保持电极连接,直到它再次被推动。如果你在音响或汽车上看到一个按钮一直按下,直到再次按下,这很可能是一个瞬时锁定按钮。

有各种各样的按钮,包括可以用于试验板的按钮(引脚间距允许其插入试验板),可以安装在面板上的按钮,或者焊接到印刷电路板上的按钮。

电容器是用来储存电荷的。当电流流过电容器时,它会积累电荷,并在电流断开后放电。这样,它就像一个电池,但不像电池,电容器充电和放电非常快。我们使用电容来存储各种电流,包括阻挡电流、降低电源和音频电路中的噪声等。图7-13显示了几个电容。

图7-13。

Capacitors

电容器有几种类型,但在为IOT项目构建电源时,我们最常遇到的是电容器。大多数电容有两个极化的引脚。即一个是正的,一个是负的。确保在电路中以正确的极性连接电容器。

二极管被设计成只允许电流单向流动。大多数都标有指向一条线的箭头,指示流向。在交流-DC转换器(将交流转换为DC电压的设备)中,二极管通常用作整流器,与其他元件一起使用,以抑制电压尖峰,或保护元件免受反向电压的影响。它们通常用于防止电流流入设备。

大多数二极管的形状像一个小圆柱体,它们通常是黑色的,有银色的字迹,有两条腿。它们看起来有点像电阻器。我们在电源中使用一种称为齐纳二极管的特殊变体来帮助调节电压。图7-14显示了几个齐纳二极管。

图7-14。

Diodes

保险丝旨在保护设备(整个电路)免受超过元件安全工作电流的影响。保险丝直列放置在正极上。当过大的电流流过保险丝时,内部零件会触发电流中断。

一些保险丝内部使用一种特殊的导线,该导线会熔化或断开(从而使其无用,但可以保护您的设备),而其他保险丝使用一种类似开关的机制(其中许多是可复位的)。当这种情况发生时,我们说保险丝“烧断”或“跳闸”保险丝的额定电流安培数表示保险丝在不跳闸的情况下允许流动的最大安培数。

保险丝有许多形状和种类,可以用交流或DC电压工作。我们要用的是一次性的。图7-15显示了两个保险丝的示例:左边是汽车式刀片保险丝,右边是玻璃筒保险丝。

图7-15。

Fuses

如果你熟悉家中装有断路器的配电板,它们就是可复位保险丝。所以,下一次当其中一个“咔嚓”一声,灯灭了,你可以说,“嘿,保险丝断了!”更好的是,现在你知道为什么了——你已经超过了断路器的最大额定值。

这可能在你不小心让红外线加热器开着的情况下是没问题的,当你弄掉烤面包和启动微波炉时(这种情况会发生),但是如果你经常在没有任何负载的情况下跳闸断路器,你应该叫电工来检查电路。

正如我们在第三章中了解到的,LED有两个引脚,较长的引脚为正极,较短的引脚为负极。发光二极管也有一个平边,表示负支路。它们有各种尺寸,小到3毫米,大到10毫米。图7-16显示了一些较小的发光二极管的例子。

图7-16。

Lightemittingdiodes

回想一下,我们还需要使用一个带LED的电阻。我们需要这一点来帮助减少电路的流量,以降低流经LED的电流。led可以在较低的电流下使用(它们会比正常情况下稍微暗一点),但不应该在较高的电流下使用。

为了确定我们需要多大的电阻,我们需要了解LED的几个方面。该数据可从制造商处获得,制造商以数据表的形式提供数据,或者在商业包装产品的情况下,在包装上列出数据。我们需要的数据包括最大电压、电源电压(LED的电压)和LED的额定电流。

例如,如果我有一个像我们在上一章中使用的LED,在这种情况下,一个5毫米的红色LED,我们在Adafruit的网站(adafruit.com/products/297)上发现,该LED的工作电流为1.8-2.2伏和20毫安。假设我们希望使用5V电源电压。然后我们可以将这些值代入公式5:

R=(Vcc-Vf)/I使用更具描述性的变量名称,我们得到如下结果。

Resistor=(Volts_supply-Volts_forward)/Desired_current把我们的数据代入,我们得到这个结果。注意,我们有mA,所以我们必须使用正确的十进制值(除以1000)。在这种情况下,它是0.020,我们将在中间选择一个电压。

Resistor=(5-2.0)/0.020=3.0/0.020=150因此,我们需要一个150欧姆的电阻。酷毙了。有时该公式会产生与任何现有电阻都不匹配的值。在这种情况下,选择一个最接近的值,但稍微大一点。记住,我们想要限制,因此宁可多限制也不要少限制。例如,如果你发现你需要一个95欧姆的电阻,你可以用一个100欧姆的,这比用一个90欧姆的更安全。

当公式产生一个没有可用电阻的值时,总是偏向限制性更强的电阻。

继电器是一种有趣的元件,可以帮助我们用低压电路控制高压。例如,假设您想要控制一个由MicroPython板提供12V电源的设备,而MicroPython板只能产生最大3V的电压。继电器可以与3V电路一起使用,以打开(或中继)来自较高电源的电源。在本例中,我们将使用MicroPython板输出来触发继电器接通12V电源。因此,继电器是开关的一种形式。图7-17显示了典型的继电器以及引脚的排列方式。

图7-17。

Relay

继电器可以采取多种不同的形式,通常具有略微不同的接线选项,例如连接电源电压的位置和连接触发电压的位置,以及初始状态是打开(无流量)还是关闭(有流量)以及如何控制电压的行为。一些继电器安装在印刷电路板上,带有明显标记的端子,用于改变其开关特性和所有插件的位置。如果您想在项目中使用继电器,请务必查看数据表,以确保根据其配置正确接线。

电阻器是电子学的标准构件之一。它的作用是阻止电流并降低电压(转化为热量)。它的影响被称为电阻,用欧姆来衡量。电阻可用于降低其它元件的电压,限制频率响应,或保护敏感元件免受过压影响。图7-18显示了几个电阻。

图7-18。

Resistors

当电阻用于上拉电压(通过将一端连接到正电压)或下拉电压(通过将一端连接到地)(电阻是双向的)时,它消除了电压在不确定状态下浮动的可能性。因此,上拉电阻确保稳定状态为正电压,下拉电阻确保稳定状态为零电压(地)。

开关设计用于控制两个或多个引脚之间的电流。开关有各种形状、尺寸和包装。一些被设计为简单的开/关,而另一些可以用来改变从一组引脚到另一组引脚的电流。像按钮一样,开关有多种安装选择,从PCB(也称为通孔)到面板安装,以便安装在外壳中。图7-19显示了各种开关。

图7-19。

Variousswitches

只有一个电极(腿或边)的开关称为单极开关。能够将电流从一组电极转移到另一组电极的开关叫做双极开关。每极只有一个次级连接的开关称为单投开关。从一组极点断开并连接到另一组极点同时保持公共输入的开关称为双掷开关。这些通常被组合并形成如下的开关类型(或种类)。

您可能会遇到其他变体。我喜欢这样保持笔直;如果我有刚开/关的情况,我想要一个单掷开关。多少极取决于我想同时接通或断开多少根电线或电路。对于双掷开关,当我有“A”条件和“B”条件时,我使用这些开关,当B断开时,我希望A接通,反之亦然。当我需要“A”、“B”和“off”时,我有时会使用多个投掷开关,其中我使用中间位置(投掷)作为off。你可以非常有创意地使用开关!

晶体管(双极晶体管)被设计成在一个周期内开关电流或放大电流的波动。有趣的是,用来放大电流的晶体管取代了真空管。如果你是一个音响发烧友,你可能知道很多关于真空管。当电阻器在开关模式下工作时,其行为类似于继电器,但其“关”位置仍允许少量电流流动。晶体管用于音频设备、信号处理和开关电源。图7-20显示了两种晶体管。

图7-20。

Transistors

晶体管有各种各样的种类、封装和额定值,适合不同的解决方案。

电压调节器(线性电压调节器)被设计成保持电流恒定。当我们需要调节或降低来自电源的电流时,电压调节器经常出现在电子设备中。例如,我们想为一个电路提供5V电压,但只有9V电源。电压调节器(大致)通过吸收电流并通过散热器耗散多余的电流来实现这一点。因此,电压调节器有三个分支:正电流输入、负电流和正电流输出。它们的典型形状如图7-21所示,但也存在其他种类。

图7-21。

Voltageregulators

延伸出电压调节器的板上的小孔是安装散热器的地方。电压调节器通常被编号以匹配其额定值。例如,LM7805产生5V,而LM7833产生3.3V。

图7-22显示了一个使用电压调节器向试验板上的3.3V电路供电的示例。该电路设计有电容来帮助平滑或调节电源。请注意,电容的额定值为uF,即微法。

图7-22。

Powersupplycircuitonabreadboardwithvoltageregulator

图7-23。

Breakoutboards

无论何时设计电路或IOT解决方案,都应该考虑尽可能使用分线板,因为它们可以简化元件的使用。以大气压力传感器为例。Adafruit设计了这种板,因此我们使用它所需要做的就是连接电源,并通过其I2C总线将其连接到我们的IOT设备。I2C总线是一种快速数字协议,它使用两条线(加上电源和地)从电路(或设备)读取数据。

因此,没有必要担心如何将传感器连接到其他组件来使用它-只需像任何I2C设备一样连接它并开始读取数据!我们将在本书后面的项目中使用几个分线板。

如果你一直跟随书中的项目,你已经遇到了一个制作非常简单电路的试验板。回想一下第三章,试验板是我们用来插入元件形成电路的工具。从技术上讲,我们使用的是无焊试验板。焊料试验板具有相同的布局,只是在PCB上只有通孔焊点。

WhyaretheyCalledBreadboards

在微电子和分立元件广泛用于实验的辉煌时代,当我们想要制作电路原型时,有些人会使用一块钉有钉子的木头(有时是网格图案),通过在钉子上缠绕电线来连接(称为“线路”)。一些人使用厨房里的试验板来制作绕线原型。这个名字一直沿用至今。

图7-24。

Assortedbreadboards

回想一下,大多数试验板(有几个品种)都有一个中心凹槽(称为峡谷)或沿着板中心的印刷线。这表示垂直于通道延伸的端子排未连接。也就是说,一侧的端子排没有连接到另一侧。这允许我们插入封装为两排引脚的集成电路(IC)或芯片。因此,我们可以将IC插入试验板,在试验板的每一侧都有一组引脚。我们在下面的例子中看到了这一点。

大多数试验板还有一组或多组电源轨,它们平行于沟道连接在一起。如果有两个集合,则这两个集合不会连接在一起。电源轨可能有一条彩色参考线,但这仅用于参考;你可以把其中一个变成积极的,另一个变成消极的。最后,一些试验板对端子排进行编号。这些仅供参考,没有其他意义。然而,它们可以方便地在你的工程笔记本上做笔记。图7-25显示了试验板的命名以及端子板和电源轨是如何连接在一起的。

电源轨组没有连接在一起。如果你想在试验板的两侧都有电源,你必须使用跳线来连接它们。

图7-25。

BreadboardlayoutFritzing:ABreadboardingSoftwareApplication

有时需要将电路与代码分开测试。例如,如果我们想确保所有设备都正确连接在一起,我们可以使用试验板电源为电路供电。这样,如果出现严重问题,我们就不会冒损坏IOT设备的风险。大多数试验板电源都建立在一个小PCB上,带有一个用于壁式电源的桶形插孔,两组用于插入试验板上电源轨的引脚,一个关闭开关(非常方便),有些可以产生不同的电压。图7-26展示了我最喜欢的Sparkfun(sparkfun.com/products/13157)的试验板电源之一。

图7-26。

Breadboardpowersupply

如果我们的电路需要比单个试验板更多的空间,您可以通过简单地跳过电源轨并继续电路来使用多个试验板。为了方便起见,一些试验板可以使用侧面的小块和插槽进行连接。最后,大多数试验板还带有背胶,您可以用它来安装在板上或外壳或类似的工作空间内。如果你决定使用背胶,要预先警告他们不能轻易拆开-他们会很好地保持不动。

现在我们对试验板的工作原理有了更多的了解,让我们来讨论一下我们的IOT解决方案中用来收集数据的组件:传感器。

传感器是一种测量物理世界现象的装置。这些现象可以是你看到的东西,像光、气体、水蒸气等等。它们也可以是你感觉到的东西,像温度、电、水、风等等。人类的感觉就像传感器一样,让我们能够体验周围的世界。然而,有些东西你的传感器看不到或感觉不到,比如辐射、无线电波、电压和安培数。在测量这些现象时,传感器的工作是以电压表示或数字的形式传达测量结果。

以下部分探讨传感器如何测量数据、如何存储数据,以及一些常见传感器的示例。

传感器是基于其化学和机械结构的独特属性产生电压的电子设备。一些人对传感器的常见误解之一是,它们不会操纵它们被设计来测量的现象(改变事件或数据)。相反,传感器对一些物理变量进行采样,并将其转换为成比例的电信号(电压、电流、数字信号等)。

图7-27。

DHT-22HumiditySensor

DHT-22设计用于测量温度和湿度。它在输出端(数据引脚)产生一个数字信号。虽然使用简单,但它有点慢,应该用于以合理的慢速度跟踪数据(不超过每3或4秒一次)。

当该传感器产生数据时,数据以一系列高(解释为1)和低(解释为0)电压的形式传输,微控制器可以读取并使用这些电压来形成一个值。在这种情况下,微控制器从传感器读取长度为40位(40个高或低电压脉冲)的值,即5个字节,并将其放入程序变量中。前两个字节是湿度值,后两个字节是温度值,第五个字节是校验和值,以确保读数准确。幸运的是,所有这些艰苦的工作都以专门为DHT-22和类似传感器设计的库的形式为您完成了。

因此,即使传感器不产生值或测量值,仍有电压流过传感器,可能导致虚假读数。您的项目需要明确区分关(零电压)和开(正电压)。上拉和下拉电阻确保您拥有这两种状态之一。模数转换器负责从传感器读取电压,并将其转换为可被解读为数据的值。

采样时(从传感器读取值时),电压读数必须解释为给定传感器指定范围内的值。请记住,比方说,一个模拟传感器输出的2伏电压可能与另一个模拟传感器输出的2伏电压不是一回事。每个传感器的数据手册都向您展示了如何解释这些值。

如您所见,使用模拟传感器比使用DHT-22数字传感器要复杂得多。稍加练习,您会发现,一旦了解如何将模拟传感器连接到微控制器,以及如何在传感器校准工作的范围内解释其电压,大多数模拟传感器都不难使用。

像DHT-22这样的数字传感器被设计成使用串行传输产生一串比特(一次一个比特)。然而,一些数字传感器通过并行传输产生数据(一次一个或多个字节6)。如前所述,这些位表示为电压,其中高电压(比如5伏)或开是1,低电压(0甚至-5伏)或关是0。这些开和关值序列称为离散值,因为传感器以脉冲形式产生一个或另一个值,即开或关。

与模拟信号相比,数字传感器的采样频率更高,因为它们生成数据的速度更快,而且不需要额外的电路来读取数值(例如A/D转换器以及将数值转换为刻度的逻辑或软件)。因此,数字传感器通常比模拟传感器更精确和可靠。但是,数字传感器的精度与其用于采样数据的位数成正比。

数字传感器最常见的形式是按钮或开关。什么,按钮是传感器?为什么,是的,这是一个传感器。考虑一下安装在家庭安全系统窗户上的传感器。这是一个简单的开关,当窗户关闭时关闭,当窗户打开时打开。当开关连接到电路中时,当车窗关闭且开关闭合时,电流是恒定且不间断的(使用上拉电阻测量正电压),但当车窗和开关打开时,电流中断(测量零电压)。这是最基本的开关传感器。

大多数数字传感器都是由几个元件组成的小电路,用于产生数字数据。与模拟传感器不同,读取它们的数据很容易,因为这些值无需转换就可以直接使用(除了转换到其他刻度或测量单位)。有些人可能认为这比使用模拟传感器更困难,但这取决于你的观点。电子爱好者会认为使用模拟传感器更容易,而程序员会认为数字传感器更容易使用。

现在,让我们看看一些可用的传感器及其测量的现象类型。

我还包括一些传感器类型的流行例子的照片。

这些传感器测量传感器或它所连接的任何东西的运动或移动。它们被设计用来感应几个轴上的运动(速度、倾斜度、振动等等)。一些包括回转仪特征。大多数是数字传感器。Wii双截棍(或WiiChuck)包含一个复杂的加速度计,用于跟踪运动。啊哈:现在你知道Wii附带的那些有趣的小东西的秘密了吧!如果您的IOT项目涉及运动中的物体,并且对该运动的观察提供了有用的信息,您可能需要添加加速度计。

也许这是显而易见的,但麦克风是用来测量声音的。大多数是模拟的,但一些更好的安全和监控传感器具有数字版本,用于传输数据的更高压缩。家庭安全、儿童监控、捉鬼或听觉健康等IOT项目都可以从集成音频传感器中受益。

这些传感器被设计用来读取条形码。最常见的是,条形码阅读器生成代表条形码的数字等价物的数字数据。这种传感器通常用在库存跟踪系统中,以在工厂或运输过程中跟踪设备。它们数量众多,而且许多价格经济实惠,使您能够将它们整合到自己的项目中。如果您的IOT项目需要从对象中捕获数据,您可能需要考虑条形码。

例如,如果您希望感应停车场用户何时进入或离开无人值守的停车场,您可以在门口放置一个条形码读取器,读取您设计并分发给用户的条形码。当汽车停在大门前时,条形码阅读器可以读取条形码,记录入口,并升起大门。如果你曾经在大城市生活过,在受控的办公大楼工作过,或者是通勤学生,你可能会遇到这样的停车解决方案。

读取指纹、虹膜或掌纹的传感器包含一个用于识别模式的特殊传感器。鉴于指纹和掌纹等图案的独特性,它们是安全访问系统的优秀组件。大多数生物传感器产生一组代表指纹或掌纹的数字数据。需要更高安全级别的IOT项目可能希望包括生物传感器来帮助识别系统的用户。

脉搏传感器是电容传感器的一种特殊应用,设计用于测量您的脉搏率,通常使用指尖作为感测部位。称为脉搏血氧仪(一些医疗专业人员称为pulse-ox)的特殊设备通过电容传感器测量脉搏率,并通过光传感器确定血液中的含氧量。

如果你拥有现代电子设备,你可能会遇到触敏按钮,它们使用特殊的电容传感器来检测触摸和压力。如果你的IOT项目需要测量任何类型的运动,或对触摸做出反应,电容传感器可以帮助提供一个未来的非触觉界面。最新MacBookPro上的TouchBar就是这种解决方案的一个例子。

图7-28。

TouchCapacitiveSensorBreakoutBoards

这些设计用于测量电压和电流。有些是为测量变化而设计的,而有些是为了测量负载。IOT的项目集成电路或需要监测电流将需要一个电流传感器。这些可能是一些更深奥的项目,但您可以使用这些传感器来监控现有解决方案的行为,而无需修改它们。

例如,如果您想采用传感器来观察制造机器,您可以添加传感器来监控各种组件的电流。也就是说,您可以记录电压何时施加到电机、致动器,甚至警告灯,以确定设备何时(或多少)被激活。然而,作为一个业余爱好者,你更可能有兴趣建立自己的万用表或类似的工具。

电阻传感器测量一块材料的弯曲或压力对传感器的影响。弯曲传感器可能有助于测量扭转效应或测量手指运动(就像任天堂的电动手套一样)。当传感器弯曲时,传感器电阻增加。例如,如果您想创建一个IOT解决方案来实时报告您的钓鱼体验,您可能希望在您的鱼竿上使用一个flex传感器来报告您每次投掷或击中鱼饵的情况。

有很多种气体传感器。有些测量潜在有害气体,如液化石油气和甲烷以及其他气体,如氢气、氧气等。其他气体传感器与光传感器相结合来感测空气中的烟雾或污染物。下次当你从烟雾探测器中听到那种警告性的、通常令人讨厌的低电量警告声8时,想想那个设备包含了什么。为什么,这是一个传感器节点!如果您的IOT项目需要观察或检测任何形式的气体,特别是如果它涉及到对某些气体或其水平的反应,您将需要使用适当的气体传感器。

测量光强或缺光的传感器是特殊类型的电阻:光敏电阻(ldr),有时也称为光敏电阻或光电池。因此,它们本质上是模拟的。

如果你有一台Mac笔记本电脑,当你的发光键盘在弱光下自动打开时,你很可能已经看到了光敏电阻的作用。特殊形式的光传感器可以检测其他光谱,如红外线(如旧的电视遥控器)。例如,如果您希望您的IOT项目自动调整其显示器的亮度,光传感器就是您需要的组件。

图7-29。

MiniPhotocell

图7-30。

ColorSensorBreakoutBoard

这些传感器类似于阀门,内嵌在管道系统中。他们测量液体通过时的流量。基本的流量传感器使用旋转轮和磁铁来产生霍尔效应(快速开/关序列,其频率等于通过的水量)。如果你的IOT项目涉及任何形式的液体,如花园池塘或灌溉系统,了解水的流动可能有助于学习或观察某些东西。

一种特殊的电阻固态器件可以用来测量水体的相对高度。一个例子是当水位高时产生低电阻,当水位低时产生高电阻。像液体流量传感器一样,液位传感器通常用于相同的解决方案中。图7-31显示了一个典型的液位传感器,当水位上升时,浮子关闭开关。

图7-31。

Water-LevelSensor

现代智能手机有GPS传感器来感应位置,当然GPS设备使用GPS技术来帮助你导航。幸运的是,GPS传感器以低成本的形式提供,使您能够将位置检测添加到您的项目中。GPS传感器生成经度和纬度形式的数字数据,大多数还可以感知海拔高度。如果你的IOT项目需要报告它的位置,GPS传感器可以给你非常准确的读数。然而,像大多数传感器一样,GPS传感器可能有一定程度的不准确性。根据你需要定位的距离,你可能需要多花一点钱买一个更精确的GPS传感器。

这些传感器从磁条(像信用卡上的磁条)读取数据,并返回数字形式的字母数字数据(实际的字符串)。包含安全组件的IOT项目可能希望使用磁条读取器来帮助识别用户。当与密码和生物传感器结合使用时,安全性可以大大提高。也就是说,某人必须知道某样东西(密码或pin),拥有某样东西(带有磁条的安全卡,磁条上有关键短语、数字、用户id等编码)。),并在获得访问权限之前被验证为某人(指纹)。

这些传感器通过磁场强度来测量方向。指南针是一种用来寻找磁北的传感器。一些磁力计提供多个轴,以便更好地检测磁场。这是另一个你可能不会经常遇到的传感器,但是如果你的IOT项目需要测量来自电机或大气现象的磁场,你可能想看看磁力计。

湿度传感器测量物质(如土壤)或空气中的湿度。它们通常以电压读数的形式发送数据,低值表示水分较少。您经常会在大气项目甚至工厂监控解决方案中发现湿度传感器。图7-32显示了一个典型的土壤湿度传感器()。请注意,尖头是传感器插入土壤的部分。

图7-32。

SoilMoistureSensor

图7-33。

PIRMotionSensor

图7-34。

UltrasonicProximitySensor

射频识别使用无源设备(有时称为RFID标签)通过电磁感应使用射频来传输数据。例如,RFID标签可以是信用卡大小的塑料卡、标签或类似的包含特殊天线的东西,通常以线圈、细线或箔层的形式调谐到特定频率。

图7-35。

RFIDReader

这些是最基本的数字传感器,用于检测某个东西是被设置(开)还是被重置(关)。尽管如此,你可以使用开关和按钮来建立一个用户界面,用于控制其他设备,甚至是打开它!

这些传感器可以检测设备何时向某个方向倾斜。虽然非常简单,但它们对于低成本运动检测传感器非常有用。它们是数字的,本质上是开关。如果您的IOT解决方案需要检测设备何时倾斜,您可以使用倾斜传感器在特定倾斜角度触发。例如,一些现代摩托车使用倾斜传感器来打开转向灯——前照灯倾斜,以改善夜间转弯时的视野。

形成小键盘、键盘、定点设备等的触敏膜是一种有趣的传感器形式。你可以使用像这样的触摸感应设备来收集人类的数据。触摸传感器可以帮助您为您的IOT项目构建一个用户界面,该界面可以以低调的形式呈现,或者节省控制台、项目箱等的空间。

如前所述,有可能获得非常小的视频传感器,这些传感器使用摄像机和电路来捕捉图像并将其作为数字数据传输。如果要将视频元素整合到IOT项目(如安全解决方案)中,可以添加摄像机或视频传感器来捕捉视觉组件,以帮助提供事件测量之外的信息。也就是说,你可以查看一张照片,了解更多信息,而不仅仅是移动或靠近设备的东西。例如,您可以构建一个IOT项目,该项目可以检测运动,并在某个物体足够接近或者运动速度超过某个阈值时拍摄照片。11

图7-36。

BMP280PressureandTemperatureSensor

有了这个和其他易于使用的传感器,就有可能用大约十几个廉价的传感器、你的MicroPython板和一点解释和组合数据的程序来建立你自己的气象站。事实上,我们将在第十章中讨论这个问题!

IWanttoLearnMore!

如果你发现你需要或想要学习比我在这一章中介绍的更多的关于电子学的知识,或者你想要学习更多的关于你在一个更高级的IOT项目中需要的电子学知识,你可能想要考虑在一所社区大学上一门课程或者尝试一门自定进度的电子学课程。

他的百科全书系列的第三卷包括对传感器的深入研究:高级IOT项目的必备。

makershed(makershed.com/collections/electronics)出售配套套件,其中包含完成《制作:电子》和《制作:更多电子书籍》中的实验所需的所有部件。这些书和工具包一起构成了一个极好的自定进度的学习体验。

学习如何把使用电子产品作为一种爱好或者创造一个IOT解决方案并不需要终生学习或者改变职业。事实上,学习如何使用电子设备是体验IOT乐趣的一部分!我遇到过许多自学电子的人,虽然大多数人承认正式学习对于掌握这个主题是必不可少的,但你可以自学很多东西——足以熟练使用IOT项目中常见的基本电子元件。

本章介绍了电子元件的基础知识,包括试验板、常见元件和示例电路的使用。这一点和一些如何使用万用表的关键知识将会让你在精通电子学的道路上走得很远。我们还了解了IOT解决方案的关键组件之一——传感器。我们发现了它们通信的两种方式(数字和模拟)以及一些可用的传感器类型。

在下一章,我们将深入我们的第一个电子项目——相当于“你好,世界!”硬件项目。我们将看到如何将我们的MicroPython板连接到几个组件,并编写一个Python程序来控制它们。酷!

但是,正规的训练是没有替代品的!如果你想在本章的教程之外探索电子学,你可以考虑正式的培训,甚至是一个自定进度的课程,如侧栏“我想了解更多!”

旧的万用表有一个模拟仪表。如果你想要一点老学校的感觉,你仍然可以找到他们。

是的,有点强迫症。检查,再检查,再检查。

这取决于并行缓冲区的宽度。8位缓冲区一次可以传输1个字节,16位缓冲区一次可以传输2个字节,依此类推。

我相信越多越好的理论,在家里有很多探测器,这很好,但是当电池耗尽时,我永远也不会知道哪个探测器在响!当它们只发出一两声哔哔声,然后就无声无息了,这就变得令人沮丧。幸运的是,我已经用最新的10年电池变体替换了几乎所有的电池。不再有野鹅追逐!

精度可能取决于环境变量,如海拔、温度等。

你有没有想过,如果你能抓拍到一张正在你的花园里吃东西的动物的照片,那该有多好?用一个接近传感器和一个红外线照相机建造你自己的动物照相机!

这是本书最有趣的部分——从事MicroPython项目!正是在这一点上,我们已经学会了如何用MicroPython编写代码,现在对硬件甚至如何使用分立电子器件和分线板有了更多的了解。

本章介绍了如何构建MicroPython项目。因此,我们还需要学习一些东西,包括在我们的MicroPython板上安装和运行项目的技术和程序。这一章将介绍那些使你的MicroPython项目成功所需要的东西。因此,这一章有点长,即使你不打算实现这个项目,也应该被认为是必读的。

正如您将看到的,所有项目章节的格式都是相同的:首先是项目概述,然后是所需组件的列表以及如何组装硬件。一旦我们掌握了如何连接硬件,我们就可以看到如何连接一切,并开始编写代码。每章都以如何执行项目结束,并附有一个项目运行的例子和美化项目的建议。

如果你现在想知道你需要哪种板来完成这些项目,不要担心,因为我们将在本章中看到如何在WiPy和Pyboard上实现这个项目,以及不同之处的演示。

那么,让我们开始我们的第一个MicroPython项目吧!

虽然一个时钟可能听起来很简单,但这个项目将引导您完成组装硬件和编写代码所需的所有步骤。正如您将看到的,除了硬件布局和引脚数之外,WiPy和Pyboard之间还有一些明显的差异。事实上,我们将看到在我们如何为每一个写代码方面有一些不同。

此外,该项目很小而且很简单,因此我们可以专注于过程,然后我们可以将其应用于更高级的项目。事实上,我们会看到,即使是一个相对简单的项目也可能有意想不到的难度。但是不要担心,因为这一章记录了你完成这个项目需要做的所有事情。

WhichDriverDoIUse

您可能会遇到这样的情况:您为您想要使用的硬件找到了多个驱动程序。事实上,我为有机发光二极管展示会找到了三个司机。它们之间的差异是微妙的,看起来至少有一个是为特定平台编写的。

其实上面列出的是最好用的一个。尽管如此,它需要做一些小的改动才能与WiPy和Pyboard一起使用。我将向您展示这些变化,正如您将看到的,它们并不难发现和修复(例如,当MicroPython抛出异常时,它将向您显示问题的根源)。

如果您遇到类似的情况——有多个驱动程序可供选择,您可能希望尝试每个驱动程序,直到找到最适合您的硬件和项目的驱动程序。有时,在这种情况下,这是真的,一个驱动程序可能不可行,或者另一个可能缺乏您需要的功能。例如,我发现的一个驱动程序不支持文本,所以它不能用于这个项目,另一个需要进行重大修改才能用于Pyboard。诀窍是找到修改量最少但效果最好的驱动程序。

现在让我们看看这个项目需要哪些组件,然后我们将看看如何将所有组件连接在一起。

表8-1列出了你需要的部件。您可以从Adafruit(adafruit.com)、Sparkfun(sparkfun.com)或任何出售电子元件的电子商店单独购买元件。如果您想购买这些组件,可以链接到供应商。当列出同一对象的多行时,您可以选择其中一行——您不需要两个都要。此外,您可能会找到销售这些组件的其他供应商。你应该货比三家,找到最好的交易。显示的成本是估计值,不包括任何运输成本。

表8-1。

RequiredComponents

请注意,在源代码中,最后两项是“使用您的备件”。这是指我们大多数人手头都有这些东西,而且在某些情况下还很丰富。例如,如果你买了一块MicroPython板,如果你还没有电缆,你也需要买一根。此外,随着USB充电设备的激增,很难想象任何拥有一台以上智能设备的人没有额外的USB充电器或电源。

本项目中使用的有机发光二极管分线板是Adafruit的一个小模块。它有一个很小但很亮的显示屏,可以安装在试验板上。分辨率为128像素宽,32像素高。有机发光二极管分线板没有安装接头,但如果你知道如何焊接(现在可能是练习的好时机)或者你可以让朋友帮助你,它们很容易添加。图8-1显示了Adafruit有机发光二极管SPI分线板。

图8-1。

Monochrome128x32SPIOLEDGraphicDisplay(courtesyofadafruit.com)

有几种有机发光二极管分线板可用,只要它们具有SPI接口并使用ssd1306控制器芯片(说明会告诉你这一点),就可以使用备用有机发光二极管显示器。我们之所以需要在控制器芯片上使用一个,是因为驱动程序是为该控制器编写的。其他控制器芯片将需要不同的驱动器。

本项目中使用的RTC分线板是Adafruit的DS1307分线板。该板也没有安装接头(但包括接头),也没有配备电池,因此您必须购买CR1220纽扣电池。如果你不想去商店的话,Adafruit也有这些东西。图8-2显示了RTC分线板。

图8-2。

DS1307Real-TimeClockAssembledBreakoutBoard(courtesyofadafrui.com)

有几种DS1307RTC时钟可用。事实上,Sparkfun有一个,或者您可以自己创建一个!参见侧栏“构建您自己的RTC模块”了解更多细节。幸运的是,我们将使用的库支持带有DS1307、DS3231或PCF8523RTC芯片的分线板。

现在,让我们看看如何将组件连接在一起。

在这一节和下一节中,我们将看到如何为WiPy和Pyboard实现这个项目。在硬件的情况下,分线板侧的连接都是相同的,但是每个板的管脚号不同。表中显示了两种板,左边显示了带有pin标签的MicroPython板,右边显示了带有pin标签的分线板。我们将使用公/公跳线通过试验板进行这些连接。

正如您将看到的,像这样绘制连接使得检查连接变得容易。这个表和一个接线图是你将在本书和互联网或其他地方的其他示例项目中看到的工具。因此,学习如何阅读地图和接线图是一项让你的项目成功的技能。

表8-2显示了本项目所需的连接。注意“导线颜色”列。使用此列记录跨接导线的颜色,以帮助管理连接。使用什么颜色的电线并不重要,但是为每个连接使用不同的颜色有助于管理您将要连接的许多电线。如果您记下每个连接使用的是哪种颜色的电线,还可以更容易地检查您的连接。传统上,我们至少用黑色代表地(负极),红色代表电源(正极)。

表8-2。

ConnectionsfortheMicroPythonClock(WiPyandPyboard)

哇,联系真多啊!让我们来复习一些元件接线的技巧。将元件连接到电路板的最佳方式是使用试验板。正如我们在第七章中看到的,试验板允许我们插入组件,并使用跳线进行连接。这简化了项目的布线,并允许您在需要腾出更多空间时移动物品。试验板也有助于布线电源和接地连接,因为试验板的两侧都有电源轨,我们可以将其用作公共连接。也就是说,用一根跳线将电源和接地连接到试验板,用另一根跳线连接到分线板。

插入组件时,务必确保针脚与中央通道平行安装。回想一下,试验板的引脚以垂直于中央通道的方式成行布线。这允许您对元件(或电路板上的引脚)进行多个连接。

项目通电时,切勿插拔跳线。

最后,务必确保您的项目布线时仔细检查所有连接,尤其是电源、接地和用于信号的任何引脚(将设置为“高”或“开”),如用于SPI接口的引脚。最重要的是,当项目(或您的板)通电时,切勿插拔跳线。这很可能会损坏您的主板或组件。4

首先,拿出你的试验板,插上元件;然后,使用不同颜色的跳线,将所有需要的电线插入试验板,并在图表中注明您使用的颜色。当您开始将跳线的另一端插入MicroPython板时,这将对您有很大帮助。

在这个项目中,我将有机发光二极管安装在一个半尺寸试验板的左侧,就在中央通道的下方,RTC模块安装在右侧,也在通道的下方。请注意,这些板使用不同的电源连接。有机发光二极管板使用3.3V,RTC板使用5V。打开项目电源之前,请务必检查组件的电源要求。再三检查你的连接。

现在,让我们看看如何连接WiPy和Pyboard,如图所示。

WiPy的布线最好将扩展板上的USB连接器朝向左侧。这将允许您读取电路板上的引脚数,即使在电线插入电路板之后。然而,这只是一个建议。只要电线连接正确,方向并不重要。图8-3显示了WiPy、有机发光二极管和RTC分线板的接线图。

图8-3。

WiringtheClockProject(WiPy)

Pyboard的布线最好将USB连接器朝向左侧。这将允许您读取电路板上的引脚数,即使在电线插入电路板之后。图8-4显示了Pyboard、有机发光二极管和RTC分线板的接线图。

图8-4。

WiringtheClockProject(Pyboard)Caution

总是再三检查你的连接,尤其是所有的电源和接地连接。请务必检查电源连接,以确保正确的电源(3V或5V)正确连接到组件。连接错误的电压会损坏部件。

如果您选择了不同于图中所示的RTC板,请务必根据需要调整连接。例如,SparkfunDS1307分线板的引脚顺序不同,所以不要只看这张图,尤其是在使用替代组件的情况下!

同样,在给主板通电之前,请务必仔细检查您的连接。现在,我们来谈谈我们需要编写的代码。暂时不要启动您的主板——在我们准备好测试该项目之前,还需要进行大量的讨论。

现在是时候为我们的项目编写代码了。由于我们正在使用几个新组件,我将依次介绍每个组件的代码。代码并不太复杂,但可能不像以前项目中的一些代码那样清晰。让我们先来看看这个项目的设计。

这五个元素是我们将在本书的所有项目中使用的,事实上,它是所有MicroPython项目都要遵循的一个好模式。新的功能步骤是我们还没有看到的新步骤。简而言之,我们将代码的操作部分包装在一个单独的函数中,以便在启动时从main.py文件中调用。当我们执行和测试这个项目时,我们将会看到更多关于它的内容。

现在我们知道了项目代码将如何实现,让我们回顾一下所需的库。

现在就下载这两个驱动程序吧。您应该能够访问这些站点,单击克隆或下载链接,然后单击下载Zip按钮将文件下载到您的PC。然后,打开下载文件的位置并解压缩。您应该找到以下文件。将这些内容复制到您电脑上的某个位置。我们复制它们是因为我们需要修改它们,如果我们犯了错误或者事情不顺利,复制它们可以让我们回到原来的样子。

同样,不要担心,因为对库的更改很小。但是,这是一个很常见的现象,你应该习惯于做这样的小改动——尤其是如果你使用的是WiPy或Pyboard之外的板!

使用驱动程序时,还有一个需要考虑的问题。您应该查看驱动程序文档以了解任何限制。例如,驱动程序可能需要较新版本的固件。在某些情况下,可能还需要旧版本的固件(但这种情况很少见)。如果您的驱动程序与您的主板不兼容,而文档声称它可以与您的主板兼容,请在文档中检查您的固件版本是否有任何不兼容之处。

在接下来的章节中,我们将会看到在WiPy和Pyboard上使用驱动程序所需的一般变化。

有机发光二极管驱动程序需要对WiPy固件进行少量的修改。WiPy上的引脚类没有high()或low()功能。取而代之的是,WiPy固件使用一个函数value(),我们将它作为参数传递,1表示高,0表示低。幸运的是,对于那些知道如何读取差异文件(diff命令6的输出)的人来说,只需将所有出现的.high()更改为.value(1)并将.low()更改为.value(0).,差异文件如清单8-1所示。

---./Pyboard/ssd1306.py2016-10-3014:06:02.000000000-0400+++./WiPy/ssd1306.py2017-07-2021:39:31.000000000-0400@@-146,23+146,23@@defwrite_cmd(self,cmd):self.spi.init(baudrate=self.rate,polarity=0,phase=0)-self.cs.high()-self.dc.low()-self.cs.low()+self.cs.value(1)+self.dc.value(0)+self.cs.value(0)self.spi.write(bytearray([cmd]))-self.cs.high()+self.cs.value(1)defwrite_framebuf(self):self.spi.init(baudrate=self.rate,polarity=0,phase=0)-self.cs.high()-self.dc.high()-self.cs.low()+self.cs.value(1)+self.dc.value(1)+self.cs.value(0)self.spi.write(self.buffer)-self.cs.high()+self.cs.value(1)defpoweron(self):-self.res.high()+self.res.value(1)time.sleep_ms(1)-self.res.low()+self.res.value(0)time.sleep_ms(10)-self.res.high()+self.res.value(1)Listing8-1.Changesforthessd1306.pycodemodulefortheWiPy(differencefile)What’saDifferenceFile

差异文件是diff命令的输出。它逐行显示同一文件的两个版本之间的变化或差异。在统一差异文件中,以减号开头的行是要删除的行,而以加号开头的行是要添加的行。文件中没有序言(符号)的行被用作定位更改的上下文(以及一个特殊的头)。差异文件可与patch命令一起使用,将更改应用于文件。因此,差异文件有时被称为“补丁”或“差异”文件。

RTC驱动程序将无法在Pyboard上正确运行(但在WiPy上无需更改即可正常运行)。所需的更改是由于I2C类的功能不同。驱动程序使用以下方法来读取和写入数据。

i2c.readfrom_mem(address,register,num_to_read)i2c.writeto_mem(address,register,buffer)但是,Pyboard固件有不同的函数名,参数顺序也不同,如下所示。请注意,read函数的参数顺序是不同的。

i2c.mem_read(num_read,address,register)i2c.mem_write(buffer,address,register)因此,我们需要改变库中的所有读写功能,以匹配我们的板的固件。你所需要做的就是打开文件并进行修改——只需要重命名函数并重新排列read函数的参数。清单8-2显示了您需要做出的更改。

有机发光二极管驱动程序也不能在Pyboard上正确运行。所需的改变是由于我们在RTC驱动中看到的I2C类函数的相同差异。您可能想知道,如果我们使用SPI接口,为什么需要进行这些更改。事实证明,该驱动程序既可用于I2C接口,也可用于SPI接口,由于I2C接口不同,因此仍需进行更改。如果我们不这样做,MicroPython会抱怨,我们将无法使用该驱动程序。是的,即使我们不用那部分代码。这是因为MicroPython将检查导入的整个代码模块的语法。

像RTC驱动程序一样,只需打开文件并进行更改。清单8-3显示了使RTC驱动程序兼容WiPy和Pyboard的差异文件。

既然我们已经有了自己的设计,下载并修改了库,我们就可以开始编写代码了。与其给你看一个长长的清单,说“要么理解,要么毁灭”,不如让我们先浏览一下代码的所有部分,以便理解每一部分。在我们遍历代码的过程中,您可以自己测试各个部分,但是如果您愿意等到最后再测试代码,您也可以这样做。此外,当我们浏览代码时,我们将看到WiPy和Pyboard所需的差异。让我们从进口部分开始。

项目的imports部分在所有其他语句之前,但在文件顶部的注释块之后。正如你在前面的例子和第四章中看到的,你应该在文件的顶部包含一些文档来解释代码的作用。你不需要写一个冗长的教程,只需要一个简短的陈述来描述这个项目,包括你的名字和其他信息。如果您希望与他人共享您的代码,并且如果您以后要重新使用这些代码,这是非常重要的。8

如果您想在我们进行的过程中键入代码,您可以用您喜欢的代码(或文本)编辑器打开一个名为clock.py的新文件。回想一下,最好的编辑器是那些具有Python语法检查功能的编辑器,比如KomodoEdit。

WiPy的进口不同于我们对Pyboard的需求;然而我们需要相同的库——我们只是从不同的地方导入它们。下面显示了WiPy的导入。这是两种板的三个不同之处之一。

importurtcimportutimefrommachineimportSPI,I2C,RTCasrtc,Pinaspinfromssd1306importSSD1306_SPIasssd我们需要Pyboard的导入包括以下内容。注意我们需要很多库。您将看到我们导入了Pyboard库、RTC库、ssd1306库以及I2C和SPI类。还要注意的是,我为一些库使用了别名(“asXXXX”短语),以使键入更容易一些(键入的字符更少)。

#ImportsfortheprojectimportpybimporturtcfrommachineimportSPI,PinaspinfrompybimportI2Cfromssd1306importSSD1306_SPIasssd建立接下来,我们需要设置用于RTC和ssd1306库的I2C和SPI接口。也就是说,这些库中的类需要传递给构造函数的接口的对象实例。我们将使用的代码类似于我们在前面的例子中看到的代码。

这是WiPy和Pyboard的另一个主要区别。下面显示了WiPy的接口设置代码。

#SetupSPIandI2Cspi=SPI(0,SPI.MASTER,baudrate=2000000,polarity=0,phase=0)i2c=I2C(0,I2C.MASTER,baudrate=100000,pins=("P9","P8"))下图显示了Pyboard的I2C和SPI设置。

spi=SPI(2,baudrate=8000000,polarity=0,phase=0)i2c=I2C(1,I2C.MASTER)i2c.init(I2C.MASTER,baudrate=500000)请注意,我们对SPI使用不同的参数,并为I2C指定引脚。我们必须为I2C接口指定引脚的原因是,SPI和WiPy上的I2C共享时钟引脚。因此,我们必须手动指定用于I2C接口的引脚。如果您愿意,可以使用其他引脚,但在将组件连接在一起时,请记住使用正确的引脚。最后,注意我们不需要WiPy上的init()函数。

接下来,我们为库中的类初始化对象实例。此时,您需要阅读每个库的文档,以了解初始化对象所需的内容。对于ssd1306驱动程序,类构造函数需要显示器的像素数(分辨率是行、列中的像素数)、接口实例(上一节中的SPI)以及我们将用于D/C、RST和CS引脚的引脚。对于RTC驱动程序,我们只需要传入接口实例(上一节的I2C)。下面显示了如何为WiPy执行这两个步骤。

#SetuptheOLED:D/C,RST,CSoled_module=ssd(128,32,spi,pin('P5'),pin('P6'),pin('P7'))#SetuptheRTCrtc_module=urtc.DS1307(i2c)Pyboard的初始化代码非常相似。唯一的区别是我们指定的引脚。

#(year,month,day,weekday,hour,minute,second,millisecond)#start_datetime=(2017,07,20,4,9,0,0,0)#rtc_module.datetime(start_datetime)新功能现在所有的设置或boilerplate工作都完成了,我们可以创建一个新的函数来启动并运行我们的项目。也就是说,一旦导入代码模块,我们就可以调用这个函数。例如,我们将文件命名为clock.py,如果我们创建一个名为run()的函数,我们可以用下面的语句开始代码。当我们将项目部署到董事会时,我们将看到更多关于如何使用这些语句的内容。

这是一个或三个助手函数的完美候选。幸运的是,这两种板的这些功能是相同的,因此不需要预测任何变化。

#Displaythedateandtimedefwrite_time(oled,rtc):#Getdatetimedt=rtc.datetime()#Printthedateoled.text("Date:{0:02}/{1:02}/{2:04}".format(dt[1],dt[2],dt[0]),0,0)#Printthetimeoled.text("Time:{0:02}:{1:02}:{2:02}".format(dt[4],dt[5],dt[6]),0,10)#Printthedayoftheweekoled.text("Day:{0}".format(get_weekday(dt[3])),0,20)#UpdatetheOLEDoled.show()注意,我们使用print()函数和format()函数从RTC获取数据,并将其格式化为大多数时钟使用的预期格式:HH:MM::SS和MM/DD/YYYY。注意这里有一个名为get_weekday()的附加函数。这个函数获取从RTC返回的一周中的第几天,并返回一个字符串作为这一天的名称。下面显示了该函数的代码。

#Returnastringtoprintthedayoftheweekdefget_weekday(day):ifday==1:return"Sunday"elifday==2:return"Monday"elifday==3:return"Tuesday"elifday==4:return"Wednesday"elifday==5:return"Thursday"elifday==6:return"Friday"else:return"Saturday"增加了一个功能——清除屏幕的功能。该功能只是清空屏幕,让我们用新数据覆盖屏幕。通常这是不需要的,但是如果驱动程序没有为你清除屏幕,这是一个很好的实践。在这种情况下,现在确实如此。这个函数被命名为clear_screen(),如下所示。它只是使用ssd1306驱动程序中的fill()和show()函数。为fill()函数传入o告诉驱动程序用无数据填充屏幕(空白或关闭)。

#Clearthescreendefclear_screen(oled):oled.fill(0)oled.show()现在我们准备为项目编写新的run()函数。我们已经开发了我们的助手函数,所以我们只需要调用它们,并在每次调用时等待一秒钟。下面显示了我们项目的run()函数。这是Pyboard与WiPy的最后一个不同之处。以下是Pyboard的代码。你能找出需要为WiPy改变的那一行吗?

utime.sleep(1)既然我们已经看到了代码各部分的完整演练,那么让我们来讨论一下代码的测试。

既然我们已经计划了代码,并且知道如何对每个部分进行编码,我们还有一件事要做——分别测试分线板。我们通过连接一个分线板并对其进行测试,然后断开该分线板的电源和布线,再连接另一个分线板并对其进行测试。

出于一个主要原因,这是养成习惯的好习惯。通过一次一个地测试项目的各个部分——尤其是硬件——您将会省去很多麻烦。这不仅可以更容易地缩小问题范围,还可以确保您能够确定问题的根源。也就是说,如果您插上所有硬件,连接所有设备,编写代码,部署它,然后启动它,但没有任何东西工作,您如何知道是哪个部分出了问题?这是我的口头禅之一:一次构建并测试一个部分。

一次测试一部分代码对我来说是一种熟悉的模式,强烈建议您自己采用这个过程。也就是说,一次编写项目的一部分,并单独测试每一部分。

对于这个项目,有两个部分RTC和有机发光二极管。让我们看看如何单独测试它们。我们将看到测试Pyboard组件的代码。您可以根据需要使用上面的信息修改代码,以便在您自己的板上工作。提供的代码旨在通过REPL控制台运行。我展示了Pyboard的代码,并将修改它以在WiPy上运行作为练习。提示:回头看看前面的部分,看看需要做哪些更改。

要测试RTC,使用下面的代码。这是我们在Pyboard演练中看到的代码的压缩形式。

如果任何陈述失败,请务必检查您的接线并查找任何打字错误。此外,请确保您使用的是正确的、经过修改的驱动程序版本(并且您已经将它们复制到主板上)。

要测试有机发光二极管,请使用下面的代码。这是我们在演练中看到的代码的精简形式。

importmachinefrommachineimportPinaspinfromssd1306importSSD1306_SPIasssdspi=machine.SPI(2,baudrate=8000000,polarity=0,phase=0)oled=ssd(128,32,spi,pin("Y4"),pin("Y3"),pin("Y5"))oled.fill(0)oled.show()oled.fill(1)oled.show()oled.fill(0)oled.show()oled.text("Hello,World!",0,0)oled.show()当您运行这段代码时,您应该会看到屏幕空白(从一开始就应该是空白的),然后填充白色-参见fill(1)-然后空白屏幕,最后显示文本消息。如果看不到任何输出,请关闭主板电源,检查所有连接,验证是否使用了正确的引脚,以及是否将正确的驱动程序修改版本复制到主板上。

Adafruit的有机发光二极管分线板(可能还有其他的)在镜头上有一个保护罩。你可以也应该把它留在原处,以确保镜头不会被损坏。此外,有机发光二极管足够亮,可以透过保护罩看到东西。

现在,在我们将它部署到我们的MicroPython板上之前,让我们看看两个板的完整代码。

在这一节中,我们将看到WiPy和Pyboard的完整代码。这些列表供您参考,以确保您拥有适合您的主板的正确代码。以后的项目将展示其中一个电路板的最终代码,并说明如何修改它以用于其他电路板。清单8-4显示了在WiPy上运行项目的完整代码。

我们终于可以将所有文件复制到我们的板上并执行项目代码了。这个过程中有几个推荐的步骤,如下所示。每次您想要部署和测试项目时,您都应该遵循这个过程。

第一步怎么说都不为过。每次接通主板电源时,请务必检查您的连接。这是为了防止好奇的手经过并“检查”你的项目,或者你移动了它,或者发生了一些其他事件来拔掉电线。格外小心无妨。

接下来,我们打开主板电源,检查是否有任何问题。没错,这就是冒烟测试!只需确保所有应该点亮的led都点亮(就像板上的那些),不应该点亮的都熄灭。例如,如果您在开机时看到有机发光二极管上有一个实心条,这不是一个好现象。如果有任何疑问,请拔掉电源并检查您的连接。如果事情仍然不对劲,断开所有连接并测试您的主板。有时损坏的组件会导致奇怪的行为。

接下来,我们将所有想要使用的驱动程序和代码复制到板上。完成后,我们就可以测试代码了。因为我们使用了一个run()函数来包含主代码,所以我们可以简单地导入代码并如下调用该函数。

>>>importclock>>>clock.run()现在启动您的主板,运行所示代码。您应该会看到类似图8-5的东西,它展示了项目运行的所有荣耀。

图8-5。

AMicroPythonClock!

BuildingYourOwnRTCModule

如果您计划构建大量使用RTC的项目,批量购买这些组件并连接您自己的RTC1307模块可能更具成本效益。此外,它增加了你的工具包的酷的因素。

在下一章中,我们将探索一个项目,该项目使用led、电阻和按钮等分立元件形式的更多低级硬件。这些是构建更复杂的解决方案所需的构件。

是的,我是那些喜欢印刷材料的触觉传感器印象的人之一。此外,你几乎可以在任何包或口袋里放一小叠文件。

猜猜我是怎么知道的。有时候打破东西是最好的学习方式。

我想其他工程师可能会说你应该先写代码,但我的看法正好相反。

我有时发现自己想知道是谁写了一段代码,却发现是我!记录或“签署”代码可以帮助你记住你写了什么和为什么写。

既然我们已经有了如何设计、连接和实现MicroPython项目的教程,现在让我们来看一个更高级的项目。在这种情况下,我们将使用一些非常基本的组件来进一步了解如何使用硬件。该项目的硬件选择将是发光二极管,电阻和一个按钮。按钮是最基本的传感器。也就是说,当按钮被按下时,我们可以让我们的MicroPython代码响应这个动作。

使用led可能更多的是一句“你好,世界!”风格项目的硬件,因为打开和关闭发光二极管很容易,除了搞清楚什么大小的限流电阻是必要的,接线发光二极管也很容易。像大多数基于LED的项目一样,我们将实现一个模拟。更具体地说,我们将实现一个交通灯和一个行人行走按钮。步行按钮是一个按钮,行人可以使用它来触发交通信号以改变和停止交通,以便他们可以穿过街道。

“循环”一词指的是一组线性作用的状态。因此,循环是指从一种状态到另一种状态的变化。

我们也将增加一个新的交通灯模拟概念。我们将使用一个网页来触发walk请求。但首先,我们将学习如何连接和编码LED灯,并在第二步添加web界面。

在这一章中,我们将实现一个带有行人行走按钮的交通信号。这个项目使用led,它允许我们看到代码执行时的状态。对于交通灯(也称为停止灯),我们将使用红色、黄色和绿色led来匹配交通灯上相同颜色的灯。我们还将使用一个红色和黄色的LED来对应禁止行走(红色)和行走(黄色)灯。

我们将使用按钮(也称为瞬时按钮),因为它只有在被按下时才会触发(开启)。释放后,它不再被触发(关闭)。Trigger是用于描述按钮状态的词,其中triggered表示从按钮的一侧到另一侧的连接被连接(on)。保持触发(锁定)状态的按钮称为锁定按钮,通常必须再次按下才能关闭。

我们将通过首先仅打开绿色交通灯LED和红色步行LED信号来模拟交通灯和步行信号。这是我们将使用的正常状态。当按钮被按下时,交通灯将变为黄色几秒钟,然后变为红色。几秒钟后,行走信号将变为黄色,几秒钟后开始闪烁。几秒钟后,步行信号将返回红色,交通灯将返回绿色。

为了让事情变得更有趣,我们还将看到如何修改这个项目来使用一个从网页模拟的按钮。是的,我们将看到如何通过网络远程控制硬件和我们的代码。如果您使用的是Pyboard或另一种没有任何网络功能的MicroPython板,您将需要一个网络模块。随着项目的发展,我们将重新审视Pyboard的网络。

表9-1列出了你需要的部件。您可以从Adafruit(adafruit.com)、Sparkfun(sparkfun.com)或任何出售电子元件的电子商店单独购买元件。如果您想购买这些组件,可以链接到供应商。当列出同一对象的多行时,您可以选择其中一行——您不需要两个都要。此外,您可能会找到销售这些组件的其他供应商。你应该货比三家,找到最好的交易。显示的成本是估计值,不包括任何运输成本。

表9-1。

注意在成本中,led和按钮的“套件”。这是指这些组件可以在我们在第二章看到的Adafruit的零件Pal套件中找到。其他供应商可能有类似的套件。成套购买led、按钮和电阻等基本元件要便宜得多。

同样,你可以买一套各种尺寸的电阻,比一次买几个便宜得多。事实上,你很可能会发现,购买一个每种尺寸5或10个电阻的小套件比购买一套要贵得多。Sparkfun的套件将为您提供大多数项目所需的所有电阻器。

另外,请注意,WiPy需要的跳线要少得多。这是因为我们将使用网络分线板(在本例中为CC3000模块)来允许Pyboard连接到我们的网络。

最后,注意我们需要一个Pyboard友好的网络模块。同样,目前这必须是基于CC3000的板或基于WIZNET5K的板。有关与Pyboard配合使用的网络分线板的示例,请参考前面的章节。

回想一下第七章,LED需要一个限流电阻来将电流降低到LED的安全水平。为了确定我们需要多大的电阻,我们需要了解LED的几个方面。该数据可从制造商处获得,制造商以数据表的形式提供数据,或者在商业包装产品的情况下,在包装上列出数据。我们需要的数据包括最大电压、电源电压(LED的电压)和LED的额定电流。

例如,如果我有一个像AdafruitPartsPal中的LED,在这种情况下是一个5毫米红色LED,我们在Adafruit的网站(adafruit.com/products/297)上发现该LED的工作电流为1.8-2.2伏和20毫安。假设我们希望使用5V电源电压。然后我们可以将这些值代入这个公式:

Resistor=(5–1.8)/0.020=3.2/0.020=160因此,我们需要一个160欧姆的电阻。然而,没有这种额定值的电阻。当这种情况发生时,我们用大一号的。例如,如果您只有220欧姆甚至330欧姆的电阻,您可以使用这些电阻。结果将是发光二极管将不会那么亮,但是具有较高的电阻比使用太小的电阻要安全得多。电流太大,LED会烧坏。

虽然这个项目需要使用WiPy连接很多电线,Pyboard甚至需要更多电线,但我们将使用的元件很容易插入试验板。表9-2显示了本项目所需的连接。

表9-2。

ConnectionsfortheMicroPython(PyboardandWiPy)

让我们来复习一些元件接线的技巧。将元件连接到电路板的最佳方式是使用试验板。正如我们在第七章中看到的,试验板允许我们插入组件,并使用跳线进行连接。在本项目中,我们将使用一根跳线从MicroPython板接地到试验板,然后在试验板上跳线连接到按钮。事实上,我们将使用试验板一侧的接地轨来插入led的一侧。

只要插销的方向如图所示,按钮在任何位置都可以工作–两条腿在中心槽的一侧。如果按钮的支脚可以伸到槽的任何一侧,按钮的方向就会正确。如果你把它移开90度,按钮要么不起作用,要么总是被触发。如果有任何疑问,使用万用表测试按钮连接的连续性。你会发现连接在未按下时打开,按下时关闭。

唯一极化的组件是LED(它有一个正极和一个负极引脚)。当您查看LED时,您会看到LED的一条腿(引脚)比另一条腿长。这条较长的边是正面。我们将插入led,使负极引脚插入接地轨,正极引脚插入试验板的主要区域。然后我们插入电阻,跳过中心槽,将电阻连接到MicroPython板上的GPIO引脚。不管你往哪个方向插电阻,它们都可以双向工作。

如果这听起来令人困惑,不要担心,因为接线图使连接更加明显。让我们看看如何连接WiPy和Pyboard,如图所示。

WiPy的布线最好也是将USB连接器朝向扩展板的右侧。图9-1显示了WiPy的接线图。注意发光二极管、电阻和按钮的方向。您应该能够使用图纸和布线图来连接您自己的组件。另外,请注意WiPy的方向。这应该有助于您更容易地将引脚与试验板的导线对齐,但只要您使用正确的GPIO引脚,物理方向并不重要。

图9-1。

WiringtheStoplightSimulation(WiPy)

现在,让我们看看Pyboard的接线图。由于需要添加一个网络分线板,所以变得有点复杂。

Pyboard的布线最好将USB连接器朝向左侧。这将允许您读取电路板上的引脚数,即使在电线插入电路板之后。网络模块需要额外的连接。回想一下,CC3000分线板需要额外的布线来将SPI接口连接到Pyboard。就像我们对led、电阻器和按钮所做的那样,我们应该计划如何连接分线板。表9-3显示了与CC3000分线板一起使用时Pyboard所需的连接。如果您使用不同的分线板,请确保使用您的连接对此计划进行注释。

表9-3。

AdditionalConnectionsforthePyboardandCC3000BreakoutBoard

由于需要这些额外的导线,Pyboard布线图有点复杂。图9-2显示了带有CC3000分线板的Pyboard的接线图。

图9-2。

哇,好多电线啊!您可以看到使用内置WiFi的MicroPython板的优势——您不必使用额外的电线,这些电线有时会使一个简单的项目变得更加复杂,或者当您看着您的项目全部连接起来时,它看起来像一个电线窝。

如果您使用Pyboard,您可以使用板载指示灯,而不是单独的指示灯。

最后,一定要确保仔细连接项目,仔细检查所有连接,尤其是电源、接地和用于信号的任何引脚(将设置为“高”或“开”),如用于SPI接口的引脚。最重要的是,当项目(或您的板)通电时,切勿插拔跳线。这很可能会损坏您的主板或组件。

项目通电时,切勿插拔跳线。您可能会损坏您的主板或组件。

现在是时候为我们的项目编写代码了。代码并不太复杂,但是比迄今为止的例子要长一点。因此,我们将分两部分编写代码。在第一部分中,我们将看到如何编写代码来模拟行人人行横道按钮和交通灯。在第二部分中,我们将放弃使用硬件按钮,而是使用web浏览器来远程控制按钮动作。

这些部分演示了WiPy的代码,并描述了Pyboard的不同之处。有关每块电路板的代码,请参见本章末尾的完整代码列表。

正如您将看到的,第二部分将重用第一部分的大部分代码,但是HTML服务器代码会稍微复杂一些。让我们从项目的第一部分开始。

该项目的第一部分的代码将需要监控按钮,当按下时,如上所述循环灯。我们还需要代码来初始化led,将它们设置为初始关闭。我们可以编写函数来监控按钮和循环发光二极管。我们将使用一个中断来将按钮的功能绑定到硬件上,这样我们就可以避免使用轮询循环。

该项目的导入将需要来自machine库和utime库的Pin类。下面显示了WiPy的导入。

frommachineimportPinimportutimePyboard的导入还需要来自pyb库的Pin类以及delay函数和ExtInt类。ExtInt类用于设置按钮被按下时触发的中断。

frompybimportPin,delay,ExtInt设置这个项目的设置代码将需要初始化按钮和LED实例,然后关闭所有的LED(作为一种预防措施),打开绿色的交通信号灯LED和红色的步行信号LED。清单9-1显示了设置和初始化的代码。

#SetupthebuttonandLEDsbutton=Pin('P23',Pin.IN,Pin.PULL_UP)led1=Pin('P3',Pin.OUT)led2=Pin('P4',Pin.OUT)led3=Pin('P5',Pin.OUT)led4=Pin('P6',Pin.OUT)led5=Pin('P7',Pin.OUT)#SetuplistsfortheLEDsstoplight=[led1,led2,led3]walklight=[led4,led5]#TurnofftheLEDsforledinstoplight:led.value(0)forledinwalklight:led.value(0)#Startwithgreenstoplightandredwalklightstoplight[2].value(1)walklight[0].value(1)Listing9-1.SetupandInitializationoftheButtonandLEDs(WiPy)需要注意的一点是按钮是如何初始化的。这是一个被设置为输入(读取)的Pin对象实例,上拉电阻打开。这使得电路板能够检测到按钮何时被按下,因为在建立连接时(按钮被按下),引脚的值将为正值。

还要注意,我创建了一个列表,其中包含交通灯和步行信号的led(代码中称为walklight)。这主要是为了演示,这样您可以看到如何管理类对象列表。正如您所看到的,使用一个循环为列表中的所有对象调用同一个函数更容易。请注意这项技术,因为在其他项目中您会不时地需要它。

Pyboard的代码基本相同。不同之处包括led和按钮的不同引脚编号(见接线图),引脚初始化的不同选项(Pin.OUT_PP而非Pin.OUT),以及Pin类使用不同的功能:high()用于value(1),而low()用于value(0)。

项目的这一部分需要两个功能。首先,我们需要一个函数来循环灯光。其次,我们需要一个功能来监控按钮的按下。我们来看一下循环灯功能。

我们将周期灯功能命名为cycle_lights()。回想一下,我们需要控制灯光如何改变状态。如前所述,我们以特定的周期来完成这项工作。总的来说,当我们想要模拟按下行走请求按钮时交通灯的变化时,我们调用这个函数。因此,这个函数将从按钮的代码中调用。清单9-2显示了cycle_lights()按钮的代码。正如您将看到的,代码相当简单。唯一棘手的部分可能是用于闪烁黄色行走LED的回路。一定要通读一遍,这样你才能理解它是如何工作的。

#Weneedamethodtocyclethestoplightandwalklight##Wetogglefromgreentoyellowfor2seconds#thenredfor20seconds.defcycle_lights():#Goyellow.stoplight[2].value(0)stoplight[1].value(1)#Wait2secondsutime.sleep(2)#Goredandturnonwalklightstoplight[1].value(0)stoplight[0].value(1)utime.sleep_ms(500)#Givethepedestrianachancetoseeitwalklight[0].value(0)walklight[1].value(1)#After10seconds,startblinkingthewalklightutime.sleep(1)foriinrange(0,10):walklight[1].value(0)utime.sleep_ms(500)walklight[1].value(1)utime.sleep_ms(500)#Stop=green,walk=redwalklight[1].value(0)walklight[0].value(1)utime.sleep_ms(500)#Givethepedestrianachancetoseeitstoplight[0].value(0)stoplight[2].value(1)Listing9-2.Thecycle_lights()Function(WiPy)Pyboard的代码与前面提到的控制led和使用delay()功能代替utime类睡眠功能的变化非常相似。

defbutton_pressed(line):cur_value=button.value()active=0while(active<50):ifbutton.value()!=cur_value:active+=1else:active=0utime.sleep_ms(1)print("")ifactive:cycle_lights()else:print("Falsepress")Listing9-3.Thebutton_pressed()Function(WiPy)Tip

最后,我们需要设置当板卡检测到中断时调用button_pressed()函数的按钮。下面设置了WiPy上的回调函数。

#Createaninterruptforthebuttonbutton.callback(Pin.IRQ_FALLING,button_pressed)Pyboard上的代码也是单行代码,但是在这种情况下,我们必须使用ExtInt类来设置中断处理程序,如下所示。

#Createaninterruptforthebuttone=ExtInt('X1',ExtInt.IRQ_FALLING,Pin.PULL_UP,button_pressed)Tip

有关对WiPy使用引脚回调和对Pyboard使用中断的更多信息,请参见在线MicroPython文档。

现在我们已经准备好测试代码了。继续打开一个名为ped_part1_wipy.py(或者Pyboard的ped_part1_pyb.py)的新文件,输入上面的代码。清单9-4显示了项目第一部分的完整代码。如果你正在使用Pyboard,通过查看本章末尾的完整列表来作弊是可以的。

>>>importped_part1_wipy一旦导入,代码将运行,您可以按下按钮来查看灯光循环通过阶段。如果您没有看到任何灯亮起(绿色停车灯和红色行走信号灯应该亮起),请检查设置和初始化代码。如果按下按钮时灯不闪烁,请检查按钮的代码以确保它是正确的。如果它们没有按顺序亮起,可能是针脚接线不正确。遇到问题时,请务必检查所有接线连接,在断开或重新连接任何电线或组件之前,请务必关闭主板电源。

当项目运行时,尝试几次,以确保它按预期运行。那你应该恭喜你自己!您刚刚将几个分立的电子元件连接在一起,制作了一个行人行走按钮和交通灯的工作模拟。酷!

现在,让我们把这个项目提升一个档次,让它可以通过互联网访问。毕竟,这就是IOT的全部!

这一部分的代码将使用第一部分的所有代码,但我们不需要按钮的代码。相反,我们将使用Socket类创建一个监听器来监听来自web浏览器的连接。该代码将向客户端发送一个简短的基于HTML的响应(一个简单的web页面),其中包括一个包含两个按钮的表单——一个用于walk请求,另一个用于关闭服务器代码。侦听器将在端口80上侦听。

如果您正在使用WiPy,您不需要添加任何网络代码,但是如果您想在自己的网络上运行该项目或者将它连接到Internet,我将向您展示如何添加代码。

HTML服务器的概念非常简单。代码监听套接字端口上的连接,然后接收请求(在本例中以HTMLGET方法的形式)并发送HTML响应(网页)。然后,代码检查请求是否包含来自两个按钮之一的表单数据:一个按钮请求步行周期,另一个按钮关闭服务器。正如您将看到的,关闭服务器迫使我们将代码写得更加整洁。

让我们看看imports部分需要做的更改。

在导入部分我们还需要几个库。我们需要socket库(为了清楚起见,用别名重新命名了)machine库,以及来自network库的WLAN类。以这种方式编写导入是完全正常的,但是只要有一点想象力,您就可以简化它们。你明白了吗?下面显示了WiPy的完整导入部分。

frommachineimportPinimportusocketassocketimportutimeimportmachinefromnetworkimportWLANPyboard的导入有点短。我们需要为网卡添加SPI库和network库以及socket库。下面显示了Pyboard的完整导入部分。

frompybimportPin,delay,ExtInt,SPIimportnetworkimportusocketassocket现在,让我们看看设置部分的变化。

WiPy的网络代码与我们在本书前面看到的代码相同。在这种情况下,它设置无线网络功能以连接到现有的无线网络,而不是WiPy的默认接入点行为。清单9-5显示了WiPy的网络代码。

#Setuptheboardtoconnecttoournetwork.wlan=WLAN(mode=WLAN.STA)nets=wlan.scan()fornetinnets:ifnet.ssid=='YOUR_SSID':print('Networkfound!')wlan.connect(net.ssid,auth=(net.sec,'YOUR_PASSWORD'),timeout=5000)whilenotwlan.isconnected():machine.idle()#savepowerwhilewaitingprint('WLANconnectionsucceeded!')print("MyIPaddressis:{0}".format(wlan.ifconfig()[0]))breakListing9-5.WirelessNetworkSetup(WiPy)Pyboard的网络代码与我们在本书前面看到的代码相同。在这种情况下,它首先设置SPI接口到网络板(在本例中是CC3000分线板),然后启动到现有无线网络的无线连接,而不是WiPy的默认接入点行为。清单9-6显示了Pyboard的网络代码。

#Setupnetworkconnectionnic=network.CC3K(SPI(2),Pin.board.Y5,Pin.board.Y4,Pin.board.Y3)#ReplacethefollowingwithyoutSSIDandpasswordnic.connect("YOUR_SSID","YOUR_PASSWORD")print("Connecting...")whilenotnic.isconnected():delay(50)print("Connected!")print("MyIPaddressis:{0}".format(nic.ifconfig()[0]))Listing9-6.WirelessNetworkSetup(Pyboard)Tip

您必须更改代码中的SSID和密码以匹配您的网络。

设置的另一部分是HTML响应代码。这似乎是代码中很难的部分,但是很简单。我们正在构造一个字符串,我们将通过套接字把它发送回客户机。该字符串包含以头开始的HTML代码。然后,我们提供一个标题(出现在浏览器的标题栏中),一些显示在页面上的文本,以及一个包含这两个按钮的表单。这些按钮的形式是,当每个按钮被按下时,都会通过套接字向服务器发送一个HTMLGET请求。简单!清单9-7显示了项目的HTML字符串。还是那句话,不用担心细节。你可以以后再改进网页。

#HTMLwebpagefortheprojectHTML_RESPONSE="""MicroPythonfortheIOT-Project2

MicroPythonfortheIOT-Project2


AsimpleprojecttodemonstratehowtocontrolhardwareovertheInternet.


REQUESTWALK

StopServer
"""Listing9-7.HTMLResponseString注意代码(标签中的按钮)。名称和值将在请求中发送到服务器。按钮的类型被定义为submit,当按钮被放置在表单上时,当按钮被按下时,会使客户端将表单数据发送到服务器。最后,结束标记前的字符串是将显示在按钮上的标签。

如果你担心这是一个占用内存的大字符串,你是对的,确实如此。如果您正在计划一个使用大量HTML响应或者多个响应的项目,您可能希望考虑将这些响应存储在一个文件中(每个文件一个响应),并在将数据发送到客户端之前从文件中读取数据。这将节省一些数据空间,并可能对使用更多内存的大型项目产生影响。

不要在意这里使用的行数。空白主要是用来装饰的,所以如果你想减少它的整体视觉尺寸,你可以去掉空白,但是通常的做法是像这样缩进HTML代码以便于阅读。

关于在MicroPython板上使用HTML,还有一件重要的事情需要弄清楚:这个例子和您可能在互联网上找到的许多其他例子不应该与健壮的web服务器混淆。更具体地说,这个例子只是在侦听网络套接字时,一旦检测到来自客户机的HTMLGET方法(请求),就将HTML发送回客户机。所以,这个例子仅仅是一个简单的HTML服务器,而不是一个web服务器,因为它能做web服务器能做的所有事情——它不能。因此,您应该注意对项目进行编码,将操作限制在特定的GET(或POST)请求上,并返回适当的HTML响应。

UsingWebPageswithImages

由于MicroPython中还没有内置的web服务器,因此为web页面提供图像或任何其他媒体是有问题的。然而,你可以使用一个小技巧和你的电脑在你的项目中使用图像。我们可以在我们的PC上使用Python中的SimpleHTTPServer来提供一个基本的web服务器。在我们的MicroPython板的HTML中,我们可以对图像使用img标签,它使用一个URL指向我们PC上的文件。例如,下面的HTML将引用与我们PC上的HTTP服务器在同一个文件夹中的图像。

$python-mSimpleHTTPServerServingHTTPon0.0.0.0port8000...127.0.0.1--[07/Aug/201714:42:30]"GET/red.pngHTTP/1.1"200-这创建了一个混合解决方案,它将允许您在您的MicroPython基于web的项目中使用图像,尽管需要我们的PC(或您网络上的任何其他PC)的一点帮助。

现在我们来看看如何制作run()函数。

代码中剩下要做的就是更改硬件按钮的代码,并创建一个包含代码主要部分的run()函数。在这个项目中,包括设置套接字的代码以及监听和响应代码。您可以保留button_pressed()功能,但它不是必需的。清单9-8显示了run()函数的代码。

循环内部是事情变得有趣的地方。我们做的第一件事是使用sock.accept()接受来自套接字的连接,它返回两项:客户机对象实例和客户机的地址。我们可以打印出客户端的地址以供调试之用。

接下来,我们告诉客户端通过client.recv(1024)调用接收多达1024个字节。这将一直等到有来自客户端的响应,所以请注意这不是一个抢占式循环——它将一直等到客户端响应。当客户端发送数据时(比如第一次连接或按下按钮时),我们可以搜索为命令发送的字符串。

注意,在代码中,我们检查搜索b'GET/WALK=PLEASE'的行走请求或搜索b'GET/shutdown=now'的关闭事件。这里有一点需要解释的诡计。我们使用请求字符串作为一个数组,从字符串中的字符数(17或18)开始搜索,用[:17]或[:18]表示。

如果检测到walk请求,我们就调用cycle_lights()函数,这是第一部分中没有修改的函数。如果检测到关机事件,我们将循环设置为终止,然后退出run()功能。

最后,您必须删除设置按钮回调(或Pyboard上的ExtInt()调用)的代码行。把它留在里面不会损害代码,但是因为我们不使用按钮,所以不需要它,所有不必要的代码都应该删除。

现在,让我们看看WiPy和Pyboard的完整代码。

在本节中,我们将看到WiPy和Pyboard的最终完整代码。这些列表供您参考,以确保您拥有适合您的主板的正确代码。清单9-9显示了在WiPy上运行项目的完整代码。

现在是有趣的部分!我们已经设置好了控制led的代码,从第一部分我们就知道它是有效的。我们还有代码来设置一个套接字侦听器,以通过我们的MicroPython板上的端口80接受连接。我们现在所需要的就是那块板的IP地址来指向我们的网络浏览器。我们可以通过运行代码从我们的调试语句中得到答案。清单9-11显示了项目在WiPy上的初始运行(Pyboard的结果类似)。

MicroPythonv1.8.6-694-g25826866on2017-06-29;WiPywithESP32Type"help()"formoreinformation.>>>importped_part3_wipyaswNetworkfound!WLANconnectionsucceeded!MyIPaddressis:192.168.42.128>>>w.run()Gotaconnectionfromaclientat:('192.168.42.127',49236)Gotaconnectionfromaclientat:('192.168.42.127',49237)Gotaconnectionfromaclientat:('192.168.42.127',49243)Requestingwalknow!Gotaconnectionfromaclientat:('192.168.42.127',49254)Goodbye!>>>Listing9-11.RunningtheStoplightSimulation(WiPy)注意,在这种情况下,IP地址是192.168.42.127。我们需要做的就是把它放入我们的浏览器,如图9-3所示。

如果您使用WiPy和telnet打开REPL控制台,请注意,一旦您运行代码的网络部分,您的REPL控制台将断开连接。这是因为IP地址会变!因此,当使用WiPy连接到您的网络时,最好通过USB使用屏幕或其他终端程序来获得REPL控制台。

图9-3。

StoplightSimulationProject

输入URL后,您应该会看到如图所示的网页。如果没有,一定要检查代码中的HTML,确保它和显示的完全一样;否则,页面可能无法正常显示。您还应该确保您的PC所连接的网络可以连接到您的主板所连接的网络。如果您的家庭办公室像我一样设置,可能有几个WiFi网络可供您使用。最好你的主板和你的电脑在同一个网络(和同一个子网)。

一旦你解决了这个问题,继续按下按钮。请记住,步行按钮将启用,您将看到灯光循环,但您将无法做任何事情,直到步行循环完成。这是因为我们直到循环完成后才返回响应HTML(请看代码来说服自己)。此外,当您单击shutdown按钮时,您将需要重新启动代码来重新运行它。只需再次调用run()函数。

这个过程的最后一步对于这个项目来说是可选的,因为除了测试之外,您不太可能希望它运行更多。然而,如果您确实想让它在每次启动您的板时运行,您可以修改板上的main.py代码模块来导入您的代码并调用run()函数。

WhenThingsGoWonky1

有时,当处理更大的脚本或更复杂的逻辑、许多库(驱动程序),甚至当使用许多字符串(内存)时,有时会遇到奇怪、简洁的错误。下面是一个例子。

Traceback(mostrecentcalllast):File"",line1,inFile"ped_part2_wipy.py",line97,inrunOSError:[Errno12]ENOMEM在这种情况下,该错误是一个内存不足错误,意味着您的MicroPython板已经为您的代码分配了所有(或几乎所有)内存,并且它无法继续。此时你唯一能做的就是重启主板。您可以尝试软启动(CTRL-D),但这通常不能解决问题,但硬重启可以。

至此,您已经完成了第一个真正的MicroPythonIOT项目。我们可以称之为IOT项目,因为它使用互联网,但它只是一个模拟,并不实际控制真正的交通灯,但我们在这个项目中看到的技术允许我们将我们的MicroPython板连接到互联网并与之交互-这就是IOT的全部内容!

如果您准备迎接真正的挑战,您可以在这个项目中重用代码,并用继电器板替换按钮逻辑,这样您就可以使用MicroPython板等低压设备来打开或关闭高压电路。在这种情况下,您可以使用HTML按钮通过互联网打开或关闭中继。

使用分立的电子元件会非常有趣。当你刚开始接触电子学时,光是让电路工作就令人兴奋不已。现在我们对MicroPython有了更多的了解,我们可以看到拥有像Python这样的易于编程的语言来直接处理硬件——甚至通过互联网——是多么强大。

在这一章中,我们实现了一个行人人行横道按钮和交通信号灯的模拟。我们用一系列发光二极管来代表交通信号灯和步行信号。我们还添加了一个硬件按钮来模拟按下真正的步行按钮,然后通过简单的HTML从我们的MicroPython板上将它转换成一个遥控按钮。如果你喜欢这个项目,你会更喜欢接下来的两个项目。

在下一章中,我们将探索一个项目,该项目使用传感器读取值,然后将数据存档,并在需要时显示在网页上。这是我们构建真正的MicroPythonIOT项目的倒数第二步。本章和下一章将向您展示如何通过互联网提供数据,项目的最后一章将向您展示如何通过云服务提供您的传感器数据。

一个高度技术性的术语,描述一种极度混乱和普遍执行失败的状态。不要与hinky混淆,hinky表示当某件事情工作但不太正确时,情况稍微不太严重。

我把这些包括在内,这样你可以增长你的知识,超越这本书的范围。当你完成书中的其他项目时,试试这些。

IOT项目最常见的形式之一是那些使用传感器监控事件的项目,这些传感器将数据提供给另一台机器、云服务或本地服务器(如HTML服务器)。一种方法是将MicroPython板连接到一组传感器上,然后记录数据。您可以在互联网上找到几个通用数据记录器的示例,但是很少将数据记录与可视化组件结合起来。事实上,理解数据是制定成功的IOT解决方案的关键。

在这个项目中,我们将探索如何将数据记录与数据可视化结合起来。我们将使用与上一章相同的HTML服务器技术以及前几章的一些技术。我们还将了解如何使用模拟传感器——这种传感器产生模拟数据,然后我们必须对其进行解释。事实上,我们将依靠电路板的模数转换(ADC)功能来将电压读数变为我们可以使用的值。当我们利用从第四章中学到的关于类和模块的知识时,我们还会在代码中看到更多的复杂性。

这个项目增加的复杂性不是新的硬件或接口,尽管我们将看到如何使用模数转换器类;复杂性在于代码的复杂性。正如你将看到的,本章中使用的代码比以前的项目更加模块化,使用了更多的功能。仅仅因为这个原因,它就更复杂了。但是,正如您将看到的,代码并不难学,并且使用了我们在前几章中看到的概念。

在这一章中,我们将实现一个植物土壤湿度监测解决方案(简称植物监测)。这将涉及到使用一个或多个连接到我们的MicroPython板上的土壤湿度传感器。我们将设置一个定时警报(中断)来定期运行,以从传感器读取数据,并将其存储在一个逗号分隔值(CSV)文件中。

图10-1描绘了该项目的概念图。MicroPython板将从土壤湿度传感器读取数据,然后根据请求通过HTML网页显示出来。

图10-1。

PlantMonitoringProjectConcept

这个项目的用户界面是一个由一个表组成的网页,该表包含从日志文件中读取的所有数据。这就是我们如何克服在循环中运行HTML服务器的潜在问题。也就是说,我们不必中断循环来读取传感器——这是通过定时器警报回调来完成的。遗憾的是,这种技术只适用于WiPy和类似的电路板。我们将不得不对Pyboard使用不同的技术。

通过将传感器读数从显示中分离出来,我们可以重用或修改它们,而不会在钻研代码时感到困惑。例如,只要可视化组件从文件中读取传感器数据,读取代码的传感器如何使用它就无关紧要。这两部分之间唯一的接口或连接是文件的格式,因为我们使用的是CSV文件,所以在我们的代码中很容易阅读和使用。

为了让事情变得更有趣和更容易编码,我们将把所有传感器代码放在一个单独的代码模块中。回想一下,这是一种技术,用于帮助减少任何一个模块中的代码量,从而使其更容易编写和维护。

由于我们已经进入了第三个项目,并且已经看到了该项目中采用的许多技术,所以关于所需组件、布线和硬件设置的讨论应该是简短的。

表10-1列出了你需要的部件。您可以从Adafruit(adafruit.com)、Sparkfun(sparkfun.com)或任何出售电子元件的电子商店单独购买元件。如果您想购买这些组件,可以链接到供应商。当列出同一对象的多行时,您可以选择其中一行——您不需要两个都要。此外,您可能会找到销售这些组件的其他供应商。你应该货比三家,找到最好的交易。显示的成本是估计值,不包括任何运输成本。

表10-1。

土壤湿度传感器有多种形式,但大多数都有两个插入土壤的插脚,使用少量电荷测量插脚之间的电阻。读数越高,土壤中的水分越多。但是,要获得可靠或现实的阈值,需要进行一些配置。虽然制造商会有阈值建议,但可能需要一些实验来找到正确的值。

这些传感器也会受到环境因素的影响,包括植物所处的花盆类型、土壤成分和其他因素。因此,用一种已知的过度湿润的土壤、干燥的土壤和适当养护的土壤做实验,将有助于你缩小你的环境门槛。

图10-2显示了Sparkfun的土壤湿度传感器,它有一个端子座,而不是引脚。你可以找到几种不同的传感器。只需选择您想要使用的一个,记住您可能需要不同的跳线将其连接到您的主板。

图10-2。

幸运的是,这个项目的布线没有前两个项目复杂。现在,让我们看看如何将组件连接在一起。

表10-2显示了本项目所需的连接。这里只显示了两个传感器,但是如果你愿意的话,你可以增加几个。但是,建议您从一个传感器开始,直到项目正常运行,然后添加其他传感器。如果更简单,您可以使用试验板将传感器连接到MicroPython板,但根据您计划放置板的位置,您可能不需要它。这是你的选择。

表10-2。

当然,你必须将土壤湿度传感器插入植物的土壤中。如果您的工厂离您的电源较远,您可能需要使用更长的电线来连接传感器。您应该从一个小型设备和一个传感器(或者为了测试,一个设备中有两个传感器)开始,将它们放在靠近您的PC(或电源)的地方。

你需要能够在3.3-5V电压下工作的土壤湿度传感器。一些MicroPython板可能会将引脚上的输出限制为3.3v。sparkfun的传感器是兼容的。

让我们看看如何连接WiPy和Pyboard,如图所示。

WiPy的布线最好是将USB连接器朝向左侧。图10-3显示了WiPy的接线图。注意使用小试验板来帮助接地连接。还要注意,传感器1在左侧,传感器2在右侧。

图10-3。

WiringthePlantMonitor(WiPy)

Pyboard的布线最好将USB连接器朝向左侧。图10-4显示了Pyboard的接线图。您可能需要使用试验板来连接网络模块,如图所示。还要注意,传感器1在左侧,传感器2在右侧。

图10-4。

WiringthePlantMonitor(Pyboard)

现在是时候为我们的项目编写代码了。代码比我们到目前为止看到的要长,由于我们正在处理的所有零零碎碎的东西,最好将项目分成几个部分。因此,我们将分两个阶段编写代码。我们直到最后才会有一个工作项目,所以大部分的讨论都是关于各个部分的。在测试这个项目之前,我们将把它们放在一起。

回想一下概述,我们将有两个主要组件:主代码和封装土壤传感器的代码模块。我们将把HTML服务器代码和支持函数放在主代码模块中。然而,在我们开始项目的代码之前,我们应该校准我们的传感器。让我们现在做那件事。

这些部分演示了WiPy的代码。该项目最适合具有类似功能的WiPy和主板:即WiFi和NTP支持。本章末尾给出了在Pyboard和Pyboard克隆板上实现项目的差异。正如您将看到的,让项目在这些板上运行需要做更多的工作。

传感器的校准非常重要。对于土壤湿度传感器来说尤其如此,因为有许多不同的版本可供选择。这些传感器对土壤成分、温度,甚至植物所在的花盆类型也非常敏感。因此,我们应该用已知的土壤湿度进行实验,这样我们就知道在我们的代码中使用什么样的范围。

更具体地说,我们希望对来自传感器的观察结果进行分类,以便我们可以确定植物是否需要浇水。我们将使用值“干”、“正常”和“湿”来对从传感器读取的值进行分类。看到这些标签,我们一眼就能轻松确定植物是否需要浇水。在这种情况下,原始数据如1756的值可能没有太大的意义,但如果我们看到“干燥”,我们就知道它需要水。

由于传感器是模拟传感器,我们将在电路板上使用模数转换。当我们从pin读取数据时,我们将得到一个0-4096范围内的值。该值与传感器在土壤中读取的电阻有关。低值表示土壤干燥,高值表示土壤潮湿。

但是,不同供应商的传感器读取的值可能会有很大差异。例如,Sparkfun的传感器倾向于读取0-1024范围内的值,但其他供应商的传感器可以读取高达4096的值。幸运的是,它们似乎都是一致的,数值越低,土壤越干燥。

因此,我们必须确定这三种分类的阈值。同样,有几个因素会影响从传感器读取的值。因此,你应该选择几盆土壤,其中一盆你觉得干燥,另一盆浇水适当,第三盆浇水过多。最好的办法是选择一个干燥的,测量,然后浇水,直到土壤湿度合适,测量,然后再次浇水,直到有太多的水。1

为了确定阈值,我们必须首先编写一小段代码来设置我们的电路板,以便从传感器读取值。这包括选择支持ADC的GPIO引脚。查看您的主板的参考图,确定包括哪些GPIO引脚。例如,在WiPy上,有几个ADCGPIO部分,包括P13至P18范围内的部分。

#MicroPythonfortheIOT-Chapter10##Project3:MicroPythonPlantMonitoring##Thresholdcalibrationforsoilmoisturesensors##Note:thisonlyrunsontheWiPy.frommachineimportADC,Pinimportutime#SetuptheADCchannelfortheread(signal)#HerewechoosepinP13andsetattnto3tostabilizevoltageadc=ADC(0)sensor=adc.channel(pin='P13',attn=3)#SetuptheGPIOpinforpoweringthesensor.WeusePin19power=Pin('P19',Pin.OUT)#Turnsensoroffpower.value(0)#Loop10timesandaveragethevaluesreadprint("Reading10values.")total=0foriinrange(0,10):#Turnpoweronpower.value(1)#Waitforsensortopoweronandsettleutime.sleep(5)#Readthevaluevalue=sensor.value()print("Valueread:{0}".format(value))total+=value#Turnsensoroffpower.value(0)#Nowaveragethevaluesprint("Theaveragevaluereadis:{0}".format(total/10))Listing10-1.CalibratingtheSoilMoistureThreshold(WiPy)如果您在一个名为threshold.py的文件中输入这个代码,那么您可以将它复制到您的WiPy中并执行它。清单10-2显示了在正确灌溉的植物中运行此校准代码的输出。

>>>importthresholdReading10values.Valueread:1724Valueread:1983Valueread:1587Valueread:1702Valueread:1634Valueread:1525Valueread:1874Valueread:1707Valueread:1793Valueread:1745Theaveragevaluereadis:1727.4>>>Listing10-2.RunningtheCalibrationCode(WiPy)这里我们看到的平均值是1727(总是取整数——你需要整数)。在干燥的土壤上运行该代码的进一步测试得到的值是425,而在潮湿的植物上是3100。因此,这个例子的阈值是500代表干,2500代表湿。但是,您的结果可能会有很大差异,因此请确保使用您选择的传感器、电路板和设备运行此代码。

为了简化阈值校准,请使用同一供应商的传感器。否则,您可能需要为每个受支持的传感器使用不同的阈值集。

现在我们已经有了传感器的阈值,我们可以从传感器的代码模块开始。

该项目的第一部分将是创建一个代码模块,包含一个名为PlantMonitor的新类,该类包含从传感器读取数据并将数据保存到文件中的所有功能。在这一节中,我们将看到如何编写模块的代码。如果您想继续编写代码,您可以打开一个新文件并将其命名为plant_monitor.py。先从高层设计来看。

正如我们前面所学的,为我们想要使用的每个代码模块(类)创建一个设计是一个好主意。我们将使用主代码中的代码模块。因此,我们需要一些函数来告诉这个类读取传感器,以及一种方法来获取这个类用于数据的文件名。

通常,人们会设计一个代码模块来完全隐藏一个文件和其上的所有操作,但在这种情况下,该类只关心读取传感器和写入数据。另外,由于主代码需要读取数据并用HTML标记对其进行格式化,因此将read函数放在主代码中更合适。也就是说,您应该努力将相似的代码功能放在一起,这有助于维护代码。例如,将所有的HTML代码保存在一个文件中使得修改HTML代码(或者重用它)变得更加容易。

表10-3。

High-LevelDesign(Functions)PlantMonitorClass

注意第一个名为__init__()的函数。这是该类的构造函数,将在从我们的主代码实例化该类时被调用。还要注意私有方法是用一个下划线命名的。

以下部分解释了初始化代码和所需的函数。我们将在后面的部分看到完整的代码。

在本节中,我们将讨论设置和初始化代码模块所需的代码。首先,我们需要一些导入,包括模数转换器、pin、安全磁盘(SD)、定时器和操作系统库。

我们还需要为这个类定义一些常量。回想一下,我们想用枚举法对土壤湿度读数进行分类。为此,我们需要使用我们为分类确定的阈值。我们可以在文件的顶部使用常量,以便在以后需要调整代码以用于其他传感器或我们的工厂条件发生变化(不同的花盆、土壤、环境等)时更容易更改它们。).我们可以使用相同的原理来设置包含数据的文件名。

我们还使用一个常数来定义读取传感器的频率。由于我们将使用一个循环来读取传感器,每次读取需要等待5秒,因此我们至少需要50-55秒来读取10个值。因此,我们不能将更新频率设置为少于一分钟。频率以秒为单位。虽然您可能希望将此设置为较低的测试值,但您肯定不希望每分钟都检查植物的土壤湿度。也就是说,你多久检查一次你的植物?几天一次还是一天一次?为什么比平时检查得早?

SamplingFrequency

在设计传感器网络时,经常会忽略从传感器采样数据的频率(也称为采样率)。趋势是存储尽可能多的值;认为数据越多越好。但这在一般情况下是不适用的。考虑工厂监控项目。如果您通常每天检查一次工厂,那么每5分钟对传感器进行一次采样对您有什么好处呢?不会,而且只会产生多余的数据!

采样率必须仔细计算,以提供您需要的数据,从而在不创建太多数据的情况下得出结论。虽然更多的数据总是比太少的数据好,但以不切实际的频率过于频繁地保存数据会产生太多的数据,可能会超出设备的存储容量。

清单10-3显示了设置和初始化部分的代码。把这个放在文件的顶部。

frommachineimportADC,Pin,SD,Timerimportosimportutime#ThresholdsforthesensorsLOWER_THRESHOLD=500UPPER_THRESHOLD=2500UPDATE_FREQ=120#seconds#FilenameforthedataSENSOR_DATA="plant_data.csv"#Formatthetime(epoch)forabetterviewdef_format_time(tm_data):#Useaspecialshortcuttounpacktuple:*tm_datareturn"{0}-{1:0>2}-{2:0>2}{3:0>2}:{4:0>2}:{5:0>2}".format(*tm_data)Listing10-3.PlantMonitorClassSetupandInitialization(WiPy)构造器类的构造函数是所有主要工作发生的地方。我们需要做几件事,包括以下几件。

我们通过尝试使用SD卡来规范化数据文件的路径。如果找不到SD卡,我们默认使用闪存盘。但是,您应该避免将数据写入闪存驱动器,因为驱动程序较小,可能会被填满,并且写入闪存驱动器会增加损坏驱动器或在执行过程中导致问题的风险。

我们为每个传感器使用一个字典,这样我们就可以定义传感器的pin、为传感器供电的pin、传感器号(任意标识)以及传感器的位置。然后,我们将字典放在一个列表中,以便使用循环同时读取所有传感器。

最后,我们通过timeralarm类设置一个中断来定期读取传感器。清单10-4显示了类构造函数的代码。

只有两个公共函数。第一个,clear_log(),简单地打开文件进行写入,然后关闭它。这实际上清空了文件。提供该功能是为了方便。第二个函数get_filename()只是返回用于存储数据的文件的名称。这个名字与常量SENSOR_DATA中的名字不同,因为我们在构造函数中规范化了路径,如前一节所示。

有三个私有函数。_get_value()函数与我们的阈值校准代码相同,我们对传感器采样10次并取平均值。_read_sensors()函数是定时器报警中断的回调函数,它读取我们定义的所有传感器并将数据保存到文件中。_convert_value()功能是基于传感器数据确定土壤分类的辅助功能。该函数返回一个字符串或“干”、“好”或“湿”。

现在我们已经看到了代码模块的所有部分,让我们来看看完整的代码。清单10-5显示了工厂监控代码模块的完整代码。同样,我们可以将这个文件保存为plant_monitor.py。

要在Pyboard上运行这个项目,还需要进行相当多的更改。其主要原因包括我们需要对导入进行的常规更改、引脚类别高/低与值的对比,以及我们使用实时时钟的方式的差异。最后,Pyboard不支持定时器警报类中断,因此我们必须使用轮询技术来读取传感器。这最后一个变化意味着我们必须使read_sensors()函数成为一个公共函数,这样我们就可以从主代码中调用它。

由于变化很多,差异文件几乎与实际代码一样长。因此,我们将看到Pyboard的完整代码。清单10-6显示了代码模块的完整代码,不同之处在于代码模块需要适应Pyboard(粗体)。虽然大多数变化很小,但如果您使用Pyboard或Pyboard克隆,请注意传感器使用的引脚。

以下部分解释了初始化代码和所需的函数。我们将在后面的部分看到完整的代码。让我们从HTML代码开始。

我们将把所需的HTML代码存储在文件中以节省内存。回想一下一次读取一行——我们不必在代码中用字符串来占用空间。随着您的项目变得越来越复杂,这可能会成为一个问题。因此,这个项目演示了一种节省内存的方法。

这个项目的HTML创建了一个带有简单表格的网页,该表格包含了请求时文件中的所有数据。为了方便起见,我们将使用三个文件。第一个文件(名为part1.html)将包含直到表格行的HTML代码;第二个文件(名为plant_data.csv),由PlantMonitor类填充;第三个(名为part2.html)将包含剩余的HTML代码。

第一个文件part1.html,如清单10-7所示。这个文件建立了表格HTML代码。它还建立了表格的特征,包括文本对齐、边框大小和填充——全部通过级联样式(