Sida 1 av 1
Open collector I/O på PIC.
Postat: 25 oktober 2006, 13:43:36
av GoAmiga
Hej!
Har lite problem med att få en open collector utgång att fungera. Jag tänker bara dra upp hur jag gör i teorin och vill veta om det finns några minor man kan springa på, för jag tror att jag gjort det
Det jag ska göra är att skicka en byte seriellt på open collector vis. När jag vill ha en HÖG nivå sätter jag PIC's aktuella I/O till ingång . När jag vill ha den låg så gör jag den till utgång (och har dess för innan satt GPIO för pinnen till LÅG)
typ så här...
(Jag förutsätter att SYSDATA initialt är ingång)
Kod: Markera allt
bcf GPIO,SYSDATA ;I/O pinnen till låg
bsf STATUS,RP0 ;Bank1
bcf TRISA,SYSDATA ; SYSDATA utgång (Låg)
call WAIT
bsf TRISA,SYSDATA ;SYSDATA Ingång (Hög)
call WAIT
bcf TRISA,SYSDATA ; SYSDATA utgång (Låg)
bcf STATUS,RP0 ;Bank0
vilket borde ge Låg, Hög, Låg....
I min "riktiga" kod så växlar jag mycket mer mellan bankerna eftersom jag har lagt vissa intressanta variabler i bank0. Kan detta ge mycket bekymmer? Finns det något smart sätt att lösa det så man slipper swappa mellan bankerna?
Jag använder en gammal 12c672. (Snälla ifrågasätt inte varför)
Postat: 25 oktober 2006, 14:27:10
av Pjoms
> "Jag använder en gammal 12c672. (Snälla ifrågasätt inte varför)"
Varför använder du en gammal 12c672?
Sorry, kunde inte hålla mig...

Postat: 25 oktober 2006, 15:31:47
av sodjan
Hur är "SYSDATA" definierat. Du har missat att visa det...
Du har en pullup på "linjen" ?
> så man slipper swappa mellan bankerna?
Och vad är problemet med just *det* ???
Att du kör en gammal utgången "C" processor är ett större problem...
> vilket borde ge Låg, Hög, Låg....
Och vad händer ???
Postat: 25 oktober 2006, 17:55:44
av Chribbe76
För att sänka en pinne måste du först sätta tris till utgång, sen lägga 0 på pinnen.
Problemet är att pinnen har gemensamt register för utgång och ingång så tillståndet utgång låg glöms bort när du ändrar till ingång.
Picar med LAT på portarna har olika register för utgång och ingång och blir då enklare att köra open collector med.
[EDIT]
Hmm... När man byter till utgång och pinnen är hög blir det ju kortslutning om någon gör utgång låg samtidigt.
Då går det alltså inte att köra open collector på ett korrekt sätt med en pic utan LAT.
Har jag rätt? Nu känner jag mig lite osäker.
Postat: 25 oktober 2006, 18:25:02
av sodjan
> För att sänka en pinne måste du först sätta tris till utgång, sen lägga 0 på pinnen.
Helt fel ordning.
> När man byter till utgång och pinnen är hög
Den ska *aldrig* vara hög när pinnen är utgång.
> Då går det alltså inte att köra open collector på ett korrekt sätt med en pic utan LAT.
Jodå...

Postat: 25 oktober 2006, 18:34:08
av Chribbe76
Är detta förfarande korrekt sodjan?
* Pinnen är utgång låg.
* Pinnen ändras till ingång och pinnen blir 1 av pullup.
* Pinnen ändras till utgång och kommer bli utgång hög eftersom den var 1 innan.
Postat: 25 oktober 2006, 18:35:45
av persika
Läser denna tråd med intresse eftersom det är nästan samma som jag frågade om igår, se tråd "PIC IO ?"
Vad är LAT för någonting ?
Postat: 25 oktober 2006, 18:52:28
av Chribbe76
Är det så att portens värde bara ändras av att man läser av porten eller skriver till den?
Isf kan man skriva till porten när den är ingång och byta till utgång så får man rätt tillstånd direkt.
Det måste vara så det fungerar, det verkar vettigt.
LAT är ett register som innehåller tillståndet för utgången även om man har använt pinnen som ingång.
Om man inte har LAT så måste man lägga 0 på porten innan varje byte till utgång om man har läst av porten när den var ingång.
[EDIT] ändrade till utgång, lite trött idag
Postat: 25 oktober 2006, 18:57:40
av persika
Vad betyder LAT ?
Postat: 25 oktober 2006, 19:07:47
av JimmyAndersson
LAT betyder att man inte orkar läsa databladet och kolla.
Men ok, LAT betyder Data Latch.

