Goeiedag,

Ik heb tijdens de eerste semester dit jaar 8051 microcontrollers leren programmeren en de kennis ervan is ondertussen al wat weggezakt. En daarom ben ik nu van 0 begonnen met het herhalen en uitdiepen ervan.

Ik heb er al een aantal lichteffectjes opzitten (looplicht, volloper, leegloper, knightrider). Nu wou ik dit combineren met een volgende stap nl. interrupts.

De bedoeling is om een verkeerslicht te maken. Wanneer een voetganger op de knop drukt (P3.2) zal een interrupt gegeven worden en moet het licht van groen -> oranje naar rood gaan indien het op groen staat natuurlijk. Ik had toen al niet veel ervaring met externe interrupts en nu al helemaal niet meer.

Is er iemand die me kan helpen bij de eerste stappen? :)

;*********************************************************************************;
;                              Oefening: verkeerslicht                            ;
;                                                                                 ;
;klokfrequentie = 12MHz                                                           ;
;*********************************************************************************;

        org 0h
        jmp start
        org 100h

;Registernamen toekennen
        IE0 equ 0003h
        
;Uitgangen en ingangen benoemen
        groen equ P1.0          ;grote lichten
        oranje equ P1.1
        rood equ P1.2
        rvoet equ P1.7          ;voetgangerslichten
        gvoet equ P1.6
        vdruk equ P3.2          ;drukknop voor voetgangers -> interrupt op programma die lichten op rood zet
                

start:  mov P1,#0               ;alles uit
        mov IE,#10000001b       ;interrupts aanzetten
        
begin:  setb rood
        call rtijd              ;tijd dat het licht op rood staat
        mov P1,#0
        setb groen
        call gtijd
        mov P1,#0
        setb oranje
        call otijd
        mov P1,#0
        jmp begin

rtijd:  mov R0,#0
        mov R1,#0
rt1:    djnz R0,rt1
        djnz R1,rt1
        ret

gtijd:  mov R0,#0
        mov R1,#0
gt1:    djnz R0,gt1
        djnz R1,gt1
        ret

otijd:  mov R0,#0
        mov R1,#0
ot1:    djnz R0,ot1
        djnz R1,ot1
        ret

end

Ik zou met het interrupt een timer starten. Door deze timer bijvoorbeeld iedere 100ms een interrupt te laten genereren kan je een variabele ophogen.
Als de variabele 0 is staat het licht op groen. Is de variabele kleiner dan 50 (5 seconden) dan zet je het licht op oranje. Is de variabele groter dan 50 kleiner 200 dan rood, groter 200 weer groen en teller uit.
Preciese voorwaarden moet je even opstellen maar kan je volgens mij eenvoudig in asm oplossen.
Ik zou trouwens voor c kiezen, maar dat terzijde.

Maar dan kan ik het toch niet zo maken dat een voetganger op de knop drukt en de boel op rood gaat? Loopt het boeltje toch gewoon in lus?

Ik mis de vectoren naar je interrupt routines. Je enabled de int's wel maar niet waar ie naartoe moet springen in geval van een interrupt :


         ORG   0x03       ; the ISV for the EXT 0 interrupt is 0x0003
EXT0INT: LJMP  Int0Isr
        
         ORG   0x0B       ; the ISV for the TMR 0 interrupt is 0x000B
TMR0INT: LJMP  Tmr0Isr

         ORG   0x13       ; the ISV for the EXT 1 interrupt is 0x0013
EXT1INT: LJMP  Int1Isr

         ORG   0x1B       ; the ISV for the TMR 1 interrupt is 0x001B
TMR1INT: LJMP  Tmr1Isr

         ORG   0x23       ; the ISV for the Serial Port interrupt is 0x0023
SERINT:  LJMP  SerIsr

Je hebt ze niet allemaal nodig maar indien je ze niet gebruikt zou ik om problemen te voorkomen een IRET geven.

Groeten, Bram

