hjælp til servo kontrol med timer (Læst 128953x)

Offline pacman

  • Højpas filter
  • *****
  • Indlæg: 311
  • Antal brugbare Indlæg: 8
  • Jens Bauer (Forsøgs-person)
    • Vis profil
Sv: hjælp til servo kontrol med timer
« Svar #270 Dato: November 25, 2011, 20:53:29 »
kan man ikke lave en løsning hvor den kun aflæser adc værdierne når der trykkes på start knappen? der er jo ingen grund til at den kigger på dem når programmet er startet op, med mindre mam selvfølgelig vil ændre doseringen, men så ma man trykke på start når det er gjort. så skal ADC interruptne jo kun køres enten ved tryk på start, eller ved timer0elapsed

Selvfølgelig. Det var egentlig forberedt på at skulle læse 2 potmetre og 2 sæt DIP-switches. ;)
...Derudover regnede jeg med at du ville køre microcontrolleren på 8MHz.
Men du kan til at starte med, prøve at kalde initADC(10) fra main().
Og så i ADC-interruptet lave følgende lille ændring, det skulle give lidt mere CPU-tid:

Kode:
ISR(ADC_vect)
{
uint8_t adLo;
uint8_t adHi;

#if 0
if(adcBits <= 8) /* using 8-bit precision */
{
if(ADCSRB & (1 << ADLAR)) /* check hardware alignment-configuration and act accordingly */
{
adLo = 0;
adHi = inb(ADCH); /* (read highbyte only) */
}
else
{
adHi = 0;
adLo = inb(ADCH); /* (read highbyte only) */
}
}
else
{
adLo = inb(ADCL); /* read lowbyte before highbyte! */
adHi = inb(ADCH); /* read lowbyte before highbyte! */
}
#else /* always 10-bit */
adLo = inb(ADCL); /* read lowbyte before highbyte! */
adHi = inb(ADCH); /* read lowbyte before highbyte! */
#endif
adcValue[adcChannel - ADC_FIRST][adcWriteIndex] = (adHi << 8) | adLo; /* save the value we've read above */

if(adcChannel++ >= ADC_LAST) /* next channel. If channel reached last channel... */
{
adcChannel = ADC_FIRST; /* ...start over */
adcWriteIndex = adcWriteIndex >= (ADC_SIZE - 1) ? 0 : (adcWriteIndex + 1); /* increment write position and wrap if necessary */
adcReadIndex = adcReadIndex >= (ADC_SIZE - 1) ? 0 : (adcReadIndex + 1); /* increment read position and wrap if necessary */
if(adcCounter < ADC_STABLE) /* if we haven't reached the number of conversions required for the ADC to stabilize... */
{
adcCounter++; /* increment counter */
}
}
ADMUX = (0 << REFS1) | (0 << REFS0) | (adcChannel & 0x07); /* set which channel to read next time */
ADCSRA |= (1 << ADSC); /* start another conversion */
}

Her har jeg sat #if 0, #else og #endif ind. Jeg har også kopieret de 2 linier, som håndterer 10-bit konvertering.
Der spares nu omkring 10 ... 11 clock cycles i interruptet, og derfor burde det køre en smule bedre. Om det er nok, vil en prøve vise.

Jeg har en lille modifikation til Timer0.c...

I TIM0_OVF_vect:
Kode:
#if (F_CPU > 2000000)
TCNT0 = 256 - ((uint8_t) ((F_CPU / 256) / 125)); /* interrupt occurs 125 times per second. */
#else
TCNT0 = 256 - ((uint8_t) ((F_CPU / 64) / 125)); /* interrupt occurs 125 times per second. */
#endif

I initTimer0:
Kode:
#if (F_CPU > 2000000)
TCCR0B = (0 | (0 << FOC0A) | (0 << FOC0B) | (0 << WGM02) | (1 << CS02) | (0 << CS01) | (0 << CS00)); /* using PRESCALER256 */
#else
TCCR0B = (0 | (0 << FOC0A) | (0 << FOC0B) | (0 << WGM02) | (0 << CS02) | (1 << CS01) | (1 << CS00)); /* using PRESCALER64 */
#endif

