PWM utsignal beroende på Analog insignal (PIC16F690)
Re: PWM utsignal beroende på Analog insignal (PIC16F690)
Ursäkta för min inkompetens. Hade helt glömt bort att man kan använda sig av interrupt(!). Detta möjliggör även att jag (i samband med prioritet på interrupten) kan 'parallellisera' programmet något. Tack för era snabba svar.
Vänligen
/Oscar
Vänligen
/Oscar
Re: PWM utsignal beroende på Analog insignal (PIC16F690)
Fördelen med att använda capture-enheten är att det inte blir något jitter. På önskad flank sparas automatiskt värdet på TMR1L och TMR1H i två register, som senare kan läsas av i lugn och ro, förslagsvis i ett Capture-interrupt.
Ifall TMR1L/-H ska läsas av i ett vanligt externt interrupt finns dels problemet att det tar olika lång tid att nå interruptrutinen vid olika tillfällen, samt att man måste läsa av TMR1L/-H på ett "säkert sätt", t.ex. genom att stänga av timern när den läses av.
De här processorerna har bara en interruptvektor, det finns alltså ingen hårdvarumöjlighet för olika prioritetsnivåer. Prioriteten måste ske i mjukvara genom att använda nästlade interrupt. Det kan ge problem med stacken, eftersom att den bara är 8 nivåer djup.
Ifall TMR1L/-H ska läsas av i ett vanligt externt interrupt finns dels problemet att det tar olika lång tid att nå interruptrutinen vid olika tillfällen, samt att man måste läsa av TMR1L/-H på ett "säkert sätt", t.ex. genom att stänga av timern när den läses av.
De här processorerna har bara en interruptvektor, det finns alltså ingen hårdvarumöjlighet för olika prioritetsnivåer. Prioriteten måste ske i mjukvara genom att använda nästlade interrupt. Det kan ge problem med stacken, eftersom att den bara är 8 nivåer djup.
Re: PWM utsignal beroende på Analog insignal (PIC16F690)
> Hade helt glömt bort att man kan använda sig av interrupt(!).
När du talade om att få RB1 att "reagera" så utgick jag ifrån
att det var i samband med interrupt. Hur hade du annars tänkt
att pinnen skulle "reagera" ?
När du talade om att få RB1 att "reagera" så utgick jag ifrån
att det var i samband med interrupt. Hur hade du annars tänkt
att pinnen skulle "reagera" ?
Re: PWM utsignal beroende på Analog insignal (PIC16F690)
Main består av ett flertal funktioner som körs 1000?ggr per sekund (while-loop) tänkte man kunde skapa en funktion och läsa av pinnen i den funktionen..
Skulle testa att skapa en bromsfunktion nyss, men fick den inte att fungera. Mätte upp +5V/0V in mot RB0/INT pinnen, så felet måste ligga i mjukvaran.
Tanken är att man med bromsen skapar en interrupt som stoppar motorn.
EDIT: Trodde det var ett logiskt fel eftersom jag inte hade någon delay i interruptrutinen. Testade och la till en delay(2000) men det gjorde ingen skillnad.
Skulle testa att skapa en bromsfunktion nyss, men fick den inte att fungera. Mätte upp +5V/0V in mot RB0/INT pinnen, så felet måste ligga i mjukvaran.
Tanken är att man med bromsen skapar en interrupt som stoppar motorn.
Kod: Markera allt
unsigned Analog0; CruiseControl; // Variablerdeklaration
void AnalogStyrning(void); // Funktion AnalogStyrning
void interrupt (void); // Interruptfunktioner
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 = 0xFF; // Sätt PORTA till input
PORTB = 0xFF;
TRISB = 0xFF; // Sätt PORTB till input
PORTC = 0xFF;
TRISC = 0xFF; // Sätt PORTC till input
OSCCON=0b01000111; // Oscillator 1 MHz
ADCON1 =0x80 ; // Config analog input och Vref
Pwm1_Init(6000); // Initierar PWM frekvens till 6000Hz Vårt optimala är kring 5000-6000Hz
Pwm1_Start(); // Starta PWM1
//Interrupt initiering
INTCON.INTEDG=1; // Interrupt triggar på RB0/INT pinnens positiva flank
INTCON.GIE=1; // Enabla globalt interrupt
INTCON.INTE=1; // Enabla INT/RB0 extern interrupt
INTCON.INTF=0; // Nollställ flaggan
}
void main()
{
InitMain(); // Initieringsvillkor
while(1)
{
AnalogStyrning();
Delay_ms(5);
}
}
void interrupt (void)
{
if(PORTB.F0==0){ // Broms aktiv? (strömställarna har brytande funktion)
CruiseControl=0; // Inaktivera CruiseControl
PWM1_Stop(); // Stäng av PWM
INTCON.INTF=0; // Klarsignalering; Nollställ interruptflagga,
}
}
void AnalogStyrning(void)
{
Analog0=ADC_READ(0)>>2; // Skiftar bort 2 LSB. ad0 har nu ett värde mellan 0 och 255.
if(Analog0<45) // Om gasreglaget är nollställd, skicka ut 0.
Analog0=0;
if(Analog0>200) // Gasreglage på maximal styrka, skicka full PWM
Analog0=255;
PWM1_SET_DUTY(Analog0); // Sätt nuvarande dutycykel för PWM1
}
Re: PWM utsignal beroende på Analog insignal (PIC16F690)
Har suttit och felsökt hela morgonen utan resultat, detta är vad som händer med denna kod när jag levererar spänning från batteriet:
1: Först sätter jag på spänningen. Inget händer, bra;
2: Skruvar lite på gasreglaget, motorn fastnar kring ca 20% PWM oavsett hur jag vrider på gasreglaget. Detta är utan att bromsen varit aktiverad.
3: När jag bromsar, så får jag full PWM ut (interruptrutinen startar och den startar full PWM???).
Det som stör mest är att jag inte vet vad som antagligen är fel i interruptrutinen. Det har fungerat tidigare med bara analog styrning (gasreglage) och detta är oförändrat.
Har någon ett tips eller misstänker någonstans där det kan ligga fel i interruptrutinen så blir jag väldigt tacksam.
/Oscar
1: Först sätter jag på spänningen. Inget händer, bra;
2: Skruvar lite på gasreglaget, motorn fastnar kring ca 20% PWM oavsett hur jag vrider på gasreglaget. Detta är utan att bromsen varit aktiverad.
3: När jag bromsar, så får jag full PWM ut (interruptrutinen startar och den startar full PWM???).
Det som stör mest är att jag inte vet vad som antagligen är fel i interruptrutinen. Det har fungerat tidigare med bara analog styrning (gasreglage) och detta är oförändrat.
Har någon ett tips eller misstänker någonstans där det kan ligga fel i interruptrutinen så blir jag väldigt tacksam.
/Oscar
Re: PWM utsignal beroende på Analog insignal (PIC16F690)
PWM_Stop() stänger ju av hela PWM-funktionen så att pinnen blir en normal utgång, vilken antagligen är satt hög eftersom att du mäter upp 100% duty. Det finns sedan inget som sätter igång PWM-funktionen när bromsen är släppt.
Det här ser inte rätt ut:
Det du vill göra är antagligen en analog interpolering så att analog0 45-200 motsvarar PWM duty 0-255.
Det här ser inte rätt ut:
Kod: Markera allt
if(Analog0<45) // Om gasreglaget är nollställd, skicka ut 0.
Analog0=0;
if(Analog0>200) // Gasreglage på maximal styrka, skicka full PWM
Analog0=255;
Re: PWM utsignal beroende på Analog insignal (PIC16F690)
Tack Bearing för snabbt svar;
Är du säker att PWM_Stop() stänger av hela PWM funktionen så att pinnen blir en normal utgång? Ur Mikro PRO-C kompilatorn får man endast följande (bristfälliga?) information:
"PWM1_Stop
Prototype void PWM1_Stop(void);
Returns Nothing.
Description Stops PWM.
Requires MCU must have CCP module. PWM1_Init must be called before using this routine. PWM1_Start should be called before using this routine, otherwise it will have no effect as the PWM module is not running.
Example PWM1_Stop(); "
Jag testade att byta programraden med PWM_SET_DUTY(0); istället, får tyvärr samma resultat.
Har du något tips på hur man gör en analog interpolering?
EDIT: Det lustiga kvarstår dock; varför startar motorn med ca 20% PWM när man vrider lite på gasreglaget och sedan fastnar där? Jag börjar få slut på idéer..
EDIT2: Såhär ser interrupt-rutinen ut nu, med samma resultat;
/Oscar
Är du säker att PWM_Stop() stänger av hela PWM funktionen så att pinnen blir en normal utgång? Ur Mikro PRO-C kompilatorn får man endast följande (bristfälliga?) information:
"PWM1_Stop
Prototype void PWM1_Stop(void);
Returns Nothing.
Description Stops PWM.
Requires MCU must have CCP module. PWM1_Init must be called before using this routine. PWM1_Start should be called before using this routine, otherwise it will have no effect as the PWM module is not running.
Example PWM1_Stop(); "
Jag testade att byta programraden med PWM_SET_DUTY(0); istället, får tyvärr samma resultat.
Har du något tips på hur man gör en analog interpolering?
EDIT: Det lustiga kvarstår dock; varför startar motorn med ca 20% PWM när man vrider lite på gasreglaget och sedan fastnar där? Jag börjar få slut på idéer..
EDIT2: Såhär ser interrupt-rutinen ut nu, med samma resultat;
Kod: Markera allt
void interrupt (void)
{
if(PORTB.F0==0){ // Broms aktiv? (strömställarna har brytande funktion)
CruiseControl=0; // Inaktivera CruiseControl
PWM1_STOP(); // Stäng av PWM
PORTC=0x00;
delay_ms(2000);
PWM1_START();
INTCON.INTF=0; // Klarsignalering; Nollställ interruptflagga,
}
}
Re: PWM utsignal beroende på Analog insignal (PIC16F690)
Jag vet inte vad PWM_stop gör, men det verkar ju troligt att den gör som jag trodde. Om kompilatorn ger dig en asm fil kan du lägga ut den här så kan vi se på assemblernivå vad kompilatorn har gjort.
Jag skulle helt struntat i de där inbyggda funktionerna för PWM, utan skrivit direkt till registrena som påverkar PWM-modulen - då får man kontroll över vad man gör.
Ser att du lagt en delay i interruptet. Det är någon man normalt undviker i det längsta.
>Det lustiga kvarstår dock; varför startar motorn med ca 20% PWM när man vrider lite på gasreglaget och sedan fastnar där?
analog0är deklarerad som unsigned. JAg vet inte om det innebär 8 eller 16 bitar, men om det är 8 bitar borde det förklara vad som händer. Då får du ett värde som trunkeras till 8 bitar, och sedan shiftas två höger så att värdet är högst 63. Sedan räknas allt under 45 som noll. Så duty hamnar i intervallet 45-63 vilka är ca 20% ifall perioden är 256.
Vad är förresten perioden? är den 256? oklart vad den där initieringsfunktionen gör...
Jag skulle helt struntat i de där inbyggda funktionerna för PWM, utan skrivit direkt till registrena som påverkar PWM-modulen - då får man kontroll över vad man gör.
Ser att du lagt en delay i interruptet. Det är någon man normalt undviker i det längsta.
>Det lustiga kvarstår dock; varför startar motorn med ca 20% PWM när man vrider lite på gasreglaget och sedan fastnar där?
analog0är deklarerad som unsigned. JAg vet inte om det innebär 8 eller 16 bitar, men om det är 8 bitar borde det förklara vad som händer. Då får du ett värde som trunkeras till 8 bitar, och sedan shiftas två höger så att värdet är högst 63. Sedan räknas allt under 45 som noll. Så duty hamnar i intervallet 45-63 vilka är ca 20% ifall perioden är 256.
Vad är förresten perioden? är den 256? oklart vad den där initieringsfunktionen gör...
-
- EF Sponsor
- Inlägg: 544
- Blev medlem: 8 december 2006, 11:18:14
- Ort: Tågarp, Svalöv
Re: PWM utsignal beroende på Analog insignal (PIC16F690)
...vad bearing sa om delay i interrupt...
delay ligger dessutom efter if-satsen i interruptet. Nivån är i praktiken odefinierad i detta läget.
Använd pushbutton funktion i main istället.
//A
delay ligger dessutom efter if-satsen i interruptet. Nivån är i praktiken odefinierad i detta läget.
Använd pushbutton funktion i main istället.
//A
Re: PWM utsignal beroende på Analog insignal (PIC16F690)
Analog interpolering var det också ja. Det handlar om att använda räta linjens funktion.
Hittade denna i ett gammalt program jag skrivit
där mul16x8Div16 är skriven i en sorts inline assembly (för att gå snabbt) i CC5X-kompilatorn.
EFtersom att y1=0 och y2=255 i ditt fall, samt att 8 bitar verkar duga för x-värden kan man optimera till detta:
Hittade denna i ett gammalt program jag skrivit
Kod: Markera allt
unsigned char linearInterpolation(unsigned int x1,unsigned int x,unsigned int x2,unsigned char y1,unsigned char y2)
{
unsigned char y;
//Några formler:
//k=(y2-y1)/(x2-x1)
//och
//y-y1=k*(x-x1)
//vilka kombineras till...
// y = ((y2-y1)*(x-x1))/(x2-x1) + y1
y=y2-y1;
x-=x1;
x2-=x1;
x=mul16x8Div16(x,y,x2);
y=x.low8+y1;
return y;
}
EFtersom att y1=0 och y2=255 i ditt fall, samt att 8 bitar verkar duga för x-värden kan man optimera till detta:
Kod: Markera allt
unsigned char linearInterpolation(unsigned char x1,unsigned char x,unsigned char x2)
{
unsigned int y;
if (x<=x1) return 0;
if (x>=x2) return 255;
//Några formler:
//k=(y2-y1)/(x2-x1)
//och
//y-y1=k*(x-x1)
//vilka kombineras till:
// y = ((y2-y1)*(x-x1))/(x2-x1) + y1
// y1=0
// y2=255
// leder till:
// y = 255*(x-x1)/(x2-x1)
x-=x1;
x2-=x1;
y=x<<8; //y=x*256
y-=x; //y=x*255
y/=x2;
return (unsigned char) y;
}
Re: PWM utsignal beroende på Analog insignal (PIC16F690)
Började faktiskt programmera i assembler för att ha direkt kontroll över vad som händer; dock fick jag inte PWM-funktionen att fungera så det är därför jag gick över till C och färdiga funktioner istället. Nu börjar jag dock bli lite irriterad över Mikro-C (eller min oförmåga att hantera denna kompilator).
Jag har en bok här som är skriven av Lars Bengtsson "Mikrocontrollers". Han använder HI-TECH PICC's kompilator. Är det någon som har erfarenhet av denna eller är det Mikro-C som är vanligast? Funderar nämligen på att byta kompilator om detta kan lösa mina problem.
Angående analog0 så fungerar det som sagt utmärkt i mina tidiga versioner av motorstyrningen. a0=ADC_read(0); Läser av analoga ingången 0 och ger ett 10 bitars värde till variabeln a0. PWM_SET_DUTY() vill ha ett värde mellan 0 och 255, varav jag skiftar ut två bitar för att få korrekt analog styrning med hjälp av gasreglaget. Ska testa din analoga interpoleringsfunktion lite senare när jag fått det viktiga att fungera först
barbarossa: Du har helt rätt att delayen borde ligga efter if-satsen. Jag testade som du sa med pushbutton funktionen och la in den i main istället, enligt följande;
Fungerar dock fortfarande inte, tyvärr.
/Oscar
Jag har en bok här som är skriven av Lars Bengtsson "Mikrocontrollers". Han använder HI-TECH PICC's kompilator. Är det någon som har erfarenhet av denna eller är det Mikro-C som är vanligast? Funderar nämligen på att byta kompilator om detta kan lösa mina problem.
Angående analog0 så fungerar det som sagt utmärkt i mina tidiga versioner av motorstyrningen. a0=ADC_read(0); Läser av analoga ingången 0 och ger ett 10 bitars värde till variabeln a0. PWM_SET_DUTY() vill ha ett värde mellan 0 och 255, varav jag skiftar ut två bitar för att få korrekt analog styrning med hjälp av gasreglaget. Ska testa din analoga interpoleringsfunktion lite senare när jag fått det viktiga att fungera först

