ATtiny vco (voltage controlled oscillator) mit timer

OP #2899767
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
}
#2901163
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
OP #2902282
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
#2902286
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.

Antwort schreiben

Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt. Bitte hier nur auf die ursprüngliche Frage antworten, für neue Fragen einen neuen Beitrag erstellen.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.