-For så kan du nemlig skifte mellem 1MHz og 8MHz som du har lyst. :)

 

Offline jascore

  • Jordet Basic
  • **
  • Indlæg: 157
  • Antal brugbare Indlæg: 0
    • Vis profil
Sv: hjælp til servo kontrol med timer
« Svar #271 Dato: November 25, 2011, 21:04:02 »
Citér
Det var egentlig forberedt på at skulle læse 2 potmetre og 2 sæt DIP-switches. ;)
...Derudover regnede jeg med at du ville køre microcontrolleren på 8MHz
ja der er rigtigt. regnede også med at der var derfor at adc prescaleren var sat til 128.
mht at køre 8 mhz. den eneste grund til ikke at gøre dette er at jeg har læst at det skulle være sværre at lave den 20 ms cycle der skal bruges til servoen. ellers er der ikke nogen grund. til ikke at gøre det
og et eller andet sted er det vel også tåbeligt ikke at køre alt hvad den kan trække.
prøver at smide ændringerne ind.
ved ikke hvad jeg skulle have gjort uden din hjælp. det er jo en helt ny verden der åbner sig, hvis man kan lide at lege med sådan noget  :P

 

Offline pacman

  • Højpas filter
  • *****
  • Indlæg: 311
  • Antal brugbare Indlæg: 8
  • Jens Bauer (Forsøgs-person)
    • Vis profil
Sv: hjælp til servo kontrol med timer
« Svar #272 Dato: November 25, 2011, 21:15:45 »
Citér
Det var egentlig forberedt på at skulle læse 2 potmetre og 2 sæt DIP-switches. ;)
...Derudover regnede jeg med at du ville køre microcontrolleren på 8MHz
ja der er rigtigt. regnede også med at der var derfor at adc prescaleren var sat til 128.
mht at køre 8 mhz. den eneste grund til ikke at gøre dette er at jeg har læst at det skulle være sværre at lave den 20 ms cycle der skal bruges til servoen. ellers er der ikke nogen grund. til ikke at gøre det

I øjeblikket kører Timer1 på clk / 1; den kan bare sættes til clk/8, så kører den samme hastighed som nu. :)
-Vi har jo gemt 16-bit timeren til det vigtige. ;)

 

Offline pacman

  • Højpas filter
  • *****
  • Indlæg: 311
  • Antal brugbare Indlæg: 8
  • Jens Bauer (Forsøgs-person)
    • Vis profil
Sv: hjælp til servo kontrol med timer
« Svar #273 Dato: November 25, 2011, 21:17:44 »
det hjalp desværre ikke. men er det nødvendigt med ADCSRA |= (1 << ADSC); i initADC kan jeg ikke bare flytte den der er i bunden af ISR(ADC_vect) op i toppen af ISR(ADC_vect) ? vil det ikke give det samme?
hvis det er ok så køre timeren hvertfald

Da vil ADC'en aldrig køre, for det er netop ADCSRA's ADSC, der starter ADC'en. (Analog-to-Digital-Start-Conversion).

 

Offline pacman

  • Højpas filter
  • *****
  • Indlæg: 311
  • Antal brugbare Indlæg: 8
  • Jens Bauer (Forsøgs-person)
    • Vis profil
Sv: hjælp til servo kontrol med timer
« Svar #274 Dato: November 25, 2011, 21:26:57 »
I øjeblikket kører Timer1 på clk / 1; den kan bare sættes til clk/8, så kører den samme hastighed som nu. :)
-Vi har jo gemt 16-bit timeren til det vigtige. ;)

Her er lidt forberedelse på at skifte frekvens til Servo.c, plus forhåbentlig bliver koden lidt mere læsbar...
Kode:
#include "leds.h"

#define PRESCALER1 ((0 << CS12) | (0 << CS11) | (1 << CS10)) /* clk / 1 (no prescaling) */
#define PRESCALER8 ((0 << CS12) | (1 << CS11) | (0 << CS10)) /* clk / 8 */
#define PRESCALER64 ((0 << CS12) | (1 << CS11) | (1 << CS10))
#define PRESCALER256 ((1 << CS12) | (0 << CS11) | (0 << CS10))
#define PRESCALER1024 ((1 << CS12) | (0 << CS11) | (1 << CS10))

