Scopeclock

Aus BraLUG-Wiki

Wechseln zu: Navigation, Suche


Inhaltsverzeichnis

Vorwort

Der folgende Artikel ist noch nicht vollständig. Er dokumentiert den derzeitigen Stand der Überlegungen und Realisierungen zum Projekt "Scopeclock". Auch in der Endversion wird höchstwahrscheinlich keine wasserdichte Nachbauanleitung zu erwarten sein. Der Text soll lediglich Hilfestellungen zu eigenen Experimenten und Projekten geben.

Warum schon wieder eine Uhr?

Die Darstellung der Uhrzeit ist schon eine interessante Geschichte, mit der man sehr viel Zeit(:-)) verbringen kann. Dass ich mich damit auch ab und zu beschäftige, zeigen einige Uhren-Projekte, die in diesem Wiki zu finden sind. Ich unterscheide dabei zwei Kategorien von Uhrenprojekten:

  • Zeitdarstellung in ungewöhnlicher Form
  • Zeitdarstellung auf ungewöhnlicher Hardware

Mein letztes Uhren-Projekt, eine Nixie-Uhr, gehört in die zweite Kategorie. Die dabei verwendete Röhrentechnik ist so faszinierend, dass ich den Entschluss gefasst habe, eine weitere Uhr aufzubauen, die ein noch ungewöhnlicheres Ausgabemedium verwendet...

Was ist eine "Scopeclock"?

Herzstück einer Scopeclock ist eine Kathodenstrahlröhre, wie sie z.B. in analogen Oszilloscopen als Anzeigeeinheit eingebaut ist. Prinzipiell wird in einer solchen Röhre ein Elektrodenstrahl erzeugt, welcher in x- und y-Richtung ablenkbar und jeder Zeit abschaltbar (austastbar) ist. Trifft dieser Strahl auf den eingebauten Leuchtschirm, leuchtet die entsprechende Stelle. Erfolgt die Ablenkung und Austastung des Kathodenstrahls in zeitlich geeigneter Art und Weise, können damit Linien, Punkte etc. erzeugt werden. Mit einem Oszilloskop wird damit z.B. der zeitliche verlauf einer Spannung dargestellt. ...und bei einer Scopeclock werden aus den Linien und Punkten Ziffern/Zeichen, Uhrenziffernblätter und Uhrzeiger zusammengesetzt...!

Sucht man bei der Suchmaschine seiner Wahl nach entsprechenden Bildern (Suchbegriff: Scopeclock), erahnt man, wie eine solche Uhr aussehen könnte. Die Bilder zu meinem Scopeclock-Simulator deuten ähnliche Darstellungsformen für Datum/Uhrzeit an.

Scopeclock-Simulator

Komischerweise fragt man sich als Softwareentwickler (fast) immer zuerst, wie müßte ungefähr das Programm, der Algorithmus aussehen, wenn man dieses und jenes Ergebnis haben möchte. Hat man ein wenig Zeit, schreibt man halt einen Simulator, um ein wenig zu experimentieren...

Simulator (analoge Zeitanzeige) Simulator (digitale Zeitanzeige)

Im Fall der Scopeclock kommt allerdings noch ein weiterer Aspekt hinzu: für die Ansteuerung der Anzeigeröhre soll ein Mikrocontroller (Hersteller/Typ steht zu diesem Zeitpunkt noch nicht fest) eingesetzt werden. Wegen des begrenzten Programmspeichers und Geschwindigkeit müssen Algorithmen gefunden werden, die schnell und platzsparend arbeiten. Gerade bei der Darstellung des analogen Ziffernblattes (es handelt sich bekanntlich um einen Kreis) verbietet es sich also Rechenoperationen mit Komma-Zahlen (welcher konkrete Typ auch immer) zu verwenden. Damit sind auch die originären Winkelfunktionen tabu! Weiterhin musste ein einfache Möglichkeit her, mit der man Zahlen (und andere Zeichen) platzsparend und skalierbar erzeugen kann.

