Aansturen MAX7219 vanuit een PIC16F877a

Wie kan me helpen?

Ik heb een PIC16F877a die ik met de volgende poorten aan wil laten sturen de MAX7219 LED DISPLAY IC

PIN B.0 --> LOAD
PIN B.1 --> DIN
PIN B.2 --> CLK

Heeft iemand een PIC basic programma waarmee ik dat kan doen.

Ik wil namelijk een 16 bit waarde uit laten geven op het LED DISPLAY ( 8 Displays gekoppeld aan de MAX7219)

het zal ongetwijfeld kunnen,
maar je kan ook 8 display's direct multiplex aansturen...

Ja, dat klopt, maar nu heb ik maar drie lijnen van de PIC nodig anders veel meer

free_electron

Silicon Member

max7219 egint EOL te worden ( end of life. ) kijk liever naar de opvolgers MAX6950 en MAX6951

De 7219 is eigenlijk een schuif register.

start conditie : CLK = 0 en LOAD=0

Je zet de bit op Din, en geeft een clockpulse op clock. ( CLK even op 1 en dan terug op 0 )
daarnaa volgende bit op DIN en opnieuw clock pulse.
Als je zo 16 keer een bitje 'ingeschoven' hebt moet je LOAD op 1 zetten. dit 'vergrendelt' de ingeschoven data in de chip.

De eerste 4 bits die je inschuift moeten altijd '1' zijn Daarna volgen 4 bits die het address vormen waar jouw data in moet terechtkomen. En dan volgt de uiteindelijke data.

De 4 bits adress geven aan wat je bedoelt met de data die je inschuift.

Je kan de data laten decoderen door de MAX door op adress '1001' aan te geven welke digite je wilt laten decoderen.

een '1' laat de decoder actief. een '0' schakelt hem uit.

Adressen 1 tot 8 zijn de individuele digits.

Stel je hebt 8 maal een '7 segmeent display aangesloten'

Je wilt de eerste 4 laten decoderen en de laatste vier controleer je volledig zelf

schrijf naar address 9 ( 1001 ) data ( 1111000 )
Om nu op het eerste display het getal 9 te laten verschijnen schrijf je (00001001 ) naar address (0001 ). om op het volgende display het getal 4 te laten verschijnen schrijf je (00000100 ) naar address 0010

Als de decoder gebypassed is dan heb je control over alle individuele segmenten.

in bovenstaand geval : zet alle segmenten van het rechtse display aan :

schrijf 11111111 naar adress (1000)
de volgorde van segmenten is
punt A B C D E F G

wil je in bovenstaand geval de punt doven dan schrijf je 01111111 naar adress 1000

een volledige datastream ziet er dus zo uit in dit geval
1111100001111111
1111AAAADDDDDDDD

AAAA = adress informatie
DDDDDDDD = de data

de linkse bit (msb) moet er eerst worden ingezet

da's alles.

Professioneel ElectronenTemmer - siliconvalleygarage.com - De voltooid verleden tijd van 'halfgeleider' is 'zand' ... US 8,032,693 / US 7,714,746 / US 7,355,303 / US 7,098,557 / US 6,762,632 / EP 1804159 - Real programmers write Hex into ROM

Op 4 januari 2005 18:25:46 schreef free_electron:
max7219 egint EOL te worden ( end of life. ) kijk liever naar de opvolgers MAX6950 en MAX6951

De 7219 is eigenlijk een schuif register.

start conditie : CLK = 0 en LOAD=0

Je zet de bit op Din, en geeft een clockpulse op clock. ( CLK even op 1 en dan terug op 0 )
daarnaa volgende bit op DIN en opnieuw clock pulse.
Als je zo 16 keer een bitje 'ingeschoven' hebt moet je LOAD op 1 zetten. dit 'vergrendelt' de ingeschoven data in de chip.

