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  Rabumm  Habt 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.
 Habt 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
    return
 
	Code:
	; 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
 
						
					
Lesezeichen