Arco
Special Member
Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com
Het gebruik van een array is natuurlijk een nogal zinloze actie in dit geval, omdat de data nooit verandert.
Dat kost onnodige GPR plaatsen, en ik neem aan dat Picbasic ook wel een mogelijkheid heeft om een fatsoenlijke tabel in het programmageheugen te maken? (Of desnoods met inline ASM)
Arco
Special Member
Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com
RAM(GPR) geheugen wordt normaal gebruikt voor data die kan veranderen.
De 7 segments data verandert nooit, dus kan net zo goed in het programmageheugen worden gezet...
Arco
Special Member
Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com
benleentje
Golden Member
Op 22 augustus 2009 12:16:48 schreef plantrekker:
Verder moet je die delays uit je programma kieperen.
Helemaal mee eens. Alles tijden moet je regelen vanuit je interrupt routine.
Daarin doe je niets anders dan bij houden hoeveel keer de timer/counter vol is. Deze telt tot 256 en gaat dan naar 0. Als het naar 0 gaat geeft het overflow interrupt door aan de cpu van PIC.
Als dit interrupt ontvangen wordt gaat de pic naar een subroutine programma als je dat tenminste geprogrammeerd hebt.
In dat interrupt programma hou je enkel bij hoeveel keer de timer/counter een overflow heeft gegeven.
Als je een kristal neemt van 32,768kHz. Dan geeft dit kristal 32768 pulsen per seconden.
Delen door 256 geeft 128. Dus nadat timer counter 128 overflow interrupt heeft gegeven is er 1 seconde voorbij.
Anders gezegd elke overflow komt om de 1sec /128 = 7.8mS
Dit kan je dan gebruiken om elke naar naar een ander digit van je display te springen.
EDIT.
Na 128 keer is er seconde voorbij. Dus als je counter op 128 staat zet je die weer terug op nul.
In je interrupt subroutine doe je dus dit.
teller = teller + 1
If teller = 128 then teller = 0
Digit = digit + 1
IF digit = 5 then digit = 1
Dit is enkel het hoofdprogramma in de interrupt routine wat er verder inmoet moet je even nakijken.
[Bericht gewijzigd door benleentje op (16%)]
sjors007
...
okee
dus als ik 6 segment displays heb dan ben ik voor 1 rondje (6 * 7.8ms) 46.8ms kwijt?
en aangezien een seconden 1000ms duurt, zou ik het eventueel
1000 / 46.8 = 21x langs kunnen gaan?? toch?
Arco
Special Member
Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com
Dat klopt. Ik zou wel voor een hogere frequentie kiezen (> 60Hz), omdat het menselijk oog knipperen met 21Hz nog goed (hinderlijk) kan waarnemen.
Je snapt het niet helemaal.
Je programma bestaat uit 3 delen:
-De teller: hier gebruik je een timer interrupt voor, deze komt exact elke 7.8 miliseconden.
-kloksoftware: elke 128 interrupts is er exact een seconde voorbij. Dan doe je dus: if (interrupts = 128) { sec = sec + 1;} als er 10 seconden voorbij zijn , sec2 + 1, uren... +1 , etc. De interrupt heeft dus niets te maken met de displays. die 7.8ms heeft niets te maken met het multiplexen van de displays.
-output naar displays: zo snel mogelijk multiplexen en de variabelen weergeven.
De kloksoftware zet je in een ifje: if (interrupts = 128) { blabla }. De teller is een interrupt functie. In de main loop zit dus enkel de output naar de displays. Op die manier zal het display continue ververst worden. Je haalt makkelijk 1000Hz met de displays, en loopt je klok heel precies.
sjors007
...
oke nou word het even teveel:P ik heb tot nu toe dit:
DEVICE 16F628A ;Gebruik een 16F628A type
CONFIG INTRC_OSC_NOCLKOUT, WDT_OFF, PWRTE_ON, LVP_OFF, MCLRE_OFF
all_digital true
symbol SegmentA = porta.0
symbol SegmentB = porta.1
symbol SegmentC = porta.2
symbol SegmentD = porta.3
symbol SegmentE = porta.4
symbol SegmentF = porta.5
symbol SegmentG = porta.6
symbol Display = portb
dim Sec as byte
dim Min1 as byte
dim Min2 as byte
dim Uur1 as byte
dim Uur2 as byte
dim Cijfers[10] as byte
Symbol GIE = INTCON.7
Symbol PEIE = INTCON.6
Symbol TMR2IF = PIR1.1
Symbol TMR2IE = PIE1.1
Symbol TMR2ON = T2CON.2
On_Hardware_Interrupt GoTo ISR
GoTo weergave
ISR:
TMR2IF = 0
sec = sec + 1
if sec >= 60 then
inc min1
sec = 0
endif
if min1 >=10 then
inc min2
min1 = 0
endif
if min2 >=6 then
inc uur1
min2 = 0
if uur1 >=10 then
inc uur2
uur1 = 0
endif
if uur2 = 2 and uur1 = 4 then
clear uur1
clear uur2
endif
Context Restore
; 76543210
PORTa = %00000000 ;Eerst alle PORTA uitgang registers uit (laag maken)
portb = %00000000
TRISa = %11100001 ;Alle PORTB poorten zijn uitgangen, behalve PORTB.0
trisb = %11110000
sec1 = 0 : sec2 = 0
min1 = 0 : min2 = 0
uur1 = 0 : uur2 = 0
T2CON = %01001011 ; Postscaler 1:10, Prescaler 1:16
PR2 = 249 ; 250 ticks geeft 40 millisec / int.
; Dus 25 interrupts per seconde
TMR2IE = 1 : PEIE = 1 : GIE = 1 ; Enable interrupts
TMR2ON = 1
; abcdefg.
cijfers[0] = %00000011
cijfers[1] = %10011111
cijfers[2] = %00100101
cijfers[3] = %00001101
cijfers[4] = %10011001
cijfers[5] = %01001001
cijfers[6] = %01000001
cijfers[7] = %00011111
cijfers[8] = %00000001
cijfers[9] = %00001001
Weergave:
; 76543210
display = %11111110
porta = cijfers[sec1]
display = %11111101
porta = cijfers[sec2]
display = %11111011
porta = cijfers[min1]
display = %11110111
porta = cijfers[min2]
display = %11101111
porta = cijfers[uur1]
display = %11011111
porta = cijfers[uur2]
hij is nog niet af want ben bezig maar ben ik goed op weg of totaal niet:P ik moet de interrupt nog goed instellen want dit kom van een andere klok van me. ook moet ik die digits nog veranderen maar ik denk laat even zien wat ik al heb. even kijken of ik in de goede richting ben
MVG Sjors
je ISR is veel te lang.
ISR functie moet enkel een tellertje steeds met 1 ophogen (en de INT flag clearen inderdaad).
In de main loop kijk je naar de waarde van het tellertje, als 25, dan 1 seconden voorbij en onderneem je actie (variabelen ophogen als nodig is)
sjors007
...
oke dus in de IRS zeg je
Inc tellertje
en dan in de mainloop
if teller >=25 then (moet dus 128 worden maar moet die waarden nog veranderen)
inc sec
teller = 0
endif
....
....
maar ben ik wel al goed op weg?
zoals dit bijvoorbeeld?
Weergave:
; 76543210
display = %11111110
porta = cijfers[sec1]
display = %11111101
porta = cijfers[sec2]
display = %11111011
porta = cijfers[min1]
display = %11110111
porta = cijfers[min2]
display = %11101111
porta = cijfers[uur1]
display = %11011111
porta = cijfers[uur2]
plantrekker
True story bro!
Weergave mag je zo niet doen, je moet weergave (dus een volgend digit aansturen) OOK op vaste tijdstippen doen. Als je dit toch in de main loop doet, zal de digit die actief is wanneer de ISR komt, langer oplichten -> flitsen
ISR:
*houdige digit uitzetten
*volgende variabele op de poortA zetten
*volgende digit aan zetten
*nu pas teller verhogen en indien 128, dan ga je naar de routine om de tijd met 1 sec te verhogen.
Je moet het in deze volgorde doen! Eerst het multiplex gedeelte, dan pas de teller. Anders licht de digit langer op wanneer eerst de uur-routine moet uitgevoerd worden. Elke seconde zal dus de laatste digit 'flitsen'.
Je MOET ook bij het multiplex gedeelte eerst de huidige digit uitzetten voordat je nieuwe data op je poort gaat zetten. Anders komt het cijfer dat voor de volgende digit bedoeld is, nog heel even op de huidige. Je mag ook niet eerst de volgende digit selecteren want dan komt het getal van de vorige digit heel even op de volgende. Dus eerst digits uitzetten, dan nieuwe data op de poort, dan juiste digit aanzetten.
[edit] Ik heb nu alles via de ISR gedaan, de tijd updaten kan je idd in je main loop doen. Maar aangezien een ISR in dit geval 7.8msec mag duren is dat geen probleem.
sjors007
...
oke dus ik moet dan allemaal even omdraaien:
; 76543210
porta = cijfers[sec1]
digits = %11111110
porta = cijfers[sec2]
digits = %11111101
porta = cijfers[min1]
digits = %11111011
oke zullen we stukje voor stukje doen:9
eerst de ISR
daarin moet dus komen:
porta = cijfers[sec1]
digits = %11111110
porta = cijfers[sec2]
digits = %11111101
porta = cijfers[min1]
digits = %11111011
enzo..
inc teller
if teller = 128 then
.....
context restore
als alles tegelijkt komt lijkt me hoofd wel een pompoen:P
ik wil eerst de ISR goed hebben;)
plantrekker
True story bro!
symbol data_poort = PORTA
symbol digit_poort = PORTB
dim uur[6] as byte ; ipv 6 losse variabelen, zet ze in een array
; volgorde: sec_eenheden, sec_tientallen, minuut_eenheden...
dim volgende_digit as byte
dim teller as byte
volgende_digit = 0;
teller = 0;
ISR:
digit_poort = %11111111 ;zet alle digits uit
data_poort = cijfers[uur[volgende_digit]] ;
digit_poort = ~(1 << volgende_digit) ; vb: volgende digit = 2 (je wil dus het 3de digit selecteren)
; ~(1 << 2) = ~(%00000100) = %11111011
teller = teller + 1
volgende_digit = volgende_digit + 1;
if(teller == 128){
teller = 0;
}
if(volgende_digit = 6){
volgende_digit = 0;
}
Dat is dus je ISR, in je mainloop moet je nu enkel de array uur updaten.
sjors007
...
okee:P
hier kom ik niet helemaal uit dat moet u even uitleggenxd:P
data_poort = cijfers[uur[volgende_digit]] ;
digit_poort = ~(1 << volgende_digit)
dus die uur word
Uur[1] = Seceenheden
uur[2] = sectientallen
zoiets..??
MVG Sjors
benleentje
Golden Member
PLantrekker Je gebruikt picbasic code en C-code door elkaar. En data_poort moet portB zijn en vise versa.
DEVICE 16F628A ;Gebruik een 16F628A type
CONFIG INTRC_OSC_NOCLKOUT, WDT_OFF, PWRTE_ON, LVP_OFF, MCLRE_OFF
all_digital true
symbol SegmentA = porta.0
symbol SegmentB = porta.1
symbol SegmentC = porta.2
symbol SegmentD = porta.3
symbol SegmentE = porta.4
symbol SegmentF = porta.5
symbol SegmentG = porta.6
symbol Display = portb
Dit gebruik je niet eens waarom staat het er dan in
dim Sec as byte
dim Min1 as byte
dim Min2 as byte
dim Uur1 as byte
dim Uur2 as byte
dim Cijfers[10] as byte
dim uur[6] as byte
dim int_teller as byte
dim digit_teller as byte
dim display_output as byte
Cijfers[0] = %-----
Cijfers[1] = enz
76543210
Uur[1] = ;00000001 ;Eertse digit van het display aanzetten
uur[2] = ;00000010 ;tweede digit enz
Symbol GIE = INTCON.7
Symbol PEIE = INTCON.6
Symbol TMR2IF = PIR1.1
Symbol TMR2IE = PIE1.1
Symbol TMR2ON = T2CON.2
On_Hardware_Interrupt GoTo ISR
GoTo weergave
ISR:
TMR2IF = 0
inc int_teller
inc digit_teller
Context Restore
Ik heb wat variabele toegevoegd en het array geinitialiseerd.
Verder de isr aangepast
Inc sec1
if sec1 >= 60 then
inc sec2
sec = 0
Endif
if sec1 >= 6 then
inc min1
sec = 0
endif
if min1 >= 60 then
inc min2
min1 = 0
endif
if min2 >=6 then
inc uur1
min2 = 0
;hier vergeet je iets??
if uur1 >=10 then
inc uur2
uur1 = 0
endif
if uur2 = 2 and uur1 = 4 then
clear uur1
clear uur2
endif
IF digit_teller => 7 then digit_teller = 1
Case digit_teller ; weet neem meer hoe case werkt
case digit_teller = 1 then display_output = sec1
= 2 then display_output = sec2
= 2 then display_output = min1
Dit had je eerst in de ISR staan En je was sec1 vergeten dit gedeelte moet je nog ergens invoegen in je programma. De case gebruik je om de waarde van sec t/m uur 2 te selecteren. Dit is dan het getal wat op het 7-segment displat komt te staan.
; 76543210
PORTa = %00000000 ;Eerst alle PORTA uitgang registers uit (laag maken)
portb = %00000000
TRISa = %11100001 ;Alle PORTB poorten zijn uitgangen, behalve PORTB.0
trisb = %11110000
sec1 = 0 : sec2 = 0
min1 = 0 : min2 = 0
uur1 = 0 : uur2 = 0
T2CON = %01001011 ; Postscaler 1:10, Prescaler 1:16
PR2 = 249 ; 250 ticks geeft 40 millisec / int.
; Dus 25 interrupts per seconde
TMR2IE = 1 : PEIE = 1 : GIE = 1 ; Enable interrupts
TMR2ON = 1
; abcdefg.
cijfers[0] = %00000011
cijfers[1] = %10011111
cijfers[2] = %00100101
cijfers[3] = %00001101
cijfers[4] = %10011001
cijfers[5] = %01001001
cijfers[6] = %01000001
cijfers[7] = %00011111
cijfers[8] = %00000001
cijfers[9] = %00001001
Dit is goed behalve de tris doe je pas NADAT je al de uitgangen heb geactiveerd. Niet goed dus. Hier heb je een stuk programma over genomen zonder dat je weet wat het doet. Er staat 250 tiks geeft 40mS interrupt en verder dat er 25 intterrupt per sec zijn. Terwijl we er 128/ sec nodig hebben en liever nog meer om aan de juiste frequentie voor de losse digits van de displays te komen.
Weergave:
; 76543210
display = %11111110
porta = cijfers[sec1]
display = %11111101
porta = cijfers[sec2]
display = %11111011
porta = cijfers[min1]
display = %11110111
porta = cijfers[min2]
display = %11101111
porta = cijfers[uur1]
display = %11011111
porta = cijfers[uur2]
Deze hele code vervang je door
porta = 0
portb = 0
Porta = Uur[Digit_teller] ;Dit selecteert dus een hele digit van het display wat om dat moment geactiveerd word.
portb = cijfers[Display_output]
Zelf even alles complementeren en in de goede volgorde zetten. En het is beter om de arrays zoals cijfer[0] t/m cijfers[9] en uur[x] ook te vervangen door een case if constructie. Dan staat alles in het programma geheugen. Dat is wat arco bedoelde.
plantrekker
True story bro!
als het bvb 09u 23min 16sec is, dan zit er in je uur-array:
uur = {6,1,3,2,9,0}
stel dat volgende_digit = 3, dat is de plaats van minuten_tientallen (=de vierde plaats in je array). (digit gaat van 0 t.e.m 5)
nu toegepast:
data_poort = cijfers[uur[volgende_digit]] ;
= cijfers[uur[3]]
= cijfers[2] ; geeft in dit geval dus de juiste cominatie om het getal 2 te vormen.
digit_poort = ~(1 << volgende_digit)
= ~(shift '1' 3 keer naar links)
= ~(%00000001 << 3)
= ~(%00001000)
= %11110111 ;selecteert het vierde displayIk schrijf niet in basic, altijd in C, de TS moet de syntax fouten maar aanpassen. 
[edit]
Benleentje, je update de variabelen sec1 enzo maar dus niet de array uur[].
ipv sec1 enzo als een byte te declarere, zet ze als symbol nadat de array uur[] gedeclareerd is. Dus:
dim uur[6] as byte
symbol Sec1 = uur[0]
symbol Sec2 = uur[1]
symbol Min1 = uur[2]
symbol Min2 = uur[3]
symbol Uur1 = uur[4]
symbol Uur2 = uur[5]
dim Cijfers[10] as byte
dim int_teller as byte
dim digit_teller as byte
dim display_output as byte
Cijfers[0] = %-----
Cijfers[1] = enz
76543210
Uur[1] = ;00000001 ;Eertse digit van het display aanzetten
uur[2] = ;00000010 ;tweede digit enzsjors007
...
oke ik begrijp het systeem;)
ik moet alleen even goed de tijd nemen om het in elkaar te zetten
en Benleentje
een paar vorige posts had ik al verteld dat die intterupt nog goed moest instellen ik had deze gebruikt voor een andere klok gewoon op LCD schermpje.
oke ben nu tot het volgende gekomen:
DEVICE 16F628A ;Gebruik een 16F628A type
CONFIG INTRC_OSC_NOCLKOUT, WDT_OFF, PWRTE_ON, LVP_OFF, MCLRE_OFF
all_digital true
dim Sec1 as byte
dim Sec2 as byte
dim Min1 as byte
dim Min2 as byte
dim Uur1 as byte
dim Uur2 as byte
dim IntTeller as byte
dim DigitTeller as byte
dim DisplayOutput as byte
dim Cijfers[10] as byte
dim Klok[6] as byte
; abcdefg.
cijfers[0] = %00000011
cijfers[1] = %10011111
cijfers[2] = %00100101
cijfers[3] = %00001101
cijfers[4] = %10011001
cijfers[5] = %01001001
cijfers[6] = %01000001
cijfers[7] = %00011111
cijfers[8] = %00000001
cijfers[9] = %00001001
; 76543210
klok[0] = %11111110
klok[1] = %11111101
klok[2] = %11111011
klok[3] = %11110111
klok[4] = %11101111
klok[5] = %11011111
Symbol GIE = INTCON.7
Symbol PEIE = INTCON.6
Symbol TMR2IF = PIR1.1
Symbol TMR2IE = PIE1.1
Symbol TMR2ON = T2CON.2
On_Hardware_Interrupt GoTo ISR
GoTo hoofdprogramma
ISR:
TMR2IF = 0
porta = 0
portb = 0
Porta = klok[Digitteller] ;Dit selecteert dus een hele digit van het display wat om dat moment geactiveerd word.
portb = cijfers[Displayoutput]
inc int_teller
inc digit_teller
Context Restore
; 76543210
PORTa = %00000000 ;Eerst alle PORTA uitgang registers uit (laag maken)
portb = %00000000
TRISa = %11100001 ;Alle PORTB poorten zijn uitgangen, behalve PORTB.0
trisb = %11110000
sec1 = 0 : sec2 = 0
min1 = 0 : min2 = 0
uur1 = 0 : uur2 = 0
T2CON = %01001011 ; Postscaler 1:10, Prescaler 1:16
PR2 = 249 ; 250 ticks geeft 40 millisec / int.
; Dus 25 interrupts per seconde
TMR2IE = 1 : PEIE = 1 : GIE = 1 ; Enable interrupts
TMR2ON = 1
HoofdProgramma:
if hulpteller >= 128 then
inc sec1
hulpteller = 0
endif
if sec1 >=10 then
inc sec2
sec1 = 0
endif
if sec2 = 6 then
inc min1
sec2 = 0
endif
if min1 >=10 then
inc min2
min1 = 0
endif
if min2 >=6 then
inc uur1
min2 = 0
if uur1 >=10 then
inc uur2
uur1 = 0
endif
if uur2 = 2 and uur1 = 4 then
clear uur1
clear uur2
clear min1
clear min2
endif
if digitteller >=6 then digitteller = 0
select digitteller
case 1
displayoutput = sec1
case 2
displayoutput = sec2
case 3
displayoutput = min1
case 4
displayoutput = min2
case 5
displayoutput = uur1
case 6
displayoutput = uur2
end select
end
ik moet me interrupt nog met de juiste waarde (128) laden ik weet alleen nog niet wat de waarde van de prescaler enz. worden
ik denk dat ik zo wel een beetje aardig in de richting kom.
ik twijfel nog of dit in de ISR moet of gewoon in het hoofdprogramma:
porta = 0
portb = 0
Porta = klok[Digitteller] ;Dit selecteert dus een hele digit van het display wat om dat moment geactiveerd word.
portb = cijfers[Displayoutput]
[Bericht gewijzigd door Henry S. op (86%)]
benleentje
Golden Member
De isr is wel goed zo. Het loopt 7mS achter de echte tijd aan omdat je de oude tijd er op zet en dan de tellers verhoogd. Lijkt me niet zo erg voor een klok.
Ik heb mijn baas nog nooit gehoort dat ik 7mS te laat was
.
T2CON = %01001011 ; Postscaler 1:10, Prescaler 1:16
PR2 = 249 ; 250 ticks geeft 40 millisec / int.
; Dus 25 interrupts per seconde
TMR2IE = 1 : PEIE = 1 : GIE = 1 ; Enable interrupts
TMR2ON = 1
Ik had je al verteld dat dit niet goed is.
postscaler moet 1:1 worden en de prescaler ook 1:1. Deze waarden gaan uit van een 4Mhz kristal terwijl ik ben uitgegaan van een 32,768khz kristal.
Verder staan er nog waat fouten in je variabele namen
Int_teller en intteller door elkaar
geld ook voor digit_teller
Hulpteller wat doet die daar is ook niet goed.
Verder kan je beter de counter en klok array vervangen door case select constructie.
select Decimaalwaarde_output
case 0; segment_output = %----- ; binaire waarde voor 0
case 1
case 2
case 9
end select
select digit_teller 76543210
case 0 then digit_output = %00000001
case 5 then digit_output = %00100000
end selectIk heb er weer een paar variabele bij gepakt. Dit mag jij weer verder verwerken in een mooi progje.
sjors007
...
ja daar kwam ik ook achter moet die namen (hulpteller) nog veranderen in IntTeller
die IntTeller moet je daarna toch weer op 0 zetten? lijkt me wel:P
ja ik moet inderdaad pre- en postscaler nog instellen. maar weet niet precies hoe ik dat moet doen.
ja opzich kan ik die array's veranderen maar is dat echt noodzakelijk in vind het wel mooi staan gewoon qua drukte enzo
Op 22 augustus 2009 17:46:01 schreef benleentje:
De isr is wel goed zo. Het loopt 7mS achter de echte tijd aan omdat je de oude tijd er op zet en dan de tellers verhoogd. Lijkt me niet zo erg voor een klok.
kan je dat verhelpen? niet dat het erg is maar toch gaat om het idee:P;)
p.s. ieder geval bedankt voor alle informatie
[Bericht gewijzigd door Henry S. op (33%)]
plantrekker
True story bro!
Displayoutput en digitteller moeten in de ISR geupdate worden!
Je verhelpt dat achter lopen door ze voor te laten lopen
. Verhoog nadat je de tijd hebt ingesteld, IntTeller direct met 1. Maar het is zinloos, je kan je klok nooit tot op 7ms nauwkeurig met de hand juist zetten.
sjors007
...
ja dan zul je ze in de isr ze moeten laten optellen nou dan maar 7ms missenxD:P
ik weet alleen nog niet hoe ik die interrupt zo moet instellen dat die op 128 komt.
kunnen jullie me op weg helpen.??
[Bericht gewijzigd door Henry S. op (44%)]
benleentje
Golden Member
Kijk even in de datasheet bij timer2 instellingen. Ik weet die ook niet uit het hoofd. Zoals ik zij de prescaler en de postscaler moeten beide 1:1 staan