Startseite  

I/O Schnitt­stellen Module, seriell über USB

USB I/O Interface mit ATmega168

Projekt Status

Die Firmware läuft sehr stabil und hat alle Features, die ich bislang implementieren wollte. Neue Funktionen sind daher in absehbarer Zeit nicht zu erwarten.

Changelog

1.4.4 19.02.2015
Update documentation.

1.4.3 28.10.2014
Fix for wrong output on Port Y after oPY command with bit number 15-31. The problem did not occur on all gcc versions.

1.4.2 20.09.2014
Changed fuse settings to enable brown-out detection at 2,7V.

1.4.1 23.04.2014
Fixes compiler warnings introduced by new avr-gcc version.

1.4.0 17.03.2014
Added support for more serial ports.

Mit I/O Schnittstellen Modulen kann man elektrische Einrichtungen überwachen und steuern. Da PC's keine herkömmlichen Parallel-Ports mehr haben, stelle ich hier einen Ersatz mit serieller bzw. USB Schnittstelle vor. Je nach Mikrocontroller erhält man 18 bis 84 steuerbare Anschlüsse. Und mit Hilfe von ein paar billigen Schieberegistern sind noch mehr Leitungen machbar.

Der Zugriff auf die I/O Ports erfolgt über einfache Textbefehle, die seriell übermittelt werden. Es funktioniert daher mit jeder beliebigen Programmiersprache auf jedem Betriebssystem.

Downloads:

Beispiel-Programme:

So funktioniert es

Baue eine Verbindung zum I/O Modul auf. Dann sende Befehle in Text-Form und empfangen Antworten auf dieser Verbindung. Zum Testen empfehle ich das Hammer Terminalprogramm, Putty oder Cutecom.

Zum Beispiel setzt man so den Pin PC3 auf High:

Sende:   oPC3,1
Antwort: Ok

So fraget man den Port D als Hexadezimalzahl ab:

Sende:   iPD
Antwort: PD=3F

Den vollständigen Befehlssatz findest du weiter unten. Du kannst mehr als 100 Befehle pro Sekunde ausführen.

Voraussetzungen

Alternativ zu "nackten" Mikrocontrollern empfehle ich Arduino Nano mit ATmega Controller. Sie habe einen USB Bootloader, damit man keinen extra Programmieradapter benötigt.

Bildschirmfotos

Test mit einem Terminalprogramm:


Die Beispiel App "ioModule" steuert zwei LEDs an:

Wie du hier sehen kannst habe ich auch versuche mit dem Bluetooth Adapter HC-06 gemacht. Damit traten allerdings häufig Kompatibilitätsprobleme zum PC/Tablet/Smartphone auf, deswegen empfehle ich sie nicht mehr.

Befehlssatz

Die Firmware wird vom PC aus mit Befehlen in textueller Form gesteuert. Die Befehle bestehen jeweils aus einem Buchstaben, gefolgt von spezifischen Parametern:

Jeder Befehl wird mit einem Zeilenumbruch (\n oder \r\n) beendet.

Die Befehle d, p, o und i können sich wahlweise auf einen einzelnen Pin, einen ganzen Port oder alle Ports gleichzeitig beziehen. Pin-Nummern werden immer als Dezimal-Zahl angegeben, und die Daten sind entweder binär (0/1) oder Hexadezimal.

Digitale Eingänge

Standardmäßig sind alle I/O Pins als Eingang. Der input Befehl liest den Eingang. Mit dem pull-up Befehl kann man die internen Pull-Up Widerstände einschalten.

Beispiel für das Lesen eines einzelnen Eingangs mit aktiviertem Pull-Up Widerstand:

Befehl:   pPB7,1
Antwort: Ok
Befehl:   iPB7
Antwort: PB7=1

Beispiel für einen ganzen Port am Stück (8 Pins):

Befehl:   iPA
Antwort: PA=FF

Beispiel für alle Ports auf einmal:

Befehl:   i
Antwort: i=000001FF

Die Hexadezimalzahl bezieht sich auf die Ports DD CC BB AA.
Bei größeren Mikrocontrollern ist sie doppelt so lang und bezieht sich auf die Ports HH GG FF EE DD CC BB AA.

Digitale Ausgänge

Zuerst muss man die gewünschten I/O Pins mit dem direction Befehl als Ausgang konfigurieren, danach kann man den Pin mit dem output Befehl steuern.

Beispiel für einen einzelnen I/O Pin:

Befehl:   dPB4,1
Antwort: Ok
Befehl:   oPB4,1
Antwort: Ok
Befehl:   oPB4,0
Antwort: Ok

Beispiel für einen ganzen Port am Stück (8 Pins):

Befehl:   dPB,FF
Antwort: Ok
Befehl:   oPB,FF
Antwort: Ok
Befehl:   oPB,00
Antwort: Ok

Beispiel für alle Ports auf einmal:

Befehl:   d,FFFFFFFF
Antwort: Ok
Befehl:   o,FFFFFFFF
Antwort: Ok
Befehl:   o,00000000
Antwort: Ok

Die größeren Mikrocontroller mit mehr Ports erwarten längere Hexadezimalzahlen für die Ports HH GG FF EE DD CC BB AA, aber ohne Leerzeichen dazwischen.

Analoge Eingänge

Analoge Eingänge vergleichen die Spannung an einem Pin mit einer einstellbaren Referenzspannung. Das ist zugleich die höchste messbare Spannung. Je nach Mikrocontroller stehen dazu folgende Referenzen zur Verfügung:

Das folgende Beispiel wählt VCC als Referenz und liest dann den analogen Eingang 3 ein:

