RS 232 Code für Mic rocontroller (GCC C ompiler)

Hier noch ein paar Beispiele, wie es in einem richtigen Betriebssystem aussieht:

formatting link
formatting link

--
Frank Buss, fb@frank-buss.de
http://www.frank-buss.de, http://www.it4-systems.de
Reply to
Frank Buss
Loading thread data ...

Mal davon abgesehen, daß du solche Konstanten am besten per GUI änderbar machst, solltest du nicht unerfahrene Leute an C-Programmierung heranlassen. Ich kenne SPS nicht, sieht aber recht ähnlich wie Pascal aus:

formatting link

und das hat einen guten Ruf:

formatting link

und ist auch für Anfänger zumindest sicherer, als in C zu programmieren. Vielleicht also in Pascal das Gerät programmieren?

Ich finde deine Lösung kryptischer. Meine Lösung ist quasi Standard, den jeder erfahrene Programmierer sofort wiedererkennt und versteht und man könnte mit C++ das Problem der fehlenden Typisierung mittels Templates lösen. So wie ich deine Lösung verstehe, verwendest du den Interrupt nur dafür, die Timer zu zählen und im Hauptprogramm läuft dann alles synchron ab, wobei du die Behandlung mehrerer gleichartiger Probleme durch eine manuell ausprogrammierte und sequentiell ablaufende Statemachine implementierst, die für jedes Einzeilproblem den Code dupliziert. Das wird schlecht wartbar und unübersichtlich.

Alles synchron im Hauptprogramm abzuarbeiten hat natürlich den Vorteil, daß der Interrupt nicht zu lange blockiert werden kann, sodaß man nicht mit reentranten Interrupts arbeiten braucht, was immer ein wenig knifflig ist. Code-Duplizierung kann man auch vermeiden. Dein Beispiel könnte so wie unten aussehen, und ließe sich beliebig erweitern auf unterschiedliche Zustandsmaschinen, oder auch tabellengesteuert usw. Übersichtlicher als mit Threads ist es allerdings nicht gerade.

Man könnte sich überlegen, sowas per GUI am PC zu generieren. Man würde dann das übliche Zustandsdiagramm mit Hilfe eines Programms zeichnen:

formatting link

und daraus würde automatisch C-Code generiert, oder auch einfach nur eine Tabelle (da müsste man sich dann elementare Operationen überlegen, wie Lese-Port, was z.B. als Bytecode einer stackbasierten VM implementiert ist), die dann auf Microcontroller-Ebene abgearbeitet wird.

Auch interessant: In einem Workflowmanagment-System, an dem ich mal mitprogrammiert habe, wurden Petri-Netze eingesetzt:

formatting link

Das müsste auch gut für Hardwareanwendungen verwendbar sein. Hier aber erstmal die langweilige Lösung :-)

int counter;

interrupt() { counter++; }

enum State { START, WAIT_FOR_RELEASE, WAIT_FOR_PRESS, WAIT };

typedef struct { int keyPin; int ledPin; int delay; State state; int counterStart; } Info;

void meinThread(void* parameter) { ThreadInfo* info = (ThreadInfo*) parameter; while (1) { setLedPin(info->ledPin, 0); while (getKeyPortPin(info->keyPin)); while (!getKeyPortPin(info->keyPin)); setLedPin(info->ledPin, 1); delay(info->delay); } }

int counterDelta(int time) { // Wraparound beachten int currentTime = counter; if (currentTime < time) { return MAX_COUNTER_VALUE - time + currentTime; } else { return currentTime - time; } }

void processInfo(Info* info) { switch (info->state) { case START: setLedPin(info->ledPin, 0); info->state = WAIT_FOR_RELEASE; break; case WAIT_FOR_RELEASE: if (!getKeyPortPin(info->keyPin)) { info->state = WAIT_FOR_PRESS; } break; case WAIT_FOR_PRESS: if (getKeyPortPin(info->keyPin)) { info->counterStart = counter; info->state = WAIT; } break; case WAIT: if (counterDelta(info->counterStart) > info->delay) { info->state = START; } break; } }

#define ROBOTER_KEY 1 #define ROBOTER_LED 1 #define ROBOTER_DELAY 123

#define ROBOTERARM_KEY 2 #define ROBOTERARM_LED 42 #define ROBOTERARM_DELAY 456

void main() { int i; Info infos[2] = { { ROBOTER_KEY, ROBOTER_LED, ROBOTER_LED, START, 0 }, { ROBOTERARM_KEY, ROBOTERARM_LED, ROBOTERARM_DELAY, START, 0 } }; for (i = 0; i < 2; i++) { Info* info = &infos[i]; processInfo(info); } }

--
Frank Buss, fb@frank-buss.de
http://www.frank-buss.de, http://www.it4-systems.de
Reply to
Frank Buss

Frank Bussschrieb: " [...]

Ich meine hier wäre noch ein Fehler drin. Wenn oben die "while (getKeyPortPin ..." aufgerufen werden, dann blockierst Du den Controller (und damit alle anderen Tasks). Der zweite Task kann in dieser Zeit nicht laufen und den Taster abfragen. Also KEY1 drücken und halten und KEY2 drücken und loslassen und dann KEY1 loslassen, würde KEY2 nicht erkennen, weil in diesen whiles kein Taskswitching stattfinden kann (der Scheduler wird ja dort nicht aufgerufen). Hinzukommt, dass startRTOS() den Scheduler aufruft, und dann nicht mehr zurückkehrt, startThread(..) also gar nicht mehr aufgerufen wird. Würde ja bedeuten, dass startThread(..) zurückkehrt und main() wäre ganz schnell beendet. startThread(...) startet ja nicht wirklich den Task, sondern trägt den Task nur in die Taskliste ein.

Dirk

Reply to
Dirk Ruth

Da blockiert nichts, falls der Scheduler präemptiv ist und z.B. nach dem Round Robin Verfahren arbeitet:

formatting link

Sowas habe ich schon auf dem C64 vor ewig langer Zeit mal implementiert :-) Ein Ansatz dazu ist, wie in einer der anderen Antworten schon beschrieben: Ein Timer-Interrupt wird aufgerufen und sichert die Register und Rücksprungadresse vom aktuellen Prozess, aber bevor er per RTI wieder zurückkehrt (auf dem 6502), schiebt er die Register und Rücksprungadresse des nächsten Prozesses auf dem Stack.

