Forum: Mikrocontroller und Digitale Elektronik ATtiny vco (voltage controlled oscillator) mit timer


von Alexander M. (alex1983m)


Lesenswert?

Guten Abend,
zu meiner Hardware:
ATtiny13, Dragon, AtmelStudio 6

vorgeschichte:
- AD-Wandlung an PB3 & PB4 (ohne Timer-Interrupt)funktioniert Wunderbar
- Timer-Interrupt (ohne AD-Wandlung) funktioniert Wunderbar

zu meinem Problem:
ich würde gerne beides kombinieren um daraus 2 vco's (z.B PB0 & PB1) zu 
realisieren, zur not tuts auch nur ein vco.

Hat irgendjemand ideen?

Hier mein Code der so nicht funktioniert:
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
4
int portb_out();
5
int init_timer();
6
int config_adc(int x);
7
8
9
volatile int a = 0;            // Zählvariable
10
volatile int b = 0;            // Zählvariable
11
12
13
unsigned int adc3h = 0;
14
unsigned int adc3l = 0;
15
unsigned int adc2h = 0;
16
unsigned int adc2l = 0;
17
18
ISR(TIM0_OVF_vect) 
19
{
20
  ++a;
21
  ++b;        
22
}
23
24
25
int main(void) 
26
{
27
  portb_out();            // aufruf des Prototypen zur Initialisierung
28
  init_timer();           // aufruf des Prototypen zur Initialisierung
29
  
30
  
31
  while(1) 
32
  {
33
    config_adc(2);
34
    adc2l = ADCL;                  // schreibt die untersten 2 Bits
35
    adc2h = ADCH;                  // schreibt die obersten 8 Bits 
36
    ADCSRA = ADCSRA & (~(1<<ADEN));                  // stoppt den ADC
37
    
38
    if (a == adc2h)
39
    {
40
      PORTB ^= 0b00000001;    // ^= toggelt PB0
41
      a = 0;
42
    } 
43
    
44
    config_adc(3);                          
45
    adc3l = ADCL;                  // schreibt die untersten 2 Bits 
46
    adc3h = ADCH;                  // schreibt die obersten 8 Bits 
47
    ADCSRA = ADCSRA & (~(1<<ADEN));                  // stoppt den ADC
48
    if (b == adc3h)
49
    {
50
      PORTB ^= 0b00000010;    // ^= toggelt PB1
51
      b = 0;
52
    }
53
    
54
  }
55
}
56
57
58
59
int portb_out()
60
{
61
  DDRB = DDRB | 0b00000011;                    
62
  PORTB = 0;       
63
}
64
65
int init_timer()
66
{
67
  TCCR0B=0x01;
68
  TIMSK0 |=1<<TOIE0;          // enable timer overflow interrupt
69
  sei();
70
}
71
72
int config_adc(x)
73
{
74
  ADMUX = x;                          // Auswahl des ADC-Kanals:
75
  DIDR0 = 0b00011000;                      
76
  ADMUX |= (0 << REFS0);                    
77
  ADMUX |= (1 << ADLAR);                  
78
  ADCSRA |= (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0);     
79
  ADCSRB |= (0 << ADTS2) | (0 << ADTS1) | (0 << ADTS1);   
80
  ADCSRA |= (1 << ADEN);                    // aktiviert den ADC
81
  ADCSRA |= (1 << ADSC);                    
82
  while(ADCSRA & (1<<ADSC))                  
83
  {
84
    asm volatile("nop");                  // NOP
85
  }
86
}

von Alexander M. (alex1983m)


Lesenswert?

Hat jmd. eine Idee?

von Jonas B. (jibi)


Lesenswert?

Moin,

warum konfigurierst du die Adc's in deiner Hauptschleife ständig neu? Es 
reicht wenn man das einmal macht.

> while(1)
>  {
>    config_adc(2);
>  ...

Sonst sind noch ein paar weitere Denkfehler drin.
Schau mal dieser Code wartet wohl bis der Adc einen Wert gesampled hat:

>while(ADCSRA & (1<<ADSC))
>  {
>    asm volatile("nop");                  // NOP
>  }

So und danach solltest du denn Wert auch speichern, fehlt bei dir. 
Ansonsten musst du einiges umstellen, damit dein Code Sinn ergibt.

Gruß Jonas

von Alexander M. (alex1983m)


Lesenswert?

Beim ständigen konfigurieren der ADC'c übergebe ich immer den Wert 2 und 
danach 3, dadurch wähle ich zu erst den ADC von Port PB4 aus lese den 
AD-Wert ein, dann wird der Port PB3-ADC gewählt und der AD-Wert 
eingelessen.

Funktioniert das mit der while-schleife so nicht? Ich speicher doch den 
Wert des ADC in der main-routine.

...
> config_adc(2);
>     adc2l = ADCL;                  // schreibt die untersten 2 Bits
>     adc2h = ADCH;                  // schreibt die obersten 8 Bits
...


Und was müsste man sonst am Code ändern damit er Sinn ergibt, versteh 
ich irgendwie nicht ganz?!

Gruß Alex

von Karl H. (kbuchegg)


Lesenswert?

Alexander M. schrieb:

> Und was müsste man sonst am Code ändern damit er Sinn ergibt, versteh
> ich irgendwie nicht ganz?!

Schau dir an, wie man den ADC sauber benutzt.

http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/Analoge_Ein-_und_Ausgabe#Nutzung_des_ADC

Da findest du auch saubere Routinen, die du mehr oder weniger direkt 
benutzen kannst. Wenn du ADLAR haben willst, dann musst du sie ein wenig 
verändern, aber im Großen und Ganzen haben die Funktionen eine sinnvolle 
Aufteilung in Initialisierung und 'Mache_eine_Messung'

Und die Signalgenerierung verlagerst du als ganzes in die Timer ISR. 
Denn das ist wichtiger das dieser Teil absolut regelmässig als ganzes 
abläuft, als das der ADC-Wert ein paar µ-Sekunden früher oder später zur 
Verfügung steht.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.