Als Vater eines Kleinkindes kommt man schon mal auf die Idee eine elektronische Spielerei zu basteln. Eine Martins-Laterne muss zwar nicht unbedingt sein, denn die werden in der Kita zu genüge von den Kleinen selbst produziert, Rabimmel Rabammel RabummHabt ihr vielleicht auch etwas Elektronik gebastelt nur um die jüngsten zu begeistern? Ich wäre für weitere Projektvorstellungen aus der Spielzeug-Branche dankbar.
Ich habe meine Idee realisiert, die Modellwaschstraße meiner Tochter mit einer Ampel aufzuhübschen. Der PIC16F675 ist für kleine LED-Anwendungen ideal. 6 IO Pins reichen z.B. für zwei Anforderungstaster, zwei grüne und zwei rote LED's.
Und so sah es dann auf der Baustelle aus:
Hier die gefädelte "Steuerungszentrale". Drei Micro-Zellen sind etwas überdimensioniert. Mit zwei Zellen (und entspr. kleineren LED Vorwiderständen) hätte es auch getan, aber der Batteriehalter stammt aus dem Kellerfundus - Reste und Projektüberbleibsel, die man bei solchen Projektchen gerne verbraucht.
Baustelle ist fertig, die Waschstraße kann den Betrieb wiederaufnehmen. Die Fahrzeuge warten schon
Nachtrag am 18.02.14
Ich habe mein Quellcode an der Stelle gelöscht, weil ich niemandem zumuten will, meine Umsetzungsfehler zu kopieren. Statt dessen hier ein PAD (oder Programmablaufplan, PAP, Flußdiagramm, Flow Chart oder wie es auch es sonst noch genannt wird). Ich habe das PAD nachträglich erstellt, um das Programm für mich zu dokumentieren:
Bei der Erstellung des PAD habe ich einige Fehler in der Umsetzung gefunden und festgestellt, dass das ganze nicht optimal strukturiert ist und alles andere als mustergültig ist. Muss es auch nicht, weil das nur eine kleine Spielerei war, entstanden mehr oder weniger aus Codeschnipseln diverser Experimente mit PIC-Timern, Interrupts und Assembler-Schrittketten.
Nachtrag am 19.02.14
Die optimale Art, das Quellcode zu strukturieren und zu dokumentieren habe ich für mich noch nicht gefunden. Das erstellen von FlowCharts z.B. mit dem OpenOffice Draw ist sehr zeitaufwändig. Es stört mich auch, zwei Dateien pflegen zu müssen, aus Programmier-Erfahrung weiß ich dass man nicht immer die Quellcode-Änderungen in die Doku aufnimmt. So lange es keine Möglichkeit gibt, aus einem Diagramm das Assembler Quellcode zu generieren ist die ASCII Art innerhalb des Quellcode glaub ich schon die richtige. Hier mein Quellcode mit überarbeitetem Kommentar. Natürlich ohne Gewährleistung!
Nachtrag am 04.03.14
So ein Projektchen ist immer wieder ein dankbares Versuchsobjekt für Programmiertechniken. Ich habe mal etwas mit Wertetabellen experimentiert und die gleiche Aufgabe mit Tabellen gelöst. Auch die Art der Kommentare ist ein Experiment an sich, im Moment versuche ich es mit einem C-ähnlichen Pseudocode.
Nachtrag am 07.03.14
Den Quellcode mit Software Timern überarbeitet in Anlehnung an A. M. König "Das große PIC-Mikro Handbuch".
Code:; Filename: main.asm ; - Zwei Rot/Grün Ampeln mit Anforderungstaster ; - Gegenverkehr gesperrt ; - Ampelphasen: Grün/Grün blinkend/Rot ; - nach 3 Minuten Standby-Modus: LED's aus, MCU in SLEEP ; - wecken durch Anforderungstaster ; ; Projekthinweise: ; - Header Files: P12F675.INC, Makrodefs.inc ; - Include Files: InitPIC12F675.asm ; - 4MHz interner Oszillator, ; - alle GPIO Ports digital I/O, Komparator und DAC aus ; - GPIE und IOC aktiv für RA0, RA3 (Wake-Up from SLEEP mit Anforderungstaster) ; ; Version | Datum | Autor | Kommentar ; --------|--------|-------|----------------------------------------------------- ; 2.0.0 |04.03.14| wg| Schaltwerk mit Tabellen ; 2.0.2 |06.03.14| wg| Softwaretimer (keine Verschwendung von TMR0 Interrupt für Blinkerei) ; 2.0.3 |07.03.14| wg| einfachere Programmstruktur ohne Interrupts ;=== Konfiguration ============================================================= LIST P=PIC12F675 #include <P12F675.INC> errorlevel -302 __CONFIG _CP_OFF & _CPD_OFF & _BODEN_OFF & _MCLRE_OFF & _WDT_OFF & _PWRTE_ON & _INTRC_OSC_NOCLKOUT #include <MakroDefs.inc> ;=== Variablen Deklaration ===================================================== cblock 0x20 W_TEMP STATUS_TEMP BaseEvent ; 4ms Basistakt-Eventwert von Timer0 BaseStep ; Basistakt Counter für abgeleitete Timer SekEvent ; Sekundentakt-Eventwert von Basistakt BlinkTmr ; Anwendungstimer für BlinkEvent SleepTmr ; Anwendungstimer für Schlafmodus, Startwert 180s AmpelTmr ; Anwendungstimer für Ampelphase-Änderung AmpelFlags ; Ampelphase ; Zustandswort der Ampelschaltung endc #define maskTaster b'00001001' ; GPIO Binärmaske Taster #define maskAmpel1Gr b'00000010' ; GPIO Binärmaske Ampel1 Grün #define maskAmpel1Rd b'00000100' ; GPIO Binärmaske Ampel1 Rot #define maskAmpel2Gr b'00010000' ; GPIO Binärmaske Ampel2 Grün #define maskAmpel2Rd b'00100000' ; GPIO Binärmaske Ampel2 Rot ;=== Programmstart ============================================================= org 0x0000 call initMCU ; //InitPIC12F675_Carwash.asm ; *** Initialisierung Variablen Startwerte bcf STATUS,RP0 ; //change to bank 0 clrf BlinkTmr ; BlinkTmr = 0; M_MOVLF SleepTmr, d'180' ; SchlafTmr = 3Minuten Startwert; clrf Ampelphase ; Ampelphase = 0; ;=== Hauptschleife ================================================================= main ; *** Basis Timer 4ms movf BaseEvent, w ; do{ subwf TMR0, w ; andlw 0xC0 ; skpz ; goto main ; } while ((TMR0 - BaseEvent) = 0 bis 63); M_ADDLF BaseEvent, d'125' ; BaseEvent += 125; // für nächten 4ms Event incf BaseStep ; BaseStep += 1; // 4ms Basis Zähler hochzählen ; *** Blinktimer movf BlinkTmr ; if ( BlinkTmr !=0 ) skpz ; decf BlinkTmr ; BlinkTmr -= 1; ; *** Sekundentimer ; movf SekEvent, w ; if (SekEvent == Basistimer) subwf BaseStep, w ; skpz ; goto main_ende ; { M_ADDLF SekEvent, d'250' ; SekEvent += 250 * 4ms; ; *** Ampeltimer ; movf AmpelTmr, f ; skpz ; if AmpelTmr != 0 decf AmpelTmr ; AmpelTmr -= 1; ; *** Sleeptimer ; decf SleepTmr, f ; SleepTmr -= 1; skpz ; goto main_wakeup ; if (SleepTmr == 0) { movlw maskTaster ; andwf GPIO, f ; GPIO &= Taster; // LED's löschen sleep ; Sleep(); nop ; } main_wakeup movf GPIO, w ; read(GPIO); //notwendig zum resetten von interrupt-on-change btfss INTCON, GPIF ; if (GPIF) goto main_ende ; { bcf INTCON, GPIF ; GPIO Interruptflag = 0; M_MOVLF SleepTmr, d'180' ; Schlafcounter = Startwert 3min; main_ende ; } ;=== Ampelmodul ================================================================ ;*** Ampelmodul Definitionen #define tasteAmpel1Anf GPIO, GP0 ; Anforderung Ampel1 #define tasteAmpel2Anf GPIO, GP3 ; Anforderung Ampel2 #define fAmpel1Anf AmpelFlags,0 ; Ampel1 angefordert #define fAmpel2Anf AmpelFlags,1 ; Ampel2 angefordert #define PhaseAmpelrd 0 ; Ampel1 und Ampel2 rot #define PhaseAmpel1gn 1 ; Ampel1 grün #define PhaseAmpel1gnblnk 2 ; Ampel1 grün blinkend #define PhaseAmpel2gn 3 ; Ampel2 grün #define PhaseAmpel2gnblnk 4 ; Ampel2 grün blinkend movf AmpelTmr ; skpz ; if (AmpelTmr == 0) goto Ampelm_Blinken ; { movf Ampelphase, w ; call tabNaechsteAmpelphase ; Ampelphase = naechste(Ampelphase); movwf Ampelphase ; call tabPhasendauer ; AmpelTmr = Phasendauer(Ampelphase); movwf AmpelTmr ; call subLEDSchalten ; LEDs Schalten(); Ampelm_Blinken ; } movf BlinkTmr, f ; if (BlinkTmr == 0) skpz ; goto Ampelm_Anfordg ; { movf Ampelphase, w ; call tabBlinkmaske ; w = Blinkmaske(Ampelphase); xorwf GPIO, f ; GPIO = GPIO ^ w; M_MOVLF BlinkTmr, d'62' ; BlinkTmr = 248ms; Ampelm_Anfordg ; } btfss tasteAmpel1Anf ; if (taste Ampel1 gedrückt) bsf fAmpel1Anf ; Ampel1 Anforderung = 1; btfss tasteAmpel2Anf ; if (taste Ampel2 gedrückt) bsf fAmpel2Anf ; Ampel2 Anforderung = 1; movf Ampelphase, w ; call tabAnforderungssperre ; andwf AmpelFlags, f ; AmpelFlags &= Anforderungssperre(Ampelphase); movf Ampelphase, f ; if (Ampelphase = Rot) skpz ; { goto Ampelm_Ende ; Ampelm_Anfordg_1 ; btfss fAmpel1Anf ; if (Ampel1 angefordert) goto Ampelm_Anfordg_2 ; { bcf fAmpel1Anf ; Ampel1 Anforderung = 0; M_MOVLF Ampelphase, PhaseAmpel1gn ; Ampelphase = Ampel1 grün; call tabPhasendauer ; AmpelTmr = Phasendauer(Ampelphase); movwf AmpelTmr ; call subLEDSchalten ; LEDs Schalten(); goto Ampelm_Ende ; } Ampelm_Anfordg_2 ; btfss fAmpel2Anf ; else if (Ampel2 angefordert) goto Ampelm_Ende ; { bcf fAmpel2Anf ; Ampel2 Anforderung = 0; M_MOVLF Ampelphase, PhaseAmpel2gn ; Ampelphase = Ampel2 grün; call tabPhasendauer ; Ampelcountdown = Phasendauer(Ampelphase); movwf AmpelTmr ; call subLEDSchalten ; LEDs Schalten(Ampelphase); ; } ;*** Ampelmodul Programmende Ampelm_Ende goto main ; ;*** UP Ampel LEDs Einschalten subLEDSchalten ; subLEDSchalten() { movf Ampelphase, w ; call tabLEDs ; W = LEDs(Ampelphase) | BinärmaskeTaster; iorlw maskTaster ; // Taster-Eingänge nicht überschreiben wegen IOC andwf GPIO, f ; GPIO &= W // überflüssige LEDs aus iorwf GPIO, f ; GPIO |= W // LEDs an return ; } ;*************************** ;*** Ampelmodul Tabellen *** ; Achtung auf die Page! tabAnforderungssperre ; Anforderungssperre(Ampelphase) addwf PCL, f dt 0xFF ; 0 -> Anforderungen erlaubt dt b'11111110' ; 1 -> Anforderungen Ampel1 gesperrt dt b'11111110' ; 2 -> Anforderungen Ampel1 gesperrt dt b'11111101' ; 3 -> Anforderungen Ampel2 gesperrt dt b'11111101' ; 4 -> Anforderungen Ampel2 gesperrt tabNaechsteAmpelphase ; NaechsteAmpelphase(Ampelphase) // nach Timer Ablauf addwf PCL, f dt PhaseAmpelrd ; 0 -> 0 dt PhaseAmpel1gnblnk ; 1 -> 2 dt PhaseAmpelrd ; 2 -> 0 dt PhaseAmpel2gnblnk ; 3 -> 4 dt PhaseAmpelrd ; 4 -> 0 tabPhasendauer ; Phasendauer(Ampelphase) addwf PCL, f dt 0 ; 0: Ampeln rot -> 0s dt d'7' ; 1: Ampel1 grün -> 7s dt d'2' ; 2: Ampel1 grün blinkend -> 2s dt d'7' ; 3: Ampel2 grün -> 7s dt d'2' ; 4: Ampel2 grün blinkend -> 2s tabLEDs ; LEDs(Ampelphase) addwf PCL, f dt (maskAmpel1Rd | maskAmpel2Rd) ; 0: Ampel1 rot, Ampel2 rot dt (maskAmpel1Gr | maskAmpel2Rd) ; 1: Ampel1 grün, Ampel2 rot dt (maskAmpel1Gr | maskAmpel2Rd) ; 2: Ampel1 grün, Ampel2 rot dt (maskAmpel2Gr | maskAmpel1Rd) ; 3: Ampel1 rot, Ampel2 grün dt (maskAmpel2Gr | maskAmpel1Rd) ; 4: Ampel1 rot, Ampel2 grün tabBlinkmaske ; Blinkmaske(Ampelphase) addwf PCL, f dt 0 ; 0: dt 0 ; 1: dt maskAmpel1Gr ; 2: Ampel1 grün blinkend dt 0 ; 3: dt maskAmpel2Gr ; 4: Ampel2 grün blinkend ;=== Ende Gelände ============================================================== #include <InitPIC12F675_Carwash.asm> END ;===============================================================================Code:; Filename: InitPIC12F675_Carwash.asm ; ; Version | Datum | Autor | Kommentar ; --------|--------|-------|----------------------------------------------------- ; 1.0.0 |05.03.04| WG | Initialisierung 12F675 für Projekt Carwash ; | | | Exclude from build ! ; 1.0.1 |07.03.04| WG | kein TMR0 Interrupt, Prescale 1:32 ; | | | kein GIE ; ;*** Initialisierung Routine *** initMCU ; *** OSCCAL auf kalibrierten wert setzen banksel OSCCAL call 0x3FF ; retrieve factory calibration value movwf OSCCAL ; update register with factory cal value ; *** OPTION_REG settings banksel OPTION_REG movlw b'11000100' ; b'1-------' GPPU: 1 = GPIO pull-ups are disabled ; b'-1------' INTEDG: 1 = Interrupt on rising edge of GP2/INT pin ; b'--0-----' T0CS: 0 = Internal instruction cycle clock (CLKOUT) ; b'---0----' T0SE: 0 = Increment on low-to-high transition on GP2/T0CKI pin ; b'----0---' PSA: 0 = Prescaler is assigned to the TIMER0 module ; b'-----100' PS2:PS0 = 100, TMR0 prescaler rate 1:32 movwf OPTION_REG banksel TMR0 ; // Write to TMR um Prescaler zu reseten clrf TMR0 ; clear GPIO banksel GPIO clrf GPIO ;*** COMPARATOR MODULE banksel CMCON movlw b'00000111' ; b'-----111' CM<2:0>: 111 = Comparators off. CxIN pins are configured as digital I/O movwf CMCON ;*** ADC MODULE banksel ANSEL clrf ANSEL ; digital I/O ; *** GPIO Settings banksel TRISIO movlw b'00001001' ; GPI0,GPIO3 Eingang, GPIO<2:1>, GPIO<5:4> Ausgang movwf TRISIO ; *** WPU Settings movlw b'00000000' ; b'--00----' WPU<5:4>: <WPU5:WPU4> Weak Pull-up Control bits ; b'-----000' WPU<2:0>: <WPU2:WPU1:WPU0> Weak Pull-up Control bits ; 1 = Pull-up enabled ; 0 = Pull-up disabled movwf WPU ; *** IOC Settings movlw b'00001001' ; IOC<5:0>: Interrupt-on-Change GPIO Control bit ; 1 = Interrupt-on-change enabled ; 0 = Interrupt-on-change disabled movwf IOC ;*** Interrupts banksel INTCON movlw b'00001000' ; b'0-------' GIE ; b'-0------' PEIE ; b'--0-----' T0IE ; b'---0----' INTE ; b'----1---' GPIE ; b'-----0--' T0IF ; b'------0-' INTF ; b'-------0' GPIF movwf INTCON returnCode:; Filename: MakroDefs.inc ; ; Version | Datum | Autor | Kommentar ; --------|--------|-------|----------------------------------------------------- ; 1.0.0 |05.03.04| WG | Makro Definitionen für Projekt Carwash ; 1.0.1 |07.03.04| WG | M_ADDLF hinzugef. ; M_MOVLF macro filereg, literal movlw literal movwf filereg endm M_ADDLF macro filereg, literal movlw literal addwf filereg, f endm








Zitieren



Lesezeichen