0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

用于 SPI 绝对编码器的 Arduino 示例代码

海阔天空的专栏 来源:Damon Tarry 作者:Damon Tarry 2025-01-26 21:35 次阅读

作者:Damon Tarry, Design Applications Engineer, Same Sky

Arduino 示例代码教程旨在为用户提供一个坚实的起点,以便通过串行外设接口 (SPI) 通信来配置和读取 [Same Sky] 的 [AMT22 绝对编码器] 的数据。该教程将提供所需的硬件和软件、关键设置要求以及单圈和多圈输出选项的示例代码包和说明。以下是入门工作所需的物料清单:

  • [Arduino 板]
  • [AMT22 编码器]
  • [AMT-06C-1-036 电缆] ,或带有相应连接器的类似电缆
  • [Arduino IDE]
  • [下载 AMT22 单圈样例代码]
  • [下载 AMT22 多圈样例代码]

AMT22 绝对位置编码器概览

Same Sky(前身为 CUI Devices)的 AMT22 是一款绝对编码器,具有 12 位或 14 位分辨率,即每圈提供精确的唯一位置数。对于 12 位型号来说,这相当于 4,096 个不同的位置,而 14 位型号每转一圈则有 16,384 个位置。无论旋转多少次,该器件都会持续报告其绝对位置,准确地向用户提供精确的器件角度反馈。

该编码器有单圈和[多圈] 两种类型。单圈器件测量的是旋转一圈 360 度过程中的位置,而多圈器件不仅跟踪旋转一圈过程中的位置,还跟踪旋转整圈的总数。此外,单圈型号还具有可编程零点,使用户能够为编码器的旋转起点定义参考点。

入门

将编码器背面的开关调至适当位置,确保器件处于 RUN(运行)模式(图 1)。现在,按照 [AMT 安装说明] 将 AMT22 编码器安装到电机或组件上,以确保安装正确。AMT22 支持 9 种不同的轴尺寸,从 2 mm 到 8 mm 不等。

Same Sky 的 AMT22 编码器切换到 RUN 模式的图图 1:将 AMT22 编码器背面的开关拨至 RUN 模式。(图片来源:Same Sky)

图 2 和表 1 中列出的连接专用于 [Arduino Uno 板] ,但所提供的代码应与大多数 Arduino 板兼容。不过,请注意不同型号的 Arduino 引脚配置可能有所不同。有关其他电路板的准确连接细节,建议参考相应的 Arduino 说明文档。

Arduino Uno 与 AMT22 编码器的线路连接图图 2:Arduino Uno 与 AMT22 编码器的线路连接。(图片来源:Same Sky)

| | 功能 | 编码器引脚数量 | Arduino Uno 引脚 | AMT-DBC-1-036 |
| ------ | ---------------- | ------------------ | --------------- |
| +5 V | 1 | 5 V | 白色/绿色 |
| SCLK | 2 | 13 | 蓝色/白色 |
| MOSI | 3 | 11 | 白色/蓝色 |
| GND | 4 | GND | 绿色/白色 |
| MISO | 5 | 12 | 橙色/白色 |
| CS | 6 | 2 | 白色/橙色 |

表 1:Arduino Uno 接线的进一步定义。(图片来源:Same Sky)

当 SPI 通信开始时,AMT22 编码器立即开始传输其绝对位置数据,无需传统的指令响应结构。在 SPI 传输的第一个字节期间,主机发送 0x00,AMT22 同时响应有效位置数据。

如果主机需要发出指令(表 2),例如置零指令,则将在传输的第二个字节中发送。这被称为扩展指令。有关详细的技术规格,请参阅 AMT22 数据表

| | 指令 | 字节 | 注意 |
| ---------- | ----------- | ---------- |
| 获取位置 | 0x00 0x00 | |
| 置零 | 0x00 0x70 | 仅限单圈 |
| 获得圈数 | 0x00 0xA0 | 仅多圈 |