startRTOS kehrt zurück, nachdem es den Interrupt-Handler installiert hat, aber eine Endlosschleife am Ende oder ein Sleep bei einigen CPUs, der durch Interrupts unterbrochen werden kann, könnte man noch einbauen.

--
Frank Buss, fb@frank-buss.de
http://www.frank-buss.de, http://www.it4-systems.de
Reply to
Frank Buss

Ich würde es leicht anders machen: Ein Timer besitzt - einen Zählerwert ( > 0 bedeutet Timer ist aktiv) - Eine Triggerinput zugleich Vorgabe für den Startwert - eine Triggermethode (Flanke/Pegel)

#define TimerKlingel DelayTriggerinput[0] in der Timerschleife dann:

if(Delaycounter[i] == 0){ /* Flankensensitiv evtl. starten*/ Delaycounter[i] = DelayTriggerinput[i]; }else{ /* runterzählen*/ if(DelayPegeltrigger[i]) /* Pegelsensitiv start */ Delaycounter[i] = DelayTriggerinput[i]; if(--Delaycounter[i] == 0){ /*...*/ } }

Bei mir ist alles jenseits von Naturkonstanten und Anzahl der Raumrichtungen konfiguriert. Magische Zahlen sind immer kleiner 4 oder selbsterklärend *benannte* Konstanten.

Das zahlt sich irgendwann aus.

Ich habe falsche Vorstellungen von Deinen Gesellen.

Soweit kam es nicht mehr. An dieser Stelle wären sie nicht geplagt gewesen. Das funktionierte zuverlässig weil wohldurchdacht und Fehler wären sofort sichtbar gewesen, da es um Datenschieben in einen Druckkopf ging...

gcc.

...

So z.B.:

void TastenThread(void* parameter) { ... }

#define KEYABORT PinA1 #define KEYOK PinA6 #define LEDROT PortB7 #define LEDGRUEN PortB4

const DELAY_ABORTLED = 3000; /* ms Nachleuchten bei Abrruch*/ const DELAY_ACKLED = 300; /* ms aufblitzen bei OK Taste*/

ThreadInfo infoAbortTaste = { KEYABORT, LEDROT, DELAY_ABORTLED }; ThreadInfo infoOKTaste = { KEYOK, LEDGRUEN, DELAY_ACKLED };

... startThread(TastenThread, &infoAbortTaste); startThread(TastenThread, &infoOKTaste);

--
Gruß, Raimund
Mein Pfotoalbum 
Mail ohne Anhang an  wird gelesen. Im Impressum der Homepage
findet sich immer eine länger gültige Adresse.
Reply to
Raimund Nisius

So, aus dem Urlaub zur=FCck.

=E4nderbar

aus:

Ich habe mal dieses stellvertretend f=FCr Deinen ganzen Text zitiert, da ich ihn globaler beantworten muss.

Erst mal liegt da ein Missverst=E4ndnis vor. Was die meisten Gesellen/Facharbeiter kennen, ist die Anweisungsliste (AWL).=20

formatting link
Deren zumindest ausbauf=E4hige Beherrschung ist zunehmend Einstellungsvorraussetzung in Maschinensteuerungen- produzierenden und

-anwendenden Betrieben, wenn SPS ein Thema ist, was zum Beispiel auf fast jeden breit automatisierten Betrieb zutrifft. (Heute hat man sogar Chancen, in der Tischlerei um die Ecke auf eine SPS zu treffen.) In der Berufsschule lernt so etwas heutzutage jeder im Fachgebiet. Nur wenige beherrschen die von Dir angesprochene (pascal=E4hnliche) Sprache. Wer die kann, kann meistens auch C oder wird es sich einigerma=DFen problemlos aneignen k=F6nnen.

Wenn eine Anwendung in AWL programmiert ist, dann folgt der Programmlauf zumeist dem zeitlichen Ablauf bzw. dem Materialfluss in der anwendenden Maschine. Anhand diesem hangelt man sich dann auch durch das Programm. Daher findet man quasi die "Konstantendefinition" an der Stelle des Programms, wo sie auch genutzt wird. Hier w=E4re es kontraproduktiv, diese "oben" oder in einem Konfigurationsmen=FC zu definieren. Denn dann m=FC=DFte man sich die Namen merken, st=E4ndig = dorthin scrollen/umschalten, die Namen dort suchen, die Werte merken und wieder zur=FCck. Im Programmtext selbst ist sie daher besser aufgehoben. Bei vielen "Konstanten" w=E4re auch die Beschreibung im Konfigurationsmen=FC/GUI wegen vieler mechanischen und programmbedingten Abh=E4ngigkeiten viel zu kompliziert. Deren "Beschreibung" wird beim Durchgehen des Programmes deutlicher, als durch jede meterlange Beschreibung. Das Programm ist sozusagen auch gleichzeitig die Beschreibung der Konstanten. Umgekehrt vermittelt der Programmcode ein Verst=E4ndnis vom Prozess. =20

Hier wird vielleicht auch klar, dass das Schreiben des Verwaltungsprogrammes trotz seiner geringen programmtechnischen Anforderungen dennoch nicht trivial ist. Die Problematik liegt eben darin, Prozess, Mechanik und Programmtext in Einklang zu bringen. Diejenigen "richtigen" Programmierer, die f=FCr die SPS Programmierer nur ein m=FCdes L=E4cheln =FCber haben, w=FCrden sich umschauen, wenn sie tats=E4chlich mal vor eine komplexe Aufgabe gestellt w=E4ren. Die Uhren ticken da vollkommen anders, als erwartet. Ich erlebe das regelm=E4ssig, wenn wir Praktikanten im Hauptstudium, oder Diplomanten oder Abschlussprojektler der Technikerschulen im Betrieb haben.

