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)

zover ben ik nog niet:P

waarom is een array zo dan zinloos?

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...

Nee, het programma geheugen. (flash)
EEProm en GPR zijn datageheugen.

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%)]

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?

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.

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)

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]

Ja je bent goed op weg!

Dit zijn de losse bouwstenen, nu nog alles goed combineren. :)

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.

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;)


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.

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

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.

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 display

Ik 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 enz

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%)]

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 :P.


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 select

Ik heb er weer een paar variabele bij gepakt. Dit mag jij weer verder verwerken in een mooi progje.

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%)]

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.

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%)]

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