De eerste 4 bits die je inschuift moeten altijd '1' zijn Daarna volgen 4 bits die het address vormen waar jouw data in moet terechtkomen. En dan volgt de uiteindelijke data.

De 4 bits adress geven aan wat je bedoelt met de data die je inschuift.

Je kan de data laten decoderen door de MAX door op adress '1001' aan te geven welke digite je wilt laten decoderen.

een '1' laat de decoder actief. een '0' schakelt hem uit.

Adressen 1 tot 8 zijn de individuele digits.

Stel je hebt 8 maal een '7 segmeent display aangesloten'

Je wilt de eerste 4 laten decoderen en de laatste vier controleer je volledig zelf

schrijf naar address 9 ( 1001 ) data ( 1111000 )
Om nu op het eerste display het getal 9 te laten verschijnen schrijf je (00001001 ) naar address (0001 ). om op het volgende display het getal 4 te laten verschijnen schrijf je (00000100 ) naar address 0010

Als de decoder gebypassed is dan heb je control over alle individuele segmenten.

in bovenstaand geval : zet alle segmenten van het rechtse display aan :

schrijf 11111111 naar adress (1000)
de volgorde van segmenten is
punt A B C D E F G

wil je in bovenstaand geval de punt doven dan schrijf je 01111111 naar adress 1000

een volledige datastream ziet er dus zo uit in dit geval
1111100001111111
1111AAAADDDDDDDD

AAAA = adress informatie
DDDDDDDD = de data

de linkse bit (msb) moet er eerst worden ingezet

da's alles.

Bedankt voor je duidelijke uitleg.

Als je nou ook nog een klein picbasic voorbeeld hebt voor mij dat zou het heel mooi zijn.

Ik heb een telletje in een 16 bits variable waarban de waarde wordt getoont op de rechste vier LED displays

Maar hoe krijg ik dat de teller doorloopt naar de andere 4 LED displays. ( Dus gewoon doorteld van 9999 naar 10000)

free_electron

Silicon Member

oei. ik programmeer niet op pic processoren. ( wel interesse )

ok jebt een 16 bit tellertje. dus je kan maximaal tot 65535 tellen .. juist ?

