Sida 4 av 4
Re: PWM utsignal beroende på Analog insignal (PIC16F690)
Postat: 11 maj 2010, 21:02:39
av Leon23
Har jag missat något? Sätter jag prescalern till 4, så verkar timern stämma.
8MHz/(4*256*4)=1953Hz...
Annars verkar timern stämma nu i alla fall!

Re: PWM utsignal beroende på Analog insignal (PIC16F690)
Postat: 11 maj 2010, 21:08:44
av bearing
Spontant undrar jag hur du mäter och vad du använder för kod?
ifall t.ex. interruptet togglar en pinne kommer ju pinnen gå hög i 1 kHz ifall interruptet sker i 2 kHz. Det är en tankevurpa jag gjort.
Annars kanske processorn går i 4MHz. Minns inte om man kunde välja en prescaler på systemklockan på de där processorerna.
Re: PWM utsignal beroende på Analog insignal (PIC16F690)
Postat: 11 maj 2010, 21:31:28
av Leon23
Hmm jag vet faktiskt inte, men det verkar väl inte helt ologiskt?
Processorn körs i 8MHz. På denna processorn körs den interna systemklockan med Fosc/4 om jag tolkat databladet rätt.
Eftersom jag tycker det är lättare att tänka i form av sekunder gjorde jag så att timer0 räknar upp en variabel (för ungefär varje ms) som heter Timer_ms.
Jag vet inte hur relevant det är, men här är koden som den är just nu:
Kod: Markera allt
/* PROGRAMVARA FÖR MOTORSTYRNIGNGSKRETS v3
Oscar Leon
CHALMERS TENISKA HÖGSKOLA
2010-05-11
*/
/* Variablerdeklaration */
int Broms=0; int Set=0; int Resume=0; int Pwm=0; int Puls=0;
int Gas=0; int CC=0; int Hastighet=0; int Timer_ms=0;
/* Funktionsdeklaration */
void interrupt(void); // Interruptfunktioner
void InitMain(void); // Initieringsrutin
void LasKnappar(void); // Funktion som läser av Broms, Set, Resume.
void AnalogStyrning(void); // Funktion AnalogStyrning
void CruiseControl(void); // Funktion Cruise Control
void LogikBox(void); // Logikfunktion som dutycycle
void MotorStyrning(void); // Sätter PWM till dutycycle
void InitMain(){
ANSEL= 0xFF; // Sätt AN0 till AN7 som analoga I/O
ANSELH= 0; // Sätt AN7-xx pinnar som digitala I/O
PORTA= 0xFF;
TRISA= 0x01; // Sätt Analog0 till input
PORTB= 0xFF;
TRISB= 0x0F; // Sätt RB0-RB3 till input
PORTC= 0x00; // Sätt PORTC till 0
TRISC= 0x00; // Sätt PORTC till output
ADCON1= 0x80; // Config analog input och Vref
PWM1_INIT(500); // Initierar PWM frekvens till 500Hz Vårt optimala är kring 5000-6000Hz
/* Interrupt settings */
OPTION_REG.INTEDG=0; // Interrupt Edge Select bit, negativ flank
OPTION_REG.T0CS=0; // Internal instruction cycle clock (Fosc/4)
OPTION_REG.PSA=0; // Prescaler is assigned to the Timer0 module
OPTION_REG.PS2=0;
OPTION_REG.PS1=0; // Prescalern sätts till 4 (8MHz/4*256*4=976Hz)
OPTION_REG.PS0=1;
INTCON.GIE=1; // Enabla globalt interrupt
INTCON.T0IE=1; // Timer0 Overflow Interrupt Enable bit
INTCON.INTE=1; // Enabla INT/RB0 extern interrupt
INTCON.INTF=0; // Nollställ flaggan
INTCON.T0IF=0; // Timer0 Overflow Interrupt Flag bit
}
void interrupt (void){
if(PORTB.B0==0 && INTCON.T0IF==0){ // Kolla om RB0 är 0, i så fall har vi negativ flank
Hastighet=1500/Timer_ms; // Ex: 100 ms mellan 2 flanker, ger en Hastighet på cykeln till 15km/h.
if(Hastighet<2)
Hastighet=0;
Timer_ms=0;
}
if(INTCON.T0IF==1){ // Om Timer0 interrupt inträffar (varje ms)
Timer_ms++; // Öka variabeln Timer_ms med 1
INTCON.T0IF=0; // Nollställ Timer0 overflow Interrupt Flag bit
}
INTCON.INTF=0; // Klarsignalering; Nollställ interruptflagga
}
void main(){
InitMain(); // Initieringsvillkor
while(1){
LasKnappar();
AnalogStyrning();
CruiseControl();
LogikBox();
MotorStyrning();
}
}
/* PIN CONFIG: RB0: Hastighetsmätning, RB1: Set RB2: Resume RB3: Broms */
void LasKnappar(void){
if(PORTB.B1==1) // Setknapp aktiv? (Slutande funktion)
Set=1;
if(PORTB.B1==0)
Set=0;
if(PORTB.B2==1) // Resumeknapp aktiv? (Slutande funktion)
Resume=1;
if(PORTB.B2==0)
Resume=0;
if(PORTB.B3==0) // Broms aktiv? (Brytande funktion)
Broms=1;
if(PORTB.B3==1)
Broms=0;
}
void AnalogStyrning(void){ // Interpolering är kvar att göra
Gas=ADC_READ(0)>>2; // Skiftar bort 2 LSB. ad0 har nu ett värde mellan 0 och 255.
if(Gas<52) // Om gasreglaget är nollställd, skicka ut 0.
Gas=0;
if(Gas>220) // Gasreglage på maximal styrka, skicka full PWM
Gas=255;
}
void CruiseControl(void){ // Tillfälligt
CC=0;
// Hastighet=15;
}
void LogikBox(void){
if(Broms==0 && Hastighet<25 && Timer_ms<10000 //temporärt){
if(CC>Gas) // Högst av CC eller Gas anger PWM
PWM=CC;
else
PWM=Gas;
}
else
PWM=0;
}
void MotorStyrning(void){
PWM1_Start();
PWM1_SET_DUTY(PWM);
}
Re: PWM utsignal beroende på Analog insignal (PIC16F690)
Postat: 11 maj 2010, 21:38:45
av bearing
Och hur har du kommit fram till att interruptfrekvensen är fel?
EDIT:
Jag vet inte hur petigt det här var... Men, som jag skrev förut, ifall ett interrupt inträffar när den här koden exekveras kommer INTF-flaggan nollställas innan interruptkoden för INTF-interruptet har körts. Det kommer ju göra att nästa gång hastigheten räknas ut blir den hälften av verkliga hastigheten.
Kod: Markera allt
if(INTCON.T0IF==1){ // Om Timer0 interrupt inträffar (varje ms)
Timer_ms++; // Öka variabeln Timer_ms med 1
INTCON.T0IF=0; // Nollställ Timer0 overflow Interrupt Flag bit
}
INTCON.INTF=0; // Klarsignalering; Nollställ interruptflagga
Re: PWM utsignal beroende på Analog insignal (PIC16F690)
Postat: 11 maj 2010, 22:00:41
av sneaky
Ville bara tipsa lite om den här sidan som jag tycker är smidig så att man slipper räkna allt manuellt:
http://eng-serve.com/pic/pic_timer.html
Re: PWM utsignal beroende på Analog insignal (PIC16F690)
Postat: 14 maj 2010, 10:39:01
av Leon23
Sneaky: Fin sida! Lite enklare än att räkna manuellt kanske?