Und genau dies m=F6chte ich in C nachbilden. Hierbei ist allergr=F6=DFtes Augenmerk auf das Debugging zu richten, denn nicht nur das Programm selbst, sondern auch der Anwendungsprozess und die Mechanik wird damit debugged, wenn das mit anderen Mitteln nicht m=F6glich ist. Da werden schon mal ein paar Zeilen eigens f=FCr eine mechanische oder prozessbedingte Fehlersuche eingef=FCgt.=20

Daher m=F6chte ich die Debuggingm=F6glichkeiten meines C-Entwicklungssystem (Watchwindow, Oszilloskop, Logikanalysator, Mouse over Variable, Trace etc.) behalten. Insbesondere die "Mouse over Variable) ist genau dasselbe, wie die Debugging Darstellung der AWL, wo neben jeder Variable der aktuelle Wert angezeigt wird. Dieses Beibehalten ist aber nicht m=F6glich, wenn ich irgendwelche Vorstufen in =46orm von Utilities, GUI oder Preprozessoren nutze. Denn der von Ihnen erzeugte C-Code ist zwar grunds=E4tzlich noch debugbar, aber kaum noch den urspr=FCnglichen Prozess zuordbar. Zum Beispiel k=F6nnen per Define oder GUI bestimmte Konstanten nicht mehr im Debugger zugegriffen werden. Im Debugger sehe ich nur noch die zugeh=F6rigen DefineNamen und muss m=FChsam durch Hochscrollen zu jeder den Wert ermitteln. Was also dem Programmierer zur Komfortabilit=E4t und besseren Lesbarkeit gereicht, macht der debuggenden Person das Leben schwer. Dem ist eher damit gedient, debugbaren Code wie diesen vor sich zu haben:

LED1 =3D Timer (156, Taste4).=20

Hier kann er =FCber Alles die Maus dr=FCberhalten und bekommt den aktuellen Wert angezeigt. Und da der Timer ein Standardelement ist, das in jedem Programm zigfach verwendet wird und somit quasi ein "Schl=FCsselwort" ist, wird intuitiv klar, dass hier die LED1 um 156ms verz=F6gert auf die Taste4 reagiert, ohne in einer Konfigurationsliste/GUI oder einer Defineanweisung an anderer Stelle nachschauen zu m=FCssen, wie es in dieser Anweisung der Fall w=E4re:=20

#define Taste4Verz=F6gerung 156 ..... 100 Seiten Text LED1 =3D Timer (Taste4Verz=F6gerung,Taste4).=20

Kurz gesagt: Der Preprozessor und andere Hilfsmittel entfernen den "Prozess verst=E4ndlich machenden" Originalcode vom erzeugten und damit debugbaren C-Code. Der prozessverst=E4ndliche Code selbst ist nicht mehr debugbar. Da der Prozess an sich schon problembehaftet genug ist, k=F6nnen weitere Erschwernisse und damit Fehlerquellen nicht geduldet werden. Der gelesene Code muss daher direkt (und niemals indirekt) debugbarer C-Code sein. Nur so kann die AWL wirklich nachgebildet werden, die eben diese debugbare Prozessn=E4he aufweist.

Genau an diesem Problem hapert es bei s=E4mtlichen im Netz verf=FCgbaren SPS-L=F6sungen f=FCr Microcontroller. Meine bescheidene L=F6sung ist die = mir bisher einzig bekannte, die das Problem angeht.=20

Im Urlaub ist mir jetzt auch endlich die eigentlich voll simple Methode eingefallen, die Schreibweise=20 LED1 =3D Timer (156, Taste4) definefrei und somit debugbar implementieren zu k=F6nnen und habe damit das urs=E4chliche Problem dieser ganzen Diskussion gel=F6st:

