Sida 2 av 2
Re: Skriva till portregistret på en PIC
Postat: 30 september 2016, 22:20:33
av lillahuset
Grubbla inte för mycket. Alla pinnar som är definierade (via TRIS) som utgångar påverkas av skrivning. Pinnar som är definierade (via TRIS) som ingångar påverkas inte av skrivning.
Sätt dig ner och studera schemat så kommer du att komma till klarhet.
Re: Skriva till portregistret på en PIC
Postat: 30 september 2016, 22:33:12
av Mr Andersson
> PORTC &= ~(0b01110111);, är inte det här exakt samma sak som att direkt skriva PORTC &= 0b10001000);, dvs man inverterar samtliga bitar?
> Sen tycker jag det här var klurigt: PORTC &= !(0b01110111);. Hur blir det egentligen? Blir det inte logiskt samma som ovan? Dvs man inverterar alla bitar? Väldigt intressant det här!
~ är bitvis NOT, dvs invertering. Helt rätt där.
! är logisk NOT. 0 blir 1, allt annat blir 0. Notera att vi pratar heltal här och inte individuella bitar. PORTC &= !(0b01110111); är samma sak som PORTC &= 0;
Re: Skriva till portregistret på en PIC
Postat: 2 oktober 2016, 00:39:17
av Magnus_K
Ahaaa, då hänger jag med. Tack för det
Mr Andersson 
Re: Skriva till portregistret på en PIC
Postat: 2 oktober 2016, 09:22:22
av TomasL
När det gäller IO-portar och att hantera individuella bitar, så skall man vara medveten om RMW problemet.
Man kan väldigt lätt få konstigheter annars.
Bästa sättet att hantera det är att använda ett "skuggregister", manipulera det och sedan kopiera hela "skuggregistret" till porten.
Dock om man använder de avsedda makrona för att skriva till portarna, så skapas "skuggregistren" per automatik.
Re: Skriva till portregistret på en PIC
Postat: 2 oktober 2016, 11:39:24
av TomasL
Och nu kommer lite förklaringar.
Man skall aldrig manipulera en IO-port direkt.
Generellt gäller:
Man skall bara läsa en PORT, skrivning och manipulation skall alltid gå via LAT om det finns eller via skuggregister.
Orsaken är, om man skall sätta enskilda bitar på en port, så kommer det att utföras en RMW instruktion, det är inte absolut säkert att man läser tillbaka det man tror att man skall läsa. Detta eftersom man läser av spänningsnivåerna på portpinnarna och under vissa förutsättningar så kan spänningen på portpinnarna vara för låga för att registrera en etta.
Ponera följande:
Vid en tidigare skrivning så har man satt pinnarna enligt följande 10101010.
Dock så är det av någon anledning så att exvis utgången för bit3 belastas hårt, vilket gör att spänningen på portpinnen faller under gränsen för att tolkas som en etta.
Nu vill man sätta bit 6 till en etta, vad som händer då är att porten läses tillbaka biten manipuleras och det hela skrivs tillbaka till porten.
Men, eftersom bit 3 är hårt belastad så kommer man att läsa tillbaka 10100010 i stället för det avsedda 10101010, och när då slutresultatet blir skrivet till porten blir det 11100010 i stället för det man trodde sig ha 11101010.
Detta fenomen kan också uppstå om man har en kapacitiv last på portpinnen
För att råda bot på detta skriver man till LAT-registren i stället, och om de inte finns till ett skuggregister vilket sedan i sin helhet skrivs till porten.
Så för att skriva till en port använder man:
LATA &= ~BITFIELD;
LATA |= BITFIELD;
eller
portAShadow&= ~BITFIELD;
portAShadow|= BITFIELD;
PORTA = portAShadow;
Re: Skriva till portregistret på en PIC
Postat: 2 oktober 2016, 14:57:35
av ecenier
Tack TomasL. Mycket bra beskrivet!
Sent using Tapatalk
Re: Skriva till portregistret på en PIC
Postat: 2 oktober 2016, 20:04:56
av Magnus_K
Ja, bra beskrivning och tror faktiskt det har varit på tal tidigare
TomasL skrev:Dock om man använder de avsedda makrona för att skriva till portarna, så skapas "skuggregistren" per automatik.
Vilka är dom avsedda makrona?
Sen hittar jag varken något om LAT eller shadow i databladet för 16F690 så där kanske man inte kan göra så mycket mer än att skriva direkt till PORT-registren?
Re: Skriva till portregistret på en PIC
Postat: 2 oktober 2016, 20:18:07
av lillahuset
Skapa bara en variabel för porten, typ mk_porta och gör operationen på den och kopiera sedan till porten.
Re: Skriva till portregistret på en PIC
Postat: 2 oktober 2016, 20:20:29
av Magnus_K
Ah, då förstår jag, tack!