Bearing: Ja, du hade rätt. Testade att flytta på nollställningen av INTF flaggan och nu verkar det fungera korrekt.
Åter till reglerproblemet:
Jag har letat efter lite relevant information på nätet, och hittat application notes för PID implementering för pic processorer på Microships hemsida; AN 937 och AN 964.
Hittade även en gammal tråd på forumet;
http://elektronikforumet.com/forum/view ... lering+pic
Dock hittar jag ingen källkod som jag kan börja utgå från. För min tillämpning räcker det antagligen med en P eller PI-regulator. Parametrarna kan jag inte matematiskt beräkna fram, eftersom jag inte vet hur stort masströghetsmoment som erhålles med en person på cykel (sen varierar den ju även beroende på hur mycket den som kör cykeln väger) samt att jag saknar tröghetsmomentet för motorn.
Min tanke var mest pröva att ändra parametrarna och finjustera något i efterhand. Kanske ska testa Z.N metod, jag får se.
Bearing: Hur fungerar ditt exempel; vad bestämmer SCALING_FACTOR och vad är det man för styrsignal man får ut egentligen? Ställer man in SCALING_FACTOR så att man får ett värde mellan 0 och 100?
Det man vill ha är väl en styrsignal som ger ett värde mellan 0 och 100, som går att PWM'a (känner mig lite vilsen här, rätta mig om jag har fel).
Barbarossa: I ditt exempel så ställer man bara in Kp och Ki till ett behagligt värde och deklarerar några variabler som behåller tidigare värde; det låter ju inte så komplicerat. Dock funderar jag på hur det fungerar praktiskt. Har du en styrsignal som är 100% från tidigare (UTgammal = 100) och nu får ett reglerfel, så lägger du till KP*(FELny-FELgammal) + Ki*FELny. Då får man ju en ny styrsignal som är över 100?
Tack för era svar!
/Oscar
Re: PWM utsignal beroende på Analog insignal (PIC16F690)
Postat: 14 maj 2010, 11:48:08
av barbarossa
Jag gjorde flödeskontroller för länge sedan, "pid" är long och jag använde andra byten uppifrån räknat till PWM-signalen. if och else if satserna tar hand om overflow.
Kod: Markera allt
flow_1=ADC_Read(0);
pid=pid+k_p*flow_0-k_p*flow_1+k_i*set_point-k_i*flow_1;
flow_0=flow_1;
if(pid>0x00FFFFFF) pid=0x00FFFFFF;
else if (pid<0) pid=0;
Re: PWM utsignal beroende på Analog insignal (PIC16F690)
Postat: 17 maj 2010, 11:53:56
av Leon23
Bearing:
Jag gick in och läste på en del om AVR's publicerade diskreta PID-reglering. Fick lite bra idéer, tack! Dock tänkte jag använda mig av en enklare PI-reglering i min tillämpning.
Barbarossa:
När du skriver att andra byten uppifrån räknat från variabeln "pid" är PWM-signalen, menar du denna byten;
pid = 0x00
FFFFFF, där dessa ger en styrsignal mellan 0 och 255?
Det är bra att du har tänkt på overflow eller "windup" som kan uppstå vid PI-reglering mha if-satserna.
Kod: Markera allt
flow_1=ADC_Read(0);
pid=pid+k_p*flow_0-k_p*flow_1+k_i*set_point-k_i*flow_1;
flow_0=flow_1;
if(pid>0x00FFFFFF) pid=0x00FFFFFF;
else if (pid<0) pid=0;
Jag förstår inte riktigt hur du har implementerat din PI-algoritm, du skrev i ett tidigare inlägg att:
"UTny = UTgammal + Kp*(FELny-FELgammal) + Ki*FELny"
Jag tycker det ser ut som "UTny = UTgammal + Kp*(Gammalt-nystyrsignal = inte ett reglerfel?) + Ki*(Börvärde-Nyttvärde=reglerfel, men inte en summa?)
Varför inte bara UTny = UTgammal + KP*(reglerfelet) +Ki*SummaFel
Dvs detta borde se ut enligt följande (tror ni denna enkla algoritm fungerar?):
Kod: Markera allt
error=setpoint-process_value;
sumerror+= error;
p_term = KP*error;
i_term = KI*sumerror;
UTny = UTgammal + p_term + i_term;
Där UTny är en variabel av typen long som ändrar sin styrsignal mellan 0 och 255 på andra byten.
/Oscar
Re: PWM utsignal beroende på Analog insignal (PIC16F690)
Postat: 17 maj 2010, 13:24:23
av barbarossa
Det finns lite olika sätt att skriva PI loop på.
FELgammal=FELny;
UTgammal = UTny;
FELny = BÖRVÄRDE - ÄRVÄRDE;
UTny = UTgammal + Kp*(FELny-FELgammal) + Ki*FELny;
I UT ackumuleras I termerna samt gamla P termen dras ifrån. Min exempelkod är densamma fast med lite andra termer och paranteser.
I ditt förslag skall UTgammal bytas ut mot en konstant.
Re: PWM utsignal beroende på Analog insignal (PIC16F690)
Postat: 17 maj 2010, 18:35:10
av Leon23
Barbarossa: Jag har tre frågor som kvarstår:
1: Hur stor kommer min motsvarande "pid" variabel att variera mellan?
Cykeln är utrustad med en skiva med 5 magneter. Säg då att hastighetsfelet är 5km/h, vilket ökar sumerror med 25 per varv. Säg att det tar ca 10 varv innan motorn hinner reglera upp, då kommer ju sumerror bli 250 (vilket nästan är 255) och därmed påverkar denna tillämpning endast variabeln mellan 0 och 255 (utan if-satser för overflow och utan hänsyn till P-delen)
-Med andra ord borde jag kunna använda mig av en variabel som endast varierar mellan 0 och 255?
Kod: Markera allt
error=setpoint-process_value;
sumerror+= error;
p_term = KP*error;
i_term = KI*sumerror;
UTny = UTgammal + p_term + i_term;
UTgammal=UTny
2: Hur ska man sätta UTgammal?
Om vi antar att man ställer in hastigheten 15km/h under drift blir ju reglerfelet 0 de första sekundrarna. Styrsignalen kommer att sättas till UTgammal som är vadå? 0? Det som man upplever då blir ju att motorn dör de första sekundrarna när man aktiverar farthållaren, för att sedan därefter regleras till rätt hastighet och hålla denna PWM-signal?
Kan man kanske lösa detta genom att låta UTgammal bero på den aktuella hastigheten? (exempelvis 15km/h *10 = 155, 155/255 vilket är ungefär 60% PWM (blir jobbigt eftersom detta beror på vilken växel man använder.., men jag tror detta fungerar ganska väl faktiskt)
Vidare tänkte jag att man sätter overflow villkor som du har gjort;
3: Hur fungerar det med windups/downs?
Om sumerror summeras för länge som exempelvis vid uppförsbackar & nerförsbackar (det vill säga att man får en wind-up/down, om motorn inte klarar av att accelerera till inställd hastighet),
Kan man lösa detta med exempelvis dessa programrader?;
Kod: Markera allt
if(sumerror>255)
sumerror=255;
if(sumerror<-255)
sumerror=-255;
/Oscar
Re: PWM utsignal beroende på Analog insignal (PIC16F690)
Postat: 17 maj 2010, 21:54:09
av barbarossa
1: Hur stor kommer min motsvarande "pid" variabel att variera mellan?
Omöjligt för mig att säga, Hur stor är hjulradien? Hur snabbt cyklar du? Använder du timer till pulsmätning, Vilken klockfrekvens använder du?
-Med andra ord borde jag kunna använda mig av en variabel som endast varierar mellan 0 och 255?
Felet kan vara negativt, sumerror likaså.
2: Hur ska man sätta UTgammal?
Om du implementerar koden som du har skrivit den, kommer du att få en I-regulator. Det funkar kanske det med, men om du INTE använder raden "UTgammal=UTny" ELLER drar ifrån föregående fel så blir det en PI regulator.
Förr eller senare måste du ha experimentell data för att kunna gå vidare. Börja med noll eller nåt annat, om du inte blir nöjd med det kan du gå vidare med hastighetsberoende.
3: Hur fungerar det med windups/downs?
Ingen aning, jag har aldrig upplevt något liknande och därmed inte heller behövt lösa problemet. Det är möjligt att det är bättre att begränsa accelerationen, men jag hade väntat till efter experimentell data.