#if (F_CPU <= 1000000)
#define PRESCALER PRESCALER1
#else
#define PRESCALER PRESCALER8
#endif

void initServo()

Længere nede, nemlig i initServo():
Kode:
	if(GPIOR2 == SERVO_ENABLED)
{
TCCR1B = (1 << WGM13) | (1 << WGM12) | PRESCALER; /* set WGM to fast PWM, choose clock source */
}

Jeg har ændret (1 << CS10) til PRESCALER

 

Offline jascore

  • Jordet Basic
  • **
  • Indlæg: 157
  • Antal brugbare Indlæg: 0
    • Vis profil
Sv: hjælp til servo kontrol med timer
« Svar #275 Dato: November 25, 2011, 22:34:01 »
mht til ADCSRA |= (1 << ADSC);
kan jeg så ikke lade den ligge i initADC og så en i startknappen. så i ISR(PCINT0_vect) fjerne ADCSRA |= (1 << ADSC);
lave en
if(adcChannel == ADC_LAST)
{
     ADCSRA |= (0 << ADSC);
}
hvis jeg gør det på den måde så køre timeren hvertfald.   

 

Offline pacman

  • Højpas filter
  • *****
  • Indlæg: 311
  • Antal brugbare Indlæg: 8
  • Jens Bauer (Forsøgs-person)
    • Vis profil
Sv: hjælp til servo kontrol med timer
« Svar #276 Dato: November 25, 2011, 22:41:51 »
mht til ADCSRA |= (1 << ADSC);
kan jeg så ikke lade den ligge i initADC og så en i startknappen. så i ISR(PCINT0_vect) fjerne ADCSRA |= (1 << ADSC);
lave en
if(adcChannel == ADC_LAST)
{
     ADCSRA |= (0 << ADSC);
}
hvis jeg gør det på den måde så køre timeren hvertfald.   

Hele denne blok...
Kode:
if(adcChannel == ADC_LAST)
{
     ADCSRA |= (0 << ADSC);
}

...gør ingenting - bortset fra at bruge CPU-tid. :)

Det vil være bedre at sætte microcontrolleren op på 8MHz, eller gå bort fra at bruge ADC-interrupt.
-Da skal vi til at kigge på at aflæse ADC'en manuelt; dvs. lave 4 aflæsninger manuelt i streg.
Det kan så gøres i getADCxValue().

...Men bemærk; én aflæsning vil nok være for upræcist / ustabil, for den vil nok virke nogle gange, men andre gange vil den slå fejl.
Det er derfor bedst at tage 4 aflæsninger (eller 8) og så lægge alle aflæsningerne sammen, og sidst dividere med antallet af aflæsninger.
...Jeg siger 4 eller 8, fordi man så kan bruge bitskift operationer, hvilket er langt mere CPU-venligt end almindelige divisioner. :)

-Men da skal initADC være lidt anderledes.

 

Offline jascore

  • Jordet Basic
  • **
  • Indlæg: 157
  • Antal brugbare Indlæg: 0
    • Vis profil