Zu Beginn des Mainloops setzt man einfach eine Rahmenvariable while (1){ TimerIndex =3D 0; Bei jedem Funktionsaufruf von Timer findet dieser am Ende der Funktion =46olgendes vor:=20 int Timer (Zeit, Eingang) ...... TimerIndex++; return

Die Timer "numerieren" sich sozusagen in der Reiehenfolge des Aufrufes im Mainloop selbst und werden damit identifizierbar. Mit dieser "Nummer" ist es ihm dann m=F6glich, durch Indizieren eines Arrays Counter[TimerIndexvariable] seinen Counterstand zu finden. Es ist nun nicht mehr erforderlich, krampfhaft einen Namen f=FCr jeden Timer zu suchen. Denn seine Funktion wird durch den an AWL angelehnten Programmtext, wie beispielsweise LED1 =3D (Timer(156,Taste4) unmittelbar klar.=20

Das Einzige was zur Optimierung vor dem Release h=E4ndisch zu tun bleibt ist, durch einen "Probelauf" des Programms zu ermitteln, wieviele Timer im Programm sind. Hierzu wird an das Ende des Mainloops geschrieben:=20 TimerAnzahlErmittlung =3D TimerIndex; }//while(1) Mainloop

Ein Probelauf des Programms ermittelt dann den Wert der einzig notwendigen define Anweisung, die sich im Deklarationsteil des Programms findet: #define Timeranzahl "hier den ermittelten Wert von TimerAnzahlErmittlung eintragen"=20 Counter[Timeranzahl]

Dieser defineWert wird dann zur Deklaration der Arraygr=F6=DFe benutzt. Eine automatische Ermittlung der Timeranzahl scheint mit den Mitteln von C oder des Preprozessors nicht m=F6glich. Eventuell k=F6nnte bei der L=F6sung der einzig =FCbrig gebliebenen Frage ein RTOS Abhilfe schaffen.=20 Die neue L=F6sung ist zumindest einfacher als die h=E4ndische Sortierung in AWL (oder den anderen SPS Programmiersprachen) oder Verweise per Defineanweisung oder sonstige in diesem Thread gefundenen L=F6sungsm=F6glichkeiten. =20

Die Selbstnumerierung und damit Anonymisierung kann auch bei anderen SPS-Funktionen angewandt werden und es werden damit folgende suggestive Schreibweisen m=F6glich:

A =3D RSFLipflop( Shot(B) & C | Timer(140,Sensor8) , Entprell(Taste2) ); nat=FCrlich mit aussagekr=E4ftiger Benamung f=FCr A, B, C, Sensor8 und Taste2.

Ersteres d=FCrfte durch die obigen Erkl=E4rungen gedeckt werden. Die Codeduplizierung war bisher die einzig gefundene M=F6glichkeit, die Debugbarkeit beizubehalten und ist dank dem neuen Konzept der "Selbstnumerierung" der Timer gottseidank vom Tisch. Der Timer wird jetzt als Funktion aufgerufen und erm=F6glicht so endlich die suggestiven Schreibweisen.

Naja, so langweilig ist die auch wieder nicht. Die Zeitbelastung des Interrupts ist wohl kaum mehr zu minimieren. Wenngleich dieser Interrupt auch mit der geringsten Priorit=E4t nach allen anderen laufen muss. Damit ist es nicht ganz so kritisch, wenn mehr Code drinsteht.

Ich habe zwar die Switch Anweisung schon in =E4hnlicher Form zur Implementierung von Bedienungsmen=FCs und dort zum Speichern des "State" genutzt. Aber jetzt nacheinander mehrere "Threads" durch den Switch zu jagen, ohne dass sie ihren "State" verlieren, ist mir noch nicht in den Sinn gekommen. Das ist sicher eine L=F6sung, die ich gegebenfalls gerne aufgreifen werde. Au=DFerdem vermute ich mal, dass Du mir mit einer didaktisch geschickten Implementatation eine Vorstellung von der Vorgehensweise eines RTOS vermitteln m=F6chtest.=20

Allerdings kann man mit Hilfe der L=F6sung nicht die genannte suggestive und AWL angelehnte Schreibweise =20 LED1 =3D (Timer(156,Taste4) herstellen, die dabei voll debugbar bleibt.=20

Die Implementierung br=FCcksichtigt nicht, dass jemand auf die Idee kommen k=F6nnte, die Taste auch dann zu bet=E4tigen, wenn der Delay = l=E4uft. Ich h=E4tte dies als Kleinigkeit nicht erw=E4hnt. Aber in diesem Falle funktioniert das Switch Konzept so nicht mehr. Es m=FCssten dann schon mehr Cases sein.=20

Die Switch Methode lohnt sich IMHO dann, wenn im Case mehr Code abgearbeitet wird. Ansonsten erzeugt der Switch zuviel Overhead, so dass er im compilierten Code doch ineffizienter als meine Methode mit dem "alten" State ist. Aber als Schulbeispiel ist es nat=FCrlich hier ideal an einem einfachen Beispiel von Dir verdeutlicht.=20

Vielen Dank f=FCr Deine umfangreichen M=FChen. Sie hahen mir neue Einsichten und insbesondere eine jetzt selbstst=E4ndig ausbauf=E4hige Anfangsvorstellung von einem RTOS vermittelt.=20

Reply to
Paul Rosen

Du schreibst doch von komplexen Steuerungen. Woran sieht der Mensch, der die 156 auf 193 anpassen soll, daß dann aber auch das Timeout von Sensor7 auf (193 + 34) ms geändert werden muß?

#define TimeoutSensor7 Taste4Verzögerung + 34

würde Dir den Notaus ersparen...

--
Gruß, Raimund
Mein Pfotoalbum 
Mail ohne Anhang an  wird gelesen. Im Impressum der Homepage
findet sich immer eine länger gültige Adresse.
Reply to
Raimund Nisius

Das sieht ja schlimmt aus, da sind ja die meisten Assembler-Befehlssätze komfortabler. Wie kann man bei solchen Programmen, fast ohne jegliche höhere Strukturierung, noch den Überblick behalten? Wikipedia scheint das auch zu bestätigen:

| AWL Programme sind aber im Vergleich zu Programmen in höheren Sprachen | insbesondere bei größeren Projekten sehr unübersichtlich und schlecht | wartbar. Heute werden daher für die Programmierung von Steuerungen | normalerweise die höheren Sprachen der IEC 61131-3, insbesondere | strukturierter Text (SCL) oder Ablaufsprache, Continuous Function Chart | oder vielfach auch "C" eingesetzt.

Und du kannst mir nicht sagen, daß das Schleifenbeispiel ganz unten im Wikipedia-Artikel einfacher zu verstehen ist, als dasselbe in C geschrieben. Mag sein, daß einfache Dinge, wie eine sequentielle Steuerung einer Maschine, ohne viel Verzweigungsmöglichkeiten und ohne viel Parallelität, damit leicht beschreibbar sind, aber sobald es dann etwas mehr sein soll, ist eins der genannten Alternativen besser.

Da lernt man also Dinge, die laut Wikipedia heute nur noch auf alten Steuerungen eingesetzt werden?

Kann ich mir bei der Sprache nicht gut vorstellen.

Das sind auch keine "richtigen" Programmierer. Richtige Programmierer sind Leute, die 20 Jahre lang und länger in verschiedenen Computersprachen geübt sind, mit Projekten die von Assembler, über echtzeitfähige Mikrocontrollersteuerungen in C, bis hin zu Warenwirtschaftsanwendungen mit SQL in Java reichen, so wie bei mir :-)

Da hast du dann den falschen Debugger. Mit Visual Studio werden z.B. auch Werte von defines per Mouse-Over angezeigt. Außerdem gibt es ein locales-Window, was alle im Kontext erreichbaren Variablen anzeigt und ein Auto-Fenster, was alle zuletzt geänderten und sonstwie wichtigen Variablen anzeigt, neben dem üblichen Watch-, Callstack- und Threads-Fenster. Ich gehe mal davon aus, daß gute Umgebungen für Microcontroller sowas auch anbieten.

Wenn es dich wirklich stört, und der Einwand von Raimund für deinen Fall nicht zutrifft, dann kannst du ja auch die Zahl direkt reinschreiben, statt ein define zu nehmen.

Das funktioniert, wenn du keine bedingten Verzweigungen in deinem Programm hast, die eine Timer-Funktion überspringt.

Eine Alternative wäre, beim Aufruf der Timer-Funktion einen neuen Eintrag in einer verketten Liste anzulegen, die dann im Interrupt abgearbeitet wird. Der Eintrag ist eine Instanz einer Struktur, in der der aktuelle Timerwert steht, der oder die Ports und eine Bearbeitungsfunktion. Die Bearbeitungsfunktion bekommt die Adresse in der verketteten Liste übergeben, sodaß die dann je nach Aufgabe z.B. bei Ablauf des Timers den Eintrag aus der verketteten Liste entfernen kann. Der Interrupt arbeitet ruft alle Bearbeitungsfunktionen der Liste auf. Das kann alles transparent für den Anwender sein, der nur den timer-Aufruf programmiert.

Generell fände ich bei so asynchronen Prozessen eine grafische Darstellung besser. Sowas in der Art von LabVIEW:

formatting link

Auch wenn man es später nicht einsetzt, kann es helfen, es mal auszuprobieren (gibt glaube ich auch eine kostenlose Demo-Version), um Ideen für eigene Umsetzungen zu bekommen, z.B. für ein eigenes System, was auf einen Microcontroller compiliert. LabVIEW hat aber glaube ich auch eine Echtzeiterweiterung.

Hier ein einfaches Projekt von mir (der LabVIEW-Anteil ist unten zu sehen)

formatting link

Wenn du es mit einer verketteten Liste programmierst, dann braucht der Interrupt nur alle aktuell aktiven Timer abzuarbeiten, nicht immer die maximal mögliche Menge des gesamten Programms. Nachteil könnte man meinen ist, daß du eine Speicherverwaltung brauchst. Aber die meisten etwas leistungsfähigeren C-Compiler für Microcontroller bieten alles von Standard C, wie malloc. Die Implementierung muß man sich aber gut anschauen, ob die schnell genug ist, um das per Interrupt verwenden zu können.

Es geht aber auch einfacher. Wenn man sich Kapitel 2.2.3 von Band 1 von "The Art of Computer Programming" durchliest, dann kann man viele interessante Ideen entdecken. U.a. ein schöner Trick: Man verwaltet zwei Listen: Eine aktive Liste, wo deine Timer-Strukturen drin stehen und eine "available"-Liste. Zu Programmstart wird die available-Liste mit leeren Einträgen gefüllt und jedesmal, wenn du einen neuen Eintrag in deiner aktiven Liste brauchst, nimmst du einen von der available-Liste weg und umgekehrt fügst ihn wieder dort hinzu, wenn er aus der aktiven Liste gelöscht werden soll. Das ist dann blitzschnell (technisch gesprochen O(1)). Du kannst mehrere aktive Listen nehmen, für FlipFlops, Timer usw. jeweils unterschiedliche, oder das auch durch die Bearbeitungsfunktion festlegen.

--
Frank Buss, fb@frank-buss.de
http://www.frank-buss.de, http://www.it4-systems.de
Reply to
Frank Buss

Aber nur, wenn viele Leute dort mitmachen :-) Hier gibt es auch noch einen überarbeitungswürdigen Artikel:

