{"id":62,"date":"2017-11-27T05:19:06","date_gmt":"2017-11-27T05:19:06","guid":{"rendered":"http:\/\/mike-netz.biz\/?p=62"},"modified":"2025-10-26T17:42:39","modified_gmt":"2025-10-26T17:42:39","slug":"atmelstudio-7-ampelplatine-mit-dem-atmega328-p-c11-und-ich","status":"publish","type":"post","link":"https:\/\/mike-netz.biz\/?p=62","title":{"rendered":"AtmelStudio 7, Ampelplatine mit dem ATmega328\/P, C++11 und ich"},"content":{"rendered":"<p>Diesmal habe ich mir eine ganz besondere Aufgabe gestellt.<\/p>\n<p>Schaffe ich, alle Phasen der Software-Entwicklung von der Spezifikation \u00fcber Design, Kodierung&nbsp; einschlie\u00dflich Test mit einer IDE zu realisieren?<\/p>\n<p>Zus\u00e4tzlich erlaubt sind Plugins, sowie kleine Extra-Tools die sich mit ein paar Handgriffen bedienen lassen. Strikt verboten sind Textprogramme wie MS-Word und UML-Mal-Tools. Okay, Schmierzettel und Kugelschreiber z\u00e4hlen nicht.<\/p>\n<p>&nbsp;<\/p>\n<p><strong>Also, los gehts.<\/strong><\/p>\n<p>Vor mir liegt eine kleine Ampelanlage. Sie besteht aus zwei Ampeln realisiert mittels 6 LEDs. Ein Taster dient als Hauptschalter. Die Ampelanlage beinhaltet einen <em>Arduino UNO<\/em> &#8211; einen Einplatinenrechner. Der Micro ist ein <em>ATmega328\/P<\/em>. In der unteren Darstellung ist die Mini-Anlage zu sehen. NR steht f\u00fcr Nebenrichtung und HR f\u00fcr Hauptrichtung.&nbsp; Die Schaltung ben\u00f6tigt eine Steuerung &#8211; die Ampelsteuerung. Sie wird in C++11 realisiert.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter\" src=\"http:\/\/mike-netz.biz\/wp-content\/uploads\/2017\/11\/Ampelanlage.jpg\" alt=\"Mini-Ampelanlage\" width=\"533\" height=\"396\"><\/p>\n<p>Die funktionalen Anforderungen werden ich in Gherkin-Syntax beschrieben. Daf\u00fcr habe ich vorab das Plugin <em>specflowC<\/em> installiert. Mit dieser Beschreibungssprache beschreibt man ein oder mehre Features mittelst textueller und spezifischer <em>UseCases<\/em>. Spezifisch, da konkrete Eingabewerte, Handlungen und Ergebnisse \/ Ausgabewerte anzugeben sind. Sp\u00e4ter werden daraus Tests wie UnitTests teilautomatisiert durch einen Parser generiert.<\/p>\n<p>&nbsp;<\/p>\n<p><strong>Anforderungen in Gherkin-Syntax<\/strong><\/p>\n<p><em>Given:&nbsp;<\/em>Ein <em>Scenario<\/em> beginnt mit einem Anfangszustand<em>. <\/em><em>When: <\/em>Eine bestimmte Handlung oder ein bestimmtes Ereignis&nbsp;tritt ein.&nbsp;<em>And :&nbsp;<\/em>Zus\u00e4tzliche Handlungen oder Ereignisse. <em>Then:&nbsp;<\/em>Draus folgt ein Ergebnis<em>. And&nbsp;: Z<\/em>us\u00e4tzliche Ergebnisse.<\/p>\n<p>Die Daten sind in einer Tabelle aufgelistet.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter\" src=\"http:\/\/mike-netz.biz\/wp-content\/uploads\/2017\/11\/Gherkin-Spezifikation.png\" alt=\"Spezifikation in Gherkin-Syntax\" width=\"770\" height=\"670\"><\/p>\n<p>&nbsp;<\/p>\n<p><strong>Software-Design im Quellcode mittels Doxygen und&nbsp;Grapgviz<\/strong><\/p>\n<p>Und nun zum Software-Design, das recht simpel ist. Der Startpunkt ist die Main-Datei. Die Klasse Ampelanlage abstrahiert die Hardware f\u00fcr die Fachklasse Ampelsteuerung.<\/p>\n<p>Die Klassen werden in der Header-Dateien entworfen. Schnittstellenfunktionen deklariert. Der Quellcode wird in der <em>Doxygen<\/em>&#8211; \/<em>Grapgviz<\/em>-Notation dokumentiert. Daraus generiert das Tool <em>Doxywizard&nbsp;<\/em>die Design-Dokumentation.<\/p>\n<p>Die Ampelanlagen-zust\u00e4nde werden mittels einer&nbsp;<em>Enum<\/em> in der Klasse Ampelsteuerung realisiert.<\/p>\n<pre class=\"lang:c++ decode:true\">\/*! \n\t\\class Ampelsteuerung\n\t\\brief Die Ampelsteuerung steuert die Betriebszustaende und Ampelphasen ueber ein Zustandsautomat.\n*\/ \nclass Ampelsteuerung final\n{\n\tprivate:\n\t\t\/*!\n\t\t\t\\enum Ampelstatus\n\t\t\t\\brief Enum Ampelstatus beinhaltet die Betriebszustaende und Ampelphasen\n\t\t\t\\see run()\n\t\t*\/\n\t\tenum class Ampelstatus : uint8_t{ \n\t\t\tAUS,\t\t\t\/*!&lt; Betriebszustand AUS: Die Hautrichtung ist aus und die Nebenrichtung ist gelb-blinkend *\/\n\t\t\tNOT_Betrieb,\t\/*!&lt; Betriebszustand Notaus: Die Hauptrichtung (HS) ist aus und die Nebenrichtung (NS) ist gelb-blinkend *\/\n\t\t\tAN_Phase_1,\t\t\/*!&lt; Betriebszustand AN Phase 1: HS und NS sind rot *\/\n\t\t\tAN_Phase_2,\t\t\/*!&lt; Betrienszustand AN Phase 2: HS rot-gelb, NR ist rot *\/\n\t\t\tAN_Phase_3,\t\t\/*!&lt; Betrienszustand AN Phase 3: HS ist gruen, NR ist rot *\/\n\t\t\tAN_Phase_4,\t\t\/*!&lt; Betrienszustand AN Phase 4: HS ist gelb, NR ist rot *\/\n\t\t\tAN_Phase_5,\t\t\/*!&lt; Betrienszustand AN Phase 5: HS und NS sind rot *\/\n\t\t\tAN_Phase_6,\t\t\/*!&lt; Betrienszustand AN Phase 6: HS ist rot, NS ist rot-gelb *\/\n\t\t\tAN_Phase_7,\t\t\/*!&lt; Betriebszustand AN Phase 7: HS ist rot, NS ist gruen *\/\n\t\t\tAN_Phase_8\t\t\/*!&lt; Betriebszustand AN Phase 8: HS ist rot, NR ist gelb *\/\n\t\t};<\/pre>\n<p><em>Doxywizard<\/em> generiert daraus folgende Darstellung.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter\" src=\"http:\/\/mike-netz.biz\/wp-content\/uploads\/2017\/11\/Doxygen-Darstellung.png\" alt=\"Darstellung der Zust\u00e4nde in der Doxy-Dokumentation\" width=\"670\" height=\"509\"><\/p>\n<p>In der Design-Dokumentation soll der Zustandsautomat grafisch dargestellt werden, deshalb f\u00fcge ich eine zus\u00e4tzliche Beschreibung ein.<\/p>\n<pre class=\"lang:c++ decode:true \">\/*!\n\t\\fn void run()\n\t\\brief Zustandsmaschine der Ampelsteuerung\n\t\\see enum class Ampelstatus\n\t\t\t\n\t\\dot\n\t\tdigraph g\n\t\t{\n\t\t\tsubgraph cluster0\n\t\t\t{\n\t\t\t\tstyle=filled;\n\t\t\t\tcolor=lightgrey;\n\t\t\t\tnode [style=filled,color=white];\n\t\t\t\tAUS\n\t\t\t}\n\t\t\tsubgraph cluster1\n\t\t\t{\n\t\t\t\tstyle=filled;\n\t\t\t\tcolor=lightgrey;\n\t\t\t\tnode [style=filled,color=white];\n\t\t\t\tAN_Phase_1 -&gt; AN_Phase_2;\n\t\t\t\tAN_Phase_2 -&gt; AN_Phase_3;\n\t\t\t\tAN_Phase_3 -&gt; AN_Phase_4;\n\t\t\t\tAN_Phase_4 -&gt; AN_Phase_5;\n\t\t\t\tAN_Phase_5 -&gt; AN_Phase_6;\n\t\t\t\tAN_Phase_6 -&gt; AN_Phase_7;\n\t\t\t\tAN_Phase_7 -&gt; AN_Phase_8;\n\t\t\t\tAN_Phase_8 -&gt; AN_Phase_1;\n\t\t\t\tlabel=\"ZEIT==FERTIG\"\n\t\t\t}\n\t\t\tsubgraph cluster2\n\t\t\t{\n\t\t\t\tstyle=filled;\n\t\t\t\tcolor=lightgrey;\n\t\t\t\tnode [style=filled,color=white];\n\t\t\t\tNOT_Betrieb\n\t\t\t}\n\t\t\tAN_Phase_8 -&gt; NOT_Betrieb [ltail=cluster2, lhead=cluster3] [label=\" Notaus==BETAETIGT\"] [style=filled,color=red];\n\t\t\tNOT_Betrieb -&gt; AUS [label=\" Hauptschalter==AUS\"] [style=filled,color=orange];\n\t\t\tAUS -&gt; AN_Phase_1 [label=\" Hauptschalter==AN\"] [style=filled,color=green];\n\t\t\tAN_Phase_1 -&gt; AUS [label=\" Hauptschalter==AUS\"] [style=filled,color=orange];\n\t\t}\n\t\\enddot\n*\/\nvoid run();<\/pre>\n<p>&nbsp;<\/p>\n<p><em>Doxywizard<\/em> generiert daraus folgendes.<\/p>\n<p><img decoding=\"async\" class=\"aligncenter\" src=\"http:\/\/mike-netz.biz\/wp-content\/uploads\/2017\/11\/Zustandsautomat-grafisch.png\"><\/p>\n<p>&nbsp;<\/p>\n<p>Klassendiagramme &#8211; welche die Beziehungen zischen den Klassen darstellen &#8211; generiert Doxywizard automatisch. Eine zus\u00e4tzlich Beschreibung ist hier nicht von N\u00f6ten.<\/p>\n<p><img decoding=\"async\" class=\"aligncenter\" src=\"http:\/\/mike-netz.biz\/wp-content\/uploads\/2017\/11\/Klassenbeziehungen.png\"><\/p>\n<p>&nbsp;<\/p>\n<p>So, das Design ist geschafft. Nun steht die Realisierung der <em>UseCases<\/em> in C++11-Code an. Ich fange mit der Main an. Zuerst wird die Ampelsteuerung initialisiert. Die Klasse Ampelanlage konfiguriert die entsprechenden Register; die 6 LEDs auf I\/O-Ausgabe-Ports legen, den Hauptschalter (Taster) auf einen I\/O-Eingabe-Port legen und den Interrupt konfigurieren.<\/p>\n<p>Datei main.cpp:<\/p>\n<pre class=\"lang:c++ decode:true \">#include \"Betriebsmodus.h\"\n#include &lt;avr\/io.h&gt;\n#include \"Ampelsteuerung.h\"\n#include &lt;avr\/interrupt.h&gt;\n\n\/\/! Variable der Klasse Ampelsteuerung\nAmpelsteuerung ampel_steuerung{};\n\n\/*!\n\t\\fn int main(void)\n\t\\brief Legt eine Variable der Ampelsteuerung an. Ruft einmalig setup() und zyklisch run() auf.\n*\/\nint main(void)\n{\t\t\n\tampel_steuerung.setup();    \n    while (1) \n    {\n\t\tampel_steuerung.run();\n    }\t\n\treturn 0;\n}\n\n\/*!\n\t\\fn ISR(INT0_vect)\n\t\\brief Service-Interrupt-Routine wird aufgerufen wenn Hauptschalter tastet.\n*\/\nISR(INT0_vect)\n{\n\tampel_steuerung.getAmpelanlage().set_Hauptschalter_tastet();\n}<\/pre>\n<p>&nbsp;<\/p>\n<p>Klasse Ampelanlage:<\/p>\n<pre class=\"lang:c++ decode:true  \">#include \"Ampelanlage.h\"\n\nvoid Ampelanlage::setup()\n{\n\t\/*! \n\t\tInitialisierung der Ausgaenge:\n\t\tAmpel_HS: gruen, Ampel_HS: gelb, Ampel_HS: rot, Ampel_NS: rot, Ampel_NS: gruen, Ampel_NS: gelb\n\t*\/\n\tDDRB |= (1&lt;&lt;DDB0);\n\tDDRD |= ( (1&lt;&lt;DDD3) | (1&lt;&lt;DDD4) | (1&lt;&lt;DDD5) | (1&lt;&lt;DDD6) | (1&lt;&lt;DDD7) );\n\t\n\t\/*!\n\t\tInitialisierung der Eingaenge:\n\t\tHauptschalter Eingang\n\t*\/\n\tDDRD &amp;= ~(1 &lt;&lt; DDD2);\n\t\n\t\/*!\n\t\tInterrupts:\n\t\tHauptschalter Eingang\n\t*\/\n\tEICRA |= ((1 &lt;&lt; ISC00) | (1&lt;&lt;ISC01));   \/*!&lt; Setze INT0 auf Triggerung mittels steigender Flanke *\/\n\tEIMSK |= (1 &lt;&lt; INT0);\t\t\t\t\t\/*!&lt; Einschalten mittels INT0 *\/\n\n\tsei();\t\t\t\t\t\t\t\t\t\/*!&lt; Interrupts einschalten *\/\n\n}<\/pre>\n<p>&nbsp;<\/p>\n<p>Im run-Betrieb werden die entsprechen Ausg\u00e4nge gesetzt, das Blinken der gelben Nebeneinrichtungs-LED generiert und der Interrupt verarbeitet.<\/p>\n<pre class=\"lang:c++ decode:true \">bool Ampelanlage::ist_Haupstschalter_tastet()\n{\n\tbool result{false};\n\t\n\t\/\/uint8_t sreg_tmp;\n\t\/\/sreg_tmp = SREG;    \/* Sichern *\/\n\tcli();\n\tresult = hauptschalter;\n\thauptschalter = false;\n\t\/\/SREG = sreg_tmp;    \/* Wiederherstellen *\/\n\tsei();\n\n\treturn result;\n}\n\nvoid Ampelanlage::Ampel_HS_Rot_An()\n{\n\tPORTD |= (1&lt;&lt;PD4);\n}\n\nvoid Ampelanlage::Ampel_HS_Rot_Aus()\n{\n\tPORTD &amp;= ~(1&lt;&lt;PD4);\n}\n\nvoid Ampelanlage::Ampel_HS_Gelb_An()\n{\n\tPORTD |= (1&lt;&lt;PD3);\n}<\/pre>\n<p>&nbsp;<\/p>\n<p>Der Ampelsteuerung-Ablauf ist mittels&nbsp;<em>switch-case<\/em> realisiert. Die Logik ist gut zu lesen und zu verstehen.<\/p>\n<pre class=\"lang:c++ decode:true \">void Ampelsteuerung::run()\n{\n\tswitch( ampel_status )\n\t{\n\t\tcase Ampelstatus::AUS:\n\t\t{\n\t\t\tampel_anlage.Ampel_HS_Rot_Aus();\n\t\t\tampel_anlage.Ampel_NS_Rot_Aus();\n\t\t\tampel_anlage.Ampel_NS_Gelb_blinken();\n\t\t\tif( ampel_anlage.ist_Haupstschalter_tastet() )\n\t\t\t\tampel_status = Ampelstatus::AN_Phase_1;\n\t\t\t\t\n\t\t\tbreak;\n\t\t}\n\t\t\n\t\tcase Ampelstatus::AN_Phase_1:\n\t\t{\n\t\t\tampel_anlage.Ampel_NS_Gelb_Aus();\n\t\t\tampel_anlage.Ampel_HS_Rot_An();\n\t\t\tampel_anlage.Ampel_NS_Rot_An();\n\t\t\t_delay_ms(2000);\n\t\t\tif( ampel_anlage.ist_Haupstschalter_tastet() )\n\t\t\t\tampel_status = Ampelstatus::AUS;\n\t\t\telse\n\t\t\t\tampel_status = Ampelstatus::AN_Phase_2;\n\t\t\tbreak;\n\t\t}\n\t\t\n\t\tcase Ampelstatus::AN_Phase_2:\n\t\t{\n\t\t\tampel_anlage.Ampel_HS_Gelb_An();\n\t\t\t_delay_ms(1000);\n\t\t\tampel_status = Ampelstatus::AN_Phase_3;\n\t\t\tbreak;<\/pre>\n<p>&nbsp;<\/p>\n<p><strong>Fazit<\/strong><\/p>\n<p>Die Software-Spezifikation konnte mittels specflowC in der IDE erstellt werden. Das Design erfolgte direkt in den Header-Datein in der Doxygen- und Graphviz-Notation. Ein aktuelles Design-Dokument mittels Doxywizard war schnell zu generieren. Die Funktionalit\u00e4t ist in C++11 realisiert, nat\u00fcrlich in abgespeckter Form, bspw. k\u00f6nnen keine Objekte zur Laufzeit generiert werden.<\/p>\n<p><strong>Offen<\/strong><\/p>\n<p>Als n\u00e4chstes steht der UnitTest an &#8230; oh, je testen.&nbsp;<img decoding=\"async\" src=\"http:\/\/mike-netz.biz\/wp-content\/plugins\/wp-edit\/plugins\/emoticons\/img\/smiley-wink.gif\"><\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Diesmal habe ich mir eine ganz besondere Aufgabe gestellt. Schaffe ich, alle Phasen der Software-Entwicklung von der Spezifikation \u00fcber Design, Kodierung&nbsp; einschlie\u00dflich Test mit einer IDE zu realisieren? Zus\u00e4tzlich erlaubt sind Plugins, sowie kleine Extra-Tools die sich mit ein paar<\/p>\n","protected":false},"author":1,"featured_media":36,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[31],"tags":[7,8,6],"class_list":["post-62","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-software-entwicklung","tag-arduino-uno","tag-atmelstudio-7","tag-c11"],"_links":{"self":[{"href":"https:\/\/mike-netz.biz\/index.php?rest_route=\/wp\/v2\/posts\/62","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/mike-netz.biz\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/mike-netz.biz\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/mike-netz.biz\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/mike-netz.biz\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=62"}],"version-history":[{"count":23,"href":"https:\/\/mike-netz.biz\/index.php?rest_route=\/wp\/v2\/posts\/62\/revisions"}],"predecessor-version":[{"id":441,"href":"https:\/\/mike-netz.biz\/index.php?rest_route=\/wp\/v2\/posts\/62\/revisions\/441"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/mike-netz.biz\/index.php?rest_route=\/wp\/v2\/media\/36"}],"wp:attachment":[{"href":"https:\/\/mike-netz.biz\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=62"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/mike-netz.biz\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=62"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/mike-netz.biz\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=62"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}