如何学习使用CircuitPython

电子说

1.3w人已加入

描述

概述

有几种编程微控制器的方法。有些方法比其他方法困难,这通常取决于人们对编程基础的熟悉程度。

本指南主要供Arduino开发人员通过演示程序的使用来学习使用CircuitPython的来龙去脉。两种语言的代码。这可能是对人们熟悉CircuitPython技能的参考。

同样有效的可能是从未使用过Arduino的Python或CircuitPython程序员。显示Arduino用于各种用途的代码可能有助于使自己更适应Arduino环境。

来源:https://www.xkcd.com/303/(CC BY-NC 2.5)

解释与编译

Arduino从大量使用中的工具中获取了很多东西数十年。这包括已编译代码的概念。代码是在没有调试的情况下在文本编辑器类型的环境中编写的。然后,在被命令时,将其馈送到一系列程序,这些程序将获取代码,最后将其从C或C ++编译为微控制器的机器语言。在市场上有各种各样的微控制器,机器代码是该代码和处理器所独有的。

如果需要在Arduino中更改代码,则必须编辑文本代码并通过编译过程将其提交回去。 。在每次发生的编译和加载过程中,进行更改,修复语法错误,“插入”最佳值可能会花费大量时间。

Python通常和CircuitPython特别是解释的。直到必须将代码转换为机器代码。这有很多优点。该代码可以在运行时给出错误消息。随后的任何更改都不需要重新编译。加载代码就像将代码文本文件复制到闪存驱动器一样简单。 CircuitPython程序开发通常只是Arduino程序所需时间的一小部分。该代码对于其他微控制器也具有高度的可移植性。

解释的代码的缺点是速度。将代码转换为机器代码是即时进行的,因此需要时间。解释器还使用微控制器上的RAM和Flash,而不是等效的Arduino用户代码和库。

材料:MS Word 2010剪贴画

Reality

现代微控制器的速度和存储容量不断提高,其价格通常与较旧的微控制器相似或更低(制造商可能希望在某个时候停产)。在现代芯片中,在微控制器上使用Python不会带来速度上的损失。 Python的灵活性以及在学校中教授的灵活性的优势使Python成为人们关注的焦点。

在这个时代,提供帮助将Arduino编码器迁移到CircuitPython的工具似乎特别合适,因为这无疑是行业发展的方向

您可能会很慢,但仍然会赢。而且乌龟的寿命很长。

计算机Python

那Linux板呢?

Arduino代码通常不能在Raspberry Pi,BeagleBone等小型Linux板上运行。为什么?

Linux是一个完整的操作系统,它可以一次运行许多东西。 Arduino代码必须学会共享资源,而不要使用整个处理器,尤其是在无限循环中。也许有一天会添加此功能,但现在不可用。