barbarossa: Du har helt rätt att delayen borde ligga efter if-satsen. Jag testade som du sa med pushbutton funktionen och la in den i main istället, enligt följande;
Kod: Markera allt
void main()
{
InitMain(); // Initieringsvillkor
while(1)
{
AnalogStyrning();
BromsAktiverad();
Delay_ms(5);
}
}
void BromsAktiverad()
{
if (Button(&PORTB, 0, 1, 1)) oldstate = 1;
if (oldstate && Button(&PORTB, 0, 1, 0)) {
PWM1_Stop();
oldstate = 0;
delay_ms(1000);
}
PWM1_Start();
}
/Oscar
-
- EF Sponsor
- Inlägg: 544
- Blev medlem: 8 december 2006, 11:18:14
- Ort: Tågarp, Svalöv
Re: PWM utsignal beroende på Analog insignal (PIC16F690)
Du skall använda den kompilator som dina kompisar använder.
//A
//A
Re: PWM utsignal beroende på Analog insignal (PIC16F690)
Med hjälp av simulatorn i MPLAB kan du nog hitta de flesta buggar. Där kan du även se vad de olika funktionerna gör med registrena som tillhör CCP-modulen, AD-omvandlaren osv. Även en assembly listing finns tillgänglig i MPLAB. Programmerar du i MPLAB nu?
Kompilatorn är det nog inget fel på. Det är ju dokumentationen som inte verkar vara top notch.
Kompilatorn är det nog inget fel på. Det är ju dokumentationen som inte verkar vara top notch.
Re: PWM utsignal beroende på Analog insignal (PIC16F690)
Problemet låg dels i mjukvaran (tror att det var att interruptflaggan som satt i en if-sats, den är nu utanför) och dels i hårdvaran (Hade bara +5V från strömbrytaren direkt in mot RB0, nu har jag ett motstånd mot jord också för att det inte ska vara några 'lösa spänningar'.
Nu är tillståndsläget följande;
1:Jag levererar spänning via batteriet, inget händer; Bra.
2:Jag kan reglera motorstyrka med hjälp av gasreglaget; Bra.
3:Motorn stängs av under 5 sekunder när jag bromsar; Bra.
Dock har två nya småfel dykt upp:
1:När motorn varit avstängd under 5 sek, startar den direkt med full kraft. Interruptrutinen ska ju låta registrerna vara opåverkade? Tittar man i koden skall man programmet hoppa tillbaka in i AnalogStyrning() där jag måste ge fullt gaspådrag för att motorn ska ge full kraft? Konstigt. När jag väl börjar gasa med gasreglaget går motorn ner inställd styrka på gasreglage, dock måste jag komma över tröskeln på ca 20% för att den ska reagera på detta.
2:I ungefär hälften av tillfällena vid tillbakagången från en interrupt så hoppar motorn till 100% utan att jag kan påverka detta via gasreglage eller något annat, utan jag får ta bort spänningskällan för att komma tillbaka till normalläget. Konstigt?
Har försökt komma på vad som kan ställa till det men kommer bara fram till att det borde vara att PWM-registrerna inte förblir oförändrade under en interrupt.
Saxat från helpfilen: "mikroC PRO for PIC saves the following SFR on stack when entering interrupt and pops them back upon return:"
Barbarossa:
Vad menar du med att jag ska använda den kompilatorn mina kompisar använder?
Tack igen för er hjälp, ni är ett ljus i mörkret
/Oscar
Nu är tillståndsläget följande;
1:Jag levererar spänning via batteriet, inget händer; Bra.
2:Jag kan reglera motorstyrka med hjälp av gasreglaget; Bra.
3:Motorn stängs av under 5 sekunder när jag bromsar; Bra.
Dock har två nya småfel dykt upp:
1:När motorn varit avstängd under 5 sek, startar den direkt med full kraft. Interruptrutinen ska ju låta registrerna vara opåverkade? Tittar man i koden skall man programmet hoppa tillbaka in i AnalogStyrning() där jag måste ge fullt gaspådrag för att motorn ska ge full kraft? Konstigt. När jag väl börjar gasa med gasreglaget går motorn ner inställd styrka på gasreglage, dock måste jag komma över tröskeln på ca 20% för att den ska reagera på detta.
2:I ungefär hälften av tillfällena vid tillbakagången från en interrupt så hoppar motorn till 100% utan att jag kan påverka detta via gasreglage eller något annat, utan jag får ta bort spänningskällan för att komma tillbaka till normalläget. Konstigt?
Har försökt komma på vad som kan ställa till det men kommer bara fram till att det borde vara att PWM-registrerna inte förblir oförändrade under en interrupt.
Saxat från helpfilen: "mikroC PRO for PIC saves the following SFR on stack when entering interrupt and pops them back upon return:"
Barbarossa:
Vad menar du med att jag ska använda den kompilatorn mina kompisar använder?

Tack igen för er hjälp, ni är ett ljus i mörkret

/Oscar
Re: PWM utsignal beroende på Analog insignal (PIC16F690)
Nuvarande kod:
Kod: Markera allt
unsigned Analog0; CruiseControl; // Variablerdeklaration
void AnalogStyrning(void); // Funktion AnalogStyrning
void interrupt(void); // Interruptfunktioner*/
void InitMain(void);
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 = 0xFF; // Sätt PORTA till input
PORTB = 0xFF;
TRISB = 0xFF; // Sätt PORTB 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 initiering
// INTCON = INTERRUPT CONTROLREGSITER, OPTION_REG: OPTION REGISTER, IOCB: Interrupt On Change PORTB
OPTION_REG.INTEDG=0; // "Interrupt Edge Select Bit", triggar på RB0/INT pinnens negativa flank
INTCON.GIE=1; // Enabla globalt interrupt
INTCON.INTE=1; // Enabla INT/RB0 extern interrupt
INTCON.INTF=0; // Nollställ flaggan*/
}
void main(){
InitMain(); // Initieringsvillkor
while(1){
AnalogStyrning();
Delay_ms(5);
}
}
void interrupt (void){
if(PORTB.F0==0){ // Broms aktiv? (strömställarna har brytande funktion)
CruiseControl=0; // Inaktivera CruiseControl
PWM1_STOP(); // Stäng av PWM
PORTC=0x00; // Se till att det verkligen kommer ut 0 på utport
delay_ms(5000); // Tillfällig delayrutin
}
INTCON.INTF=0; // Klarsignalering; Nollställ interruptflagga
}
void AnalogStyrning(void){
Analog0=ADC_READ(0)>>2; // Skiftar bort 2 LSB. ad0 har nu ett värde mellan 0 och 255.
if(Analog0<52) // Om gasreglaget är nollställd, skicka ut 0.
Analog0=0;
if(Analog0>220) // Gasreglage på maximal styrka, skicka full PWM
Analog0=255;
Pwm1_Start(); // Starta PWM1
PWM1_SET_DUTY(Analog0); // Sätt nuvarande dutycykel för PWM1
}