formatting link

Einige Informationen in den Diskussionen sind schon interessant.

Klingt nach einer guten Idee, wobei ich allerdings eher für sprechende Namen der Variablen bin, statt jedes mal einen langen Kommentar zu lesen.

Würde mich wundern. Alleine schon dein Beispiel mit der Programmierung einer Menüführung käme mir da in den Sinn, wenn man z.B. ein Display anschließt. Für reine Maschinensteuerungen könnte es aber vielleicht möglich sein, wenn man damit auch Schleifen mit speziellen Bausteinen abbilden kann, z.B. statt in einer Warteschleife auf ein Ereignis zu warten, das mit deiner Timer-Funktion zu programmieren.

Das ist übrigens ein gutes Konzept von SPSs mit den asynchronen Befehlen, denke ich. Habe noch nie eine SPS programmiert, aber damit direkt sowas wie asynchron laufende Timer zu starten, die bestimmte Ereignisse auslösen können, oder FlipFlops zu implementieren, finde ich eine gute Idee, besonders für das Anwendungsgebiet der Maschinensteuerungen.

Ist schade, daß viele gute alte Ideen leicht verloren gehen. Hatte gerade den Fall, daß ich ein hierarchisches Speichersystem suchte, weil das am besten zu einer vorgegebenen Anforderung passte. Im Internet findet man dazu aber meist nur, wie man das in SQL abbildet, aber kaum Informationen dazu, wie das früher mit IMS/DB auf Großrechnern implementiert wurde (und teilweise immer noch gut läuft). Werde mir also wieder mal was selber programmieren müssen.

Die Verwaltungsarbeit hält sich aber sehr in Grenzen.

Ideal wäre, wenn man auch das Entwicklungssystem dynamisch erweitern kann, um das leicht darstellbar machen zu können. Bei Common Lisp wäre sowas bereits eingebaut. Dort kann man z.B. auch in laufende Webserver einzelne Module austauschen und generell in laufenden Programmen Funktionen interaktiv, z.B. fürs Debugging, aufrufen.