表 2:已定义的 AMT22 命令。(图片来源:Same Sky)

代码教程 - 包含内容和定义

由于 Arduino 的 SPI 总线用于连接 AMT22 编码器,因此代码中需要包含 SPI 库。要将位置数据从 Arduino 发送到计算机,需要使用 Arduino IDE 内置的 USB 串行连接,并在 115200 波特率下进行配置。

此外,还需要定义 AMT22 使用的指令。由于编码器不处理第一个字节的内容,因此分配了一个 NOP(无操作)来简化通信过程(列表 1)。

副本
/* Include the SPI library for the arduino boards */
#include < SPI.h >
 
/* Serial rates for UART */
#define BAUDRATE      115200
 
/* SPI commands */
#define AMT22_NOP     0x00
#define AMT22_ZERO    0x70
#define AMT22_TURNS   0xA0

列表 1:设置 SPI 接口。

初始化

在 setup() 函数(列表 2)中,首先初始化所有必要的 SPI 引脚并配置串行通信接口

应初始化串行端口,以便向主计算机传输数据。这可以通过把已定义的 BAUDRATE 传入 Serial.begin() 函数来实现。

启用 SPI 之前,确保芯片选择 (CS) 线设置为适当的状态,以便编码器做好通信准备。

选择 SPI 总线与 AMT22 通信的时钟频率。对于原型开发而言,尽管 AMT22 支持高达 2 MHz 的时钟频率,但 500 kHz 的时钟频率还是比较合适的。通过 SPI_CLOCK_DIV32 设置可实现 500 kHz 频率。假定 Arduino Uno 的时钟频率为 16 MHz,这种分频的结果是 SPI 时钟频率为 500 kHz。有关 SPI 时钟配置的更多详情,请查阅 Arduino 说明文档。

配置完成后,可使用 SPI.begin() 对 SPI 总线进行初始化,这将设置三个专用 SPI 引脚:MISO、MOSI 和 SCLK,并使系统做好与编码器通信的准备。

复制
voidsetup()
{
  uint8_t cs_pin = 2;
 
  //Set the modes for the SPI CS
  pinMode(cs_pin, OUTPUT);
  //Get the CS line high which is the default inactive state
  digitalWrite(cs_pin, HIGH);
 
  //Initialize the UART serial connection for debugging
  Serial.begin(BAUDRATE);
 
  //set the clockrate. Uno clock rate is 16Mhz, divider of 32 gives 500 kHz.
  //500 kHz is a good speed for our test environment
  //SPI.setClockDivider(SPI_CLOCK_DIV2);   // 8 MHz
  //SPI.setClockDivider(SPI_CLOCK_DIV4);   // 4 MHz
  //SPI.setClockDivider(SPI_CLOCK_DIV8);   // 2 MHz
  //SPI.setClockDivider(SPI_CLOCK_DIV16);  // 1 MHz
  SPI.setClockDivider(SPI_CLOCK_DIV32);    // 500 kHz
  //SPI.setClockDivider(SPI_CLOCK_DIV64);  // 250 kHz
  //SPI.setClockDivider(SPI_CLOCK_DIV128); // 125 kHz
 
  //start SPI bus
  SPI.begin();
}

列表 2:用于初始化所有 SPI 引脚的 setup() 函数。

SPI 通信

与 AMT22 的 SPI 通信通过 Arduino 的 SPI 库完成,而芯片选择 (CS) 控制则通过使用数字 I/O 引脚的代码进行管理。digitalWrite() 函数用于断言或解除断言 CS 线路(列表 3)。

AMT22 预计发送两个 0x00 字节,并在收到这些字节后立即返回数据。由于响应速度快,因此必须遵守 AMT22 规格书中列出的某些最低时序要求。

无论编码器是 12 位还是 14 位,始终会响应两个字节(16 位)的数据。上两位是校验位,用于验证数据完整性。对于 12 位版本,下两位均为 0,返回值必须右移 2 位(或除以 4)才能正常使用。