Python在Linux板上非常流行。 CircuitPython可以通过Adafruit提供的名为Blinka的帮助程序层在小型Linux板上运行。这提供了CircuitPython在微控制器上可以做什么以及如何在Linux上运行之间所需的映射。它们旨在共同发挥作用(只要您的代码也写得很好。

因此,对于基于Linux的小型单板计算机,CircuitPython是目前的唯一选择。但这是一个不错的选择。

在本指南中,我们将不介绍在Linux上通过CircuitPython使用硬件的详细信息。在此处查看有关Blinka的指南

简单的代码结构

Arduino strong》

编程

上图显示了最简单的Arduino程序,即从菜单中选择文件-》 新建会得到的结果。有两个强制性函数调用:

setup-程序启动时将执行一次的代码

loop-连续的代码一遍又一遍地循环运行

这两个函数都不做任何事情。有些草图仅在setup中执行所有操作,而有些程序根本不使用setup而仅使用loop。但是,即使它们是空的(如上所示),也必须同时定义两者。

CircuitPython

CircuitPython并没有限制像Arduino setup函数这样的开始执行的代码重复的主要代码,例如Arduino loop函数。

也就是说,许多CircuitPython程序的结构与Arduino素描程序的结构非常相似。

一个简单的示例。程序将变量var定义为值5,然后一遍又一遍地打印该值,类似于旧的BASIC Hello World程序。在Arduino中,您可以这样编写:

编程

程序会添加一些代码以打开串行连接并输出输出。

等效的CircuitPython程序为:

编程

任何setup类型语句放在程序顶部附近。

可以在Python中通过loop循环将条件设置为while,因此它永远不会退出True。

串行监视器已“嵌入”到CircuitPython中,用户无需设置任何内容即可使用它,并且将对此进行详细讨论。

没有任何限制,CircuitPython完全必须执行无限循环。一个简单的程序可以读取温度传感器,打印输出并结束。

但是,Arduino和CircuitPython都在微控制器上运行。在课堂上,您可能想要做一次读取和打印温度值之类的操作。如果将这个项目部署到农民的田地中,它可能会一遍又一遍地反复读取温度,可能每分钟或一小时读取一次。在农民的田野里,代码永远都不应停止。

因此执行某些功能的无限循环非常有用,并且在大多数微控制器程序中都使用。这就是Arduino为初学者简化事情的原因,以表明您可能想拥有while和setup。您可以在CircuitPython中执行完全相同的操作,只需构建代码以提供相同的功能即可。

处理数字

照片Nick Hillier在Unsplash上发表的文章

您会认为所有语言中的“数字就是数字”,但事实并非如此。所有数字在内部都以二进制形式在微控制器/计算机内部表示,但是编程语言如何提供数字支持会因语言而异。

数字类型

整数

浮点数

布尔值(true/false)

通常,您需要了解 precision -选择最佳的使用方式,数字的大小可能是多少它在计算机程序中。这使使用数字有些棘手,但学习起来却很容易。

Arduino

在Arduino中,您具有以下类型的变量:

int 表示整数,一个值没有小数点。整数的典型范围是-32,768到零到32,767。例如279、1001、0,-23,-990。

long 是一个大整数,值可以是-2,147,483,648到2,147,483,647。

float (浮点数)(浮点数(带小数点和小数的数字))。例子是3.1415,-22.2、0.0、430000.01。单个字符的数字最大为38 x的3 x 10

char 。例如,读取串行数据可能涉及在接收到数据时提供字符值的接收功能。字符基本上可以是键盘上的任何符号(0到255)。

types.h 库提供了趋于表现的数字的更现代表示形式

函数经常使用无符号短整数 uint8_t ,它的范围也从0到255。

布尔数学通常使用 int 值完成。 0是 false ,而任何非零的值(例如1)都是 true 。

Python/CircuitPython

CircuitPython尝试尽可能接近标准的Python实现(通常称为CPython) 。给定微控制器没有操作系统,某些事情会有所不同,但已记录在案。

以下是CircuitPython中的当前类型:

整数,但不是当前的长整数

浮点数。

字符串

布尔值

布尔值是CircuitPython中的实际类型,可以是值 True 或 False 。

CircuitPython具有专用的 Strings 类型,而不是像Arduino那样使用字符数组(以零/零终止)。请注意,CircuitPython 字符串不是以零/零结尾的,所以使用length属性是您处理字符串长度的方法。

更改数字类型

在Arduino/C中,这称为转换。

下载:文件

复制代码

int a;

float b;

b = (float)a;

a = (int)b; int a;

float b;

b = (float)a;

a = (int)b;

在CircuitPython中,您使用类似于函数的语法:

下载:文件

复制代码

x = 5

y = 3.14

z = float(x)

z = int(y) x = 5

y = 3.14

z = float(x)

z = int(y)

除法,一个斜杠对两个斜杠

两种语言中的单个正斜杠/是浮点除法。

Python中的双斜杠//很特殊。它将除以小数点后的任何值(通常称为下限函数)并进行除法。

示例:

下载:文件

复制代码

# Python code for / and // operators

x = 15

y = 4

# Output: x / y = 3.75

print(‘x / y =’, x/y)

# Output: x // y = 3

print(‘x // y =’, x//y) # Python code for / and // operators

x = 15

y = 4

# Output: x / y = 3.75

print(‘x / y =’, x/y)

# Output: x // y = 3

print(‘x // y =’, x//y)

逻辑运算符

逻辑运算符主要用于if语句和其他块/循环语句中。这些不是用于按位运算符和/或/或仅用于构造逻辑比较的运算符。

AND

OR

不是

Arduino/C

&&

||

!Python/CircuitPython

不是

下载:文件

复制代码

// Arduino / C Logical Operators

a = 5;

b = 7;

if( a 》 2 && b 《 10) {

Serial.println(“Success”);

} // Arduino / C Logical Operators

a = 5;

b = 7;

if( a 》 2 && b 《 10) {

Serial.println(“Success”);

}

下载:文件

复制代码

# CircuitPython Logical Operators

a = 5

b = 7

if a 》 2 and b 《 10:

print(“Success”) # CircuitPython Logical Operators

a = 5

b = 7

if a 》 2 and b 《 10:

print(“Success”)

变量,类型,范围

从Wikipedia中,没有列出创建者

快速参考

变量

Arduino

int a;

int b = 5;

CircuitPython

b = 5

阵列

Arduino

int a[5];

int a = {1, 2, 3, 4, 5};

CircuitPython

a = [1, 2, 3, 4, 5]

讨论

变量

变量就像计算机内存中的小盒子或信箱,可以在其中保留值。

要在C/C ++中创建变量,必须对其进行声明。这就需要给它一个类型,名称和可选的值。

下载:文件

复制代码

int a;

int b = 5; int a;

int b = 5;

在CircuitPython中,您无需声明变量。第一次分配值时便会分配它们。

下载:文件

复制代码

b = 5 b = 5

您只需使用名称即可在两种语言中使用变量的值。

下载:文件

复制代码

int x = a_number; // in C/C++

x = a_number # in CircuitPython int x = a_number; // in C/C++

x = a_number # in CircuitPython

在两种语言中,使用未知变量都是错误的:尚未声明(在C/C ++中)或未初始化(在CircuitPython中)

在C/C ++中,变量使用类型声明,并被静态类型化。它们仅具有该类型的值。

相反,CircuitPython是动态类型的。变量没有关联的类型,并且可以在不同时间具有不同类型的值。每种方法都有优点和缺点,但是在阅读某人的CircuitPython代码时,您应该记住这一点,以防某人重复使用变量并更改其类型。

集合

两种语言都可以创建和操作值的集合。

“终极”-比其他任何集合都要好。只是不要单击它。

(来自维基百科的图像,已获得合理使用许可)

Arduino

Arduino只有一种创建集合作为语言一部分的方法:数组。由于语言是C ++,因此您可以使用大多数C ++库。具有足够的CPU性能和内存,您甚至可以将Arduino版本的标准C ++和Boost库及其集合类一起使用,但是出于讨论的目的,我们假设您使用的是基本语言功能。 p》

数组是简单的固定大小,固定顺序的值序列。 C数组中的所有值都具有相同的类型。实际上,由于C是静态类型的,所以数组项的类型是数组本身类型的一部分。

例如,如果要创建一个可以容纳5个变量int中的值,您可以将其声明为:

下载:文件

复制代码

a int a[5];

如果在编译时已知初始值,则可以初始化数组创建时,并忽略其大小,因为将从初始值的数量中推断出大小。

下载:文件

复制代码

int a[5]; int a[] = {1, 2, 3, 4, 5};

要访问数组中的特定项目,请使用下标符号。可以用来从数组中获取值,或将其设置为新值。

下载:文件

复制代码

int a[] = {1, 2, 3, 4, 5}; int x = a[0];

a[1] = x + 1;

CircuitPython 》

基本的CircuitPython集合是List,其外观和工作方式与C的数组非常相似。但是,它是一个动态得多的结构:您可以自由地删除和插入项目。它的长度是其中当前有多少个项目的函数,而不是它要保留的内容的函数。由于它们是动态的,因此通常不需要提前分配它们。您可以通过将项目放在方括号中来创建列表。

下载:文件

复制代码

int x = a[0];

a[1] = x + 1; 》》》 a = [1, 2, 3, 4, 5]

与C数组一样,您使用下标符号来访问项目。

下载:文件

复制代码

》》》 a = [1, 2, 3, 4, 5] x = a[0]

a[1] = x + 1

CircuitPython的列表提供了比C数组更多的功能,但这超出了本指南的范围。 CircuitPython还具有其他内置集合:元组和字典。请参阅本指南,了解有关Python的基本数据结构,以及该指南的更多内容,重点是列表和流。

Arduino/C和Python都在0处开始元素/数组组。因此对于3元素项,它是x [0],x [1],x [2],这与某些语言(例如FORTRAN)在数组处开始元素1。

范围

来自Elborgo用户的维基百科

变量的作用域是代码中何时何地可用。 C/C ++和CircuitPython都在词法范围内。这意味着变量的范围由代码的结构定义。如果您在函数中创建变量,则该变量在该函数中可用,但不在外部。

下载:文件

复制代码

x = a[0]

a[1] = x + 1 void f() {

int a = 5;

print(a); // 1

}

print(a); // 2

由于void f() {

int a = 5;

print(a); // 1

}

print(a); // 2为范围。即它在函数a中定义,可以使用。但是,第2行会导致编译错误,因为此时名称f尚不清楚。在CircuitPython中,情况类似:

下载:文件

复制代码

a def f():

a = 5

print(a) # 1

print(a) # 2

Local and Global

上面的代码说明了本地状态。即局部于功能。这就是为什么从函数外部引用变量是一个问题。另一个范围是全局范围。在整个代码中都可以使用具有全局范围的内容。

下载:文件

复制代码

def f():

a = 5

print(a) # 1

print(a) # 2 int b = 1;

void f() {

int a = 5;

print(a + b);

}

print(b);

// prints:

// 6

// 1

这是可行的,因为int b = 1;

void f() {

int a = 5;

print(a + b);

}

print(b);

// prints:

// 6

// 1具有全局作用域,因此可以在。在CircuitPython中也是如此。

下载:文件

复制代码

b f

如果我们具有相同名称但在两个作用域中都有变量,该怎么办。现在事情开始不同了。在C/C ++中没有麻烦。

Download:file

Copy代码

b = 1

def f():

a = 5

print(a + b)

print(b)

# prints:

# 6

# 1 b = 1

def f():

a = 5

print(a + b)

print(b)

# prints:

# 6

# 1

但是,CircuitPython中的工作方式却大不相同。

下载:文件

复制代码

int a = 1;

void f() {

int a = 5;

print(a);

}

print(a);

// prints:

// 5

// 1 int a = 1;

void f() {

int a = 5;

print(a);

}

print(a);

// prints:

// 5

// 1

a = 1

def f():

a = 5 # 1

print(a)

print(a)

# prints:

# 5

# 1的分配可能存在问题。这是因为在本地作用域中没有名为“ a”的变量,因此将创建一个变量,因为这是该作用域中对a = 1

def f():

a = 5 # 1

print(a)

print(a)

# prints:

# 5

# 1的第一个赋值。对于该功能的其余部分,将使用此局部变量a,并且将保持不变(且未使用)全局范围内的变量a。

如果这正是您想要的,很好。但是,您的意图可能是将全局a的值更改为5。如果是这种情况,那么您就有问题了。像pylint这样的工具将提醒您以下事实:外部范围(在本例中为全局范围)的名称“ a”正在重新定义。那至少会引起您的注意。如果确实要使用全局a,则可以使用a语句告诉CircuitPython这是您的意图。

下载:文件

复制代码

a global

现在pylint可能会警告您,您正在使用全局语句。这是因为全局变量通常不被接受。但是用一个简单的脚本就可以了(在作者看来)。在更大,结构更强的程序中,它们使用较少,您有办法避免使用它们。

CircuitPython和C/C ++不能共享的一项有趣功能是能够关闭。

数字输入/输出

格雷厄姆·詹金斯(Grahame Jenkins)提供的UnSplash免费许可证

微控制程序的一部分正在使用I/O。 I/O的最基本形式是数字I/O引脚。这些被称为GPIO引脚( G 通用 P 设置 I 输入 O utput)

快速参考 配置输出引脚

Arduino

pinMode(13, OUTPUT);

CircuitPython

import digitalio

import board

led = digitalio.DigitalInOut(board.D13)

led.direction = digitalio.Direction.OUTPUT

为输入引脚配置而不上拉

Arduino

pinMode(13, INPUT);

CircuitPython

import digitalio

import board

button_a = digitalio.DigitalInOut(board.BUTTON_A)

button_a.direction = digitalio.Direction.INPUT

配置带有上拉的输入引脚

Arduino

pinMode(13, INPUT_PULLUP);

CircuitPython

import digitalio

import board

button_a = digitalio.DigitalInOut(board.BUTTON_A)

button_a.direction = digitalio.Direction.INPUT

button_a.pull = digitalio.Pull.UP

从引脚读取

Arduino

int pinValue = digitalRead(inputPin);

CircuitPython

pinValue = button_a.value

写到别针

Arduino

digitalWrite(13, HIGH);

digitalWrite(13, LOW);

CircuitPython

led.value = True

led.value = False

讨论

配置数字I/O引脚

在使用引脚进行输入或输出之前,必须对其进行配置。这涉及将其设置为输入或输出,以及在需要时附加上拉或下拉。

Arduino

Arduino框架提供了pinMode为此。它带有两个参数:

正在配置的引脚号。您以后可以使用相同的引脚号来使用I/O线

模式:INPUT,OUTPUT或INPUT_PULLUP。

要将标准的插针13板载LED设置为可用,您将使用:

下载:文件

复制代码

pinMode(13, OUTPUT); pinMode(13, OUTPUT);

CircuitPython

在CircuitPython中,还有很多工作要做。您需要创建一个DigitalInOut实例。为此,您必须首先导入digitalio模块。像在Arduino示例中一样,给它提供要使用的引脚号。

在上面的Arduino示例中,我们如何知道要使用的引脚号?简短的答案是我们刚刚做了。在此示例中,一个约定是板载LED位于引脚13上。对于其他GPIO引脚,您需要检查所使用的板,以查看可用的引脚以及将电路连接到的引脚。

在Arduino中,没有编译时检查您选择的引脚是否有效或存在。 CircuitPython只允许您使用板子知道的管脚,这可以防止您输入错误。

(如果您导入板子模块(稍后再介绍),您可以使用它列出可用的管脚。 )

下载:文件

复制代码

》》》 import digitalio

》》》 import board

》》》 led = digitalio.DigitalInOut(board.D13)

》》》 led.direction = digitalio.Direction.OUTPUT 》》》 import digitalio

》》》 import board

》》》 led = digitalio.DigitalInOut(board.D13)

》》》 led.direction = digitalio.Direction.OUTPUT

如果需要输入,可以使用digitalio.Direction.INPUT,如果需要设置上拉,则可以单独进行。

下载:文件

复制代码

》》》 import digitalio

》》》 import board

》》》 button_a = digitalio.DigitalInOut(board.BUTTON_A)

》》》 button_a.direction = digitalio.Direction.INPUT

》》》 button_a.pull = digitalio.Pull.UP 》》》 import digitalio

》》》 import board

》》》 button_a = digitalio.DigitalInOut(board.BUTTON_A)

》》》 button_a.direction = digitalio.Direction.INPUT

》》》 button_a.pull = digitalio.Pull.UP

CircuitPython运行的SAMD板还支持在输入引脚上设置下拉。为此,您将使用

下载:文件

复制代码

》》》 pin.pull = digitalio.Pull.DOWN 》》》 pin.pull = digitalio.Pull.DOWN

使用数字I/O引脚

现在您已经设置了引脚,如何读取和写入值?

Arduino

该框架提供了digitalRead函数,该函数以引脚号作为参数。

下载:文件

复制代码

int pinValue = digitalRead(inputPin); int pinValue = digitalRead(inputPin);

从digitalRead返回的值是int类型,将是常量HIGH或LOW之一。

digitalWrite功能用于设置引脚值。它的参数是引脚号和将其设置为的值:HIGH或LOW。例如,假设已如上所述将其设置为输出,则打开连接到引脚13的LED,您可以使用:

下载:文件

复制代码

digitalWrite(13, HIGH); digitalWrite(13, HIGH);

并关闭它:

下载:文件

复制代码

digitalWrite(13, LOW); digitalWrite(13, LOW);

此处的示例显示了如何使用数字输出引脚来闪烁内置的LED:微控制器编程的事实上的 Hello World 。

下载:文件

复制代码

void setup()

{

pinMode(13, OUTPUT); // sets the digital pin 13 as output

}

void loop()

{

digitalWrite(13, HIGH); // sets the digital pin 13 on

delay(1000); // waits for a second

digitalWrite(13, LOW); // sets the digital pin 13 off

delay(1000); // waits for a second

}

void setup()

{

pinMode(13, OUTPUT); // sets the digital pin 13 as output

}

void loop()

{

digitalWrite(13, HIGH); // sets the digital pin 13 on

delay(1000); // waits for a second

digitalWrite(13, LOW); // sets the digital pin 13 off

delay(1000); // waits for a second

}

将数字输入和输出放在一起,下面是一个示例,该示例从开关读取并控制LED作为响应。

下载:文件

复制代码

int ledPin = 13; // LED connected to digital pin 13

int inPin = 7; // pushbutton connected to digital pin 7

int val = 0; // variable to store the read value

void setup()

{

pinMode(ledPin, OUTPUT); // sets the digital pin 13 as output

pinMode(inPin, INPUT); // sets the digital pin 7 as input

}

void loop()

{

val = digitalRead(inPin); // read the input pin

digitalWrite(ledPin, val); // sets the LED to the button‘s value

} int ledPin = 13; // LED connected to digital pin 13

int inPin = 7; // pushbutton connected to digital pin 7

int val = 0; // variable to store the read value

void setup()

{

pinMode(ledPin, OUTPUT); // sets the digital pin 13 as output

pinMode(inPin, INPUT); // sets the digital pin 7 as input

}

void loop()

{

val = digitalRead(inPin); // read the input pin

digitalWrite(ledPin, val); // sets the LED to the button’s value

}

CircuitPython

假设led和switch的设置如上所述。

输入引脚可以通过查询其value属性进行读取:

下载:文件

复制代码

》》》 button_a.value 》》》 button_a.value

我们可以通过设置value属性来打开和关闭led = 1》反对一个布尔值:

下载:文件

复制代码

DigitalInOut 》》》 led.value = True

》》》 led.value = False

要在CircuitPython中实现闪烁的演示,我们将做一些类似的事情:

下载:文件

复制代码

》》》 led.value = True

》》》 led.value = False 》》》 import time

》》》 import digitalio

》》》 import board

》》》 led = digitalio.DigitalInOut(board.D13)

》》》 led.direction = digitalio.Direction.OUTPUT

》》》 while True:

。.. led.value = True

。.. time.sleep(0.5)

。.. led.value = False

。.. time.sleep(0.5)

模拟输入

快速参考

配置模拟输入引脚

Arduino

不需要

CircuitPython

import board

import analogio

adc = analogio.AnalogIn(board.A0)

使用模拟输入引脚

Arduino

int val = analogRead(3);

CircuitPython

adc.value

讨论

配置模拟输入引脚

Arduino

配置模拟输入引脚不需要任何特殊操作。需要以与数字输出引脚相同的方式将模拟输出引脚配置为输出。请注意,仅某些引脚可以用作模拟引脚。查看特定电路板的文档以查找哪些电路板。

CircuitPython

在CircuitPython中使用模拟引脚类似于

像以前一样,使用board模块可以按名称访问正确的引脚。另外,analogio模块为您提供模拟I/O类。

要读取模拟输入,您需要创建AnalogIn的实例:

下载:文件

复制代码

》》》 import board

》》》 import analogio

》》》 adc = analogio.AnalogIn(board.A0) 》》》 import board

》》》 import analogio

》》》 adc = analogio.AnalogIn(board.A0)

要设置模拟输出,请创建一个AnalogOut实例。

下载:文件

复制代码

》》》 import board

》》》 import analogio

》》》 led = analogio.AnalogOut(board.A0) 》》》 import board

》》》 import analogio

》》》 led = analogio.AnalogOut(board.A0)

使用模拟输入引脚

Arduino

模拟I/O与数字类似。不同的板可以具有不同数量和位置的模拟引脚。查看您的文档以获取有关主板功能的详细信息。

下载:文件

复制代码

int val = analogRead(3); int val = analogRead(3);

返回的值是一个介于0和1023之间(包括0和1023)的int。该范围假设一个10位模数转换器。通常,模数转换器中的位数决定范围,范围是0到2 bits -1。例如。一个12位转换器将得出0到4095之间的值。请参考您开发板的文档以找到转换器的大小。

CircuitPython

具有上面所示的AnalogIn对象后,只需获取其value属性:

下载:文件

复制代码

adc.value adc.value

在CircuitPython中,模拟如上所示,您输入的输入值将始终在0到65535之间。这并不意味着总会有一个16位转换器。相反,将从转换器读取的值映射到16位范围。这使您不必担心板上的转换器的详细信息。

AnalogIn对象为您提供了一种方便的方法来查询转换器的参考电压,因此如果您需要了解要测量实际电压,只需使用以下代码即可。请记住,其结果将根据引脚上的电压以及参考电压而有所不同。

下载:文件

复制代码

》》》 adc.value / 65535 * adc.reference_voltage

3.2998 》》》 adc.value / 65535 * adc.reference_voltage

3.2998

模拟和PWM输出

快速参考

配置模拟输出引脚

Arduino

大多数开发板没有真正的模拟输出。

CircuitPython

import board

import analogio

dac = analogio.AnalogOut(board.A1)

使用模拟输出引脚

Arduino

大多数板子都没有真正的模拟输出。

CircuitPython

dac.value = 32767

PWM输出引脚

Arduino

不需要

CircuitPython

import board

import pulseio

led = pulseio.PWMOut(board.A1)

使用PWM输出引脚

Arduino

analogWrite(9, 128);

CircuitPython

led.duty_cycle = 32767

讨论 Arduino

直接写入模拟引脚。从技术上讲,这通常不是真正的模拟值,而是PWM信号。即您正在写入的值将设置PWM信号的占空比。范围是0-255(含)。 analogWrite用于此目的,和digitalWrite一样,用于获取引脚和值。

Arduino DUE具有2个实际的模数转换器,可输出实际的模拟电压,而不是输出

下载:文件

复制代码

analogWrite(pin, val);

analogWrite(pin, val);

将它们放在一起,我们可以从模拟引脚读取并写入另一个引脚。区别在于需要容纳值范围,这就是4的除法。

下载:文件

复制代码

int ledPin = 9; // LED connected to digital pin 9

int analogPin = 3; // potentiometer connected to analog pin 3

int val = 0; // variable to store the read value

void setup()

{

pinMode(ledPin, OUTPUT); // sets the pin as output

}

void loop()

{

val = analogRead(analogPin); // read the input pin

analogWrite(ledPin, val / 4); // analogRead values go from 0 to 1023, analogWrite values from 0 to 255

} int ledPin = 9; // LED connected to digital pin 9

int analogPin = 3; // potentiometer connected to analog pin 3

int val = 0; // variable to store the read value

void setup()

{

pinMode(ledPin, OUTPUT); // sets the pin as output

}

void loop()

{

val = analogRead(analogPin); // read the input pin

analogWrite(ledPin, val / 4); // analogRead values go from 0 to 1023, analogWrite values from 0 to 255

}

CircuitPython

》 CircuitPython硬件上有两种类型的模拟输出:真实模拟和PWM(与Arduino一样)。

对于真实模拟输出,AnalogOut对象的value参数设置为a值介于0到65535之间,与AnalogInput的值范围相同:0将输出设置为0v,65535将其设置为参考电压。

下载:文件

复制代码

dac.value = 32767 dac.value = 32767

一个相关的输出功能是PWM(脉冲宽度调制)。它以完全不同的方式完成。代替使用analogio模块,您需要使用pulseio并使用要在其上生成信号的Pin创建一个PWMOut对象。

下载:文件

复制代码

》》》 import board

》》》 import pulseio

》》》 led = pulseio.PWMOut(board.A1) 》》》 import board

》》》 import pulseio

》》》 led = pulseio.PWMOut(board.A1)

编程

一个PWMOut对象,可以将其占空比(输出为高的时间百分比)设置为16位整数(0-65535)。例如:

下载:文件

复制代码

# set the output to 100% (always high)

》》》 led.duty_cycle = 65535

# set the output to 0% (always low)

》》》 led.duty_cycle = 0

# set the output to 50% (high half the time)

》》》 led.duty_cycle = 32767 # set the output to 100% (always high)

》》》 led.duty_cycle = 65535

# set the output to 0% (always low)

》》》 led.duty_cycle = 0

# set the output to 50% (high half the time)

》》》 led.duty_cycle = 32767

时间

编程

苏甘斯摄在Unsplash

快速参考

延迟

Arduino

delay(1500);

CircuitPython

import time

time.sleep(1.5)

系统时间

Arduino

unsigned long now = millis();

CircuitPython

import time

now = time.monotonic()

讨论

能够等待特定的时间时间在许多项目中都很重要。

Arduino和CircuitPython的处理方法非常相似。

延迟 Arduino

该函数用于等待特定时间, delay,已内置在Arduino框架中。不需要#include。单个参数是延迟时间,以毫秒为单位。

一个示例是如下所示的简单闪烁LED代码:

下载:文件

复制代码

int ledPin = 13; // LED connected to digital pin 13

void setup()

{

pinMode(ledPin, OUTPUT); // sets the digital pin as output

}

void loop()

{

digitalWrite(ledPin, HIGH); // sets the LED on

delay(1000); // waits for a second

digitalWrite(ledPin, LOW); // sets the LED off

delay(1000); // waits for a second

} int ledPin = 13; // LED connected to digital pin 13

void setup()

{

pinMode(ledPin, OUTPUT); // sets the digital pin as output

}

void loop()

{

digitalWrite(ledPin, HIGH); // sets the LED on

delay(1000); // waits for a second

digitalWrite(ledPin, LOW); // sets the LED off

delay(1000); // waits for a second

}

每次打开或关闭delay以创建闪烁的灯光时,ledPin函数都会等待一秒钟(1000毫秒)。

CircuitPython

CircuitPython中与delay等效的函数是time.sleep函数。默认情况下不包含time模块,必须将其导入到程序中。

传递给time.sleep的参数是延迟时间(以秒为单位)。 》(不是毫秒)。该值可以是十进制,因此如果要等待一秒钟,请放入1.0,如果要等待50毫秒,则为0.050。

下面的代码重复打印单词Hello。打印件之间的间隔为0.1秒,即100毫秒。

下载:文件

复制代码

import time

while True:

print(“Hello”)

time.sleep(0.1) import time

while True:

print(“Hello”)

time.sleep(0.1)

Djim Loic在Unsplash上拍摄的照片

获取系统时间

通常,微控制器和单板计算机通常缺少实时时钟(RTC)模块来了解时间。每个系统通常具有的功能是对自打开电源以来的时间进行计数。对于完成一段时间的某些工作而言,这仍然很有用。

Arduino

要获取自Arduino开发板以来的时间,常用功能是millis。它没有任何参数,并返回自从上次打开该板电源以来的毫秒数。

以下代码草图显示了每秒从串行端口上电以来的时间(1000毫秒)。

下载:文件

复制代码

unsigned long initial;

void setup(){

Serial.begin(9600);

initial = millis();

}

void loop(){

unsigned long now;

now = millis();

if( now - initial 》 3 ) { // Print done after 3 milliseconds elapses

Serial.print(“done”);

}

else {

initial = now;

}

} unsigned long initial;

void setup(){

Serial.begin(9600);

initial = millis();

}

void loop(){

unsigned long now;

now = millis();

if( now - initial 》 3 ) { // Print done after 3 milliseconds elapses

Serial.print(“done”);

}

else {

initial = now;

}

}

CircuitPython

Python具有许多时间函数。但是许多板卡都遇到了与Arduino发现的相同的问题-没有RTC。

CircuitPython具有与Arduino delay类似的功能,称为time.monotonic。但是它返回的是秒,而不是像delay那样的毫秒。

注意,不建议比较大于一小时的时间,因为该值将开始四舍五入,可能会浪费时间,从而造成准确性。

下载:文件

复制代码

import time

initial = time.monotonic() # Time in seconds since power on

while True:

now = time.monotonic()

if now - initial 》 0.003: # If 3 milliseconds elapses

print(“done”)

else:

initial = now import time

initial = time.monotonic() # Time in seconds since power on

while True:

now = time.monotonic()

if now - initial 》 0.003: # If 3 milliseconds elapses

print(“done”)

else:

initial = now

参考 Arduino

Arduino参考

延迟

millis

CircuitPython

时间-与时间和计时相关的功能

库和模块

长爱尔兰都柏林三一学院室内。来自Wikipedia的用户Diliff,CC BY-SA 4.0

快速参考

Arduino

include

CircuitPython

import time

讨论

Arduino和CircuitPython都提供了一种从正在处理的文件外部提取代码的方法。这可能是您编写的另一个文件,是框架的一部分,或者是传感器支持模块。

Arduino

C和C ++将代码分为代码文件(分别以.c或.cpp结尾)和头文件(以.h结尾)。 Arduino环境为您的草图/程序的主文件收取了少量费用。它以.ino结尾。

头文件通常包含函数和全局变量声明以及宏和类型定义。在C ++中,类定义也位于此处。代码文件包含函数定义。头文件提供了到库的接口,告诉您的代码如何访问/调用库的工具。

要使用头文件(及其包含的库)您包括它:

下载:文件

复制代码

#include #include

现在,您的代码可以使用string.h中定义的函数和类型,该函数和类型是字符串的集合操作功能,例如strcpy()用于复制字符串。

CircuitPython

所有CircuitPython代码文件均具有.py扩展名(结束)。没有定义接口的单独文件。

CircuitPython具有与Arduino/C相似的机制,称为模块。代码创建者为特定目的收集了一组功能并创建了一个模块。

预编译的模块具有.mpy文件扩展名。并非所有模块都必须预先编译,这样只会节省空间。

使用CircuitPython模块,则应将适当的文件(通常是.mpy文件)放置在开发板闪存驱动器上的/lib文件夹中。

“时间”页面上的较早位置, time模块已导入,并提供了两个功能:time.sleep和time.monotonic。

请注意,当您如上所述导入模块时,不能仅引用里面的东西,你必须给它们加上模块名的前缀。即time.monotonic(),而不仅仅是monotonic()。有很多方法可以避免这种情况,但这超出了本指南的范围。

下载:文件

复制代码

import time

while True:

print(“Hello”)

time.sleep(0.1) import time

while True:

print(“Hello”)

time.sleep(0.1)

CircuitPython无法将完整的Python/CPython可用的大型模块导入为微控制器上的内存非常有限。

Adafruit致力于提供大量模块来支持广泛的硬件。这包括传感器,显示器,智能LED(NeoPixel等)等等。正如Adafruit是提供开源Arduino库的领导者一样,Adafruit也在Python世界中努力做到这一点。

Python模块有更多功能,但以上内容基础。有关更多信息,请参见此类Python参考。

有关最新的CircuitPython模块的信息,请参考Adafruit GitHub存储库。

董事会模块

图片作者:Unsplash上的rawpixel

您正在微控制器板上编写嵌入式代码。这几乎总是意味着您正在通过董事会的一些图钉与外界互动。您如何知道哪些代码在做什么,以及在代码中使用哪些代码?

Arduino

在编译之前在Arduino IDE中,选择要使用的板。这基本上告诉了编译器信息,该信息需要专门针对MCU和该特定板的配置进行编译。但是,那无助于知道使用什么引脚。您必须查看电路板的文档并弄清楚。 Arduino硬件平台提供了一些有用的标准。您将始终有一些以“ D”为前缀的引脚。这些用于数字I/O。有些将以“ A”为前缀。这些可以用于模拟信号,但并非全部都支持真实的模拟输出。

将有I2C(SCL和SDA)和SPI(MOSI,MISO和SCK)引脚。在代码中,您将使用适当的管脚编号,尽管某些板具有在Arduino IDE中选择板时可使用的那些管脚的预定义值。

CircuitPython

CircuitPython采用了非常不同的方法来处理各种受支持的电路板。首先,CircuitPython驻留在板上,而Arduino是计算机上的一组工具,该工具会生成一个二进制文件,然后将其保存在板上。

进行此项工作的一部分是制作以下版本的CircuitPython:特定于每个受支持的板。例如,如果您想将CircuitPython与Feather M4 Express一起使用,则可以得到CircuitPython的Feather M4 Express版本,并将其放到Feather M4 Express板上。有关详细信息,请参见本指南。

之所以如此重要,是因为CircuitPython知道其运行在哪个板上,并且知道该板上的功能,以及该板上的引脚是什么。以及他们可以做什么。

要使此功能可用,您可以导入board模块。该模块包含特定板上引脚的常数。 CircuitPython中用于另一块板的board模块将具有特定于该板的不同常量。知道,用户不必告诉CircuitPython它在什么板上运行。

所有这些使使用板模块成为使用板引脚的最安全,最可靠的方法。它使您不必担心板子引脚连接到哪个MCU引脚。对于围绕ARM内核构建的更复杂的MCU(例如SAMD或nRF52系列MCU),这更是一个问题。

例如,可以将I2C信号连接到MCU有多种方式(我们将不介绍),但是使用板卡模块,您可以轻松执行以下操作:

下载:文件

复制代码

import board

import busio

i2c = busio.I2C(board.SCL, board.SDA) import board

import busio

i2c = busio.I2C(board.SCL, board.SDA)

这将在CircuitPython中任何受支持的板上工作。/p》

那么您如何知道板上有哪些引脚可用?他们叫什么?您可以使用CircuitPython的dir函数。这是在Circuit Playground Express上:

下载:文件

复制代码

》》》 import board

》》》 dir(board)

[‘A0’, ‘A1’, ‘A2’, ‘A3’, ‘A4’, ‘A5’, ‘A6’, ‘A7’, ‘A8’, ‘A9’,

‘ACCELEROMETER_INTERRUPT’, ‘ACCELEROMETER_SCL’,

‘ACCELEROMETER_SDA’, ‘BUTTON_A’, ‘BUTTON_B’, ‘D0’, ‘D1’,

‘D10’, ‘D12’, ‘D13’, ‘D2’, ‘D3’, ‘D4’, ‘D5’, ‘D6’, ‘D7’,

‘D8’, ‘D9’, ‘I2C’, ‘IR_PROXIMITY’, ‘IR_RX’, ‘IR_TX’, ‘LIGHT’,

‘MICROPHONE_CLOCK’, ‘MICROPHONE_DATA’, ‘MISO’, ‘MOSI’,

‘NEOPIXEL’, ‘REMOTEIN’, ‘REMOTEOUT’, ‘RX’, ‘SCK’, ‘SCL’,

‘SDA’, ‘SLIDE_SWITCH’, ‘SPEAKER’, ‘SPEAKER_ENABLE’, ‘SPI’,

‘TEMPERATURE’, ‘TX’, ‘UART’]

》》》 》》》 import board

》》》 dir(board)

[‘A0’, ‘A1’, ‘A2’, ‘A3’, ‘A4’, ‘A5’, ‘A6’, ‘A7’, ‘A8’, ‘A9’,

‘ACCELEROMETER_INTERRUPT’, ‘ACCELEROMETER_SCL’,

‘ACCELEROMETER_SDA’, ‘BUTTON_A’, ‘BUTTON_B’, ‘D0’, ‘D1’,

‘D10’, ‘D12’, ‘D13’, ‘D2’, ‘D3’, ‘D4’, ‘D5’, ‘D6’, ‘D7’,

‘D8’, ‘D9’, ‘I2C’, ‘IR_PROXIMITY’, ‘IR_RX’, ‘IR_TX’, ‘LIGHT’,

‘MICROPHONE_CLOCK’, ‘MICROPHONE_DATA’, ‘MISO’, ‘MOSI’,

‘NEOPIXEL’, ‘REMOTEIN’, ‘REMOTEOUT’, ‘RX’, ‘SCK’, ‘SCL’,

‘SDA’, ‘SLIDE_SWITCH’, ‘SPEAKER’, ‘SPEAKER_ENABLE’, ‘SPI’,

‘TEMPERATURE’, ‘TX’, ‘UART’]

》》》

这是在Gemma M0上:

下载:文件

复制代码

》》》 import board

》》》 dir(board)

[‘A0’, ‘A1’, ‘A2’, ‘APA102_MOSI’, ‘APA102_SCK’, ‘D0’,

‘D1’, ‘D13’, ‘D2’, ‘I2C’, ‘L’, ‘RX’, ‘SCL’, ‘SDA’, ‘SPI’,

‘TX’, ‘UART’]

》》》 import board

》》》 dir(board)

[‘A0’, ‘A1’, ‘A2’, ‘APA102_MOSI’, ‘APA102_SCK’, ‘D0’,

‘D1’, ‘D13’, ‘D2’, ‘I2C’, ‘L’, ‘RX’, ‘SCL’, ‘SDA’, ‘SPI’,

‘TX’, ‘UART’]

您可以看到有一些共同的引脚,但也有特定于主板的引脚。
       责任编辑:wv

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分