Sv: hjælp til servo kontrol med timer
« Svar #277 Dato: November 25, 2011, 22:45:02 »
Citér
Hele denne blok...
gg ok  :-[
men skal der være en ADCSRA |= (1 << ADSC);
både i initADC og i ISR(PCINT0_vect)
er det ikke nok at starte den et sted ?

 

Offline pacman

  • Højpas filter
  • *****
  • Indlæg: 311
  • Antal brugbare Indlæg: 8
  • Jens Bauer (Forsøgs-person)
    • Vis profil
Sv: hjælp til servo kontrol med timer
« Svar #278 Dato: November 25, 2011, 22:54:59 »
Citér
Hele denne blok...
gg ok  :-[
men skal der være en ADCSRA |= (1 << ADSC);
både i initADC og i ISR(PCINT0_vect)
er det ikke nok at starte den et sted ?

Den starter kun én konvertering ad gangen. :)
-Den kører nemlig ikke kontinuerligt, men skal sættes igang manuelt hver gang.

 

Offline jascore

  • Jordet Basic
  • **
  • Indlæg: 157
  • Antal brugbare Indlæg: 0
    • Vis profil
Sv: hjælp til servo kontrol med timer
« Svar #279 Dato: November 26, 2011, 03:39:27 »
prøvede lige en sidste ting inden sove til
Kode:
ISR(ADC_vect)
{

if(ADCL > 128)
   {
setLED1(1);
setLED2(0);

   }
     
   else
   {
setLED1(0);
setLED2(1);
 
   }
ADCSRA |= (1 << ADSC);
}
void initADC(uint8_t aBits)
{

ADMUX = (0 << REFS1) | (0 << REFS0);
ADCSRA = (1 << ADEN) | (1 << ADIF) | (1 << ADIE) | (0 << ADPS2) | (1 << ADPS1) | (1 << ADPS0);
sei();
ADCSRB = (0 << ADTS2) | (0 << ADTS1) | (0 << ADTS0) | (1 << ADLAR);

ADCSRA |= (1 << ADSC);
 }

Når jeg gør sådan så skifter led kun efter jeg ændre på dips og pot (ADCL) slukker strøm og tænder igen.
den vil ikke skifte mens der er tændt og jeg skifter. alle andre init er kommenteret ud.

 

Offline jascore

  • Jordet Basic
  • **
  • Indlæg: 157
  • Antal brugbare Indlæg: 0
    • Vis profil
Sv: hjælp til servo kontrol med timer
« Svar #280 Dato: November 26, 2011, 23:23:31 »
nu har jeg simpelthen været ISR(ADC_vect) igennem fra a-z (det siger jeg hvertfald til mig selv :o ).
har enda haft lavet et komplet tomt program der kun tog sig af adc interrupt i free running mode og lige meget hvad
jeg gør så kræver det at jeg slukker og tænder for strømmen til avr, før den registrerer ændringer på adc'en. jeg kan ikke forstå det.

Lige et hurtigt spørgsmål.
hvis jeg vil ændre f_cpu kan jeg godt bare nøjes med at ændre clock i makefilen?

og lige en ting til. ved ikke om det har betydning for hvordan chippen har det, men device signature er som den skal være.
« Senest Redigeret: November 26, 2011, 23:25:32 af jascore »

 

Offline pacman

  • Højpas filter
  • *****
  • Indlæg: 311
  • Antal brugbare Indlæg: 8
  • Jens Bauer (Forsøgs-person)
    • Vis profil
Sv: hjælp til servo kontrol med timer
« Svar #281 Dato: November 26, 2011, 23:53:05 »
nu har jeg simpelthen været ISR(ADC_vect) igennem fra a-z (det siger jeg hvertfald til mig selv :o ).
har enda haft lavet et komplet tomt program der kun tog sig af adc interrupt i free running mode og lige meget hvad
jeg gør så kræver det at jeg slukker og tænder for strømmen til avr, før den registrerer ændringer på adc'en. jeg kan ikke forstå det.

Mærkeligt. Der må være noget vi har glemt i opsætningen, for det skal kunne virke.

Citér

Lige et hurtigt spørgsmål.
hvis jeg vil ændre f_cpu kan jeg godt bare nøjes med at ændre clock i makefilen?
Nej.
lfuse skal ændres til 0xe2, hvilket sætter frekvensen til 8MHz (bit 7) plus CLOCK skal ændres så den passer til den nye frekvens. -Hvis du kun ændrer F_CPU, vil det virke som om microcontrolleren kører 8 gange langsommere.

Citér
og lige en ting til. ved ikke om det har betydning for hvordan chippen har det, men device signature er som den skal være.

Nogle gange laver Atmel nye chips, og de laver derfor nye 'Device Signatures'.
I sådanne tilfælde skal man lave en konfiguration til den nye chip i sin avrdude.conf (hvor den så end befinder sig).
avrdude brokker sig hvis device-signature er forkert; ellers oplyser den bare hvad device-signature er, derfor kan du bare ignorere denne besked. :)

 

Offline jascore

  • Jordet Basic
  • **
  • Indlæg: 157
  • Antal brugbare Indlæg: 0
    • Vis profil