Ergebnis ist ein Scopeclock-Simulator, der in Tcl/Tk geschrieben wurde. Innerhalb der Software wurden die beiden vorgesehenen Anzeigemodi (eine analoge und eine digitale Darstellungsform) umgesetzt. Sämtliche verwendete Algorithmen kommen mit 16-Bit-Integer aus. Eine Portierung der entscheidenen Tcl-Routinen in C sollte problemlos möglich sein. Speziell wurde folgendes getestet/umgesetzt:

  • Definition der Zeichen als Punktfolgen, die mit Geraden untereinander verbunden werden und skalierbar sind
  • Zeichnen von Linien mit Hilfe des Bresenham-Algorithmus (Kreise zeichnen auch, wird aber wahrscheinlich später nicht benötigt...)
  • Berechnung von Winkelfunktionen mit Hilfe einer Lookup-Tabelle und temporärer Skalierung auf verlustminimierter Integer-Operationen

Im Simulator wird nicht die eigentliche Ansteuerung der Oszillographenröhre nachgestellt. Es wird von der Annahme ausgegangen, dass es einen zweidimensionalen Bildspeicher (128x128x1 Bit, also in 2048 Byte RAM abbildbar) gibt, in dem das anzuzeigende Bild statisch aufgebaut wird. Dieser Bildspeicher wird später zyklisch fortlaufend (Stichwort: Timer-Interrupt) von einer weiteren Routine ausgelesen werden, die wiederum die Hardware (insbesondere Digital-/Analog-Wandler) zur Röhrenansteuerung mit Daten versorgt.

Ein paar vorbereitende Software-Experimente

ein EO 213...

Irgendwo muss man anfangen! Mit 600V "in Hardware" wollte ich nicht beginnen. Also musste ein analoges Oszilloscope her, welches in X-/Y- sowie Z-Richtung ("Strahl-Helligkeit") jeweils seperat ansteuerbar ist. Ein gutes altes EO-174A aus DDR-Zeiten scheint genau das Richtige für diese prinzipielle Experimente zu sein und konnte im Bekanntenkreis aufgetrieben werden... Später kam dann ein EO 213 zum Einsatz.

Einfach mal etwas auf dem Oszi ausgeben...

Vier Punkte...

Einfachste Geschichte ist, wenn man aus zwei Bits vier Punkte ({L, L}, {H, L}, {H, H}, {L, H}) aus den resultierenden Spannungspegeln für Low/Height generiert und an den entsprechenden X-/Y-Eingängen des Oszi ausgibt. Für ein Stellaris Launchpad würde das dazu notwendige Programm wie folgt aussehen:

#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "driverlib/gpio.h"
#include "driverlib/sysctl.h"
     
#define XY_PORT_BASE		GPIO_PORTB_BASE
#define XY_SYSCTL_PERIPH	SYSCTL_PERIPH_GPIOB
#define PIN_XOUT	 	GPIO_PIN_0
#define PIN_YOUT 		GPIO_PIN_1

#define DELAY			100
     
int main()
{
	SysCtlPeripheralEnable(XY_SYSCTL_PERIPH);
	GPIOPinTypeGPIOOutput(XY_PORT_BASE, PIN_XOUT|PIN_YOUT);
	while (1) {
		GPIOPinWrite(XY_PORT_BASE, PIN_XOUT|PIN_YOUT, 0);
		SysCtlDelay(DELAY);
		GPIOPinWrite(XY_PORT_BASE, PIN_XOUT|PIN_YOUT, PIN_XOUT);
		SysCtlDelay(DELAY);
		GPIOPinWrite(XY_PORT_BASE, PIN_XOUT|PIN_YOUT, PIN_XOUT|PIN_YOUT);
		SysCtlDelay(DELAY);
		GPIOPinWrite(XY_PORT_BASE, PIN_XOUT|PIN_YOUT, PIN_YOUT);
		SysCtlDelay(DELAY);
	}
}

Striche zeichnen

An der nicht ganz optimalen Darstellung ist das Oszi schuld, dass vielleicht mal einen "wissenden" Elektroniker zur Reparatur benötigt...