Als eerste mag ik weten welke 8051 je gaat gebruiken??
Je moet eerste precies schrijven in jou eigentaal wat je wilt en daarna kunt je dat vertalen naar een processor taal. Ten eerste over hoeveel stoplichten praten we hier twee een ???
bv.
1.) Alle lampjes moeten op rood staan en ook blijven.
2.) Als er een auto aan komt (knopje) dan moet de groene lamp na 2sec naar aan gaan. Zolang er auto's door groen rijden krijgt je pulsen van de drukknop. Deze pulsen die zorgen voor de interupt en ook voor een timer. Deze timer moet aangeven hoe lang deze auto door groen mogen rijden voordat een aanliggende auto ook voor een stoplicht staat.
Enz enz.

Ik verwijs je naar http://www.8052.com/tutint.phtml heel simpel uitgelegd. Andere uitleg http://www.mikroe.com/en/books/8051book/ch2/#ch2.8

Succes!!

mvgr uzion

Bedankt uzion maar die 8052.com gebruikte ik al lang. Op het moment gebruik ik een at89s4051.

Het is de bedoeling van te beginnen met lichten op rood -> lichten groen -> oranje. Op het moment een voetganger op de drukknop zou duwen = P3.2 (int0)zou hij naar de interrupt routine moeten springen en zou het verkeerslicht op oranje -> rood moeten springen.
Voor de voetgangers moet dan het licht op groen komen te staan. Op het moment dat het terug rood is voor voetgangers wordt er verder gegaan met groen voor de voertuigen.

groen equ P1.0          ;voertuiglichten
        oranje equ P1.1
        rood equ P1.2
        rvoet equ P1.7          ;voetgangerslichten 'rvoet' = rood voetgangers
        gvoet equ P1.6
        vdruk equ P3.2        ;drukknop voor voetgangers

(int0)zou hij naar de interrupt routine moeten springen

@Gitaarstudentje
Moet je wel je vector zetten anders springt ie niet (goed), zie mijn eerdere reply.

Groeten, Bram

Dus dat zou dan zoiets moeten zijn kan dat? Als ik simuleer en ik zet op een willekeurig ogenblik een 1 op men interruptpoort dan blijft men programma vastzitten op die regel?

Misschien zou je er wat meer commentaar bij moeten zetten van wat je denkt dat er zou moeten gebeuren.
Het is nogal een ondoorzichtig geheel helaas...
De irq routine bv. test een output wat natuurlijk weinig zin heeft. (Je hebt die net zelf hoog of laag gezet dus je weet de status al...)
Beter om een 'state machine' te maken...

Plaats de geassembleerde versie eens zodat we de adressen kunnen zien aub.

Op 30 mei 2008 14:59:51 schreef gitaarstudentje:
... en ik zet op een willekeurig ogenblik een 1 op men interruptpoort dan blijft men programma vastzitten op die regel?

bedoeld je echt een 1 of bedoeld je een 0. De int poorten reageren op een 0. Als je de zelfde tijd gebruikt voor rtijd gtijd dan kon je beter alleen een subroutine maken met de goeie delay time. Voor de otijd mag je wel een aparte tijd maken, die is normalite ook minder.

Verder is de tijd die je aangeeft (R0 en R1) te klein je ligt daar rond de 130msec tijd dacht ik, bij deze tijd gaat de lampjes knipperen.
Ik veronderstelt dat de IT0 is ook gezet. Wanneer je naar de int routine gaat zal ik als eerste de INT uitdoen ( clr EX0). Dan is het ook verstandig om een klein delay te maken voor de contact debouncer.

Verder zou ik in die INT routine alleen een flagje zetten. En bij het terugkeren uit de int. Een controle doen op die flag of het gezet is of niet. En waarom dit truck? Om een memory effect te creeren. Want in jou programma als de lampje niet groen is springt ie uit de int. En dan gebeurd er ook verder niets meer. De IT0 reageert op neergaande flank. Dus als de voetganger de knopje blijft drukken gebeurd er toch niets. En als de lampje bij de int groen was dan springt de programma naar oranje en valt weer in de normale loop van groen oranje rood. En springt nooit meer uit de INT (problemen). Wanneer die voetganger het knopje drukt dan moet de lampjes van de auto op rood en die van de voetganger op groen, ik ziet dit niet in de programma. Er zijn meer punten maar begint alvast die te bekijken. Bij het bedenken wordt je er slimmer van!!
mvgr uzion

Op 30 mei 2008 15:26:13 schreef bprosman:
Plaats de geassembleerde versie eens zodat we de adressen kunnen zien aub.

