Na eindeloos lezen in datasheets en het voorbeeld programma in Proton te hebben bestudeerd, is het me nog steeds niet gelukt om een verbinding te leggen tussen twee PIC's (PIC18F458 als master en PIC16F877A als slave).
Wat wel gelukt is is een master verbinding naar een I2C EEPROM. Wat het programmatje doet is een teller van de master naar het geheugen van de EEPROM schrijven, vervolgens haalt hij deze gegevens weer op en schrijft ze naar een LCD-scherm.
Nu zou ik zo'n zelfde soort programmatje willen maken, voor de PIC master / PIC slave verbinding. Is er iemand die eens een Slave verbinding heeft geprogrammeerd in Proton? En deze aan mij wil geven?
Ik heb al veel gelezen over de interrups en statusregister (SSPSTAT) en de SSPCON/SSPCON2 registers. Maar een goed programma hieruit filteren is een lastige klus.
Videomodulator
AKA Naftebakje @Tweakers.net --- Zonder dwarsliggers geen spoor
Meestal is een I2C slave niet voorzien in een PIC compiler, omdat een PIC doorgaans master is, en omdat een slave gemakkelijk te maken is met de ingebouwde hardware in je PIC.
Wat je moet doen is de datasheet goed lezen, met name het stuk over I2C, maak de juiste instellingen voor de slave en alles gaat vanzelf (vlagje hoog als er iets toekomt, en je kan gaan inlezen, netjes byte per byte). Heeft dus niets te zien met je compiler.
Zo ziet het eruit in ASM op een PIC16F88:
I2C
bcf PIR1,SSPIF ; interrupt I²C clearen
banksel SSPSTAT
movfw SSPSTAT ; sspstat in w steken
banksel SSPBUF
movwf I2CSTAT
; movf SSPBUF,W ; adres (zit in buffer) wissen
btfsc I2CSTAT,2 ; moet ik iets verzenden
goto I2Csend ; ga naar subroutine
movf SSPBUF,W ; adres (zit in buffer) wissen
IC0
banksel SSPSTAT
movfw SSPSTAT ; sspstat in w steken
banksel SSPBUF
movwf I2CSTAT
btfsc I2CSTAT,4 ; werd er laatst een stopbit ontvangen
goto uitvoeren ; voer de gevraagde actie uit
btfss PIR1,SSPIF ; byte ontvangen via I²C?
goto IC0
bcf PIR1,SSPIF ; interrupt I²C clearen
banksel SSPSTAT
movfw SSPSTAT ; sspstat in w steken
banksel SSPBUF
movwf I2CSTAT
movf SSPBUF,W ; ontvangen byte in W
movwf I2C0 ; ontvangen byte in I2C0
btfsc I2CSTAT,4 ; werd er laatst een stopbit ontvangen
goto uitvoeren ; voer de gevraagde actie uit
En dan nog voor de volgende bytes verder hetzelfde stukje herhalen (IC0), en dan uitvoeren wat moet uitgevoerd worden met de ontvangen data.
In je main-lus komt de verwijzing:
btfsc PIR1,SSPIF ; byte ontvangen via I²C?
call I2CBekijk het eens naast de datasheet, je komt er wel uit.
[Bericht gewijzigd door Videomodulator op ]
In iedergeval bedankt voor de reactie. De interrups die softwarematig gereset moeten worden wil ik eigenlijk in Proton programmeren. Het probleem is dat ik met dit programma het programmeren met PIC heb geleerd.
De code die ik van jou heb gekregen moet ik eerst goed op me laten inwerken omdat ik niet bekend ben met deze code.
Alvast een paar vraagjes:
Zodra ik in een programma zeg "variabele = SSPBUF" weet de I2C hardware van de slave dan dat deze is gelezen en cleared hij dan automatisch bit BF van SSPSTAT?
In de code lees ik een aantal keer SSPSTAT in w steken, wat betekend dat eigenlijk?
Is I2CSTAT een variabele?
Hier heb ik trouwens een stukje gepruts, in Proton.
Misschien zijn hier mijn denk fouten uit te halen.
Device 16F877A
Config HS_OSC , WDT_ON , PWRTE_ON , BODEN_OFF , LVP_OFF , CP_OFF , DEBUG_OFF
ALL_DIGITAL TRUE ;Alle ingangen digitaal (voor de toetsen)
Declare XTAL = 20
;LCD type
LCD_TYPE = TOSHIBA ;We gebruiken een Toshiba T6963 graphic LCD
;LCD interface pin assignments
Declare LCD_DTPORT = PORTD ;LCD's Data poort
Declare LCD_WRPIN = PORTE.2 ;LCD's WR line
Declare LCD_RDPIN = PORTE.1 ;LCD's RD line
Declare LCD_CEPIN = PORTE.0 ;LCD's CE line
Declare LCD_CDPIN = PORTA.5 ;LCD's CD line
Declare LCD_TEXT_HOME_ADDRESS = 0 ;Zie help
Declare LCD_COMMANDUS = 1000 ;zie help
;LCD characteristics
LCD_X_RES = 128 ;LCD's X Resolutie
LCD_Y_RES = 64 ;LCD's Y Resolutie
;I2C settings
SSPSTAT = %10000000
SSPCON = %00111110
SSPCON2 = %10000000
SSPADD = %10101000
' Alias pins
Symbol SCL = PORTC.3 ' I2C clock input
Symbol SDA = PORTC.4 ' I2C data input
' Define used register flags
Symbol SSPIF PIR1.3 ' SSP (I2C) interrupt flag
Symbol BF SSPSTAT.0 ' SSP (I2C) Buffer Full
Symbol i_Start SSPSTAT.3 ' SSP (I2C) Startconditie gedetecteerd
Symbol i_Stop SSPSTAT.4 ' SSP (I2C) Stopconditie gedetecteerd
Symbol R_W SSPSTAT.2 ' SSP (I2C) Read/Write
Symbol D_A SSPSTAT.5 ' SSP (I2C) Data/Address
Symbol CKP SSPCON.4 ' SSP (I2C) SCK Release Control
Symbol SSPEN SSPCON.5 ' SSP (I2C) Enable
Symbol SSPOV SSPCON.6 ' SSP (I2C) Receive Overflow Indicator
Symbol WCOL SSPCON.7 ' SSP (I2C) Write Collision Detect
' Allocate RAM
Dim Datain As Byte ' Data in
Dim Dataout As Byte ' Data out
Dim Teller As Byte ' Data out
Dim Test1 As Byte
Dim Test2 As Byte
Dim Test3 As Byte
Dim Test4 As Byte
Dim Test5 As Byte
Dim Test6 As Byte
Dim Test7 As Byte
TRISC = %11111111
DelayMS 500 ;LCD stabilisering
Cls
Clear
Test1 = SSPSTAT
Test2 = SSPCON
Test3 = SSPCON2
Test4 = SSPADD
Test5 = PIR1
Test6 = SSPIF
Test7 = SSPBUF
Print At 0,1, "SSPSTAT = ", BIN8 Test1
Print At 1,1, "SSPCON = ", BIN8 Test2
Print At 2,1, "SSPCON2 = ", BIN8 Test3
Print At 3,1, "SSPADD = ", BIN8 Test4
Print At 4,1, "Datain = ", Dec Datain
Print At 5,1, "SSPIF = ", BIN Test6
Print At 6,1, "SSPOV = ", BIN SSPOV
Print At 7,1, "SSPBUF = ", BIN8 Test7
While 1=1
If i_Start = 1 Then
SSPIF = 0
Cls
Print At 1,1, "Start gedetecteerd"
If SSPSTAT.0 = 0 And SSPOV = 0 Then
SSPBUF = Datain
Print At 2,1, BIN8 Datain
WCOL = 0
; end if
; IF sspstat.0 = 1 then
SSPBUF = Datain
SSPIF = 0
Print At 3,1, BIN8 Datain
End If
If i_Stop = 1 Then
SSPIF = 0
Print At 4,1, "Stop gedetecteerd"
End If
If SSPOV = 1 Then Clear SSPOV : Print At 6,1, "SSPOV error"
If WCOL = 1 Then Clear WCOL : Print At 7,1, "WCOL error"
End If
Wend
Videomodulator
AKA Naftebakje @Tweakers.net --- Zonder dwarsliggers geen spoor
Op 20 juli 2006 11:57:25 schreef RayOls:
In iedergeval bedankt voor de reactie. De interrups die softwarematig gereset moeten worden wil ik eigenlijk in Proton programmeren. Het probleem is dat ik met dit programma het programmeren met PIC heb geleerd.De code die ik van jou heb gekregen moet ik eerst goed op me laten inwerken omdat ik niet bekend ben met deze code.
Dat voorbeeldje is pure ASM (=assembly), de uitleg daarover vind je in de datasheet (35 instructie's, niet moeilijk toch). Assembly is de machinetaal zelf, met het assembly programma kan je exact de '1'en en '0'len bepalen die in het programmageheugen van de PIC gaan, alles wat gebeurt staat letterlijk en exact beschreven in de datasheet.
Alvast een paar vraagjes:
Zodra ik in een programma zeg "variabele = SSPBUF" weet de I2C hardware van de slave dan dat deze is gelezen en cleared hij dan automatisch bit BF van SSPSTAT?
Yep, door de buffer uit te lezen zet hij zichzelf automagisch klaar voor de volgende byte.
In de code lees ik een aantal keer SSPSTAT in w steken, wat betekend dat eigenlijk?
W is het werkregister van de PIC, een byte groot. De PIC processor kan maar rekenen met het werkregister en de instructie die toekomt (één regeltje ASM code), als je getal A wil optellen met getal B moet je eerst getal A in het werkregister steken, en dan de functie "tel wat in het werkregister zit op met getal B" uitvoeren, hij kan niet gewoon in een instructie getal A en getal B optellen.
Hier wordt het W register gebruikt om de byte SSPSTAT van een plaats (bank) in het geheugen naar een andere te krijgen (in I2CSTAT), zodat ik dan kan doen met I2CSTAT wat ik wil (die bank verplaatsen doet een assembler als proton voor je, dus daar moet je je gelukkig niets van aantrekken).
Is I2CSTAT een variabele?
Yep, zoals ik al hierboven vertel heeft het te maken met de banking. Het geheugen in de PIC waar de statusbits en byte's zitten, en waar de variabelen die je kan gebruiken zitten, is in 2 (bij kleine PIC's) of 4 stukken verdeeld. Als je in het ene stuk (bank) bezig bent, kan je niet aan de zaken in een andere bank. Mijn programma loopt in de ene bank, en SSPSTAT zit in de andere bank, dus kopieer ik SSPSTAT (via W, die in alle banks bereikbaar is) naar een eigen gekozen variabele I2CSTAT.
Nogmaals: die banking mag je vergeten, kijk gewoon naar de opbouw, en naar wat in de datasheet staat, 95% zal je begrijpen door alleen de datasheet te bekijken, die 5% vind je door ff te vergelijken met mijn voorbeeldje. De banksel instructie is om naar een ander bank te verplaatsen, die mag je gewoon negeren.
Op het eerste zicht zie ik dat je nog geen controle hebt of er gevraagd wordt om te zenden of ontvangen, je gaan uit van ontvangen, das een mogelijke fout die je bijna niet zal vinden (laatste bit van het adres is zenden of ontvangen). Ook hou je er geen rekening mee dat de eerste keer dat je SSPBUF uitleest, je het adres uitleest. Ook ga je er van uit dat er 2 bytes data komen, mag je niet doen want zo ga je al in de fout (eerste byte is adres, dan 2 bytes data die je verzend, 2e byte data doet em in de soep draaien) Maak gewoon een lusje dat zolang geen stopbit onvangen is, de data blijft ontvangen, en zo netjes aan het einde van de communicatie alles weer klaarzet.
En nog ff niet aan de TS: ik gebruik MikroBasic als compiler, dikwijls krijg ik slechte reacties als ik MikroBasic aanraad (Proton wordt veel meer gebruikt, daar krijg je direct hulp van op CO), maar ik zie hier wééral dat iemand die in de problemen zit met Proton, alleen van mij wat hulp krijgt, en al die proton adepten gezellig hun mondje dicht houden...jammer.
Ik ken proton niet, en ik heb geen zin om me erin te verdiepen, das lui van mij, I know.
Bedankt voor de moeite die je hierin hebt gestoken!!!!
Ik ga ermee aan de slag mocht ik nog een vraagje hebben post ik heb wel weer.
Om je een idee te geven over mijn programmeer vaardigheden. Ik ben een kleine 8 maanden bezig met de materie microcontrollers. Dus alle programma's die er zijn om deze te programmeren ken ik niet. Ik ben met Proton gestart omdat er een goede Nederlandse site bestaat die je vertrouwd maakt met microcontrollers en het programmeren daarvan. Dus ik ben geen promoter van deze software maar simpelweg een gebruiker, mocht je nog goede suggesties hebben voor andere software sta ik daar geheel voor open.
Alle datasheets ten spijt het lukt gewoon weg niet.
Mijn register instellingen zijn:
;I2C settings
SSPSTAT = %10000000 ; Slew rate control uit
SSPCON = %00110110 ; I2C aan - CKP aan - 0110 7-bit slave
SSPCON2 = %10000000 ; General call aan
SSPADD = %10101000 ; Slave adres (dec = 168)Met deze instellingen reageert hij nergens op. Zet ik SSPCON.4 = 1 dan reageert hij een beetje.
Op mijn LCD staat dan voortdurend:
SSPSTAT = 10010000
Datain = 255
SSPBUFF = 11111111
Op de I2C-master loopt de teller op de LCD gewoon vrolijk door.
Mijn programma listing:
GoTo Main ; Spring over subroutines en ga naar label Main
I2C_slave:
I2Cstat = SSPSTAT ; Stop SSPSTAT in een variabele
Print At 0,1, "SSPSTAT = ", BIN8 I2Cstat ; Print de SSPSTAT op een LCD
If SSPSTAT.5 = 0 And SSPIF = 1 Then ; Deze Byte bevat het SSPADD en staat in de Buffer
Buffer = SSPBUF ; Lees de buffer om BF te clearen
SSPIF = 0 ; Interrupt I2C-clearen
Print At 7,1, "SSPBUF = ", BIN8 Buffer ; Print de waarde naar een LCD
GoTo Main
End If
If SSPSTAT.5 = 1 And SSPSTAT.2 = 0 Then GoTo I2C_ontvangen ; In de buffer zit data + Ga naar Subroutine Ontvangen
If SSPSTAT.2 = 1 Then GoTo I2C_zenden ; Lees adres uit buffer en print op een LCD + Ga naar Subroutine Zenden
GoTo Main ; Ga terug naar Label Main
I2C_zenden:
Print At 4,1, "Datain = ", "Zenden???" ; Latere zorg nu eerst alleen data ontvangen
GoTo Main ; Alleen maar een controle dat het programma niet in deze label terecht komt
I2C_ontvangen:
I2Cstat = SSPSTAT ; Stop SSPSTAT in een variabele
Print At 0,1, "SSPSTAT = ", BIN8 I2Cstat ; Print de SSPSTAT op een LCD
If SSPSTAT.4 = 1 And SSPIF = 0 Then GoTo Main ; Is er een STOP bit ontvangen? Ja, ga dan terug naar Label Main
If SSPIF = 1 Then GoTo Uitvoeren ; Als de buffer een byte bevat ga naar Label Uitvoeren
Uitvoeren:
Datain = SSPBUF ; Lees de buffer uit en stop deze in de variable Datain
SSPIF = 0 ; Clear SSPIF
Print At 4,1, "Datain = ", Dec Datain ; Print de inhoud van variabele datain op een LCD
GoTo I2C_ontvangen ; Ga terug naar Label I2C_ontvangen
While 1=1 ; Oneindige programma lus
Main:
If SSPIF = 1 Then GoTo I2C_slave ; Als een data byte binnen komt ga naar Label I2C_slave
If SSPOV = 1 Then Clear SSPOV : Print At 6,1, "SSPOV error" ; Overflow error printen op een LCD + clear de error
If WCOL = 1 Then Clear WCOL : Print At 7,1, "WCOL error" ; Collision error printen op een LCD + clear de error
Wend