Neben dem Stellaris Launchpad kam bei diesem Versuch ein Digital/Analog-Wandler (DAC) vom Typ TLC7528 zum Einsatz. Dieser DAC besitzt 2 Kanäle mit jeweils 8-Bit Breite. Die Kanalwahl erfolgt über ein entsprechendes Eingangs-Pin und die umzusetzenden Digitalwerte werden parallel an den DAC weitergegeben. Das Datenblatt des TLC7528 sollte genügend Aufklärung geben. Für diesen Versuch wurde der DAC im "Voltage Mode" betrieben. Mit den beiden DAC-Kanälen werden die Spannungswerte für die x- und y-Auslenkung am Oszi generiert. Der Rest sollte aus dem Quelltext hervorgehen:

#include <stdint.h> 
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "driverlib/gpio.h"
#include "driverlib/sysctl.h"

// Daten-Port DAC (TLC7528)
#define DATA_OUT           GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7
#define DATA_PORT_BASE     GPIO_PORTB_BASE
#define DATA_SYSCTL_PERIPH SYSCTL_PERIPH_GPIOB

// Steuerleitungen DAC (TLC7528)
#define DAC_CTL_PORT_BASE     GPIO_PORTE_BASE
#define DAC_CTL_SYSCTL_PERIPH SYSCTL_PERIPH_GPIOE
#define DAC_AB                GPIO_PIN_1
#define DAC_WR                GPIO_PIN_2
#define DAC_CS                GPIO_PIN_3

#define DAC_CH_A 0
#define DAC_CH_B DAC_AB

#define MAX_X	255
#define MAX_Y	255
#define DT_X	255/MAX_X
#define DT_Y	255/MAX_Y

// *********************************  	   
void xy_set(uint8_t x, uint8_t y)
{
	// x
	GPIOPinWrite(DAC_CTL_PORT_BASE, DAC_AB, 0);
	GPIOPinWrite(DATA_PORT_BASE, DATA_OUT, x*DT_X);
	GPIOPinWrite(DAC_CTL_PORT_BASE, DAC_WR, 0);
	GPIOPinWrite(DAC_CTL_PORT_BASE, DAC_WR, DAC_WR);
	// y
	GPIOPinWrite(DAC_CTL_PORT_BASE, DAC_AB, DAC_AB);
	GPIOPinWrite(DATA_PORT_BASE, DATA_OUT, y*DT_Y);
	GPIOPinWrite(DAC_CTL_PORT_BASE, DAC_WR, 0);
	GPIOPinWrite(DAC_CTL_PORT_BASE, DAC_WR, DAC_WR);
	// Punkt kurz halten	
	SysCtlDelay(20);

}

// *********************************  	   
int abs(int value)
{
	return value<0 ? -value : value;
}

// *********************************  
// http://de.wikipedia.org/wiki/Bresenham-Algorithmus
//	   
void line(int x0, int y0, int x1, int y1)
{
	int dx =  abs(x1-x0), sx = x0<x1 ? 1 : -1;
	int dy = -abs(y1-y0), sy = y0<y1 ? 1 : -1;
	int err = dx+dy, e2; /* error value e_xy */
	for(;;){  /* loop */
		xy_set(x0,y0);
		if (x0==x1 && y0==y1) break;
		e2 = 2*err;
		if (e2 > dy) { err += dy; x0 += sx; } /* e_xy+e_x > 0 */
		if (e2 < dx) { err += dx; y0 += sy; } /* e_xy+e_y < 0 */
	}
}
  	