要获取位置数据,需要调用 SPI.transfer() 函数,发送 AMT22_NOP 命令。在此过程中,CS 线保持低电平。AMT22 首先发送高字节,因此接收到的字节会左移 8 位,以便与 uint16_t 变量的上半部分对齐。该值将一次性地分配给编码器位置变量。经过短暂延迟以满足时序要求后,二次调用 SPI.transfer(),发送另一条 AMT22_NOP 指令。将结果与编码器位置 (encoderPosition) 中的当前值进行 OR,从而有效地将接收到的两个字节合并为一个 uint16_t 变量。最后,释放 CS 线路,完成通信。

复制
uint8_t cs_pin = 2;
 
//set the CS signal to low
digitalWrite(cs_pin, LOW);
delayMicroseconds(3);
 
//read the two bytes for position from the encoder, starting with the high byte
uint16_t encoderPosition = SPI.transfer(AMT22_NOP) < < 8; //shift up 8 bits because this is the high byte
delayMicroseconds(3);
encoderPosition |= SPI.transfer(AMT22_NOP); //we do not need a specific command to get the encoder position, just no-op
 
//set the CS signal to high
digitalWrite(cs_pin, HIGH);

列表 3:设置 SPI 通信。

校验和验证

完成 SPI 传输后,必须使用校验和来验证接收到的数据(列表 4)。

为实现这一验证,可根据规格书中提供的方程创建一个函数。校验和包含在接收值的上两位中,并在位置响应的奇数和偶数位中使用奇校验。

