De toestand van het data (ram) geheugen is 'unknown' bij power-up. Al je bepaalde waardes wilt moet je dat zelf doen.
Bij alle GPR SFR registers staat duidelijk wat hun waarde is bij diverse soorten resets...
Special Member
Golden Member
Hm, Dit voorbeeld is een opsomming van de waarde van PoortB.
Een byte definiëren in het programma komt toch in het flash geheugen?
Het probleem wat ik zelf een beetje heb, is dat dankzij de snelle respons van Arco ik iedere keer weer een stapje meer leer.
Maar hoe je nu uit jezelf uit de (omvangrijke) datasheet bij een GPR register komt..
Special Member
Ramlocaties kunnen willekeurige waardes hebben na een power-up, ik heb ook vaak dat ze 0xFF zijn...
(met GPR bedoelde ik eigenlijk SFR in het voorbeeld...)
Golden Member
Ik heb het programmaatje inmiddels weer wat opgeschoond en uitgebreid met seconden.
Het ding loopt perfect op tijd (2x 22pF aan het 10Mhz kristal).
Het 'grappige' is dat het lastig lijkt om tussen digit 3 en 4 twee dubbele puntjes te maken.
Dat kan ik wel, maar kost een heleboel IF's en andere code, wat ik weer jammer vindt omdat het programma nu lekker kort is.
Je kan ook niet standaard enkele ledjes (puntjes) aanzetten, omdat de hele rij wordt geschreven via de MAX7219 chips.
Tenzij het toch wat korter kan...(wellicht extra regel schrijven met een AND?)
pic basic code:
Program MatrixKlok
'Klok met uren, minuten en seconden
'Display Matrix Led 8 * 8, type 1088AS
Dim Digit As Byte[6]
Seccount As Byte
MinCount As Byte
KeyCount As Byte
Flags As Byte
fKeyRpt As sBit At Flags.0
fDigit As Byte 'Indicates which Digit has to be updated
ClockPin as sbit at PORTC.3 'pin 18
Latch as sbit at PORTC.7 'pin 26
Datapin as sbit at PORTC.5 'pin 24
Row as Byte
Const Keytime = 120 '0.6sec
Keydebounce = 10 '40mS
Const font as byte[80] = 'Character tabel, 90 Degrees turn left
(
0x3c, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3c,
0x00, 0x7e, 0x18, 0x18, 0x18, 0x1c, 0x18, 0x18,
0x00, 0x7e, 0x06, 0x0c, 0x30, 0x60, 0x66, 0x3c,
0x00, 0x3c, 0x66, 0x60, 0x38, 0x60, 0x66, 0x3c,
0x00, 0x30, 0x30, 0x7e, 0x32, 0x34, 0x38, 0x30,
0x00, 0x3c, 0x66, 0x60, 0x60, 0x3e, 0x06, 0x7e,
0x00, 0x3c, 0x66, 0x66, 0x3e, 0x06, 0x66, 0x3c,
0x00, 0x18, 0x18, 0x18, 0x30, 0x30, 0x66, 0x7e,
0x00, 0x3c, 0x66, 0x66, 0x3c, 0x66, 0x66, 0x3c,
0x00, 0x3c, 0x66, 0x60, 0x7c, 0x66, 0x66, 0x3c
)
' 0x00, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3c,
'===============================================================================
Sub Procedure Max_Write(Dim pCol, pDig0, pDIg1, pDig2, pDig3, pDig4, pDig5 as Byte)
'===============================================================================
Latch = 0
SPI1_Write(pCol)
SPI1_Write(pDig0)
SPI1_Write(pCol)
SPI1_Write(pDig1)
SPI1_Write(pCol)
SPI1_Write(pDig2)
SPI1_Write(pCol)
SPI1_Write(pDig3)
SPI1_Write(pCol)
SPI1_Write((pDig4))
SPI1_Write(pCol)
SPI1_Write(pDig5)
Latch = 1
delay_ms(2)
End sub
'===============================================================================
Sub Procedure Max7219_Init()
'===============================================================================
Max_Write(0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00)
Max_Write(0x0B, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07)
Max_Write(0x0C, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01)
Max_Write(0x0A, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01)
End sub
'===============================================================================
Sub Procedure Display_Testen() 'Testen van het display; alle LEDS aan
'===============================================================================
Max_Write(0x0F, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01)
DELAY_MS(50)
Max_Write(0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00)
DELAY_MS(50)
End sub
'===============================================================================
Sub Procedure Uitzetten_Leds() 'Leds uitzetten per Row
'===============================================================================
FOR Row = 1 TO 8
Max_Write(Row, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00)
delay_ms(5)
NEXT Row
End sub
'===============================================================================
Sub Procedure Update_LED 'Update LED
'===============================================================================
If (Digit[0] > 9) then Digit[0] = 0 inc (Digit[1]) end if
If (Digit[1] > 5) then Digit[1] = 0 inc (Digit[2]) end if
If (Digit[2] > 9) then Digit[2] = 0 inc (Digit[3]) end if
If (Digit[3] > 5) then Digit[3] = 0 inc (Digit[4]) end if
If (Digit[4] > 9) then Digit[4] = 0 inc (Digit[5]) end if
If (Digit[5] > 2) then Digit[5] = 0 end if
If (Digit[5] = 2) And (Digit[4] > 3) Then
Digit[0] = 0 Digit[1] = 0 Digit[2] = 0 Digit[3] = 0
Digit[4] = 0 Digit[5] = 0
end if
For Row = 1 to 8
Max_Write(Row, Font[(Digit[0]<<3) + (Row - 1)],
Font[(Digit[1]<<3) + (Row - 1)],
Font[(Digit[2]<<3) + (Row - 1)],
Font[(Digit[3]<<3) + (Row - 1)],
Font[(Digit[4]<<3) + (Row - 1)],
Font[(Digit[5]<<3) + (Row - 1)])
Next Row
End sub
'===============================================================================
sub procedure Interrupt() iv 0x0004 ics ICS_AUTO
'===============================================================================
If TMR2IF_bit Then 'See if timer2 irq
Inc(Seccount) 'If so, update coun-
If Seccount = 250 Then 'ters.
Seccount = 0 'Set flag if second is passed
fDigit = 7 'Set Flag to Update LED
End If
'----------------------------------------------------------------------------
if portb = 255 then 'No key pressed
fKeyRpt = 0
KeyCount = 0
Else
Inc(KeyCount)
if KeyCount = KeyDebounce then '
if portb.3 = 0 then FDigit = 6 end if
if portb.2 = 0 then FDigit = 5 end if
if portb.1 = 0 then FDigit = 4 end if
if portb.0 = 0 then FDigit = 3 end if
Digit[0] = 0
Digit[1] = 0 '
SecCount = 0 '
End if
End if '
TMR2IF_bit = 0
End If
End sub
'===============================================================================
Main:
'===============================================================================
T2CON = %00100110 'Post:5 - Pre:16
PR2 = 124 'Timer load value
ANSELh = %00000000 'Port B digital
TRISC = %00111101
TRISB = %00000000
PORTB = %11111111
GIE_bit = 1 'Enable timer2 irq
PEIE_bit = 1
TMR2IE_bit = 1
For fDigit = 0 to 5 'Start with 00:00
Digit[fDigit] = 0
Next fDigit 'Flag Display
fDigit = 0
SPI1_Init()
Max7219_Init()
Display_Testen()
Uitzetten_Leds()
Update_LED()
'Loop ----------------------------------------------------------------------
While True
if fDigit > 0 then
select case fDigit
case 1, 2, 3, 4, 5, 6
Inc (Digit[(fDigit - 1)])
Update_LED()
case 7
Inc(Digit[0])
Update_Led()
end select
Fdigit = 0
End if
Wend
End.
Golden Member
Ramlocaties kunnen willekeurige waardes hebben na een power-up, ik heb ook vaak dat ze 0xFF zijn...
(met GPR bedoelde ik eigenlijk SFR in het voorbeeld...)
SFR snap ik
Het sterkt me in de gedachte gewoon initiële waarden altijd te zetten voordat een programma begint.
Golden Member
Oplossing voor dubbel punten is gelukt en is eigenlijk best wel simpel:
pic basic code:
For Row = 1 to 8
if (Row = 2) or (Row = 7) then i1= 128 else i1 =0 end if 'Double Points
Max_Write(Row, Font[(Digit[0]<<3) + (Row - 1)],
Font[(Digit[1]<<3) + (Row - 1)],
Font[(Digit[2]<<3) + (Row - 1)],
Font[(Digit[4]<<3) + (Row - 1)],
Font[(Digit[4]<<3) + (Row - 1)] >>1 + i1,
Font[(Digit[5]<<3) + (Row - 1)] >>1)
Next Row
Op de 2e en 7e rij een extra ledje laten branden door 128 op te tellen bij het getoonde cijfer. De display's 4 en 5 eentje naar links opschuiven voor de sym
metrie.
Golden Member
Zo nog eens een vraagje over de PIC16F1826:
Poort A.6 is de datapin voor een SPI interface. Maar ook de clockout voor een extern kristal.
Zijn die dan door elkaar te gebruiken of is het het één of het ander?
Golden Member
Als ik wil afvragen of de eerste 4 bits (0 t/m 3) van een poort '1' zijn, kan ik het natuurlijk zo afvragen:
pic basic code:
if (PORTA.0 = 1) AND (PORTA.1 = 1) AND (PORTA.2 = 1) AND (PORTA.3 = 1) then ....etc
Maar ik vermoed dat het ook makkelijker kan.
Special Member
pic basic code:
if (PORTA And 0x0F) = 0x0F Then ...etc
De SPI pin kun je verplaatsen in het APFCON0 register... (zit default trouwens op RB2, niet op RA6)
Golden Member
De SPI pin kun je verplaatsen in het APFCON0 registe
Jawel, maar stel dat je de SPI pin dus op RA6 zet, dan betekent dat automatisch dat je dan in dat geval geen externe oscillator kunt gebruiken?
Special Member
Ja, uiteraard...
Je kunt 1 pin niet tegelijk voor twee dingen gebruiken...
Geldt voor een kristal: een externe oscillator kan wel (die zit aan RA7)
[Bericht gewijzigd door Arco op woensdag 18 december 2019 14:29:07 (33%)
Golden Member
Ik moet zeggen dat de 'truc' die Arco aangaf om een offset in de klok in te bouwen die ieder uur een correctie aanbrengt goed werkt en makkelijker is dan met condensatortjes met de klokfrequentie aan de gang te gaan.
Golden Member
Soms kunnen kleine dingen je lang bezighouden (dwz vermoedelijk ergens zwaar overheen kijken...
Hieronder een simpel voorbeeld van een tabel (16 bytes).
Het werkt als ik een waarde van i1 invul:
pic basic code:
const Font As Byte[16] = ( 'Character table
0xcc, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0x78, 0x00,
0x3e, 0x66, 0x66, 0x3e, 0x66, 0x66, 0x3e, 0x00
)
Main:
Row = 2
i1 = 0
Max_Write(Row, Font[(i1*8) + (Row - 1)]*2)
i1 staat dus op 0.
Maar wanneer ik dan de waarden invul in de formule, dan krijg ik een foutmelding: Getal '408' buiten de waarde van een byte.
pic basic code:
const Font As Byte[16] = ( 'Character table
0xcc, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0x78, 0x00,
0x3e, 0x66, 0x66, 0x3e, 0x66, 0x66, 0x3e, 0x00
)
Row = 2
i1 = 0
Max_Write(Row, Font[(0*8) + (2 - 1)]*2)
Deze gaat dus fout. Maar wat is nu het verschil met de eerste regels? i1 is toch immers 0 en row 2?
Ik heb al we gezien dat 408 een tweevoud is van 204 (0x66). Er gebeurt in mijn ogen iets onverklaarbaars..
Special Member
204 = 0xCC, x2 = 408. Dit is meer als een byte dus foutmelding klopt... (zouden beide een foutmelding moeten geven...)
Zou kunnen dat de compiler de eerste niet controleert, omdat die niet 'hard-coded' is...
[Bericht gewijzigd door Arco op donderdag 2 januari 2020 01:28:55 (28%)
Golden Member
Dat zou het idd kunnen verklaren.
(Grappig dat het wel werkt in de uitvoering)
In dat geval zit er wel een fout in de code.
Het is de bedoeling om het juiste byte te selecteren aan de hand van de waarde van i1.
Maar hij slaat blijkbaar aan het rekenen met de inhoud van de byte,
Golden Member
De code komt voor in mijn (nog steeds op de seconde gelijk lopende klok)
pic basic code:
For Row = 1 to 8
if (Row = 2) or (Row = 7) then i1 = 128 else i1 = 0 end if 'Double Points
if (Row = 2) or (Row = 7) then j1 = 1 else j1 = 0 end if
Max_Write(Row, Font[(Digit[0]<<3) + (Row - 1)]<<1,
Font[(Digit[1]<<3) + (Row - 1)]<<1 + j1,
Font[(Digit[2]<<3) + (Row - 1)],
Font[(Digit[3]<<3) + (Row - 1)],
Font[(Digit[4]<<3) + (Row - 1)] >>1 + i1,
Font[(Digit[5]<<3) + (Row - 1)] >>1)
Next Row
In dit geval met 6 digits.
Ik ben nu aan het testen met 1 Led Matrix, maar dan met karakters cijfers en letters)
Golden Member
bericht verwijderd
[Bericht gewijzigd door Bavelt op donderdag 2 januari 2020 02:05:46 (89%)
Golden Member
pic basic code:
Max_Write(Row, Font[(Digit[0]<<3) + (Row - 1)]<<1,
Ik begin nu zelf te twijfelen of die <<1 wel goed is...
Ik snapte al niet wat die daar deed (vermenigvuldigen met 2)
[Bericht gewijzigd door Bavelt op donderdag 2 januari 2020 02:05:27 (20%)
Special Member
Een << 1 en vermenigvuldigen met 2 zijn hetzelfde. (de compiler maakt zelf al een '<<1' van een '*2')
(wat je er mee wilt is me ook duister. Je kunt ermee het font 1 rij naar links verschuiven, maar met waardes groter als 127 gaat dat niet)
[Bericht gewijzigd door Arco op donderdag 2 januari 2020 02:17:27 (12%)
Golden Member
Ik ga het gewoon aanpassen; dingen die ik zelf al niet snap haal ik er uit.
Maar niet voordat ik de beste wensen voor 2020 heb overgebracht!
Golden Member
Er is een aardig programma online beschikbaar, waarmee je cijfers, letters, etc kan maken voor een 8*8 Matrix: LED Matrix Editor.
Hij genereert zelfs de bijbehorende code, maar die is geënt op C.
Dan krijg je bv
c code:
const uint64_t IMAGES[] = {
0x6666667e66663c00 }
Het grappige is dat je hier blijkbaar een reeks kan opgeven, waarbij je eerst aangeeft dat alle volgende bytes hexadecimaal zijn en daarna de inhoud per byte.
Vertaald naar MikroBasic is dat:
pic basic code:
const Font As Byte[8] = ( 'Character table
0x66, 0x66, 0x66, 0x7e, 0x66, 0x66, 0x3c, 0x00)
Je moet dus voor iedere byte er 0x voor zetten om aan te geven dat het hexadecimaal is.
Of is er wellicht een mogelijkheid zoals in C?
Special Member
0x moet altijd voor een hex getal notatie. En 64 bit variabelen zijn er alleen bij de PIC32 32 bits compiler. (bij een 8 bit MCU niet erg efficient)
Golden Member
Ok, de LED Editor genereert de codes voor de karakters.
Dat betekent dan dat je voor de reeks maximaal 255 * 8 = 2040 keer '0x' (plus een komma) voor de bytes moet tikken.
Met wat handigheid met de editor is dat wat te verlichten.
En als je dan bv alles 90 Graden wilt draaien (Led matrix kwart slag gedraaid) je het nog een keer moet doen.
Tja..
Special Member
Tja...
Niemand gaat een 255 karaktertabel bouwen, de meeste karakters gebruik je nooit en/of heb je niks aan...
En karakters in twee posities zie je ook al zelden (je weet vooraf toch wel in welke positie je de zaak wilt laten zien?)
Daarbij kun je ook een functie schrijven die het karakter desnoods 90 graden draait...
Golden Member
Klopt.
Ik heb het al voor elkaar, mbv Find-Replace kom je al een knap eind.
En kwart slag draaien ga ik een routine-tje schrijven, mooie oefening .