Sv: hjælp til servo kontrol med timer
« Svar #282 Dato: November 27, 2011, 18:17:55 »
Hej igen.
nu bliver det lidt mere konkret gg
det er denne linie der fryser systemet i ISR(ADC_vect)
adcValue[adcChannel - ADC_FIRST][adcWriteIndex] = (adHi << 8 ) | adLo;            /* save the value we've read above */
og den hænger jo sammen med if (adcBits <= 8 )

ISR(ADC_vect)
{
    toggleLED1();

    uint8_t        adLo;
    uint8_t        adHi;

    if(adcBits <= 8 )                                                /* using 8-bit precision */
   {
        if(ADCSRB & (1 << ADLAR))                                          /* check hardware alignment-configuration and act accordingly */
      {
            adLo = 0;
            adHi = inb(ADCH);                                             /* (read highbyte only) */
      }
        else
      {
            adHi = 0;
            adLo = inb(ADCH);                                             /* (read highbyte only) */
      }
   }
    else
   {
        adLo = inb(ADCL);                                             /* read lowbyte before highbyte! */
        adHi = inb(ADCH);                                             /* read lowbyte before highbyte! */
   }

så længe jeg køre 8 bit kan jeg jo reducere den til at fjerne alle else og når jeg ved at jeg har sat ADLAR i initADC kan jeg vel ogso fjerne if condition og det samme når jeg ved at adc er 8 bit sat i main.c fjerner jeg også den sidste if lige for en stund, og ender ud med en værdi for adLo og adHI. dem smider jeg så ind i linien der skaber problemer og den kommer til at hedde

adcValue[adcChannel - ADC_FIRST][adcWriteIndex] = (inb(ADCH) << 8 ) | 0;

er det korrekt reduceret?
hvordan den linie så fungerer har jeg ingen ide om endnu, men tror den har noget med de værdier der skal bruges i tabellen, og hvad det er der får den til at fryse har jeg heller ikke gennemskuet endnu  :o
Men erstatter jeg det før = tegnet med en anden variabel, så virker det godt og så må det være adcValue[adcChannel - ADC_FIRST][adcWriteIndex] der fryser systemet men det kan selvfølgelig også være værdien den vil skrive der er noget galt med

ved godt der er et mellemrum for meget i 8 ) men det er for at slippe for smily
« Senest Redigeret: November 27, 2011, 18:54:38 af jascore »

 

Offline jascore

  • Jordet Basic
  • **
  • Indlæg: 157
  • Antal brugbare Indlæg: 0
    • Vis profil
Sv: hjælp til servo kontrol med timer
« Svar #283 Dato: December 10, 2011, 17:54:09 »
Har fundet ud af at hvis jeg istedet for freerunning mode sætter den til singleconversion mode og så starter en ny conversion med ADCSRA |= (1 << ADSC); inde i ISR(ADC_vect) så konverterer den der ud af.

HAr også haft servoen til at køre dog ikke ved hjælp af adc værdierne, men med konstante værdier.
MEN - -  er der en metode der elimere støj på pwm. for servoen står og sitre når den egentlig skulle stå stille. Så der må være en eller anden form for støj i pwm signalet eks vil værdien 1,2 ikke være konstant men nogle gange eks 1.21 og 1.19

og den eneste måde jeg kan få den til at køre 8 mhz er ved at sætte CLOCK til 1mhz og lfuse til e2 tror jeg
jeg tester det ved at hvis jeg lader lfuse være som den burde til 8 mhz, altså e2 og så sætter clock til 8mhz så kører blinker min timer langsommere
sætter jeg den som den skal i 1 mhz altså ifuse 62 så er den 8 gange langsomere med 8mhz clock end 1 mhz clock
kan dog kun se forskellen med en delay.
« Senest Redigeret: December 11, 2011, 01:22:56 af jascore »

 

Offline jascore

  • Jordet Basic
  • **
  • Indlæg: 157
  • Antal brugbare Indlæg: 0
    • Vis profil
Sv: hjælp til servo kontrol med timer
« Svar #284 Dato: December 11, 2011, 02:41:23 »
fandt lige en bummert mere jeg har lavet.
det nytter jo ikke noget at jeg køre 8 bit adc og søger resultatet i en 10 bit tabel eller tager jeg fejl