Befehl:   rVCC
Antwort: Ok
Befehl:   a3
Antwort: ADC3=01A3

Das Ergebnis ist eine hexadezimale Zahl, entsprechend dem Messwert der analogen Spannung.

Erweiterte Eingänge

Mit Hilfe von Schieberegistern kann man die Anzahl der Eingänge erweitern. Diese zusätzlichen Eingänge nenne ich "Port X". Sie können mit dem i Befehl abgefragt werden. Je nach Anzahl der Schieberegister antwortet der input Befehl mit unterschiedlich großen Hexadezimal-Zahlen (8-32 Bits). Zum Beispiel:

Befehl:   iPX
Antwort: PX=FFFF

Beispiel zur Abfrage eines einzelnen Pins:

Befehl:   iPX9
Antwort: PX9=1

Die Befehle d und p stehen bei erweiterten Eingängen und Ausgängen nicht zur Verfügung!

Erweiterte Ausgänge

Mit Hilfe von Schieberegistern kann man die Anzahl der Ausgänge erweitern. Diese zusätzlichen Ausgänge nenne ich "Port Y". Sie können mit dem o Befehl beschrieben werden. Je nach Anzahl der Schieberegister erwartet der output Befehl unterschiedlich große Hexadezimal-Zahlen (8-32 Bits). Zum Beispiel:

Befehl:   oPY,FFFF
Antwort: Ok

Beispiel zum Ändern eines einzelnen Pins:

Befehl:   oPY12,1
Antwort: Ok

Die Befehle d und p stehen bei erweiterten Eingängen und Ausgängen nicht zur Verfügung!

15 Minuten Tutorial mit Qt

Ich möchte dir zeigen, wie einfach das Modul mit einem selbst geschriebenen PC Programm gesteuert werden kann. Es erfordert nur wenige Minuten.

Vorbereitung der Hardware

Baue dir ein I/O Modul mit USB auf Basis eines Arduino Moduls auf. Am Anschluss PD2 soll eine LED mit Vorwiderstand hängen:

                470Ω      LED

      PD2 o-----[===]-----|>|----| GND

Lade die Firmware mit einem ISP Programmieradapter (oder dem vorinstallierten Bootloader) in den Mikrocontroller, und schließe das Modul an den PC an. Der USB Treiber wird automatisch installiert. Schaue im Gerätemanager von Windows nach, welcher COM-Port dem Gerät zugewiesen wurde. Benutze bei Linux den dmesg Befehl. In meinem Fall ist es "COM3".

Installiere die Qt Creator Entwicklungsumgebung. Damit kannst du schicke Programme für Windows, Linux und Mac in der Sprache C++ entwickeln.

Programmierung

Lege in Qt Creator ein neues Projekt an, wobei du die Vorlage "Anwendung/Qt-Widgets-Anwendung" wählst. Gebe der Anwendung den Namen "test" und klicke dann ein paar mal auf "Weiter", um den Assistenten abzuschließen. Du erhältst folgende Ansicht:

Füge ganz oben in die Datei mainwindow.cpp eine Zeile für die QSerialPort Klasse ein:

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QSerialPort>

Öffne die Projektdatei test.pro durch Doppelklick und ergänze die folgende Zeile um das Wort "serialport":

    QT += core gui serialport

Öffne das Formular, indem du doppelt auf die Datei mainwindow.ui klickst. Ziehe aus dem Widget Katalog (links) einen "Push Button" in das Formular, etwa so:

Klicke doppelt auf die Beschriftung "PushButton", um den Knopf "Start" zu nennen.

Nun wollen wir festlegen, was beim Klick auf den Knopf passieren soll. Klicke dazu mit der rechten Maustaste auf den Knopf, und dann auf "Slot anzeigen...".

Wähle das Signal clicked() aus. Dadurch wird in der Datei mainwindow.cpp eine leere Funktion mit Namen on_pushButton_clicked() erzeugt, die beim Klick auf den Knopf ausgeführt wird. Fülle die leere Funktion wie folgt aus:

void MainWindow::on_pushButton_clicked()
{
    // Seriellen Port öffnen
    QSerialPort port("COM3");
    port.setBaudRate(QSerialPort::Baud115200);    
    port.open(QIODevice::ReadWrite);

    // Konfiguriere PD2 als Ausgang
    port.write("dPD2,1\n");  
    port.flush();
    
    // Setze PD2 auf High Pegel
    port.write("oPD2,1\n");  
    port.flush();
    
    // Schließe den seriellen Port
    port.close();
}

Anstelle von "COM3" sollst du den Port angeben, den Windows deinem Modul zugewiesen hat. Darunter muss die richtige Baudrate angegeben werden, entsprechend der Firmware auf deinem Mikrocontroller.

Probiere das Programm aus, indem du Strg-R drückst.

Wenn du auf den Start Knopf klickst, geht die LED am Port D2 an. Zur Übung könntest du noch einen zweiten Knopf hinzufügen, der die LED wieder aus schaltet.

Um die Antwort des Moduls zu lesen, kannst du nach dem flush() dies einfügen:

    QTime time;
    time.start();
    while (!serialPort.canReadLine())
    {
        if (time.elapsed()>1000) 
        {
            break;
        }
        QThread::msleep(10);
        QCoreApplication::processEvents();
    }
    QByteArray response=serialPort.readAll().trimmed();

Hier wird maximal eine Sekunde lang auf die Antwort gewartet, damit sich das Programm im Fall eines technischen Defektes nicht aufhängt.

Schaue dir die Dokumentation von QSerialPort, sowie ganz allgemein die Einsteiger-Hilfen von Qt an.