Hoi,

ik wil beginnen met het inlezen van analoge waardes op mijn ATMEGA8 op 16MHz.
Na een zoektocht heb ik een begrijpelijke tutorial gevonden. Opzich snap ik in grote lijnen wel wat er gebeurt, alleen nog wat vraagjes:

ADCSRA=(1<<ADEN)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0);
Waarom kan ik niet zeggen: ADEN=1 etc.? Is dat omdat de AVR 'ADCSRA' wel fysiek kent, maar 'ADEN' niet?

Op bovenstaande manier wordt de sample frequentie ingesteld, in dit geval 16M / 128 = 125KHz. Ik wil in mijn ontwerp 2 ADC's uitlezen op minimaal 20Hz, een bipolaire stepper op max 3000 steps/sec aansturen en een op max 6000 steps/sec. Is het dan verstandig om de ADC op minder dan 125KHz uit te lezen, of is dat onmogelijk?

Bovendien: ik wil 20x per seconde de snelheid van beide steppers aanpassen aan de hand van de ADC waardes. Hoe moet ik tegelijk continu twee steppers op verschillende snelheden laten draaien, twee ADC waardes inlezen en die berekenen? Ik heb iets gehoord over threaden, maar hoe werkt dat?

Als ik vaag ben wil ik dat graag weten.

Tom

Hee TomTom

De samplefrequentie is de adc klok gedeeld door 13, 125kHz/13 dus. Je moet de adc klok niet boven de 1MHz laten komen, dus je kan maximaal 80ksps doen, 2 adc's op 40ksps.

ADEN = 1 kan niet omdat ADEN niets anders is dan een positie in het ADCSRA register. ADEN is een definitie van een nummer (bijvoorbeeld #define ADEN 7)

(1<<ADEN) set het bitje op positie 7 op 1.

Op 16 augustus 2009 20:17:37 schreef muddy:
ADCSRA=(1<<ADEN)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0);
Waarom kan ik niet zeggen: ADEN=1 etc.?

ADCSRA is het register waarvan je bepaalde bits wil setten. Kijk daarvoor zeker eens naar de datasheet p207!
ADEN ziet de compiler als een getal, in dit geval is dat 7. Dus: (1<<ADEN) wil zeggen, shift de laagste bit(1 dus) 7 plaatsen naar links. Je kan dit bvb ook vervangen door het getal 128 maar daarmee ziet niemand direct wat het betekent. Deze notatie wordt dus gebruikt omdat je direct ziet wat je doet.
At compile time, wordt er van "=(1<<ADEN)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0)" dus gewoon een getal gemaakt.

Op bovenstaande manier wordt de sample frequentie ingesteld, in dit geval 16M / 128 = 125KHz. Ik wil in mijn ontwerp 2 ADC's uitlezen op minimaal 20Hz, een bipolaire stepper op max 3000 steps/sec aansturen en een op max 6000 steps/sec. Is het dan verstandig om de ADC op minder dan 125KHz uit te lezen, of is dat onmogelijk?

De frequentie die je instelt is de clock voor de ADC module. Een convertie is klaar na 13 van die clocks. De frequentie bepaalt dus enkel hoe snel de convertie gebeurt. Hoeveel converties per seconde je doet heeft hier niets mee te maken (onrechtstreeks wel, hoe sneller, hoe meer je er zal kunnen doen natuurlijk)
Vanaf een frequentie van 1MHz is je nauwkeurigheid kleiner dan 8 bit.

Hoe moet ik tegelijk continu twee steppers op verschillende snelheden laten draaien, twee ADC waardes inlezen en die berekenen?

Door juist te kiezen wat je in je main loop doet en wat je via interrupts zal doen. Interrupts onderbreken je main loop, handelen iets af (bvb de adc converties) en laten nadien de main loop weer verder doen.

Ah, nu snap ik het een beetje, ik had ook verkeerd gelezen.
Ik dacht: shift ADEN met 1 plaats naar links, en dacht WTF. Het moet dus zijn: shift 1 met ADEN (dus 7) plaatsjes naar links).

Nog iets:
//Select ADC Channel ch must be 0-7
ch=ch&0b00000111;
ik neem aan dat de drie enen op het einde staan voor 7?

Ik snap nu hoe ik tijdens het aansturen van een stepper ADC waardes kan inlezen, met die interrupts, maar nog niet hoe ik twee steppers op verschillende snelheden tegelijk aan kan sturen. Want je krijgt dan toch twee loops:
pinnetje van motor 1 hoog, wacht even, ander pinnetje hoog etc,
pinnetje van motor 2 hoog, wacht net iets langer, ander pinnetje hoog etc. En ik zie niet hoe ik die loops tegelijk kan laten draaien.

ch=ch&0b00000111 staat idd voor kanaal 7.

Datasheet p205:
ADMUX bits 3:0 - MUX3:0: Analog Channel Selection Bits:

0000 ADC0
0001 ADC1
  .   .
  .   .
0110 ADC6
0111 ADC7

Je leest toch beter eens de delen van de datasheet met betrekking op jouw toepassing. Lees eens alles over de ADC module van de AVR. Het is maar 14 blz. en je zal er veeel aan hebben.
Hoe je steppers aangestuurd moeten worden weet ik niet dus kan weinig zeggen over hoe je best je main loop en interrupts implementeert.

Timer's gebruiken? Zodra de motor 1 hoog wordt een timer starten, en dan in de interrupt je andere hoog maken. Voor die ander hetzelfde maar dan met een andere timer. Door een offset in de timer te zetten kan je de wachttijd voor een interrupt beinvloeden.

Ja binary 000000000111 is 7 in decimaal, hex, en octaal.

Tja, twee steppers op verschillende snelheden is lastig. Je kunt bijhouden wanneer je weer iets moet doen met beide steppers.


while (1) {
   time_to_sleep = min (sleep1, sleep2);
   sleep (time_to_sleep);
   sleep1 -= time_to_sleep;
   sleep2 -= time_to_sleep; 
   if (!sleep1) {
       // Doe iets met motor1 
       .... 
       sleep1 = ...; / *tijd om te  wachten voor motor1. 
   }   
   if (!sleep2) {
       // Doe iets met motor2
       .... 
       sleep2 = ...; / *tijd om te  wachten voor motor2. 
   }
}

Dit is dan met sleeps in het hoofdprogramma, maar iets dergelijks kun je maken op basis van interrupts.

een tijdje geleden heb ik ook zoiets gemaakt
voor 2 hardware PWM's ziet het er ongeveer zo uit in assembly...
(meer details kun je vinden op mijn site)


...

Start_ADC:

    ldi   Input,32       ;ADLAR + ADC0 > 0b00100000 = 32 decimaal
    
 Next_Input:

    out   ADMUX,Input
    in    temp,ADCSR
    sbr   temp,(1<<ADSC); aanleggen startbit ADSC
    out   ADCSR,temp

 Busy:

    sbic  ADCSR,ADSC    ;wachten tot startbit ADSC 0 wordt
    rjmp  Busy
 	
    cpi   Input,32      ;ADLAR + ADC0 > 0b00100000 = 32 decimaal
    breq  Laden_OCR1A
    cpi   Input,33      ;ADLAR + ADC1 > 0b00100001 = 33 decimaal
    breq  Laden_OCR1B
    rjmp  Start_ADC   
      
 Laden_OCR1A:
  
    in     temp,ADCH
    out    OCR1A,temp
    inc    Input
    rjmp   Next_Input

 Laden_OCR1B:

    in     temp,ADCH
    out    OCR1B,temp
    rjmp   Start_ADC
   
 .exit