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.

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    I2C

Bekijk 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

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