// *********************************  	   
// *********************************  	   
// *********************************  	   
int main()
{
	// Systemtakt 80MHz...
	SysCtlClockSet(SYSCTL_SYSDIV_2_5 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ);
	// ...DAC-DATA-Port
	SysCtlPeripheralEnable(DATA_SYSCTL_PERIPH);
	GPIOPinTypeGPIOOutput(DATA_PORT_BASE, DATA_OUT);
	// ...DAC-Control-Pins
	SysCtlPeripheralEnable(DAC_CTL_SYSCTL_PERIPH);
	GPIOPinTypeGPIOOutput(DAC_CTL_PORT_BASE, DAC_AB|DAC_WR|DAC_CS);
	// ... CS=Low; WR=Hight
	GPIOPinWrite(DAC_CTL_PORT_BASE, DAC_WR|DAC_CS, DAC_WR);
	while (1) {
		line (0, 0, MAX_X, 0);
		line (MAX_X, 0, MAX_X, MAX_Y);
		line (MAX_X, MAX_Y, 0, MAX_Y);
		line (0, MAX_Y, 0, 0);
		line (0, 0, MAX_X, MAX_Y);
		line (0, MAX_Y, MAX_X, 0);
	}
}

Damit sind eigentlich alle Voraussetzungen vorhanden, die Software für die Scopeclock zu schreiben, denn wenn man Punkte und Linien zeichnen kann, sollte alles andere kein Problem darstellen. Der Rest ist dann nur noch Fleißarbeit, wie man auf den folgenden Bildern sieht:


ein paar "Zahlen/Zeichen"(:-)) auf einem Oszi vom Typ EO 213) ...sieht schon fast wie eine Uhr aus ;-)... Ausgabe Temperatursensor auf Launchpad ... ...Bilder gehen auch :-)...

Die Geschichte mit der ausreichend schnellen Ansteuereinheit

Messergebnisse der Performance-Messung am "lebenden Objekt"

Meine Scopeclock

Hardware

Kathodenstrahlröhre

Die Anschaffung der notwendigen Kathodenstrahlröhre war die erste vollendete Tatsache (also die erste finanzielle Ausgabe) zu diesem Projekt. Meine Wahl fiel auf ein Exemplar mit "niedrigen" Betriebsspannungen, eine DG7-32 von Philips. Da solche Röhren nicht mehr im regulären Handel erhältlich sind, wurde sie über ein bekanntes Internet-Auktionshaus beschafft. Einige spezialisierte Privathändler haben ebenfalls solche Bauteile im Sortiment (z.B. "Frag' Jan zuerst").

DG7-32 Draufsicht DG7-32 Leuchtschirm (die vermeindlich sichtbaren Kratzer sind nur Spiegelungen... DG7-32 Sockel Fassung


Datenblatt der Kathodenstrahlröhre DG7-32


...achso, "Niedrige Betriebsspannungen" bedeuten immer noch ca. 600V für die Gitterspannung...;-) Bei anderen Röhrentypen geht das auch schon mal weit über 1000V!

Netzteil

Heute kam mein bestellter Ringkerntrafo (und die Röhrenfassung) an. Diese beiden Teile habe ich bei Jan Wüsten geordert.


Ringkerntrafo Ringkerntrafo Ringkerntrafo


Das heißt also, dass es jetzt langsam mit dem Aufbau der Hardware losgehen kann, wenn der Rest der notwendigen Bauteile von meinem Lieblings-Elektronik-Versender angekommen sind...

Als Vorlage für Netzteil wird die entsprechend angepasste Schaltung aus dem Projekt von Sascha Ittner (Seite 2 bis 4) verwendet.

Ansteuereinheit

Blockschaltbild Ansteuereinheit Stellaris Launchpad DAC, RTC etc. Launchpad huckepack...

Software

  • Scopeclock Version 0.1
    • erste vorzeigbare Version
    • Aufbau bestehend aus:
      • Oszilloskop (EO 213)
      • Stellaris Launchpad
      • Ansteuereinheit mit:
        • DAC TLC7528
        • RTC DS1307
    • folgende Funktionen:
      • digitale Anzeige Datum/Uhrzeit
      • analoge Uhr (noch mit Fehlern!)
      • Ausgabe interner Temperatursensor des Stellaris Launchpads
      • ...ein Bild

Linksammlung

Kontakt

Fragen und Anregungen können an Uwe gerichtet werden...

'Persönliche Werkzeuge