该函数将执行以下步骤:

  1. 计算奇数位(1、3、5、7、9、11、13 位的奇偶性
  2. 计算偶数位(0、2、4、6、8、10、12、14 位)的奇偶性
  3. 将计算出的奇偶性与校验位指示的值进行比较

如果校验和有效,该函数将返回 true,表明数据完整性已得到确认。如果校验和无效,函数将返回 false,表明接收到的数据可能存在错误。

复制
/*
 * Using the equation on the datasheet we can calculate the checksums and then make sure they match what the encoder sent.
 */
boolverifyChecksumSPI(uint16_t message)
{
  //checksum is invert of XOR of bits, so start with 0b11, so things end up inverted
  uint16_t checksum = 0x3;
  for(int i = 0; i < 14; i += 2)
  {
    checksum ^= (message > > i) & 0x3;
  }
  return checksum == (message > > 14);
}

列表 4:验证校验和。

数据格式化

如果校验和验证确认了数据的完整性,下一步就是删除上两位,以更新 encoderPosition 变量(清单 5)。这可以通过对 0x3FFF(或 0b0011111111111111)进行逐位 AND 运算来实现,从而有效保留位置数据的所有 14 个低位。

此外,还需要考虑编码器的分辨率:12 位还是 14 位。如果分辨率为 12 位,则编码器位置值必须向右移动 2 位,以适应较低的分辨率。这可确保位置数据在编码器位置变量中得到准确表达,即根据编码器的指定分辨率反映编码器的实际位置。

复制
if (verifyChecksumSPI(encoderPosition)) //position was good
{
  encoderPosition &= 0x3FFF; //discard upper two checksum bits
  if (RESOLUTION == 12) encoderPosition = encoderPosition > > 2; //on a 12-bit encoder, the lower two bits will always be zero
 
  Serial.print(encoderPosition, DEC); //print the position in decimal format
  Serial.write('n');
}
else//position is bad
{
  Serial.print("Encoder position error.n");
}

列表 5:更新 encoderPosition。

设置零位置(仅限单圈)

AMT22 编码器的某些型号具有可编程零位功能。要设置该零位,就必须发送一个特定的双字节指令序列。该过程包括首先发送 AMT22_NOP 指令,然后短暂等待,以满足 AMT22 规定的最低时序要求。等待之后,发送 AMT22_ZERO 命令,同时确保芯片选择 (CS) 线被释放。一旦编码器收到该指令,就将执行复位操作(列表 6)。

为了避免在复位期间与编码器通信,可实施 250 ms 延迟,以确保在编码器通电期间不会向其发送任何指令。

虽然利用代码可在开始运行时设置编码器零位,但在典型应用中,更常见的做法是在系统内使用器件的初始配置过程中只设置一次零位。这种做法有助于在编码器的整个运行寿命期间保持其位置反馈的完整性。

复制
/*
 * The AMT22 bus allows for extended commands. The first byte is 0x00 like a normal position transfer,
 * but the second byte is the command.
 * This function takes the pin number of the desired device as an input
 */
voidsetZeroSPI(uint8_t cs_pin)
{
  //set CS to low
  digitalWrite(cs_pin, LOW);
  delayMicroseconds(3);
 
  //send the first byte of the command
  SPI.transfer(AMT22_NOP);
  delayMicroseconds(3);
 
  //send the second byte of the command
  SPI.transfer(AMT22_ZERO);
  delayMicroseconds(3);
 
  //set CS to high
  digitalWrite(cs_pin, HIGH);
 
  delay(250); //250 millisecond delay to allow the encoder to reset
}

列表 6:设置单圈 AMT22 编码器的零位。

圈数读取计数器(限多圈)

AMT22 编码器的某些型号支持多圈计数器,允许用户在单数据检索序列中读取位置和圈数。

如果接收到的位置数据无效,系统应将错误通知用户。相反,如果位置有效,程序应以十进制格式报告位置(列表 7)。这一功能增强了编码器功能,可全面地反馈绝对位置和完整的圈数,从而在需要精确旋转数据的应用中实现更精确的监测和控制。

复制
uint8_t cs_pin = 2;
 
//set the CS signal to low
digitalWrite(cs_pin, LOW);
delayMicroseconds(3);
 
//read the two bytes for position from the encoder, starting with the high byte
uint16_t encoderPosition = SPI.transfer(AMT22_NOP) < < 8; //shift up 8 bits because this is the high byte
delayMicroseconds(3);
encoderPosition |= SPI.transfer(AMT22_TURNS); //we send the turns command (0xA0) here, to tell the encoder to send us the turns count after the position
 
//wait 40us before reading the turns counter
delayMicroseconds(40);
 
//read the two bytes for turns from the encoder, starting with the high byte
uint16_t encoderTurns = SPI.transfer(AMT22_NOP) < < 8; //shift up 8 bits because this is the high byte
delayMicroseconds(3);
encoderTurns |= SPI.transfer(AMT22_NOP);
delayMicroseconds(3);
 
//set the CS signal to high
digitalWrite(cs_pin, HIGH);

列表 7:AMT22 多圈读取编码器中的编码器位置和圈数计数器。

运行代码

代码创建成功后,就可以将其上传到 Arduino 并与 AMT22 编码器建立通信。

要监控输出,请打开 Arduino IDE 中的串行监控器,并确保将数据速率设置为 115200 波特。这样,用户就可以观察编码器的运行情况,并实时查看位置报告数据。串行监控器启动后,编码器应开始传输位置信息,显示其在系统中的功能(图 3)。

编码器报告位置信息图 3:Arduino 收到的编码器报告的位置(图片来源:Same Sky)

多个编码器

能够与同一总线上的多个编码器进行通信,是使用 SPI 器件的一大优势。为此,需要为每个编码器分配一个额外数字 I/O 引脚,以实现单独的芯片选择 (CS) 控制。

在示例代码(列表 8)中,利用 CS 引脚阵列支持任意数量的编码器。这种设计实现了可扩展通信,使用户能够根据需要轻松地添加更多的编码器。通过修改功能以接受与所需器件相对应的引脚编号,使用代码能以动态方式控制 SPI 总线上哪个编码器处于活动状态,从而确保能独立地访问和操作每个器件。

复制
uint8_t cs_pins[] = {2}; //only one encoder connected, using pin 2 on arduino for CS
//uint8_t cs_pins[] = {2, 3}; //two encoders connected, using pins 2 & 3 on arduino for CS

列表 8:设置读取多个编码器阵列。

下一步是循环读取阵列中的每个 CS 引脚,并从每个连接的编码器中读取位置。这样,通过断言每个编码器的芯片选择线,执行 SPI 传输并检索位置数据,系统就可以激活每个编码器。代码将依次选择每个编码器,执行 SPI 通信并释放 CS 线,以确保所有连接的器件都能查询到其位置信息(列表 9)。

复制
voidloop()
{
  for(int encoder = 0; encoder < sizeof(cs_pins); ++encoder)
  {
    uint8_t cs_pin = cs_pins[encoder];
 
    //set the CS signal to low
    digitalWrite(cs_pin, LOW);
    delayMicroseconds(3);
 
    //read the two bytes for position from the encoder, starting with the high byte
    uint16_t encoderPosition = SPI.transfer(AMT22_NOP) < < 8; //shift up 8 bits because this is the high byte
    delayMicroseconds(3);
    encoderPosition |= SPI.transfer(AMT22_NOP); //we do not need a specific command to get the encoder position, just no-op
 
    //set the CS signal to high
    digitalWrite(cs_pin, HIGH);
 
    if (verifyChecksumSPI(encoderPosition)) //position was good, print to serial stream
    {
      encoderPosition &= 0x3FFF; //discard upper two checksum bits
      if (RESOLUTION == 12) encoderPosition = encoderPosition > > 2; //on a 12-bit encoder, the lower two bits will always be zero
 
      Serial.print("Encoder #");
      Serial.print(encoder, DEC);
      Serial.print(" position: ");
      Serial.print(encoderPosition, DEC); //print the position in decimal format
      Serial.write('n');
    }
    else//position is bad, let the user know how many times we tried
    {
      Serial.print("Encoder #");
      Serial.print(encoder, DEC);
      Serial.print(" position error.n");
    }
  }
 
  //For the purpose of this demo we don't need the position returned that quickly so let's wait a half second between reads
  //delay() is in milliseconds
  delay(500);
}

列表 9:从多个编码器读取编码器位置变量。

数据传输结束后,在释放芯片选择线之前需要极短的等待时间。根据规格书,这个极短的时间为 3 ms。虽然这种延迟通常是在较慢的数据传输速率下自然观察到的,但好的做法是在代码中明确实现这种延迟,以确保正常运行并遵守时序规范。这就确保了与 AMT22 编码器的可靠通信。

结束语

用户现在应该对配置和读取 Same Sky AMT22 绝对编码器的数据有了基本了解。本文重点介绍了 AMT22 绝对编码器。Same Sky 还拥有一系列 [AMT 模块化编码器] ,包括增量式、绝对式和换向式版本。

审核编辑 黄宇

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

    关注

    45

    文章

    3664

    浏览量

    135208
  • SPI
    SPI
    +关注

    关注

    17

    文章

    1721

    浏览量

    92069
  • 代码
    +关注

    关注

    30

    文章

    4823

    浏览量

    69005
  • 绝对编码器
    +关注

    关注

    0

    文章

    14

    浏览量

    6988
  • Arduino
    +关注

    关注

    188

    文章

    6477

    浏览量

    187767
收藏 人收藏

    相关推荐

    Arduino开发板的旋转编码器如何使用

    在本篇文章中,我们将学习如何在Arduino开发板上使用旋转编码器。我们将以带符号的数字同时显示顺时针和逆时针方向的编码值。 所需的组件 ● Arduino UNO开发板 ● 旋转
    的头像 发表于 10-26 15:47 8136次阅读
    <b class='flag-5'>Arduino</b>开发板的旋转<b class='flag-5'>编码器</b>如何使用

    单圈绝对编码器

    单圈绝对编码器采用了独特的条纹编码方式, 突破了传统的编码原理, 克服了传统编码器实现的局限性, 并引进了最新的传感
    发表于 07-10 09:35 34次下载

    增量型编码器绝对编码器的区别

    增量型编码器绝对编码器的区别 编码器如以信号原理来分,有增量型编码器,绝对
    发表于 09-26 17:36 2632次阅读

    绝对编码器安装

    绝对编码器安装目前市场上提供的绝对编码器,一般情况下主要 有两种型号,分别是单圈绝对编码器
    的头像 发表于 12-06 16:49 1.3w次阅读

    什么叫绝对编码器

    对于绝对编码器的内部的“绝对值”的定义,是指编码器内部的所有位置值,在编码器生产出厂后,其量程内所有的位置已经“
    的头像 发表于 12-07 16:33 3w次阅读

    增量式编码器绝对编码器的区别

    本文主要阐述了增量式编码器绝对编码器的区别。
    的头像 发表于 11-06 14:56 6.3w次阅读

    绝对编码器的特点_绝对编码器应用

    本文首先阐述了绝对编码器的原理,其次阐述了绝对编码器的特点,最后阐述了绝对编码器应用。
    的头像 发表于 11-06 16:27 1.3w次阅读

    绝对编码器是如何定义的

    旋转编码器是工业中重要的机械位置角度、长度、速度反馈并参与控制的传感,旋转编码器分增量值编码器绝对
    的头像 发表于 03-12 15:59 5337次阅读

    增量式编码器绝对编码器选哪个?

    增量式编码器绝对编码器哪个好? 编码器是伺服系统上的重要组成部分,可以发送脉冲给驱动用于
    的头像 发表于 03-19 23:30 3910次阅读

    增量型编码器绝对编码器

    增量型编码器绝对值型编码器怎么选择?在进行编码器选择时,增量型编码器绝对值型
    的头像 发表于 05-08 11:28 2178次阅读
    增量型<b class='flag-5'>编码器</b>与<b class='flag-5'>绝对</b>值<b class='flag-5'>编码器</b>

    增量式编码器绝对编码器有哪些区别?

    增量式编码器绝对编码器有哪些区别?增量式编码器通过对变化量进行计数来测量位置变化,而绝对编码器
    的头像 发表于 07-05 13:34 4841次阅读
    增量式<b class='flag-5'>编码器</b>和<b class='flag-5'>绝对</b>值<b class='flag-5'>编码器</b>有哪些区别?

    绝对编码器校正调零方法,绝对编码器调零怎么调

    绝对编码器是一种用于测量旋转位置或线性位移的传感。与增量编码器不同,绝对
    的头像 发表于 07-26 09:53 2.3w次阅读

    26位多圈绝对编码器是什么?

    26位多圈绝对编码器是什么?26位多圈绝对编码器是一种用于测量旋转角度的装置,它可以提供高精度的角度测量结果,而且具有较高的可靠性和稳定
    的头像 发表于 11-08 11:18 2538次阅读
    26位多圈<b class='flag-5'>绝对</b>值<b class='flag-5'>编码器</b>是什么?

    绝对编码器结构及工作原理 绝对编码器的信号输出及应用

    绝对编码器是一种常用的位置反馈传感,广泛应用于各种电机控制系统。绝对编码器还可
    的头像 发表于 05-21 11:08 5115次阅读

    增量编码器绝对编码器的区别

    增量编码器绝对编码器的区别:增量编码器绝对编码器在精度特点对比 增量
    的头像 发表于 11-18 16:38 1036次阅读
    增量<b class='flag-5'>编码器</b>与<b class='flag-5'>绝对</b>值<b class='flag-5'>编码器</b>的区别