Re: Skriva till portregistret på en PIC
Postat: 2 oktober 2016, 21:27:12
av sodjan
> Sen hittar jag varken något om LAT eller shadow i databladet för 16F690...
LAT är internt i F690 (inte synligt från programkoden).
"Shadow" är bara ett begrepp för ett temporärt register som man
gör bitoperationer till och sen skriver hela till PORT registret...
Hur som helst, inget av detta har egentligen något direkt med din
ursprungliga fråga att göra. Svaret på det har du fått, det är inget
problem att skriva till hela PORT registret även om några pinnar
är satta som ingångar.
Re: Skriva till portregistret på en PIC
Postat: 2 oktober 2016, 21:32:10
av lillahuset
Just det.
Re: Skriva till portregistret på en PIC
Postat: 2 oktober 2016, 22:37:38
av baron3d
En bra regel är att bara läsa och skriva till IO endast en gång.
T.ex.
Kod: Markera allt
int main(void) {
unsigned char in_uc;
unsigned char ut_uc;
while(1) {
in_uc = PortB; // läs ingångar
// diverse kod
PortC = ut_uc; // skriv till utgångar
}
}
Re: Skriva till portregistret på en PIC
Postat: 2 oktober 2016, 23:39:48
av Magnus_K
Är inte det så en PLC jobbar? Läs alla ingångar, modifiera, skriv alla utgångar?
Re: Skriva till portregistret på en PIC
Postat: 2 oktober 2016, 23:44:46
av sodjan
Så kan det nog vara, det ger en bättre "sync" mellan olika
utgångar, och alla ingångar läses av vid samma tidpunkt.
Kan minska risken för olika "race conditions".
Re: Skriva till portregistret på en PIC
Postat: 3 oktober 2016, 07:31:55
av TomasL
Magnus_K skrev:Vilka är dom avsedda makrona?
Sen hittar jag varken något om LAT eller shadow i databladet för 16F690 så där kanske man inte kan göra så mycket mer än att skriva direkt till PORT-registren?
Makrona är de som är beskrivna i ditt IDE, för PIC32 är det till exempel:
PORTSetBits(IOPORT_A, BIT_2 | BIT_4);
Du hittar dessa i hjälpen under PLIB troligen.
EN del processorer saknar LAT-registren, uppenbarligen är din processor en av dem. och då får du använda shadow-register i stället, dvs en variabel som du skapar.
En fördel med att bara skriva/läsa portarna på specifika platser är för att det är lättare att ha kontroll på det också.
Så, för att sammanfatta;
Skapa x antal variabler för de portar som fungerar som ingångar.
Om bara delar av en port används som ingång, skapa en mask för dessa, till exempel :
#define PORTA_INPUTMASK 0x1111000 // bit 4 till 7 används som ingångar.
När du läst av porten kan du maska bort de pinnar om är utgångar genom att "OCHa" det inlästa värdet med masken, blir lite tydligare då.
Skapa en funktion som läser ingångarna, denna funktion skall bara läsa och eventuellt hantera avstudsning.
Skapa x antal variabler för dina utgångar, samma här skapa en mask för de pinnar som används, i masken skall utgångarna vara ettor.
skapa en funktion som skriver till dina portar efter avmaskning..
Dessa två funktioner anropar du nu från ditt programs huvudloop, till exempel:
ReadPorts(); i början av loopen,
och
WritePorts(); i slutet av loopen.
Ett annat tips, vilket inte har ett dugg att göra med ämnet.
Om du använder PIC32, så deklarera lokala räknarvariabler som "register uint32", då läggs de i ett av CPUns register i stället för i RAM, går mycket fortare och du sparar lite RAM.