dan is voor jouw het simpelste dat je inderdaad de decodering aanzet ( door allemaal 1en te schrijven in et controle register

ik doe een poging in basic ( opgelet ik ken niks van picbasic )

de routine om een commando te verzenden

sub sendcommand (woord):
B.0 =0 ' load
B.1 =0 ' din
B.2 =0 ' clk
t=1 'variabele voor bitmaskering
for x = 0 to 15
if (woord and t) >0 then
B.1=1
else
B.1=0
end if
t = t*2 ' hiermee laten we het bitje 'wandelen'
b.2=1
b.2=0

next x
b.0=1 ' load het comando in
end sub

en dan het hoofdprogramma

sendcommand (&b1111100111111111) ' dit zet alle decoders aan

do while 1
teller = teller+1 ' teller is jouw 16 bit variabele
tmpteller=teller
t = int(tmpteller /10000) ' dit geeft je eerste cijfer
sendcommand (&b1111010100000000 + t)
t = int((tmpteller-(10000 * t))/1000) ' dit geeft je tweede cijfer
sendcommand (&b1111010000000000 + t)
t = int((tmpteller-(1000 * t))/100) ' dit geeft je derde cijfer
sendcommand (&b1111001100000000 + t)
t = int((tmpteller-(100 * t))/10) ' dit geeft je vierde cijfer
sendcommand (&b1111001000000000 + t)
t = int(tmpteller-(10 * t)) ' dit geeft je vijfde cijfer
sendcommand (&b1111000100000000 + t)

wend

in assembler is dit veel korter omdat je daar de rest na deling direct kan ophalen. o een 8051 kan ik ditdirect bakken.

nogmaals ik ken niks van PIC processor of PICbasic. Hierboven staat in normale BASIC wat je zou moeten doen.

groeten

Professioneel ElectronenTemmer - siliconvalleygarage.com - De voltooid verleden tijd van 'halfgeleider' is 'zand' ... US 8,032,693 / US 7,714,746 / US 7,355,303 / US 7,098,557 / US 6,762,632 / EP 1804159 - Real programmers write Hex into ROM

Hier is de code die ik gevonden heb

'-----CHIP SET-UP-----
include "modedefs.bas"
define OSC 4

'-----VARIABLES-----
ADDRESS var word 'variable address for display
DATAREG var word 'variable data register for display
X var word 'misc variable used in loops

'-----PIN SETUPS-----
low portb.0 'data pin for MAX7219 (1)
low portb.1 'clock pin for MAX7219 (13)
low portb.2 'load pin for MAX7219 (12)

'-----MAX7219 SETUP-----
ADDRESS = $0C : DATAREG = $01 : gosub MaxWrite 'normal operation
ADDRESS = $09 : DATAREG = $0F : gosub MaxWrite 'decode mode Code B-digits 3-0
ADDRESS = $0A : DATAREG = $04 : gosub MaxWrite 'intensity 0..15
ADDRESS = $0B : DATAREG = $03 : gosub MaxWrite 'scan limit 0..7
ADDRESS = $0F : DATAREG = $00 : gosub MaxWrite 'display normal format
gosub Blank 'make the display blank

'-----PROGRAM-----
Start:
for X = 0 to 9999 'have the variable X count from 0 to 9999
gosub ValueToMax 'send X to get converted and displayed by MAX7219
pause 1000 'pause 10ms so you can see the numbers count
next X 'increment the counter X

goto Start 'do it all over again
end

'-----SUBROUTINES-----
ValueToMax:
ADDRESS = 1 : DATAREG = X DIG 0 'extract 1000s digit from variable X
gosub MaxWrite 'send the 1000s digit to the MAX7219
ADDRESS = 2 : DATAREG = X DIG 1 'extract 100s digit from variable X
gosub MaxWrite 'send the 100s digit to the MAX7219
ADDRESS = 3 : DATAREG = X DIG 2 'extract 10s digit from variable X
gosub MaxWrite 'send the 10s digit to the MAX7219
ADDRESS = 4 : DATAREG = X DIG 3 'extract 1s digit from variable X
gosub MaxWrite 'send the 1s digit to the MAX7219
return

MaxWrite:
shiftout portb.0,portb.1,1,[ADDRESS,DATAREG] 'Shift out the data to the
MAX7219
'first the address, then data.
pulsout portb.2,1 'load the data into the MAX7219
return

Blank:
for X = 1 to 4 'write $0F (blank) to all digits
ADDRESS = X : DATAREG = $0F : gosub MaxWrite
next X
return

Vraag is nu
Hoe kan alle 8 digits aansturen?

1. ADDRESS = $09 : DATAREG = $FF : gosub MaxWrite 'decode mode Code B-digits 7-0
2. ADDRESS = $0B : DATAREG = $07 : gosub MaxWrite 'scan limit 0..7

Maar hoe krijg ik een waarde > 65536 op het LED DISPLAY
( digit 5 t.m 8)?

free_electron

Silicon Member

aha nu komen we ergens

. ADDRESS = $09 : DATAREG = $FF : gosub MaxWrite 'decode mode Code B-digits 7-0
2. ADDRESS = $0B : DATAREG = $07 : gosub MaxWrite 'scan limit 0..7
is inderdaad juist

de for next moet 0 tot 65535 lopen ipv 0 to 9999

en dan denk ik

ADDRESS = 5 : DATAREG = X DIG 4
gosub MaxWrite

wat dat DIG commando doet weet ik niet hoor. aar het is het proberen waard

Professioneel ElectronenTemmer - siliconvalleygarage.com - De voltooid verleden tijd van 'halfgeleider' is 'zand' ... US 8,032,693 / US 7,714,746 / US 7,355,303 / US 7,098,557 / US 6,762,632 / EP 1804159 - Real programmers write Hex into ROM

Op 5 januari 2005 09:05:09 schreef free_electron:
aha nu komen we ergens

. ADDRESS = $09 : DATAREG = $FF : gosub MaxWrite 'decode mode Code B-digits 7-0
2. ADDRESS = $0B : DATAREG = $07 : gosub MaxWrite 'scan limit 0..7
is inderdaad juist

de for next moet 0 tot 65535 lopen ipv 0 to 9999

en dan denk ik

ADDRESS = 5 : DATAREG = X DIG 4
gosub MaxWrite

wat dat DIG commando doet weet ik niet hoor. aar het is het proberen waard

Dan kan ik maar 5 digits aansturen ipv de acht digit
Hij telt dus niet verder dan 65536

Hoe kan dat opgelost worden?

free_electron

Silicon Member

Ach ge wilt to 99999999 kunne tellen ? dan gaat ge er met uw 16 bit getalleke niet komen vrees ik. 16 bit = max 65535. ge zult meer bits moeten gebruiken. aangezien ik niet weet of uw ding 32 bit aankan heb ik het opgeleost met 2 16 bit variablen.

en hop hier gan we :

-----CHIP SET-UP-----
include "modedefs.bas"
define OSC 4

'-----VARIABLES-----
ADDRESS var word 'variable address for display
DATAREG var word 'variable data register for display
X var word 'misc variable used in loops
Y var word ' DEZE TOEVOEGEN

'-----PIN SETUPS-----
low portb.0 'data pin for MAX7219 (1)
low portb.1 'clock pin for MAX7219 (13)
low portb.2 'load pin for MAX7219 (12)

'-----MAX7219 SETUP-----
ADDRESS = $0C : DATAREG = $01 : gosub MaxWrite
ADDRESS = $09 : DATAREG = $FF : gosub MaxWrite
ADDRESS = $0A : DATAREG = $04 : gosub MaxWrite
ADDRESS = $0B : DATAREG = $03 : gosub MaxWrite
ADDRESS = $0F : DATAREG = $00 : gosub MaxWrite
gosub Blank

'-----PROGRAM-----
Start:
for Y = 0 to 9999
for X = 0 to 9999
gosub ValueToMax
pause 1000
next X
X = 0
NEXT y
goto Start 'do it all over again
end

'-----SUBROUTINES-----
ValueToMax:
ADDRESS = 1 : DATAREG = X DIG 0
gosub MaxWrite
ADDRESS = 2 : DATAREG = X DIG 1
gosub MaxWrite
ADDRESS = 3 : DATAREG = X DIG 2
gosub MaxWrite
ADDRESS = 4 : DATAREG = X DIG 3
gosub MaxWrite
ADDRESS = 5 : DATAREG = y DIG 0
gosub MaxWrite
ADDRESS = 6 : DATAREG = y DIG 1
gosub MaxWrite
ADDRESS = 7 : DATAREG = y DIG 2
gosub MaxWrite
ADDRESS = 8 : DATAREG = y DIG 3
gosub MaxWrite
return

MaxWrite:
shiftout portb.0,portb.1,1,[ADDRESS,DATAREG] 'Shift out the data to the
MAX7219
'first the address, then data.
pulsout portb.2,1 'load the data into the MAX7219
return

Blank:
for X = 1 to 4 'write $0F (blank) to all digits
ADDRESS = X : DATAREG = $0F : gosub MaxWrite
next X
return

Professioneel ElectronenTemmer - siliconvalleygarage.com - De voltooid verleden tijd van 'halfgeleider' is 'zand' ... US 8,032,693 / US 7,714,746 / US 7,355,303 / US 7,098,557 / US 6,762,632 / EP 1804159 - Real programmers write Hex into ROM

Bij het zoeken naar info over de MAX7219 kwam ik dit (oude) bericht tegen:

Op 4 januari 2005 18:25:46 schreef free_electron:
max7219 egint EOL te worden ( end of life. ) kijk liever naar de opvolgers MAX6950 en MAX6951

Een post van bijna 5 jaar geleden.
Grappig detail: De MAX6950 is nu moeilijk te verkrijgen (EOL?) alsmede de MAX6951 (ook EOL?), en kosten bijna 2x zoveel als een MAX7219, die nog steeds vol op te verkrijgen is.

By the way, zijn er nog andere types 7-segment display drivers bekend (I²C, SPI)?
Ik wil een artikeltje schrijven voor picbasic.nl over 7-segment drivers.

Ohm sweet Ohm | www.picbasic.nl
Bavelt

Golden Member

Ik ben ook even aan het testen met een 8-digits 7 segment.
met MikroBasic.
Ik wilde op iedere display een cijfer tonen.

Maar ergens doe ik iets fout; het displaytje blijft uit.

pic basic code:

Program Test_887

'====================================================================================================
' Project name: Test_887
' MCU:          PIC16F887
' Oscillator:   Internal 8 MHz
' SDO:          PORT C.5                 Pin 24
' CLK:          PORT C.3                 Pin 18
' CS:           PORT C.1                 Pin 16

'====================================================================================================

Dim  ClockPin As sbit at PORTC.3         'pin 18                   'Clock
     Datapin  As sbit at PORTC.5         'pin 24                   'SDO
     C_S      As sbit at PORTC.1         'pin 16                   'Chip Select

Dim i1 as byte
    j1 as byte
    Latch as Byte

'===============================================================================
Sub Procedure Max_Write(Dim pAdr, pDat As Byte)
'===============================================================================
 Latch = 0
 SPI1_Write(pAdr)
 SPI1_Write(pDat)
 Latch = 1
 delay_ms(2)
End sub

'===============================================================================
Sub Procedure Max7219_Init()
'===============================================================================
Max_Write(0x09, 0xFF)                      'Decode Mode Code B-Digital digits 7-0
Max_Write(0x0B, 0x03)                      'Scan Limit 0-7
Max_Write(0x0C, 0x01)                      'Normal Operation
Max_Write(0x0A, 0x01)                      'Intensity
End sub

'====================================================================================================
Main:                                      'Main program
'====================================================================================================

  ANSEL  = %00000000
  ANSELH = %00000000
  TRISC  = %00000000

  OSCCON = %01110000                      '8 Mhz internal
  PORTC =  %00000000

  SPI1_Init()
  Max7219_Init()

 Max_Write(0x01,0x01)
 Max_Write(0x02,0x02)
 Max_Write(0x03,0x03)
 Max_Write(0x04,0x04)
 Max_Write(0x05,0x05)
 Max_Write(0x06,0x06)
 Max_Write(0x07,0x07)
 Max_Write(0x08,0x08)

  While True
  Wend

 End.
Fouten zijn het bewijs dat je het probeert..
Kruimel

Golden Member

Zou je hiervoor niet een nieuw topic openen? Inmiddels is er al zo veel op dit gebied veranderd dat de informatie op dit topic na 10 jaar wellicht verouderd is.

Bavelt

Golden Member

Fouten zijn het bewijs dat je het probeert..
Kruimel

Golden Member

Wacht even: je hebt zo een topic reeds geopend: PIC 16F887 en MikroBasic. Geen dwaalspoor aan topics en posts maken nu hè?

edit: En deze PIC16F887

[Bericht gewijzigd door Kruimel op donderdag 14 mei 2020 23:44:01 (20%)

Bavelt

Golden Member

Klopt, maar dat was met een LED Matrix 8*8.
Dat werkt wel. Maar ik was nu aan de gang met een 7-Segment SPI met 8 digits.

Ik zocht in het Forum en zag een topic dat aansloot op mijn test.

Fouten zijn het bewijs dat je het probeert..
Bavelt

Golden Member

Maar het is inmiddels al opgelost (ik had het te snel gepost).

Fouten zijn het bewijs dat je het probeert..
Bavelt

Golden Member

De 7-Segmentjes (8 digits) die ik heb zijn gemaakt voor SPI protocol.
Je kan ze ook 'doorlussen". De D_out van de eerste gaat dan naar de D_in van de tweede.

Dus maar eens geprobeerd (net als met de matrix leds).
Het schrijven naar de displays gaat dan als volgt:

pic basic code:

'====================================================================================================
Sub Procedure Max_Write(Dim pAdr, pDat1, Pdat2 As byte)
'====================================================================================================
 C_S = 0
 SPI2_Write(pAdr)
 SPI2_Write(pDat1)
 SPI2_Write(pAdr)
 SPI2_Write(pDat2)
 C_S = 1
 Delay_ms(1)
End sub

Dit werkt, maar het opvallende is dat de tweede (laatste in de rij) display een aanzienlijk mindere lichtopbrengst geeft dan de eerste.
Het ligt niet aan de display zelf, want als ik ze omdraai blijft de eerste in de rij mooi fel.

Ik kan dat compenseren door de intensity van de tweede hoger te maken dan de eerste:

pic basic code:

Max_write(0x0A, 0X0E, 0x06)

Maar dat lijkt me wat gekunsteld. Waarom zou die tweede display zoveel minder licht geven?

Fouten zijn het bewijs dat je het probeert..
Arco

Special Member

Zijn de Iset weerstanden wel indentiek bij beide?
De HCMS displays die ik heb werken vergelijkbaar, en zijn altijd netjes gelijk van sterkte...

Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com
Bavelt

Golden Member

Tja, de weerstand zit voorgemonteerd. Ik neem aan dat R1 die Iset weerstand is. Ik heb ze beiden doorgmeten: exact 10K.

Daarbij zoals als vermeld: als ik de moduultjes omwissel dan is het steeds de eerste in de rij met de meeste lichtopbrengst.

Maar ik kan het dus oplossen door de zwakste van de twee wat op te haken met het Intensity register.

Maar vreemd blijt het wel.

Fouten zijn het bewijs dat je het probeert..
Arco

Special Member

Staan de scan-limit registers goed? Uit de datasheet:

If the scan-limit register is set for three digits or less,
individual digit drivers will dissipate excessive amounts
of power.

Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com
Bavelt

Golden Member

De ScanLimit staat voor allebei op 0x07.

Maar inmiddels heb ik het redelijk onder controle. Hoe, weet ik niet precies. Wel dat ik een exra C-tje van 100nF vlak bij de voeding van beide displays heb gezet. En een nieuw kabelboompje er tussen.
(Wellicht voorheen een slechte verbinding?)

De verschillen in lichtsterkte zijn nu verwaarloosbaar:

De waarden die hier worden getoond zijn overigens de tijd en op iedere display wordt de temperatuur getoond afkomstig van 2 verschillende DS18B20's. Die staan op 5 cm afstand van elkaar.

Fouten zijn het bewijs dat je het probeert..
Bavelt

Golden Member

Het zijn overigens leuke displaytjes. Ik kocht ze voor € 0,85 bij ALie (en ca € 0,23 bezorgkosten).
Zo ongeveer de prijs van een postzegel dus..

Fouten zijn het bewijs dat je het probeert..
Bavelt

Golden Member

Ik heb overigens wat metingen gedaan om te kijken hoe de gemeten temperatuur zich verhoudt tot de voedingsspanning:

Spanning DS18B20-1 DS18B20-2

3,3...... 26,1......... 25,3
4,0...... 26,1......... 25,3
4,5...... 26,0......... 25,3
4,75..... 26,1......... 25,3
5,0...... 25,5......... 25,2

De eerste sensor gaat in de buurt van de 5 Volt afwijken (maar wel dichter bij de werkelijkheid). De tweede is mooi constant.

Fouten zijn het bewijs dat je het probeert..