Postat: 25 oktober 2006, 20:39:05
av sodjan
> Är detta förfarande korrekt sodjan?
*Detta* är korrekt :
- Pinnen är utgång och låg.
- Pinnen sätts till ingång och "lyfts" till hög av pullup.
- En operation utförs som medför att GPIO (eller PORTx på en större PIC)
läses och återskrivs (Read-Modify-Write, eller RMW). Pinnen kommer att
läsas som hög och sättas som hög i GPIO (eller PORTx i en störe PIC).
- Pinnen sätts som utgång och kommer nu att "driva" pinnen hög...
Utan punkt 3 ovan händer ingenting...
> Är det så att portens värde bara ändras av att man läser av porten eller skriver till den?
*ALLA* operationer som skriver till ett register (behöver inte vara en *port*)
innebär att det först läses, sedan modifieras, slutningen skrivs tillbaka.
Det är klart att för instruktioner som hanterar *hela* registeret (CLRF,
MOVWF, INCF eller liknande) så är det ingen problem. Det är speciellt
BCF/BSF som medför RMW problem om man inte ser upp.
Lösningen är att hålla reda på "läget" på de pinnar som man vill
hantera på detta sätt någon annanstans än enbart i GPIO/PORTx.
Och sedan justera GPIO/PORTx precis innan man ändrar TRISIO/TRISx
LAT är (förrutom Jimmys helt korrekta förklaring) ett extra register i PIC18
serien som gör att man i princip inte har RMW problemet med dessa.
Om man har mycket "pin-wiggling" i sin kod, så är PIC18 betydligt
smidigare p.g.a detta.
Postat: 26 oktober 2006, 14:08:45
av GoAmiga
Hej!
Finns det någon del i denna kod där man enkelt kan visa på att
här uppstår det ett fel. Ni behöver inte rätta till den i helhet men visa på var
jag får problem med att portarna ändras utan att jag "vill"
Kod: Markera allt
SEND_KEY
bcf GPIO,SYSDATA ;Sätter SYSDATA LÅG
bcf GPIO,SYSCLK ;Sätter SYSCLK LÅG
bsf STATUS,RP0 ;Bank1
bcf TRISA,SYSDATA ;Data Går först låg (startbit)
NEXT_SEND_BIT
bsf STATUS,RP0 ;Behövs då vi hoppar till "NEXT_SEND_BIT" längre ner i koden.
call WAIT20
bcf TRISA,SYSCLK ; CLK går låg för att klocka ut startbiten.
call WAIT12
bsf TRISA,SYSCLK ; CLK går hög
bcf STATUS,RP0 ;Bank0 , där ligger SENDW varablen
rrf SENDW,f ; Rotera värdet i SENDW genom carry
btfss STATUS,C ;Var biten 1 eller 0?
goto LOW_S
goto HIGH_S
LOW_S
bsf STATUS,RP0 ;Bank1
bcf TRISA,SYSDATA
goto SEND_END
HIGH_S
bsf STATUS,RP0 ;Bank1
bsf TRISA,SYSDATA
SEND_END
bcf STATUS,RP0 ;Bank0, Där COUNT varabel ligger.
decfsz COUNT,f
goto NEXT_SEND_BIT
rrf SENDW,f ;rotera Datat så det hamnar "rätt"
bsf STATUS,RP0
call WAIT20
bcf TRISA,SYSCLK
call WAIT12
bsf TRISA,SYSCLK
Postat: 26 oktober 2006, 18:47:23
av sodjan
Definitioner till SYSDATA och SYSCLK ?
Använd inte "egna" symboler utan att även visa att du har definierat dom rätt.
Använd gärna BANKSEL istället för BCF/BSF direkt på bank-bitarna.
Det blir mindre risk för (slarv-) fel. Därmed inte sagt att det är fel
i din kod, det vet jag inte (och jag tänker inte slå upp varje register
i data bladet för att kolla, kör med BANKSEL så slipper man det...)
(1) bcf GPIO,SYSDATA ;Sätter SYSDATA LÅG
(2) bcf GPIO,SYSCLK ;Sätter SYSCLK LÅG
(3) bsf STATUS,RP0 ;Bank1
(4) bcf TRISA,SYSDATA ;Data Går först låg (startbit)
Här har du precis det som har beskrivits i tidigare inlägg.
Jag utgår från att de "linjer" som båda SYSDATA och SYSCLK är kopplade
till har externa pullup motstånd ?
Förutsättning är att SYSDATA är ingång innan SEND_KEY...
I (1) sätts biten som SYSDATA pekar i GPIO låg.
I (2) sätts biten som SYSCLK pekar i GPIO låg.
*Samtidigt* kommer biten som sattes låg i (1), d.v.s SYSDATA, att
sättas hög igen eftersom *pinnen* hålls hög av pullup motståndet.
RMW fenomenet alltså!
I (4) sätts SYSDATA till utgång och *hög* !!
O.s.v....
Läs tidigare inlägg igen...
EDIT : Blandade ihop DATA och CLK lite...
Postat: 26 oktober 2006, 19:55:20
av GoAmiga
Ok, då börjar jag förstå. Ursäkta för min tröghet och tack för ditt tålamod

Postat: 26 oktober 2006, 21:16:30
av sodjan
Kanske detta skulle fungera bättre :
Kod: Markera allt
bcf GPIO,SYSDATA ;Sätter SYSDATA LÅG
banksel trisa
bcf TRISA,SYSDATA ;Data Går först låg (startbit)
banksel gpio
bcf GPIO,SYSCLK ;Sätter SYSCLK LÅG
D.v.s att SYSDATA är *utgång* när SYSCLK sätts låg.
Då drivs DATA-linjen låg av SYSDATA, och den kommer alltså
att läsas "låg" när SYSCLK läses (i BCF instruktionens read-fas).
Beroende på hur snabt du kör processorn och hur mycket
capacitiv last DATA linjen har, så skulle jag sätta in en eller två
NOP för att säkerställa att DATA linjen hinner byta läge...
I resten av koden ser jag inte att du har just RMW fenomenet.
Men den kanske inte fungerar ändå...
