Stap 2: Software
Deze stap zal gaan door elk onderdeel van de software en uitleggen wat het doet. Als u geen belang hebben bij de aanpassing van de software en wil gewoon om te bouwen van het ding, kan je op naar de volgende stap. Het hex bestand zal het project werken zoals ontworpen.
Fundamentele configureation van chip periferials
#pragma config OSC = INTIO2, WDT = OFF, LVP = OFF
#include < p18f1320.h >
Dit stelt de oscillator op interne en laadt de instellingen voor de 18F1320, als u wilt gebruiken een andere pic die dit is een van de belangrijkste dingen die u moet wijzigen
Setup pinnen PWM invoerfilter
#define ReceiverPin PORTBbits.RB3
#define ReceiverTris TRISBbits.TRISB3
Dit is gewoon een naam geven aan de pin voor de ontvangst van het signaal, dus het is duidelijker om te verwijzen naar.
PWM vangen variabelen
unsigned int PWM1RiseTime = 0; timer waarde aan stijgende rand vastleggen
unsigned int PWM1FallTime = 0; timer waarde bij dalende rand beleg
unsigned int PWM1Width = 0; berekende breedte
unsigned int CH1_width = 0;
unsigned int CH2_width = 0;
unsigned int CH3_width = 0;
unsigned int PWMGap = 0; berekende kloof tussen pulsen
char PWM1Edge = 1; rand 1 momenteel wordt gecontroleerd = stijgende, 0 = vallen
knop variabelen
unsigned char button_1_debounce_wait = 0;
Aangezien het PWM-signaal van de ontvanger communiceert door verzendende pulsen van wisselende breedte variabelen verklaard deze breedtes houden zodra ze worden berekend.
unsigned char calibration_mode = 0;
#define mode_operate 0
#define mode_CH1_high 1
#define mode_CH1_med 2
#define mode_CH1_low 3
#define mode_CH2_high 4
#define mode_CH2_med 5
#define mode_CH2_low 6
unsigned int limit_CH1_high = 2381;
unsigned int limit_CH1_med = 3307;
unsigned int limit_CH1_low = 4286;
unsigned int limit_CH2_high = 2022;
unsigned int limit_CH2_med = 2946;
unsigned int limit_CH2_low = 3983;
unsigned int CH_temp = 0;
Wanneer de kalibratie-modus is op het systeem zal worden resetten van deze "limieten" om aan te passen van het signaal. Dit zijn de standaardwaarden, hoe de kalibratie werkt zal later worden verklaard.
motorische controle variabelen
#define Motor_PWM_Rez 16 //number als verschillende snelheden mogelijk voorwaartse en omgekeerde
#define center_buffer 20 //this is de breuk van het bereik voordat beweging begint
Dit zijn de constanten die u aanpassen kunt als u met verschillende delen. De center-buffer is echt de dode zone in het midden waar de controller de motor ken om het even wat maken zal. De rezolution is hoeveel verschillende snelheden, het systeem zal verdelen het bereik van de controle in.
unsigned char Motor_Phase = 0; //as het cycli dit zal tijd de motoren
unsigned int CH1_range = 2000;
unsigned char Motor_A_Speed = 0; Dit is de snelheid van de motor A, het zal gelijk zijn aan de rezolution 100%
unsigned char CH1_forward_increment = 10; //the breedte van bereik voor elke uitvoer snelheid
unsigned char CH1_reverse_increment = 10;
unsigned int CH2_range = 2000;
unsigned char Motor_B_Speed = 0; Dit is de snelheid van de motor A, het zal gelijk zijn aan de rezolution 100%
unsigned char CH2_forward_increment = 10; //the breedte van bereik voor elke uitvoer snelheid
unsigned char CH2_reverse_increment = 10;
typedef struct
{
niet-ondertekende motor_A_Direction: 1;
niet-ondertekende motor_B_Direction: 1;
niet-ondertekende button_1_last_state: 1;
} BITS;
unsigned char motor_A_inverted = 1; //this aan kalibratie gerelateerde
unsigned char motor_B_inverted = 1;
unsigned char motor_calibration_needed = 1;
vluchtige BITS Bits;
timing variabelen
unsigned char slow_count = 0; Dit wordt gebruikt om het maken van de geschaalde timer voor langzamere evenementen
De bovenstaande variabele zal gewoon een teller zodat een subsectie van de timer onderbreken alleen eenieder uit vele timer teken kan afgaan.
interrupt instellen
VOID low_ISR (void); //prototype
#pragma code low_vector = 0x08 //0X08 IS laag 0X18 IS hoog
VOID low_interrupt (void) {}
_asm goto low_ISR _endasm
}
#pragma code
#pragma interrupt low_ISR
Dit deel is niet de interrupt op zich maar het set up voor de interrupt optreden. De interrupt is gewoon een gebeurtenis waarmee iets te worden geactiveerd, zodat het programma niet hoeft te worden een grote lus.
void main(void)
{
OSCCON = 0X72; 8MHz klok
terwijl (!. OSCCONbits.IOFS); Wachten op OSC tot stabiele
configureren van timer1
PIR1bits.TMR1IF = 0; Hiermee wist u de timer 1 onderbreken vlag
T1CONbits.TMR1ON = 1; inschakelen van de timer
T1CONbits.T1CKPS1 = 0; prescaler instellen
T1CONbits.T1CKPS0 = 0; prescaler instellen
installatie timer2
PIR1bits.TMR2IF = 0; Hiermee wist u de timer 2 onderbreken vlag
PIE1bits.TMR2IE = 1; de interrupt inschakelen
PR2 = 199;
T2CON = 0b00000100; (-) altijd 0 (-) postscale (-) aan/uit (-) prescale
CCP1 configureren
CCP1CON = 0b0000101; configureren van CCP1 voor het vastleggen, stijgende rand
INTCONbits.PEIE=1; inschakelen van perifere interrupts
PIE1bits.CCP1IE=1; CCP1 interrupt ingeschakeld
INTCONbits.GIE=1; inschakelen als u wilt onderbreken vertakking
ReceiverTris = 1; RB3 voor invoer instellen zodat de opname kunt werken.
TRISBbits.TRISB2 = 1; rb2 voor instellenin zodat het kan worden gebruikt om te onderscheiden van de kanalen
De capture module doet al het zware werk hier. Boven deze wordt geïnitialiseerd om te wachten op het signaal te stijgen, later dit verandert dynamisch te vangen pulsbreedte.
poorten configureren
ADCON1 = 0XFF; alle digitale
INTCON2bits.RBPU = 0; poort b zwakke pullups op
Deze zullen motor uitgangen
TRISAbits.TRISA0 = 0;
#define Motor_Pin_A1 LATAbits.LATA0
TRISAbits.TRISA1 = 0;
#define Motor_Pin_A2 LATAbits.LATA1
TRISAbits.TRISA2 = 0;
#define Motor_Pin_B1 LATAbits.LATA2
TRISAbits.TRISA3 = 0;
#define Motor_Pin_B2 LATAbits.LATA3
Deze kunt u instellen dat de pinnen die nodig zijn voor de controle van de motoren om op te treden als uitgang. Dan is de motor pinnen heten voor gemakkelijke toegang.
Deze zullen indicator uitgangen
TRISAbits.TRISA6 = 0;
TRISAbits.TRISA7 = 0;
Dit zal de servo-signaalingang
TRISBbits.TRISB0 = 1;
in eerste instantie het kalibreren van de RC bereiken
motor_calibration_needed = 1;
while(1)
{
}
}
Dit terwijl loops voorkomt dat het programma einde. Laat u niet misleiden door het feit dat het leeg is. Interrupts zal leiden tot gebeurtenissen en de timer is nog steeds actief.
Hieronder is de start van de timer onderbreken. Het afgaat periodiek op de hoogste snelheid die elke functie zijn vereist, voor snelle operaties zoals beslissen als het is tijd om te zetten van de motor in- of uitschakelen, dan is onderverdeeld met tellers te bedienen van de functies die geen dergelijke hoge snelheid vereisen, zoals toezicht op de invoer en te beslissen als de snelheid moet veranderen.
VOID low_ISR(void)
{
Timer 2 vlag (momenteel ingesteld op onderbreken bij 10Khz)
if(PIR1bits.TMR2IF == 1)
{
PIR1bits.TMR2IF = 0; Hiermee wist u de timer 1 onderbreken vlag
Dus wat niet afval tijd doen dingen sneller dan nodig (een goede manier om te kijken naar vele soorten werk) het gedeelte hieronder maakt gebruik van de variabele "slow_count" alleen uitvoeren elke 100 keer de buitenste lus wordt uitgevoerd.
withen deze functie uitvoert op 100 Hz ***
slow_count ++;
if(slow_count > 100)
{
slow_count = 1; //reset tellen voor de volgende keer
Handvat kalibratie knop
if(button_1_debounce_wait > 0) {button_1_debounce_wait--;}
if(PORTBbits.RB0 == 0) {}
Als (Bits.button_1_last_state == 0 & & button_1_debounce_wait == 0) //button enkel gedrukt
{
button_1_debounce_wait = 10; //set debounce graaf
calibration_mode ++;
if(calibration_mode > 6) {calibration_mode = 0;}
}
Bits.button_1_last_state = 1;
}
anders
{
Bits.button_1_last_state = 0;
}
einde van kalibratie knop
Hieronder is de kalibratie daadwerkelijk worden toegepast. Dit gebeurt in de normale werkingsmodus zodat de lichten beide zijn uitgeschakeld. Het programma controleert of het kalibratietraject achterstevoren, hoog lager dan de lage en vice versa is, en zo ja een vlag wordt zo ingesteld dat de richtingen van de motoren dienovereenkomstig zullen handelen.
Omgaan met Led modus indicatoren
if(calibration_mode == mode_operate)
{
LATAbits.LATA6 = 0;
LATAbits.LATA7 = 0;
if(motor_calibration_needed == 1)
{
motor_calibration_needed = 0; markering wissen
kalibratie variabelen voor CH1 herberekenen
if(limit_CH1_low < limit_CH1_high) //speed neemt toe naarmate het aantal toeneemt
{
motor_A_inverted = 0;
}
anders / / snelheid afneemt als er
{
swap hen zo hoog is de grotere waarde
CH_temp = limit_CH1_low;
limit_CH1_low = limit_CH1_high;
limit_CH1_high = CH_temp;
motor_A_inverted = 1;
}
CH1_range = limit_CH1_high-limit_CH1_low;
CH1_forward_increment = (limit_CH1_high-limit_CH1_med--((limit_CH1_high-limit_CH1_med)/center_buffer)) / Motor_PWM_Rez;
CH1_reverse_increment = (limit_CH1_med-limit_CH1_low--((limit_CH1_med-limit_CH1_low)/center_buffer)) / Motor_PWM_Rez;
}
kalibratie variabelen voor CH2 herberekenen
if(limit_CH2_low < limit_CH2_high) //speed neemt toe naarmate het aantal toeneemt
{
motor_B_inverted = 0;
}
anders / / snelheid afneemt als er
{
swap hen zo hoog is de grotere waarde
CH_temp = limit_CH2_low;
limit_CH2_low = limit_CH2_high;
limit_CH2_high = CH_temp;
motor_B_inverted = 1;
}
CH2_range = limit_CH2_high-limit_CH2_low;
CH2_forward_increment = (limit_CH2_high-limit_CH2_med--((limit_CH2_high-limit_CH2_med)/center_buffer)) / Motor_PWM_Rez;
CH2_reverse_increment = (limit_CH2_med-limit_CH2_low--((limit_CH2_med-limit_CH2_low)/center_buffer)) / Motor_PWM_Rez;
}
einde van led modus indicatoren
Onder kalibratie wordt afgehandeld. Telkens wanneer de knop is ingedrukt de kalibratie-modus verandert, die aangeeft dat een nieuwe limiet wordt ingesteld. Het patroon is volledig voorwaarts, CH1 midden rust, volledige achteruit, dan hetzelfde drie posities weer op kanaal twee. De lichte indicatoren voor niet in pronken kalibratie-modus, een op voor forward, de andere voor reverse en zowel voor midden punt rusten. Het is niet een krachtige interface maar het krijgt de klus te klaren.
kalibratie
if(calibration_mode == mode_CH1_high)
{
Al deze LATA spul is gewoon de verlichting wordt ingeschakeld om aan te geven van de modus voor de gebruiker. Zoals u het zien kunt instellen niet eigenlijk de limieten wanneer u de knoop raakt. Het stelt hen gewoon op welke plek ze terwijl in die modus, zijn dus als je duwt de knop weer en die modus eindigt, dat het kalibratiepunt blijft.
LATAbits.LATA6 = 0;
LATAbits.LATA7 = 1;
limit_CH1_high = CH1_width;
}
if(calibration_mode == mode_CH1_med)
{
LATAbits.LATA6 = 1;
LATAbits.LATA7 = 1;
limit_CH1_med = CH1_width;
}
if(calibration_mode == mode_CH1_low)
{
LATAbits.LATA6 = 1;
LATAbits.LATA7 = 0;
limit_CH1_low = CH1_width;
}
if(calibration_mode == mode_CH2_high)
{
LATAbits.LATA6 = 0;
LATAbits.LATA7 = 1;
limit_CH2_high = CH2_width;
}
if(calibration_mode == mode_CH2_med)
{
LATAbits.LATA6 = 1;
LATAbits.LATA7 = 1;
limit_CH2_med = CH2_width;
}
if(calibration_mode == mode_CH2_low)
{
LATAbits.LATA6 = 1;
LATAbits.LATA7 = 0;
limit_CH2_low = CH2_width;
motor_calibration_needed = 1;
}
Nu de motor snelheden worden berekend moeten. De vergelijking wordt de breedte van de puls voor die motor, besluit als het over het middelpunt of niet te beslissen richting, dan vindt er variëren met behulp van de resolutie van de motorische controle binnen het totale bereik van mogelijke breedtes.
berekenen van de motorsnelheid A
Motor_A_Speed = 0;
if(CH1_width > limit_CH1_med+((limit_CH1_high-limit_CH1_med)/center_buffer)) //upper bereik
{
Motor_A_Speed = (CH1_width-limit_CH1_med--((limit_CH1_high-limit_CH1_med)/center_buffer)) / CH1_forward_increment;
Bits.motor_A_Direction = motor_A_inverted;
}
if(CH1_width < limit_CH1_med-((limit_CH1_med-limit_CH1_low)/center_buffer)) //lower bereik
{
Motor_A_Speed = (limit_CH1_med-CH1_width--((limit_CH1_med-limit_CH1_low)/center_buffer)) / CH1_reverse_increment;
Bits.motor_A_Direction =! motor_A_inverted;
}
Bereken motor snelheid B
Motor_B_Speed = 0;
if(CH2_width > limit_CH2_med+((limit_CH2_high-limit_CH2_med)/center_buffer)) //upper bereik
{
Motor_B_Speed = (CH2_width-limit_CH2_med--((limit_CH2_high-limit_CH2_med)/center_buffer)) / CH2_forward_increment;
Bits.motor_B_Direction = motor_B_inverted;
}
if(CH2_width < limit_CH2_med-((limit_CH2_med-limit_CH2_low)/center_buffer)) //lower bereik
{
Motor_B_Speed = (limit_CH2_med-CH2_width--((limit_CH2_med-limit_CH2_low)/center_buffer)) / CH2_reverse_increment;
Bits.motor_B_Direction =! motor_B_inverted;
}
einde van de berekening van de motorsnelheid
} //end van 100hz sectie
Hier de als verklaring en teller die ervoor zorgen dat het bovenstaande alleen uitvoeren bij 100Hz zijn beëindigd en we op de volledige timer-interrupt-frequentie zijn. Het deel onder grepen genereren van het signaal van de motorische controle van de snelheid berekend boven
Contol pulsen motor
Motor_Phase ++;
if(Motor_Phase > Motor_PWM_Rez) {Motor_Phase = 1;}
Motor A
Als (Motor_A_Speed > = Motor_Phase & & Motor_A_Speed < 20) {}
if(bits.motor_A_Direction == 0) {}
Motor_Pin_A1 = 1;
Motor_Pin_A2 = 0;
}
if(bits.motor_A_Direction == 1) {}
Motor_Pin_A1 = 0;
Motor_Pin_A2 = 1;
}
}
else {}
Motor_Pin_A1 = 0;
Motor_Pin_A2 = 0;
}
Motor B
Als (Motor_B_Speed > = Motor_Phase & & Motor_B_Speed < 20) {}
if(bits.motor_B_Direction == 0) {}
Motor_Pin_B1 = 1;
Motor_Pin_B2 = 0;
}
if(bits.motor_B_Direction == 1) {}
Motor_Pin_B1 = 0;
Motor_Pin_B2 = 1;
}
}
else {}
Motor_Pin_B1 = 0;
Motor_Pin_B2 = 0;
}
} //end van timer onderbreken
Hieronder is het begin van de CCP-interrupt. Dit is het deel dat behandelt de pulsbreedte te meten. Eerder was deze op worden geactiveerd door een stijgende rand gezet. Wanneer de stijgende rand wordt gedetecteerd zal het opnemen van de tijd met behulp van CCPR1, dan zal het overschakelen om te letten om te vallen en verander de PWM1Edge variabele aan. Wanneer het detecteert terug te vallen het schakelaars en registreert de tijd.
CCP interrupt
if(PIR1bits.CCP1IF == 1)
{
PIR1bits.CCP1IF = 0; de markering wissen
if(PWM1Edge == 1) //if detecting rising
{
CCP1CON = 0b0000100; //switch te detecteren vallende rand
PWM1Edge = 0; //switch om aan te geven van de dalende rand is volgende
PWMGap = CCPR1 - PWM1FallTime; berekenen van de kloof tussen pulse begint
PWM1RiseTime = CCPR1; //save de lage timer-waarde voor de stijgtijd
if(PWMGap < 10000) {CH2_width = PWMGap;}
}
anders //if opsporen die vallen
{
CCP1CON = 0b0000101; //switch te detecteren stijgende rand
PWM1Edge = 1; //switch om aan te geven van de stijgende rand is volgende
PWM1Width = CCPR1 - PWM1RiseTime; (pwm stijgtijd is het moment dat de opkomst van de pwm optrad)
PWM1FallTime = CCPR1; //save de lage timer-waarde voor de val tijd
Je moet echt te begrijpen van de logica achter dit deel als u wilt wijzigen van de code om te werken op andere ontvangers. De ontvanger van de traxxas die ik gebruikte zet alle van de pulsen rug aan rug. Dit maakte het zodat ik kon niet via slechts één pin lezen omdat de hele reeks van pulsen één lange puls was wanneer gecombineerd. Dus ik ontwierp het programma zodat de chip alleen op elke andere uitvoer aangesloten is, uitgangen in dit geval servo 1 en 3. Op die manier is er een kloof. De korte kloof (degene die minder dan 10000 opgespoord door de als verklaring hieronder) is de tussentijdse en de lengte van de middelste pols, pulse nummer 2. De eerste puls na de lange kloof is pulse nummer 1 en de één na de korte kloof pulse nummer 3 is.
if(PWMGap > 10000) {CH1_width = PWM1Width;}
if(PWMGap < 10000) {CH3_width = PWM1Width;}
}
}
}
Aarzel niet om vragen te stellen. Het zal me dingen duidelijker maken zodat ik waardeer hen helpen.
Zoals ik in die laatste opmerking is dit plan draait van de pulsen die rug aan rug. Sommige ontvangers uitspreiden hen. Als dat het geval was moet u zou niet deze truc om helemaal te doen. In plaats daarvan zou je alleen weten dat na de lange kloof pulse een was, vervolgens na elke extra korte kloof je pulse 2, 3, 4 enzovoort kijkt. U zou enkel Maak een variabele om bij te houden hoeveel pulsen u had gevangen sinds de laatste kloof en resetten wanneer u had de lange, dan gebruiken om te beslissen welk kanaal u een vastgelegde pulsbreedte aan toegeschreven.