IR spårning torn med PIC och C (6 / 9 steg)
Steg 6: programmering
Kodning för detta är ganska enkel. Det finns bara fyra metoder för att skriva. Vi får alla förhandlingar I2C signal från I2C biblioteket vi ska generera med mikrochip kod konfiguratorn.
- initWiiCam(); Behövs endast en gång du konfigurerar kameran
- readWiiCam(); Ber kameran för ställning av fyren
- updatePan(); Uppdaterar pannan om krävs att centrera fyren på X-axeln
- updateTilt(); Uppdaterar tilt om krävs att centrera fyren på Y-axeln
Installera MPLABX
Så låt oss komma igång. Första, data överför och installera MPLABX från Microchip: http://www.microchip.com/pagehandler/en-us/family/...
Skapa ett projekt
När installationen är klar startar upp och gå till Arkiv > nytt projekt
Detta tar dig genom en guide för att konfigurera våra projekt.
- Välj projekt
- Kategorier: Mikrochip inbäddade
- Projekt: Fristående projekt
- Välj enhet
- Familj: Mellanklass 8-bitars MCU (PIC12/16/MCP)
- Enhet: PIC16F1503
- Välj rubrik
- -Header: Ingen (eller AC244051 * om du har det och vill använda den)
* Om du använder ett debug huvud, du har att bygga projektet för felsökning för att programmera huvudet
- -Header: Ingen (eller AC244051 * om du har det och vill använda den)
- Välj verktyget
- PICkit3 eller kompatibla verktyg
- Välj kompilatorn
- XC8
- Välj projekt och mapp
- Namn: vad du vill (ex. IR_Tracking_Turret)
- Mapp: standard
- Kodning: ISO-8859-1
- Plats: standard
Okej, projektet skapat. Nu låt oss generera några källfiler.
Mikrochip kod konfiguratorn (MCC)
Detta är ett trevligt verktyg i MPLABX som låter dig välja och konfigurera kringutrustning som timers, PWM generatorer och I2C kommunikation. När projektet har skapats gå till Redskapen > Embedded > mikrochip koden Configuratior
En skärm kommer med pinut av chip och pin uppdrag på den högra, och markerade och tillgängliga kringutrustningen till vänster. I han övre center blir en [generera kod] knappen. Att klicka på den kommer att generera koden och konfiguration som du väljer i MCC. Eftersom det finns inga källkodsfiler ännu, MCC kommer att be om du vill generera en main.c-fil - Klicka på Ja. Vi kommer att behöva följande kringutrustningsenheter konfigurerats för vårt program:
- TMR1 - 16-bitars timer
- TMR2 - 8-bitars timer
- PWM2 - PWM ute på stift 7
- PWM3 - PWM ute på stift 11
- MSSP - I2C Master, SDA på stift 9, SCL på stift 10
I listan längst ned till höger, hitta och dubbelklicka på den ovanstående kringutrustningen att lägga till den i listan över valda kringutrustning i det övre vänstern. När du har fått dem alla, låt oss skapa några perifera stöd kod.
Systemet
- Systemet klocka Välj: INTOSC
- Välj frekvens > interna klocka: 16MHz_HF
- CONFIG1 > MCLR Pin funktion Välj [MCLRE OFF]
TMR1
- Klocka Källa: FOSC/4
- Prescaler: 1:8 Timer
- Period: 100ms
- Aktivera avbrott: kontrollera
- Callback-funktionen Rate: 30 x (3s) - timeout för åter centrering tornet
TMR2
- Prescaler: 1: 64
- Timer Period: 4ms
- Starta TImer efter initiering: kontrollera
- Aktivera timern avbrott: kontrollera
- Callback-funktionen Rate: 5 x (20ms) - för att driva servon, de flesta servon kommer också att arbeta med en 12ms.
PWM2, PWM3
- Aktiverar PWM: kontrollera
- Aktiverar Pin PWM-utgång: kontrollera
- PWM polaritet: Inverterad (period 4ms)
MSSP::I2C
- MASTER aktivera I2C: kollade
- Aktiverar SM Bus Output: kollade
- Slew Rate reglaget: Hög hastighet SDA
- Håll tid: 100ns
- I2C klockfrekvens: 400KHz
- Slavadress: 7-bitars
- Storlek på läsbuffert: 10 - beroende på hur många byte som du förväntar dig tillbaka från enheten du pratar med, i detta fall enklaste konfiguration, Pixart camerawill tillbaka 10 byte.
- Skriv buffertstorlek: 2 - vi kommer att tala till Pixart kameran 2 byte i taget.
Att lägga till din egen kod
Nu mest av koden för projektet skapas, men vi har fortfarande att förklara vissa konstanter och variabler och lägga till lite extra kod, inklusive fyra metoderna som nämns ovan.
Main.c
Hitta raden:
/*
Huvudprogrammet
*/
Lägg till följande kod under den
#define SLAVE_I2C_GENERIC_RETRY_MAX 100
I2C_MESSAGE_STATUS status = I2C_MESSAGE_PENDING;
Initieringsinställningar för Wii IR-kamera
statisk const uint8_t wiiCameraAddress = 0x58;
statisk const uint8_t wiiCameraReadCmd = 0x37;
< p > statisk const uint8_t wiiCamInitData [14] [2] = {{0x30, 0x01},
/ * Känslighet config Block A * /
{0x00, 0x00}, {0x01, 0x00}, {0x02, 0x00}, {0x03, 0x00}, {0x04, 0x00}, {0x05, 0x00},
{0x06, 0x90}, / / p0: MAXSIZE: maximal storlek för blob. Wii använder värden från 0x62 till 0xc8
{0x07, 0x00},
{0x08, 0x41}, / / p1: få: Sensor få. Mindre värden = högre vinst
/ * Känslighet config Block B * /
{0x1A, 0x40}, / / p2: GAINLIMIT: Sensor få gräns. Måste vara mindre än vinst för kameran att fungera.
{0x1B, 0x00}, / / p3: MINSTORLEK: Minimum blob storlek. Wii använder värden från 3 till 5 < /p >< p > / * läge config * /
{0x33, 0x01}, / / läge: 1 = basic, 3 = extended, 5 = full
{0x30, 0x08}}; < /p >
uint16_t DcPan = 630;
uint16_t DcTilt = 630;
uint8_t skrivbuffert [2], cmdBuffer [1], läsbuffert [10].
uint8_t * i2cData;
uint16_t b1x, b1y;
void initWiiCam(void) {
för (int cnt = 0; cnt < 14; cnt ++) {
i2cData = (uint8_t *) & wiiCamInitData [cnt];
för (int jag = 0; jag < 2; i ++) skrivbuffert [i] = 0;
skrivbuffert [0] = * i2cData ++;
skrivbuffert [1] = * i2cData ++;
I2C_MasterWrite (skrivbuffert, 2, wiiCameraAddress & status);
medan (status == I2C_MESSAGE_PENDING);
}
}
void readWiiCam (void) {
Läs Wii Kameradata
i2cData = (uint8_t *) & wiiCameraReadCmd; initiera datakällan
cmdBuffer [0] = 0;
cmdBuffer [0] = * i2cData ++;
I2C_MasterWrite (cmdBuffer, 1, wiiCameraAddress & status);
vänta tills meddelandet ska skickas eller status har ändrats.
medan (status == I2C_MESSAGE_PENDING);
__delay_ms(3);
för (int jag = 0; jag < 10; i ++) läsbuffert [i] = 0x00;
i2cData = (uint8_t *) & läsbuffert;
I2C_MasterRead (i2cData, 10, wiiCameraAddress & status);
medan (status == I2C_MESSAGE_PENDING);
om (läsbuffert [0]! = 0xFF & & läsbuffert [0]! = 0x00) {
b1x = ((läsbuffert [2] & 0x30) << 4) + läsbuffert [0];
b1y = ((läsbuffert [2] & 0xC0) << 2) + läsbuffert [1].
TMR1_CallBackReset();
}
annat {
b1x = 0x00;
b1y = 0x00;
}
}
void updatePan(void) {
Justera pan och tilt servon
om ((b1x == 0x00) || (b1x == 0xFF)) hemkomst.
om (b1x > 522) DcPan += (b1x-522)/(20*3);
om (b1x < 502) DcPan-= (502-b1x)/(20*3);
om (DcPan > 875) DcPan = 875;
om (DcPan < 375) DcPan = 375;
PWM2DCH = DcPan >> 2.
PWM2DCL = DcPan << 6.
}
void updateTilt(void) {
om ((b1y == 0x00) || (b1y == 0xFF)) hemkomst.
om (b1y > 394) DcTilt-= (b1y-394)/(20*3);
om (b1y < 374) DcTilt += (374-b1y)/(20*3);
om (DcTilt > 875) DcTilt = 875;
om (DcTilt < 375) DcTilt = 375;
PWM3DCH = DcTilt >> 2.
PWM3DCL = DcTilt << 6.
}
Aktivera avbrott och lägga till följande kod i den huvudsakliga funktionen:
void main(void) {
initiera enheten
SYSTEM_Initialize();
Aktivera Global avbrotten
När du använder avbrott, måste du ange de globala och perifera avbryta aktiverar bits
Använda de följande makrona till:
INTERRUPT_GlobalInterruptEnable();
Aktivera perifera avbrotten
INTERRUPT_PeripheralInterruptEnable();
Inaktivera de globala avbryter
INTERRUPT_GlobalInterruptDisable();
Inaktivera perifera avbrotten
INTERRUPT_PeripheralInterruptDisable();
initWiiCam();
__delay_ms(10);
samtidigt (1) {
readWiiCam();
updatePan();
updateTilt();
__delay_ms(10); }
}
/ ** Filslut * /
tmr2.c
Servon använder en.5 till 2,5 ms puls en 20ms period för att bestämma deras målpositionen. Vår konfigurationen ger TImer2 en 4ms period, vilket är bra för att ge oss en hel del precision inom denna period, men för kort för servo användning. Så använder vi en motringning som körs varje 5: e gången Timer2 flödar över. Vi hålla PWM avaktiverad tills det 5: e passet, vilket ger oss en 20ms period med en högre precision puls längd. Detta ger oss smidigare rörelser i spårning och bättre svar på små rörelser. Gå ner till funktionerna avbryta tjänsten rutin (ISR) och motringning och redigera dem att se ut enligt följande.
void TMR2_ISR(void) {
statiska volatile unsigned int CountCallBack = 0; < br > / / Rensa flaggan TMR2 avbrott
PIR1bits.TMR2IF = 0;
TRISCbits.TRISC5=1;
TRISAbits.TRISA2=1;
TRISCbits.TRISC3=1;
callback-funktionen - kallas varje 5: e pass
om (++ CountCallBack > = TMR2_INTERRUPT_TICKER_FACTOR) {
ticker funktionsanrop
TMR2_CallBack();
Återställ räknaren för ticker
CountCallBack = 0;
}
Lägg till din TMR2 avbrott anpassad kod
}
void TMR2_CallBack(void) {
Lägg till din anpassade callback kod här
denna kod körs varje TMR2_INTERRUPT_TICKER_FACTOR perioder av TMR2
TRISCbits.TRISC5=0;
TRISAbits.TRISA2=0;
TRISCbits.TRISC3=0;
}
tmr1.c
Jag har precis lagt detta till centrera av tornet om det inte ser någonting i 3 sekunder. Vi måste deklarera variabeln CountCallBack som globala. Hitta raden:
flyktiga uint16_t timer1ReloadVal;
Lägg till ths rad under den:
flyktiga unsigned int CountCallBack = 0;
Gå nu ner till avbryta tjänsten rutin (ISR) och Callback funktioner och redigera dem att se ut enligt följande.
void TMR1_ISR(void) {
statiska volatile unsigned int CountCallBack = 0;
Avmarkera flaggan TMR1 avbrott
PIR1bits.TMR1IF = 0;
TMR1 += timer1ReloadVal;
callback-funktionen - kallas varje 30 pass
om (++ CountCallBack > = TMR1_INTERRUPT_TICKER_FACTOR) {
ticker funktionsanrop
TMR1_CallBack();
Återställ räknaren för ticker
CountCallBack = 0;
}
Lägg till din TMR1 avbrott anpassad kod
}
void TMR1_CallBack(void) {
Lägg till din anpassade callback kod här
CONST uint16_t DcTiltReset = 630;
CONST uint16_t DcPanReset = 630;
PWM3DCH = DcTiltReset >> 2.
PWM3DCL = DcTiltReset << 6.
PWM2DCH = DcPanReset >> 2.
PWM2DCL = DcPanReset << 6.
}
tmr1.h
Hitta raden
void TMR1_CallBack(void);
Lägg till följande rad under den
void TMR1_CallBackReset(void);
Nu all kod är på plats och w kan bygga och programmera enheten.
Rengör och bygga projektet, sedan Make och Program enheten. PIC är redo att kontakten i uttaget på PCB.