Wenn es solche Fehler geben kann, dann hast du noch andere Probleme, denn es könnte sich ja z.B. auch das Programm ändern. Dann musst du mit fehlerkorrigierenden Codes arbeiten, wie man es von ECC-Speicher her kennt, oder besser gleich betriebssicherere Microcontroller einsetzen. Bei hochkritischen System werden auch gerne mehrere CPUs parallel betrieben und dann per Mehrheitsentscheid die Ausgänge verwendet, was bei den Preisen von heutigen Microcontrollern vielleicht gar nicht mehr so teuer wäre und Hardwarefehler minimieren würde.

Habe dazu was gefunden:

formatting link

Ich könnte mir vorstellen, daß manche Leute damit einfacher Steuerungen erstellen können.

Debugging wird bei LabVIEW gut gelöst, wie man es auch mit dem Oszilloskop oder Multimeter machen würde: Man kann einfach Logging-Funktionsblöcke in das Diagramm einbauen oder Probes, und Breakpoints auf Bedingungen der Probes setzen. Man kann sich natürlich zusätzlich alle Daten im Debugger ansehen.

Ideal für sowas wäre ein etwas schlaueres System. Da du nicht viel bedingte Sprünge usw. hast, könnte ich mir gut vorstellen, daß man große Teile des Programms zur Compilierzeit analysieren kann, also z.B. feststellen kann, daß der Timer am Anfang, hundert Zeilen später abgelaufen sein muß und die Stelle für andere Timer verwendet werden kann. Dann könnte man dies recht optimiert umsetzen, auch für kleine Microcontroller.

Bei den heutigen Geschwindigkeiten der Microcontroller wäre aber eine dynamische Lösung wohl besser und einfacher, auch da die nur genau die benötigte Anzahl Timer in jedem Augenblick abarbeiten muß und nicht alle möglichen und der Overhead gegenüber statischen Timern vernachlässigbar ist (ein Pointer mehr dereferenzieren usw., also alles konstante Zeit).

--
Frank Buss, fb@frank-buss.de
http://www.frank-buss.de, http://www.it4-systems.de
Reply to
Frank Buss

Ich hoffe, ich verstehe Deine Frage richtig. Es geht darum, dass im =46alle einer Wert=E4nderung auch ein anderer Wert mitge=E4ndert werden m=FCsste, damit nichts den Bach heruntergeht? Ist das so richtig? Falls ja:

Ich habe versucht, es schon mehrfach zu betonen: Ich habe mich hier bem=FCht, die Beispiele so einfach wie m=F6glich und f=FCr jeden verst=E4ndlich zu halten. Daher habe ich ein einfach zu formulierendes und verstehbares wohlbedachtes Minimalproblem konstruiert, das alle Widrigkeiten des zu l=F6senden Problems enthielt. Hierzu ben=F6tigte man mindestens zwei dieser Minimaltimer mit je einem Eingang, suggestiv als Taste dargestellt - und einem Ausgang, suggestiv als Klingel oder LED dargestellt. Nat=FCrlich soll das Ganze letztendlich nicht als die Hausklingelanlage von Tante Gerda und Onkel Franz fungieren. Der Begriff "Timeout" kommt dem Ganzen nat=FCrlich schon n=E4her, impliziert aber nicht bei jedem die Vorstellung eines Ausganges oder Einganges.=20

In Wirklichkeit gibt es verschiedenartige Timer, n=E4mlich anzugsverz=F6gerte, abfallverz=F6gerte, pulsformende, pulsverz=F6gernde, jeder dieser mit retriggerbaren und nicht retriggerbaren Eing=E4ngen, dazu Schrittketten etc. Diese und weitere Bausteine lassen sich aber nach L=F6sung des Problems der beschriebenen Minimaltimer mit Anzahl 2 ebenfalls l=F6sen. So kann aufgrund der gefundenen L=F6sung jetzt auch = der Zeitwert eines Timers nicht nur fest, sondern auch eine Variable sein, so dass man beispielsweise auch schreiben kann:

Taste4Verz=F6gerung =3D A + B; Q_LED1 =3D Timer (Taste4Verz=F6gerung , I_Taste4); TimeoutSensor7 =3D Taste4Verz=F6gerung + 34; St=F6rungsmeldungSensor7 =3D Timer (TimeoutSensor7 , I_Sensor7); alternativ: St=F6rungsmeldungSensor7 =3D Timer (Taste4Verz=F6gerung + 34 , Sensor7); VerhindereAnfahrenStrecke3 =3D St=F6rungsmeldungSensor7 | !StreckeFrei Q_St=F6rmeldelampe =3D St=F6rungsmeldungSensor7 & Sekundenblinken G_FokussiereQuittungstaster =3D St=F6rungsmeldungSensor7 //Touchscreen

Die Anonymisierung bei der L=F6sung ist also ein Kann, kein Muss. Man kann sie jederzeit durch Einf=FCgen eines Zwischenergebnisses aufheben, wenn es denn dem Prozessverst=E4ndnis oder sp=E4ter beim Debuggen hilfreich ist. Das hat au=DFerdem zur Folge, dass auf Wunsch die Zeitwerte auch zur Laufzeit ge=E4ndert und berechnet werden k=F6nnen.=20

All dies verkompliziert den Code und erschwert das Herausarbeiten des springenden Punktes. Darum habe ich dieses und vieles Andere hier bei der Diskussion so vereinfacht, dass die infrage stehenden Probleme dennoch erhalten bleiben.=20

So k=F6nnten durchaus noch andere auf Deiner Stirn stehende Fragezeichen dem Umstand der Vereinfachung geschuldet sein.=20

Reply to
Paul Rosen

Display

Das Display ist nat=FCrlich ein Baustein.=20

Befehlen,

wie

Jetzt verstehst Du vielleicht, warum mir die Timer so wichtig waren. Sie nehmen Dir viele realtimem=E4=DFig problematischen Dinge ab und erleichtern sp=E4ter das Debugging von Maschinenproblemen, nicht Programmproblemen.

kann,

sowas

einzelne

