Как считать сигнал с аналоговых входов Teensy++ и вывести их на экран

в 10:35, , рубрики: arduino, diy или сделай сам, python, teensy, Песочница, метки: , ,

image

Недавно обзавелся вот этой штукой и захотел попробовать поиграться с ней. Стандартных примеров со светодиодом хватило ненадолго, поэтому я решил попробовать считать значения с аналоговых входов Teensy (которых, к слову, 8 штук) и как-то визуализировать их.

Создатели предлагают две альтернативы для программирования Teensy — С с AVR-GCC или Arduino IDE с установленным плагином для Teensy. Возможно, программирование через AVR-GCC предоставляет большие возможности — но я все равно остановился на Arduino IDE, так как для новичка она ощутимо проще.

Итак, для начала нужно скачать Arduino отсюда.
Если вы работаете под Linux — в udev нужно добавить правило для Teensy — его можно найти тут. Выглядит это примерно так:
sudo cp 49-teensy.rules /etc/udev/rules.d/

Затем необходимо скачать устанощик плагина Teensyduino отсюда. При установке можно выбрать, какие модули устанавливать (я установил все — в хозяйстве пригодится :).

После этого в Arduino IDE появится поддержка Teensy.

Теперь нужно написать код, который будт считывать значения с аналоговых входов и отправлять их в USB serial.

void setup() {                
  Serial.begin(9600);
}

int pins[] = {0, 1, 2, 3, 4, 5, 6, 7};
int val;
int i;

void loop() {
  for (i = 0 ; i < 8 ; i++) {
    val = analogRead(pins[i]);
    
    Serial.print("p");
    Serial.print(i);
    Serial.print(":");
    Serial.print(val);
    Serial.print("n");
  }
  delay(100);
}

Код достаточно банален — в методе setup инициализируем наш последовательный порт, в цикле проверяем значения на входах и записываем их в порт.

Перед разверткой программы на вашу плату в меню Tools необходимо выбрать модель вашей платы (в моем случае это Teensy++ 2.0) и последовательный порт (у меня это был /dev/ttyACM0). Для того, чтобы программа корректно использовала последовательный порт, мне пришлось запустить IDE от sudo.
Компиляция и запуск программы осуществляются при помощи нажатия кнопки Verify (галочка в левом верхнем углу). После этого вылезет диалог Teensy Loader, показывающий, что нужно нажать на кнопку на плате. Нажмите ее — в окне появится надпись Reboot, и прошивка будет развертнута.
image

После перезагрузки устройство начнет спамить вам прямо в последовательный порт :)
Вывод можно посмотреть довольно банально:
sudo cat /dev/ttyACM0
Там должно быть что-то вроде
p0:294
p1:290
p2:286
p3:275
p4:272
p5:274
p6:273
p7:270

Теперь можно приступить к визуализации пересылаемых данных.
В качестве визуализатора я использовал связку Python + PyQt + pySerial.

import serial as Serial
import re
import random
import thread
import time
import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *

class Fetcher(QThread):
  def __init__(self, parent = None):
    QThread.__init__(self, parent)

  def run(self):
    pinRe = re.compile("d+")
    pinValues = [0, 0, 0, 0, 0, 0, 0, 0]

    serial = Serial.Serial('/dev/ttyACM0', 9600, timeout = 0.1)

    while True:
      pinString = serial.readline()
      pinParseResult = pinRe.findall(pinString)

      if (len(pinParseResult) == 2):
        pinValues[int(pinParseResult[0])] = int(pinParseResult[1])
        self.emit(SIGNAL("pinupdate"), pinValues)

    serial.close()

class Form(QDialog):
  MAX_VALUE = 1200
  pins = [0, 0, 0, 0, 0, 0, 0, 0]
  pinInfos = [0, 0, 0, 0, 0, 0, 0, 0]

  def __init__(self, parent=None):
    super(Form, self).__init__(parent)

    for key in range(8):
      self.pins[key] = QProgressBar()
      self.pins[key].setOrientation(Qt.Vertical)
      self.pins[key].setValue(35)

      self.pinInfos[key] = QLabel()

    mainLayout = QVBoxLayout()
    topLayout = QHBoxLayout()
    bottomLayout = QHBoxLayout()

    for key in range(len(self.pins)):
      if key % 4 == 0 and key / 4 == 1:
        topLayout.addItem(QSpacerItem(100, 10))

      if key % 4 == 2 and key / 4 == 1:
        bottomLayout.addItem(QSpacerItem(100, 10))

      if key % 4 == 0 or key % 4 == 1:
        topLayout.addWidget(self.pinInfos[key])
        topLayout.addWidget(self.pins[key])
        topLayout.addItem(QSpacerItem(40, 10))
      else:
        bottomLayout.addWidget(self.pinInfos[key])
        bottomLayout.addWidget(self.pins[key])
        bottomLayout.addItem(QSpacerItem(40, 10))

    mainLayout.addLayout(topLayout)
    mainLayout.addLayout(bottomLayout)

    self.setLayout(mainLayout)
    self.setWindowTitle("Pin display") 

  def connectSlots(self, fetcher):
    self.connect(fetcher, SIGNAL('pinupdate'), self.updateBars)

  def updateBars(self, values):
    valuesNormalised = map(lambda x: (float(x) / self.MAX_VALUE) * 100, values)

    for key in range(len(values)):
      self.pins[key].setValue(valuesNormalised[key])
      self.pinInfos[key].setText("Pin %i, Value: %4i" % (key, values[key]))

app = QApplication(sys.argv)
form = Form()
form.show()

fetcher = Fetcher()
fetcher.start()

form.connectSlots(fetcher)

app.exec_()

Вкратце — создается форма с восемью прогрессбарами, обозначается слот для обновления значения на пинах, запускается поток, непрерывно получающий данные из последовательного порта и оповещающий об этом форму.

Что из этого получилось — можно увидеть в самом начале статьи.

Автор: skayred

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js