Ik zit net te grasduinen in de datasheet van de 1827. En zojuist ook de bijbehorende .inc bekeken.
Ik begin het toch wel leuk te vinden moet ik zeggen.
Golden Member
Ik zit net te grasduinen in de datasheet van de 1827. En zojuist ook de bijbehorende .inc bekeken.
Ik begin het toch wel leuk te vinden moet ik zeggen.
Golden Member
Er zat nog een klein foutje in het programma:
pic asm code:
call delay_250mS
delay_250ms movlw d'250'
De S van delay_250mS staat als hoofdletter.
Blijkbaar is alles case-sensitive (of je moet dat uit kunnen schakelen).
Special Member
Case sensitivity altijd uitzetten:
Project -> Build Options -> Project -> MPAsm assembler -> Disable case sensitivity...
SET en EQU zijn om constantes een naampje te geven. Zijn beiden hetzelfde met 1 verschil:
EQU is eenmalig (kan niet gewijzigd worden), terwijl SET wel gewijzigd kan worden.
[Bericht gewijzigd door Arco op zaterdag 9 november 2019 01:59:27 (42%)
Golden Member
pic asm code:
sysclock equ d'10000000' ;Crystal frequency 10MHz
fclock set sysclock >> 2 ;Internal cycle clock
delay1ms_value set fclock / d'54000' + fclock / d'500000' ;Delayloop value 1 ms
Dit ontgaat me even, wat er hier nu precies gebeurt.
sysclock, fclock, delay1ms_value zijn allemaal naampjes voor constanten en geen instructies voor zover ik het begrijp.
Maar wie zet nu de frequentie goed? Welke instructie doet dat dan?
en vanwaar het delen door 54000 en 500000?
Ik heb een fysiek kristal van 4 Mhz aangesloten en de waarde van d'10000000 veranderd in d'4000000.
De Led knippert nu met een interval van 40 seconden.
Special Member
De deling is nodig, om (ongeveer) de juiste delays te krijgen.
(hangt van de routines af. Als je andere routine maakt zul je die deling weer moeten tweaken om de juiste waarde te krijgen...)
Sysclock is de oscillatorfrequentie, fclock de instructieclock en delay1ms de waarde voor de delayroutines. Zijn allemaal constantes.
Het programma zou 500mS aan/uit moeten knipperen. 40sec kan niet, is veel te veel.
Ik zie wel dat ik de config op externe oscillator had laten staan. Voor een kristal moet je die veranderen.
- _FOSC_LP voor een 32kHz kristal
- _FOSC_XT voor 4MHz en lager
- _FOSC_HS voor hoger als 4MHz
Er valt in frequentie niks 'goed te zetten'. De delayloops is zuiver een kwestie van instructiecycles tellen...
(op 4MHz een kwestie van tot 1.000.000 tellen voor 1sec... )
Golden Member
Het aanbrengen van _FOSC_XT bracht de LED inderdaad naar een beduidend lagere knipperfrequentie terug.
Dat doe hij nu ca 0,5 sec.
De waardes van delay_250ms t/m delay_1ms hebben vrijwel geen invloed op de knipperfrequentie. Ik heb wat waarden geprobeerd tussen d'0 en d'250 maar dat geeft geen (zichtbaar) effect.
Verder valt me op dat er geen RETURN instructie is na de call delay_250 ms
Dat hoeft niet?
Special Member
Welke delay je kiest heeft wel degelijk invloed op de knipperfrequentie.
Bij delay_500mS moet de 250mS loop twee maal worden doorlopen, daarom geen return achter de eerste keer...
pic asm code:
delay_500ms call delay_250mS ;Eerste 250mS loop
delay_250ms movlw d'250' ;Tweede 250mS loop
goto delay_ms
...
...
...
decfsz mscount,f
goto delay_ms_lp1
retlw 0
Dit had ook gekund (maar kost meer code en levert niks extra's op):
pic asm code:
delay_500ms call delay_250mS ;Eerste 250mS loop
call delay_250mS ;Tweede 250mS loop
return
delay_250ms movlw d'250'
goto delay_ms
...
...
...
decfsz mscount,f
goto delay_ms_lp1
retlw 0
[Bericht gewijzigd door Arco op zondag 10 november 2019 12:34:48 (32%)
Golden Member
Maar wanneer (bij welk statement) eindigt dan een call zonder return?
Special Member
Beide hebben een return: de retlw aan het eind van de routine. Let op dat alleen de eerste een call is, de tweede niet.
pic asm code:
delay_500ms call delay_250mS ;Eerste 250mS loop
delay_250ms movlw d'250' ;Tweede 250mS loop
goto delay_ms
...
...
...
decfsz mscount,f
goto delay_ms_lp1
retlw 0 <<<<<<<<----
Golden Member
Het kosttte wat moeite om alles te doorgronden, maar ik ben nu een heel eind.
De vele goto's maken een programma wat lastig om te doorgronden. Maar daar kom je niet onderuit denk ik.
In een ander artikel las ik dat de instructietijd = 4 / oscillatorfrequentie.
Maar waar dient dit statement
pic asm code:
fclock set sysclock >> 2 ;Internal cycle clock
dan voor?
Special Member
In een ander artikel las ik dat de instructietijd = 4 / oscillatorfrequentie.
Instructieclock is oscillatorfrequentie / 4...
( sysclock >> 2 is hetzelfde als sysclock / 4 )
Golden Member
Ik heb het programmaatje wat versimpeld zodat er een knipperfrequentie overblijft van ca 1 sec.
Het lukt nu allemaal. Het blijft wel even wennen bij het maken van loops en condities, omdat door bijvoorbeeld de Decfsz er één statement wordt overgeslagen.
Er is geen end if of wat daar op lijkt, waarmee je een aantal statements zou kunnen vangen in het blok (zoals in basic).
In plaats daarvan moet het dan worden opgevangen met goto's.
Ik heb het nu zo:
pic asm code:
;**********************************************************************
#include <p16f1827.inc> ;processor specific variable definitions
__CONFIG _CONFIG1, _FOSC_XT & _WDTE_OFF & _BOREN_OFF & _PWRTE_ON & _CP_OFF & _CPD_OFF & _MCLRE_OFF & _IESO_ON
__CONFIG _CONFIG2, _LVP_OFF & _PLLEN_OFF & _BORV_19
ErrorLevel - 302
;**********************************************************************
org 00h ;beginadres kiezen
banksel TRISA ;kies bank 1
clrf TRISA ;alles pinnen poort A uitgang maken
CBLOCK 0X20
Count1 ; delen door 250
Count2 ; delen door 200
Count3 ; delen door 4
ENDC
knipper
banksel LATA
movf LATA,w ;laad 01h in W
xorlw 1
movwf LATA ;zet de waarde van W
call delay_1sec
goto knipper
Delay_1sec ;delen door 4*200*250 = 200.000
movlw d'4'
movwf count3
loop1
movlw d'200'
movwf count2
loop2
movlw d'250'
movwf count1
loop3
nop
nop
decfsz count1,f
goto loop3
decfsz count2,f
goto loop2
decfsz count3,f
goto loop1
return
END
Special Member
MPSIM is heel handig om timeloops te bestuderen, kun je stap voor stap of animated er doorheen lopen...
Er zweven wel hulpfiles met macro's rond die FOR/WHILE/DO/SELECT CASE functionaliteit bieden, zoals ENGR2210.INC (een keer getest en werkt, maar ik gebruik 't niet)
Golden Member
Bij nieuwe projecten wordt de vraag gesteld of het 'absolute' of 'relocatable' moet worden gebuild.
Wat is aanbevelenswaardig?
Special Member
Golden Member
Op 6 november 2019 16:12:56 schreef Arco:
Hier heb ik al eens een leuk voorbeeld gegeven in assembly: een 4 digit led klok met gelijkzetmogelijkheid in maar 171 words geheugen...
https://www.circuitsonline.net/forum/view/message/2107242#2107242
Ik heb geen 648A. De uitdaging is om dit aan de praat te krijgen met een PIC16F628A.
Beiden lijken veel op elkaar als ik in de datasheets kijk, zij het dat de 648A meer Flash geheugen heeft zo te zien.
De displays lichten echter niet op.
(connecties / aansluitingen zijn goed, een testprogrammaatje toont dit aan).
Ik gebruik een extern kristal van 4 Mhz.
Special Member
Zou gewoon moeten werken. Je moet wel de clock goedzetten met _FOSC_XT. (staat op externe oscillator 10MHz)
Voor 4 MHz moet je dan
code:
banksel pr2 ;Timer 2 value
movlw d'124'
movwf pr2
veranderen in
code:
banksel pr2 ;Timer 2 value
movlw d'49'
movwf pr2
Je kunt ook de 1827 code gebruiken. (die heb je toch ook?)
Golden Member
Ik heb er voor alle zekerheid een 10Mhz kristal in gedaan en de oude waarden laten staan.
Maar help niet.
Het programma lijkt niet te 'lopen'; zo staan alle Poorten B op 0, net zoals de vier 'driver' Poorten A3 t/m A0.
De MCLR is hoog, met een pull-up naar de +5V.
Special Member
Zoals gezegd, hij staat op externe oscillator, dus geen kristal. Voor 10MHz moet je die op _FOSC_HS zetten...
Werkt hier prima met een 628a/648a/1827
Hexfile voor de 628a attached.
Golden Member
Nu weer even terug naar MikroBasic om 7-segment displays te multiplexen.
Ik tel tot 59 met 1 seconde als telfrequentie.
Op zich lukt dat wel, maar ik worstel alleen nog even met de vraag waar je nu de delay van 1000 ms neerlegt.
Onderstaand programma telt tot 59, maar je ziet de displays maar in een flits van 5ms vanwege de delay_ms(5).
Verhoog ik die delay, dan krijg je knipperen als effect.
Eigenlijk zou je de display loop continue willen laten lopen voor een strak beeld, maar hoe krijg je er dan in dat je per seconde de waarden ververst?
pic basic code:
program LedBasic
' Declarations section
Const Cijfer as Byte [10] = (63, 6, 91, 79, 102, 109, 125, 7, 127, 111)
Const Disp as Byte [4] = (1, 2, 4, 8)
Dim Inhoud as Byte[4]
Dim D1 as byte
Dim D2 as byte
Dim X1 as byte
sub procedure Tonen()
for x1 = 0 to 1
Portb = Inhoud[x1]
Porta = Disp[x1]
delay_ms(5)
Porta = %00000000
next x1
end sub
main:
trisa = %00000000
porta = %00000000
trisb = %00000000
portb = %00000000
while true
For D2 = 0 to 5
Inhoud[1] = Cijfer[D2]
For D1 = 0 to 9
delay_ms(1000)
Inhoud[0] = Cijfer[D1]
Tonen()
Next D1
Next D2
wend
end.
Special Member
Eigenlijk heb je voor nette timing interrupts nodig zoals in mijn klok voorbeeld...
Belangrijkste is dat je alle displays om de beurt even lang laat zien. En dat met een snelheid hoger als een mens kan waarnemen.
(in mijn klok voorbeeld is de multiplexrate 250Hz, dwz. elk display is 1/250 seconde aan)
Golden Member
Jawel,
Maar als je ergens een delay inbouwt van 1 sec, dan wordt de subroutine Tonen pas om de seconde aangeroepen. En zie je daardoor maar heel even de displays oplichten.
Special Member
Je moet ook 250x per seconde van display wisselen, niet 1 seconde lang hetzelfde display... Dus:
- Disp1 aan, 4mS wachten, disp1 uit.
- Disp2 aan, 4mS wachten, disp2 uit.
- Disp3 aan, 4mS wachten, disp3 uit.
- Disp4 aan, 4mS wachten, disp4 uit.
- Disp1 aan, 4mS wachten, disp1 uit.
...
...
Golden Member
Dat was dus inderdaad de truc.
Het MikroBasic programma werkt nu.
Misschien wel niet helemaal zuiver qua tijd: 4 display's met een vertraging van 1ms 250 keer laten knipperen levert in principe 1000ms op.
Daarbij is de tijd die nodig is voor het aansturen van de displays niet meegeteld (wellicht valt dat mee).
In ieder geval hier mijn programma. (Wie had dat kunnen denken nog geen 2 maanden geleden...)
pic basic code:
program LedBasic
' Declarations section
Const Cijfer as Byte [10] = (63, 6, 91, 79, 102, 109, 125, 7, 127, 111)
Const Disp as Byte [4] = (1, 2, 4, 8)
Dim Inhoud as Byte[4]
Dim D1 as byte
Dim D2 as byte
Dim D3 as byte
Dim D4 as byte
Dim X1 as byte
Dim T1 as byte
sub procedure Tonen()
For T1 = 1 to 250
For X1 = 0 to 3
Portb = Inhoud[x1]
Porta = Disp[x1]
delay_ms(1)
Porta = %00000000
Next X1
Next t1
end sub
main:
trisa = %00000000
porta = %00000000
trisb = %00000000
portb = %00000000
while true
For D4 = 0 to 5
Inhoud[3] = Cijfer[D4]
For D3 = 0 to 9
Inhoud[2] = (Cijfer[D3] OR %10000000)
For D2 = 0 to 5
Inhoud[1] = Cijfer[D2]
For D1 = 0 to 9
Inhoud[0] = Cijfer[D1]
Tonen()
Next D1
Next D2
Next D3
Next D4
wend
end.