Im Moment machen mich Deine Aussagen etwas konfus. Meines Wissens nach ist doch nicht m=F6glich, einfach irgendetwas zu einer Microcontroller Entwicklungsumgebung hinzuzuf=FCgen, und dann damit INLINE, also direkt mit dem in der Anwendung eingebautem Microcontroller Debugging direkt von der Oberfl=E4che des Hinzugef=FCgten zu betreiben. Oder liege ich da falsch?

Hardware

denn

kennt,

und

Preisen von

Hier verstehen wir uns vollkommen miss. Es geht bei diesem Inline Debugging nicht um Probleme im Controller oder im Programm, sondern um Probleme in der Maschine. Sei es zum Beispiel, dass ein Sensor f=FCr einen Sekundenbruchteil ausl=F6st, obwohl er es nicht sollte. Dadurch hat es den Anschein, dass das Programm verr=FCckt spielt.=20

Ich bin mal davon ausgegangen, dass Du dies ausgehend vom SPS Artikel findest.

vom

direkte

Oszilloskop

Logging-Funktionsbl=F6cke in

Debugger

Das ist mir alles schon klar. Aber Du wolltest Labview dazu verwenden, um die Funktionsbausteinsprache auf einem Microcontroller zu implementieren. Und da habe ich die gr=F6=DFsten Fragezeichen auf der Stirn. Es stellen sich n=E4mlich folgende Fragen:

Ich erstelle also mit den Funktionsbausteinen von Labview ein Programm, das auf dem Microcontoller implementiert werden soll. Woher kennt Labview die implementierte Hardware des Controllers sowie deren Benennung und kann somit den richtigen Code erzeugen? Wie kann ich dann zum Zwecke des Debuggens von der Labview Oberfl=E4che aus den in einer Maschinensteuerung befindlichen Controller debuggen, wenn es hierzu nicht ein vom Controllerhersteller und dem Entwickler der Hardwareverbindung vom PC zum Controller (h=E4ufig auch der Controllerhersteller) bereitgestelltes Plugin gibt?

Reply to
Paul Rosen

Mit Eclipse wäre das möglich: Man kann die Entwicklungsumgebung selbst durch Plugins ändern, die dann mit selbst entwickelten Bibliotheken und passenden Hardware-Schnittstellen mit dem Microcontroller kommunizieren können. Common Lisp war ein Beispiel für eine weitere Umgebung, wo das per Commandline Interface meist möglich ist, oder auch in Verbindung mit Emacs. Oder man schreibt sich was selber mit Tcl/TK.

Um das auf möglichst vielen Microcontrollern laufen lassen zu können, wäre ein möglicher Ansatz ein Interpreter auf dem Microcontroller. Oder auch ein Forth-System, wobei sich eine indirect threaded Implementierung (

formatting link
) gut dafür eignen würde, da man damit leicht Breakpoints einbauen kann oder es im Single-Step ausführen kann. Forth ist auch eine sehr kompakte Sprache, was bei heutigen Microcontrollern allerdings nicht mehr so wichtig ist, und der stackbasierte Ansatz müsste dir als AWL-Profi vertraut sein.

Für sowas wäre vielleicht Forth eine gute Idee. Ich habe damit schonmal programmiert und man kann interaktiv einzelne Programmteile testen, die Variablen evaluieren usw. Fand ich sehr nützlich, mal eben ad-hoc eine Schleife laufen zu lassen, um z.B. einen SPI-Sensor abzufragen. Relativiert sich aber wieder, wenn man eine moderne Entwicklungsumgebung hat und schnell Testprogramme einspielen kann.

Unter

formatting link
stehen mehrere Einträge, wovon Funktionsbausteinsprache und Grafcet, je nach unterschiedlichen Normen, sowas zu sein scheint, was du meinst. Scheint aber beides ähnlich zu sein.

NI hat da was:

formatting link

Ich weiß aber nur, daß es das gibt, habe es aber noch nicht ausprobiert. Sowas selber zu programmieren, sodaß es z.B. mit dem Interpreter-basierten Ansatz auf unterschiedlichen Zielplattformen laufen würde, wäre interessant, aber wohl ein paar Jahre Aufwand, um das stabil und benutzerfreundlich hinzubekommen.

Hier noch ein nettes Marketing-Video und weitere Informationen:

formatting link

Ist aber bestimmt nicht preiswert und hat dann auch wieder andere Nachteile, als wenn man es direkt in C oder AWL low-level implementiert.

Das Plugin könnte man selber programmieren, da LabVIEW auch erlaubt, selbst programmierte Plugins einzusetzen. Oder auch innerhalb von LabVIEW, mit reinen LabVIEW-Komponenten. Ein Beispiel ist mein Silabs-Test, der über die serielle Schnittstelle mit LabVIEW kommuniziert. Aber auch das wäre recht viel Aufwand, verglichen mit deiner reinen C-Lösung.

--
Frank Buss, fb@frank-buss.de
http://www.frank-buss.de, http://www.it4-systems.de
Reply to
Frank Buss

Paul Rosen schrieb:

Zumindest in Forth ist das durchaus möglich. Gibt sicher noch mehr gängige Programmierumgebungen, die das können. Eine weitere hat Frank ja genannt, die ich allerdings nicht kenne.

- Henry

--
www.ehydra.dyndns.info
Reply to
Henry Kiefer

selbst

=FCber die

recht

Aufwand, der sich nicht lohnt, da ja jetzt Alles bis auf die genannten Kleinigkeiten gut l=E4uft. Jede L=F6sung, die Ihre eigenen Platinen oder Chips mit fertig gebrannter unzug=E4nglicher Firmware ben=F6tigt, ist aus leidvoller Erfahrung ungeeignet. Man liefert sich dabei dem jeweiligen Hersteller aus, ist auf dessen Bugl=F6sungen, Featureimplementation bzw Liefertreue angewiesen. Au=DFerdem machen sie mich extrem unflexibel bei einer effizienten Hardwareimplementation. Alles wird aufgeblasen mit eigenen Hardware und Software Tools sowie Compiler, die das wiederholen, was es eigentlich in effizienter Form schon alles (in diesem Falle bei Microchip) erprobt von einer Unmenge an Personen schon gibt. Man br=E4uchte seine L=F6sung hier nur reinzuimplementieren. Dazu kommen aufwendige Hardware, Geh=E4use und Steckverbindungen. F=FCr das Ganze braucht man denn wieder gro=DFe Schaltschr=E4nke.=20