Geen idee wat je bedoelt? Als ik assembleer krijg ik toch hexfile... of bedoel je het bestand voor in het programma?

Op 30 mei 2008 16:26:27 schreef uZion:
[...]
Verder is de tijd die je aangeeft (R0 en R1) te klein je ligt daar rond de 130msec tijd dacht ik, bij deze tijd gaat de lampjes knipperen.

Wel met een 12MHz kristal is 1 macchinecyclus = 1µs, dus zou men lusje 256 x 256 x 3 = 196608µs duren dus zo'n 200ms. Inderdaad te kort. (mov= 1mc en djnz = 2mc)

Dus om dat nog is wat te verlengen naar een 20tal seconden zou dit moeten lukken:

rtijd:  mov R0,#0
        mov R1,#0
        mov R2,#103d
rt1:    djnz R0,rt1
        djnz R1,rt1
        djnz R2,rt1
        ret

256 x 256 x 102 x 3 = 20054016µs = 20 s
Of vergis ik me?

/edit: Kwestie van die tijd subroutines; het is de bedoeling voor elke lamp een andere tijd. Er moeten er nog bijkomen voor de andere bestuurders aan't kruispunt die dan mogen doorrijden als't voor de ene richting rood is. Zoals ze doen aan drukke straten, de drukste krijgt wat langer groen licht. -> wordt leuk speelgoed voor men zusje ;)

Oh ja waarom moet die IT0 enabled? Die is toch timer interrupt en niet extern?

Op 30 mei 2008 18:47:20 schreef gitaarstudentje:
Oh ja waarom moet die IT0 enabled? Die is toch timer interrupt en niet extern?

Look for TCON register bit0 http://www.ikalogic.com/tut_8051_4.php

Hierbij een aantal stukjes code die je verder zouden moeten helpen

1) Constante voor een delay van 10ms


;Constant = (Delay * Fosc) / 12
;Delay = Time in µs		10000		10000		10000
;Fosc = Osc frequency in MHz	12		22.1184	11.0592
;Constant = 			10000		18432		9216
;+9 due to reload timer & latency
;
Time_0			equ 65535 - 10000 + 9	;55544

2) Initialiseren en starten van Timer 0 in auto reload mode

			mov  TH0,#HIGH Time_0		;initialize interrupts
			mov  TL0,#LOW  Time_0
			mov  TMOD,#01H          	;timer 0 mode 1
			setb ET0                	;enable interrupt timer 0
			setb EA
			setb TR0			;start timer 0

Deze code moet je dus slechts éénmaal doorlopen

3) Code bij de aanvang van je ISR


Timer_0:		mov  th0,#High Time_0		;Restart timer
		      mov  tl0,#Low  Time_0
			push acc				;Save registers used in ISR
			push b
            	push dph
		      push dpl
			push psw

4) Code juist voor het verlaten van je ISR. Zorg ervoor dat je ALTIJD langs deze code je ISR verlaat


;Einde ISR: reset registers
;		
Timer_0_End:	pop  psw			;Restore registers
			pop  dpl
			pop  dph
			pop  b
			pop  acc		
			reti				;Einde ISR

Met deze opzet zal je code continu om de 10msec door de ISR van T0 gaan.
Aan jouw om daar tellerkes in te zetten die de lichten controleren.

Probeer eerst je probleem in een 'state machine' te vertalen.
State 1 = Hoofdbaan rood voor x * 10ms
State 2 = Hoofdbaan groen voor y * 10ms
State 3 = ... ...
Je kan dat best doen aan de hand van een uitgetekend tijddiagramma. Telkens er iets wijzigt heb je een nieuwe state nodig.

Als je in de ISR van T0 komt moet een bepaalde teller (x, y, ... ...) aangepast worden. Dewelke zal afhangen van de actuele state.
Dus als je in de ISR T0 komt:
1) Check welke state
2) Increment teller van die state en check naar eindwaarde
3) Eindwaarde bereikt?
3a) Ja: ga naar de volgende state
3b) Neen: niets doen

Als er een interrupt binnenkomt van de drukknop moet je de state machine in de juiste state zetten en de teller initialiseren.
De rest loopt dan terug vanzelf over de ISR T0.

[Bericht gewijzigd door mcs51mc op (23%)]