I vår tidigare handledning lärde vi oss att blinka en LED med PIC-mikrokontroller och byggde samma krets på Perf-kortet. Sedan använde vi PICkit 3, ICSP och MPLAB IPE för att dumpa programmet på vårt Perf-kort. Nu, i denna handledning kommer vi att utveckla oss till att använda fler stift på PIC-mikrokontrollern. Vi kommer att använda 7 utgångar (LED) och en ingång. För denna handledning använder vi det gamla Perf-kortet (visas nedan) och lägger till bergpinnar för att dra ut de nödvändiga stiften på det andra LED-kortet. I slutet av denna handledning kommer vi att generera en sekvens av blinkande lysdioder med PIC-mikrokontroller PIC16F877A och lära oss hur man använder flera in- och utgångar, några grunder för 'för' loop- och funktionsanrop.
LED-kortet är inget annat än ett annat perfekt kort, på vilket vi kommer att löda lysdioderna med en strömbegränsande motstånd (visas nedan). Vi lägger också till en tryckknapp för att starta sekvens-LED-lampan blinkar.
Kretsschema:
PIC Microcontroller PIC16F877A LED blinkande sekvenskod och arbetsförklaring:
Komplett kod har angivits nedan (kontrollera i slutet), här kommer vi att få det genom rad för rad. Den här koden börjar lysa lysdioderna i följd när du trycker på tryckknappen. För att förstå sekvenserna, se videon i slutet av självstudien. Jag skulle rekommendera dig att jämföra utdata som visas i video med koden nedan och försöka förstå programmet.
Låt oss titta på koden rad för rad. De första raderna är för att ställa in konfigurationsbitar som förklarades i föregående handledning så jag hoppar över dem för tillfället. Det bästa sättet att förstå något program är att börja från huvudfunktionen ( void main () ), så låt oss göra det
TRISB0 = 1; // Instruera MCU att PORTB-stift 0 används som ingång för knapp. TRISD = 0x00; // Instruera MCU att alla stift matas ut PORTD = 0x00; // Initiera alla stift till 0
Ordet TRIS används för att definiera om stiftet används som ingång / utgång och ordet PORT används för att göra en stift hög / låg. Linjen TRISB0 = 1 gör den 0: e stiftet i PORT B som ingång. Det här blir vår tryckknapp. Linjerna TRISD = 0x00; PORTD = 0x00; kommer att göra alla stiften i port D som utgång och tilldela ett initialt värde på LOW till dessa stift.
Eftersom vi sa att B0 används som ingång ansluter vi ena änden av tryckknappen till stiftet B0 och den andra änden till marken. När vi trycker på knappen hålls stiftet till marken som visas i anslutningsdiagrammet ovan. Men för att detta ska ske måste vi använda ett uppdragningsmotstånd så att stiftet hålls högt när knappen inte trycks in. Ett uppdragsmotstånd är ungefär så här.
Men vår PIC MCU har ett internt svagt uppdragningsmotstånd som kan aktiveras av programvara på det sättet vilket sparar mycket krångel (när fler knappar ska anslutas).
Vad är ett svagt uppdragningsmotstånd?
Det finns två typer av pull-up-motstånd, en är Weak Pull Up och en är Strong Pull Up. De svaga uppdragningsmotstånden är av högt värde och låter således en svag ström strömma igenom och de starka uppdragningsmotstånden har lågt värde, vilket gör att en stark ström kan strömma. Alla MCU använder mestadels svaga pull-up-motstånd. För att aktivera detta i vår PIC MCU måste vi titta på vårt datablad för OPTION_REG (alternativregister) som visas i ögonblicksbilden nedan.
Som visas handlar bit 7 om det svaga motståndet. Det bör göras noll för att aktivera det. Detta görs av OPTION_REG <7> = 0 . Detta handlar specifikt om biten 7 som lämnar de andra bitarna till dess standardvärden. Med detta kommer vi in i vår while-loop, där det kontrolleras om knappen trycks in med hjälp av if (RB0 == 0). Om villkoret är uppfyllt kallar vi vår funktion med parametrarna 1, 3, 7 och 15.
sblink (1); // FUNCTION CALL 1 med parameter 1 sblink (3); // FUNCTION CALL 3 med parameter 3 sblink (7); // FUNCTION CALL 7 med parameter 7 sblink (15); // FUNCTION CALL 4 med parameter 15
Varför använder vi funktioner?
Funktioner används för att minska antalet rader i vår kod. Det här är vad de flesta av oss skulle ha vetat. Men varför behöver vi minska antalet rader, särskilt när det gäller MCU-programmering. Den Anledningen är det begränsade utrymmet i vårt program minne. Om vi inte optimerar koden ordentligt kan vi ta slut på minnesutrymme. Detta kommer att vara till nytta när vi skriver långa sidor med koder.
Varje funktion har en funktionsdefinition ( sblink (int get) i vårt fall) och en funktion Call ( sblink (1) i vårt fall). Det är valfritt att ha en funktionsdeklaration, för att undvika det har jag lagt min funktionsdefinition innan jag anropade funktionen till min huvudfunktion.
Funktionsparametrar är det värde som överförs från funktionsanropet till funktionsdefinitionen. I vårt fall är helvärdena (1, 3, 7, 15) de parametrar som skickas från funktionsanropet och variabeln "get" får parametrarnas värde till funktionsdefinitionen för att bearbeta dem. En funktion kan ha mer än en parameter.
När funktionen väl har anropats kommer följande rader i funktionsdefinitionen att köras.
för (int i = 0; i <= 7 && RB0 == 0; i ++) {PORTD = get << i; // LED-rörelse Vänster sekvens __fördröjning_ms (50); } för (int i = 7; i> = 0 && RB0 == 0; i--) {PORTD = get << i; // LED-rörelse Vänster sekvens __fördröjning_ms (50); }
Nu verkar den här raden vara udda: PORTD = få << i . Jag kommer att förklara vad som faktiskt händer här.
"<<" är en vänsterskiftoperatör som flyttar alla bitar till sitt vänstra läge. Nu när vi kallar sblink (int get) -funktionen med parameter '1' som sblink (1), kommer den att göra värdet av 'get' som 1, vilket i binär är 0b00000001. Därför kommer denna linje att vara som PORTD = 0b00000001 << i .
Värdet på "i" varierar från 0 till 7 eftersom vi har använt en "for loop" för (int i = 0; i <= 7 && RB0 == 0; i ++). Värdet av att "i" är från 0 till 7 ändrar resultatet enligt följande:
Som du kan se har vi tänt en lysdiod i taget (från vänster till höger) genom att hålla resten AV. Nästa 'for loop' för (int i = 7; i> = 0 && RB0 == 0; i--) , kommer också att göra detsamma men den här gången tänds lysdioden från höger till vänster i en sekvens, när vi började från 7 och går ner till 0. Vi har använt en fördröjning på 200 ms så att vi kan visualisera att lysdioden slås PÅ och AV.
Nu när vi skickar värde 3 i sblink (int get) -funktionen så kommer funktionen sblink (3) att köras vilket gör värdet "get" till 0b00000011, följaktligen blir resultatet på PORTD:
Så nu den här gången kommer två lysdioder att tändas vid varje given tidpunkt med sblink (3). På samma sätt för sblink (7) och sblink (15) lyser tre och fyra lysdioder i en sekvens. När detta är klart kommer vi att göra att alla lysdioder tänds med linjen PORTD = 0xFF . Se videon nedan för fullständig demonstration.
Hoppas att du har förstått koden och därmed har lärt dig hur man använder funktioner 'för' och 'samtidigt' för att få önskade utgångar. Nu kan du justera runt koden för att få din olika LED-sekvens att blinka. Fortsätt kompilera din kod och dumpa den på din MCU och njut av utdata. Du kan använda kommentarsektionen om du fastnar någonstans. Jag har också bifogat simulerings- och programfilerna här.
Det är det för tillfället i vår nästa handledning lär vi oss hur man använder PIC16F877A-timers istället för att använda fördröjningsfunktioner. Du kan bläddra bland alla PIC-mikrokontrollerhandledningarna här.