Dabei k=F6nnte es so einfach sein. Mit einem Controller und ein bi=DFchen Peripherie sowie in die Entwicklungsumgebeung direkt hinein zu implementierenden Tools, das deren Inline-Debugging Schnittsttelle nutzt, kann man schon eine ganze Menge erschlagen. Aber so etwas gibt es einfach nicht. Hier liegt meiner Meinung nach eine rein in Software zu implementierende echte Marktl=FCcke brach, f=FCr die es eine Unmenge zahlungskr=E4ftige Klientel g=E4be. Es br=E4uchte "nur" eine Art = erweitertes

formatting link
oder Labview zu geben, das den C- oder Assembler-Code produziert und im Debugger sowohl das Grafikfenster, als auch das des erzeugten C/Assembler-Codes parallel anzeigt und beim Einzelschritt, Breakpoint, animierten Run und den sonstigen =FCblichen M=F6glichkeiten des = Debuggings beide unterst=FCtzt, wobei der User das vom Debugging bediente Fenster durch Focussierung ausw=E4hlt. Die Nutzung der Inline Schnittstelle h=E4tte den unsch=E4tzbaren Vorteil, dass alle schon jetzt in der Entwicklungsumgebung funktionierenden Hardware und Softwaretools problemlos weiter verwendet werden k=F6nnten.

Ein kleines Beispiel f=FCr eine Minimierung unn=F6tigen Overheads: Ein Messger=E4t in einem gro=DFen 19 Zoll Geh=E4use, Preis 16.000 Euro habe = ich nach jahrelanger Suche des Messverfahrens durch einen Controller und ein bi=DFchen Peripherie ersetzen k=F6nnen. Bisher war der Aufwand an zus=E4tzlicher Hardware und Software immens, um das empfindliche Analogsignal unbesch=E4digt von der Messstelle aus der bewegten Mechanik zum Ger=E4t zu bef=F6rden, das zudem ein Hindernis bei der Wartung der Maschine darstellte. F=FCr diese Ger=E4te gibt es weltweit nur einen einzigen Hersteller. Daher ging man dort auch nicht auf unsere =C4nderungsw=FCnsche ein (oder konnte es mangels nicht mehr greifbarem Software Entwickler nicht mehr). Da wir das Ger=E4t nicht exakt seiner urspr=FCnglichen Zielsetzung entsprechned nutzen, w=E4re es n=E4mlich = f=FCr uns sehr hilfreich gewesen, eines der Zwischenergebnisse beim Berechnen des ausgegebenen Endwertes gehabt zu haben, ohne das unser Prozess nur suboptimal lief und daher aufwendige Ma=DFnahmen zur Kompensation erforderlich waren.=20

Diese analoge L=F6sung des Herausf=FChrens des Messsignales selbst zu entwickeln, w=E4re mir zeitlich kaum m=F6glich gewesen. Jetzt f=E4hrt der Controller mit gerade mal 200 Zeilen Paules SPS Code + Spezial-Software- Messbaustein spazieren und setzt das Signal 1 cm von der Messstelle entfernt um, die analoge Herausf=FChrung braucht es nicht mehr, das Zwischenergebnis ist bekannt und alle Probleme sind in Luft aufgel=F6st. Auch s=E4mtliche bisherigen St=F6rungen des Messsignals = durch den EMV verseuchten Prozess existieren nicht mehr. F=FCr die Messung muss der Prozess jetzt nicht mehr aufwendig gestoppt werden. In der n=E4chsten Generation kann die Mechanik der Maschine erheblich vereinfacht werden. Z.B. auf einem Controller mit Fertigfirmware w=E4re diese Entwicklung wegen des ganzen Overheads und damit Verschleierung beim hardwarenahen Debugging und der fehlenden Flexibilit=E4t wohl kaum m=F6glich gewesen. =20 =20 Das bei den L=F6sungsanbietern nat=FCrlich niemals laut ausgesprochene Motto "Nach der Kohle die Sintflut." ist sogar ein St=FCck weit verst=E4ndlich. Schlie=DFlich braucht man immer wieder neue Einnahmequellen. Solange bleibt wohl nichts Anderes =FCbrig, als dass jeder seine eigene L=F6sung immer wieder neu erfindet.=20

Reply to
Paul Rosen

Schau dir doch mal das Konzept von Forth an. Etwas Lesen schadet nicht der Bildung. Da hast du eine Kombination aus schlanker compilierter und interpretierter Sprache. Kannst jederzeit Submodule einzeln testen. Kannst dir eigene Spracherweiterungen schreiben, weil der Kern nachvollziehbar ist wegen 1. wenig Code und 2. offengelegt. Es gibt auch diverse Ansätze Multitasking in Forth einzubauen. Einen davon in der Form von IPS nannte ich bereits.

Aber wie Frank schon schrieb, die modernen Entwicklungsumgebungen machen viele Vorteile von Forth relativ. Was heute rulez, ist C, allein schon weil alle Mikrocontroller-Hersteller es bevorzugen und die Entwicklungsumgebung samt den nicht unwichtigen Bibliotheken in C liefern. Es ist auch sehr schwierig ein Sprachkonstrukt vom 8-Bitter bis zum Pentium durchzuziehen. Da ist auf der einen Seite die Resourcenknappheit der Mikrocontroller, auf der anderen Seite die Komplexität eines PC-Systems. Beides muß händelbar bleiben.

- Henry

--
www.ehydra.dyndns.info
Reply to
Henry Kiefer

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.