Forum: Mikrocontroller und Digitale Elektronik Einfache Spannungsmessung attiny15


von NickJag (Gast)


Lesenswert?

Hallo ich finde in meinem quellcode den fehler nicht, und der tiny gibt 
mir einfach an den ausgängen nichts aus, egal welche spannung ich an PB4 
anlege, hab ich etwas vergessen?

An PB4 lege ich eine externe spannung an die gemessen werden soll
an PB0-3 sind einfach leds mit widerstand an gnd angeschlossen

quellcode:
1
#include <avr/io.h>
2
#include <inttypes.h>
3
#ifndef F_CPU
4
#warning "F_CPU war noch nicht definiert, wird nun mit 1000000 definiert"
5
#define F_CPU 1000000     /* Quarz mit 1 Mhz  */
6
#endif
7
#include <util/delay.h>     /* bei alter avr-libc: #include <avr/delay.h> */      
8
9
10
11
uint16_t ReadChannel(uint8_t mux)
12
{
13
  uint8_t i;
14
  uint16_t result;
15
 
16
  ADMUX = mux;                      // Kanal waehlen
17
  
18
  /* interne Referenzspannung nutzen (atmega8 2.56V) 10-bit = 0-1023
19
    2.56V/1024 = 0.0025V  4Led's alle 0,5V /0.0025= 200
20
   200 = 0,5V --> Led1 --> 0b0011001000 --> 0x00C8
21
   400 = 1,0V --> Led2 --> 0b0110010000 --> 0x0190
22
   600 = 1,5V --> Led3 --> 0b1001011000 --> 0x0258
23
   800 = 2,0V --> Led4 --> 0b1100100000 --> 0x0320
24
  1000 = 2,5V --> Alle --> 0b1111101000 --> 0x03E8
25
  */
26
  ADMUX |= (1<<REFS1);
27
  ADMUX &= ~(1<<REFS0); 
28
29
30
 /* Frequenzvorteiler berechnen 
31
  TFmin = 1Mhz/200Khz = 5
32
  TFmax = 1Mhz/50Khz = 20   
33
  setzen auf 8 (1) und ADC aktivieren (1) */
34
  ADCSRA = (1<<ADEN) | (1<<ADPS1) | (1<<ADPS0);    
35
 
36
  /* nach Aktivieren des ADC wird ein "Dummy-Readout" empfohlen, man liest
37
     also einen Wert und verwirft diesen, um den ADC "warmlaufen zu lassen" */
38
  ADCSRA |= (1<<ADSC);              // eine ADC-Wandlung 
39
  while ( ADCSRA & (1<<ADSC) ) {
40
     ;     // auf Abschluss der Konvertierung warten 
41
  }
42
  result = ADCW;  // ADCW muss einmal gelesen werden,
43
                  // sonst wird Ergebnis der nächsten Wandlung
44
                  // nicht übernommen.
45
 
46
  /* Eigentliche Messung - Mittelwert aus 4 aufeinanderfolgenden Wandlungen */
47
  result = 0; 
48
  for( i=0; i<4; i++ )
49
  {
50
    ADCSRA |= (1<<ADSC);            // eine Wandlung "single conversion"
51
    while ( ADCSRA & (1<<ADSC) ) {
52
      ;   // auf Abschluss der Konvertierung warten
53
    }
54
    result += ADCW;        // Wandlungsergebnisse aufaddieren
55
  }
56
  ADCSRA &= ~(1<<ADEN);             // ADC deaktivieren (2)
57
 
58
  result /= 4;                     // Summe durch vier teilen = arithm. Mittelwert
59
 
60
  return result;
61
}
62
 
63
 
64
65
 
66
int main()
67
{
68
69
uint16_t LED1 = 0x00C8;
70
uint16_t LED2 = 0x0190;
71
uint16_t LED3 = 0x0258;
72
uint16_t LED4 = 0x0320;
73
uint16_t ALLE = 0x03E8;
74
75
76
DDRB &= ~(1 << PB4);                          // PB4 als ADC Eingang
77
DDRB |= (1 << PB0)|(1 << PB1)|(1 << PB2)|(1 << PB3);// PB0-PB3 als Ausgang (LED's)
78
79
80
while(1)
81
{
82
  uint16_t wert;
83
 
84
  wert = ReadChannel(3); /* MUX-Bits auf 0b0011 -> Channel 3 */
85
86
/* Ausgabe der Spannungen an LED's */
87
88
  if (wert < LED1)
89
    {
90
    PORTB = 0x00;
91
  }
92
    if ((wert >= LED1) & (wert < LED2))
93
  {
94
    PORTB = (1 << PB0);
95
  } 
96
  if ((wert >= LED2) & (wert < LED3))
97
  {
98
    PORTB = (1 << PB1);
99
  }
100
  if ((wert >= LED3) & (wert < LED4))
101
  {
102
    PORTB = (1 << PB2);
103
  }
104
  if ((wert >= LED4) & (wert < ALLE))
105
  {
106
    PORTB = (1 << PB3);
107
  }
108
  if (wert >= ALLE)
109
  {
110
    PORTB = (1 << PB0)|(1 << PB1)|(1 << PB2)|(1 << PB3);
111
  }
112
113
}
114
 
115
}


währe nett wenn ihr mir weiterhelfen könntet

von Hannes Lux (Gast)


Lesenswert?

Ich wusste gar nicht, dass man RAMlose AVRs in C programmieren kann...

...

von Michael U. (amiga)


Lesenswert?

Hallo,

zumindest mein WinAVR kann das nicht...

../main.c:1: error: MCU 'attiny15' supported for assembler only

c:/winavr-20090313/lib/gcc/../../avr/include/avr/iotn15.h:51:4: warning: 
#warning "MCU not supported by the C compiler"

Gruß aus Berlin
Michael

von Christian H. (netzwanze) Benutzerseite


Lesenswert?

NickJag wrote:
> An PB4 lege ich eine externe spannung an die gemessen werden soll
> an PB0-3 sind einfach leds mit widerstand an gnd angeschlossen

AVRs haben OC-Ausgänge. Hänge die LED daher zwischen Vcc und Port.

Ansonsten könnte es mit ramlosen AVRs schon funktionieren, wenn die 
Variablen sauber in die Register passen. Kommt aber auf den Compiler 
drauf an. Zur Sicherheit vor den Variablendefinitionen "register" davor 
hängen.
1
uint16_t ReadChannel(uint8_t mux)
2
{
3
  register uint8_t i;
4
  register uint16_t result;

und
1
while(1)
2
{
3
  register uint16_t wert;


Außerdem:
1
static uint16_t LED1 = 0x00C8;
2
static uint16_t LED2 = 0x0190;
3
...

Hier sollte aber zur Sicherheit überall ein "static" davor stehen. 
Eventuell erkennt es der Compiler aber selber, dass diese Variablen nie 
verändert werden und trägt sie als konstant in den Code ein.

Christian

von Johannes M. (johnny-m)


Lesenswert?

Christian Harf wrote:
> NickJag wrote:
>> An PB4 lege ich eine externe spannung an die gemessen werden soll
>> an PB0-3 sind einfach leds mit widerstand an gnd angeschlossen
>
> AVRs haben OC-Ausgänge. Hänge die LED daher zwischen Vcc und Port.
Unsinn. AVRs haben Push-Pull-Ausgänge und dementsprechend ist es in den 
meisten Fällen wurscht, ob man LEDs High- oder Low-Side anschließt.

> Ansonsten könnte es mit ramlosen AVRs schon funktionieren, wenn die
> Variablen sauber in die Register passen. Kommt aber auf den Compiler
> drauf an. Zur Sicherheit vor den Variablendefinitionen "register" davor
> hängen.
Auch das bringt nichts. Erstens funktioniert es sowieso nur dann, wenn 
der Compiler die besagten Controller überhaupt unterstützt. Und wenn 
er sie unterstützt, dann legt er sich die Variablen schon selber zurecht 
(also da hin, wo Platz ist)!

Der Typqualifizierer register bringt hier nicht nur nichts, der 
Compiler ist auch generell nicht daran gebunden. Und ein Compiler, der 
die RAM-losen AVRs unterstützt, weiß selber, dass er Variablen in 
Register legen muss. Wohin auch sonst?

> Hier sollte aber zur Sicherheit überall ein "static" davor stehen.
> Eventuell erkennt es der Compiler aber selber, dass diese Variablen nie
> verändert werden und trägt sie als konstant in den Code ein.
Hä? Bitte nimm Dir ein gutes C-Buch zur Hand und lies es gründlich 
durch! static hat ausschließlich einen Einfluss auf den 
Gültigkeitsbereich (Scope) einer Variablen. Es hat weder etwas mit 
"konstant" noch mit dem "Verändern" von Variablen zu tun! Außerdem trägt 
der Compiler nirgends etwas als "konstant" ein.

Bei wenig Speicherressourcen sollte man auf lokale /static/-Variablen 
eher verzichten, weil die genau wie globale Variablen permanent den 
ihnen zugeteilten Speicher belegen!

Eine Variable, die sich nicht verändert, gehört übrigens in den 
Flash-Speicher und nicht ins RAM und erst recht nicht in ein Register...

von Walter (Gast)


Lesenswert?

zum einen:
> /* nach Aktivieren des ADC wird ein "Dummy-Readout" empfohlen, man liest
>     also einen Wert und verwirft diesen, um den ADC "warmlaufen zu lassen" >*/
das ist nur 1x nach Reset notwendig

und zum anderen was zumindest ein wichtiger Fehler ist:
>    if ((wert >= LED1) & (wert < LED2))
du meintest vermutlich && statt &

von Felix F. (wiesel8)


Lesenswert?

Hallo,
hab auch mal ne Spannungsanzeige auf nen atmega8 gemacht. Weil es aber 
mehr als 5V waren, hab ich einfach 3x10k widerstände in reihe geschaltet 
und von einem die Spannung abgenommen.

(in basic)

dim A(und B) as Single

A = 5 / 1024   // für 5V und 10-bit

B = (ADC-Wert * A) * 3    // * 3 wegen spannungsteiler

und dann mit Fusing b so umwandeln dass es ausgegeben werden kann (vlt. 
gehts in C auch so)

mfg

von Johannes M. (johnny-m)


Lesenswert?

Walter wrote:
> zum einen:
>> /* nach Aktivieren des ADC wird ein "Dummy-Readout" empfohlen, man liest
>>     also einen Wert und verwirft diesen, um den ADC "warmlaufen zu lassen" >*/
> das ist nur 1x nach Reset notwendig
Nein, das ist nach dem Aktivieren des ADC über ADEN notwendig. Und wenn 
man den ADC nach jeder Wandlung ausschaltet, sollte man auch bei jedem 
Wiedereinschalten einen Dummy-Read-Out machen. Allerdings ist es in den 
meisten Fällen sinnvoll, den ADC einfach anzulassen. Nur wenn man 
wirklich Strom sparen muss und nur sporadisch wandelt, sollte man den 
ADC nach einer Messung ausschalten.

> und zum anderen was zumindest ein wichtiger Fehler ist:
>>    if ((wert >= LED1) & (wert < LED2))
> du meintest vermutlich && statt &
Ist in dem Fall aber egal. Beide Teilausdrücke können nur 0 oder 1 sein, 
und da klappt es auch mit nem bitweisen UND.

von Christian H. (netzwanze) Benutzerseite


Lesenswert?

Johannes M. wrote:
> Unsinn. AVRs haben Push-Pull-Ausgänge und dementsprechend ist es in den
> meisten Fällen wurscht, ob man LEDs High- oder Low-Side anschließt.
Hmm, stimmt. Habe gerade nochmal in der Doku nachgeschaut. Sorry, dann 
war ich bisher immer falsch informiert. Ich meinte, mal sowas gelesen zu 
haben.
Danke für den Hinweis.

> Der Typqualifizierer register bringt hier nicht nur nichts, der
> Compiler ist auch generell nicht daran gebunden. Und ein Compiler, der
> die RAM-losen AVRs unterstützt, weiß selber, dass er Variablen in
> Register legen muss. Wohin auch sonst?

Kommt auf den Compiler an. Wenn er nichts davon weiß, ob Ram oder kein 
Ram, dann ist "register" notwendig. Ich weiß natürlich nicht, was hier 
für ein Compiler verwendet wird.

"Normally, the compiler determines what data is to be stored in the 
registers of the CPU at what times. However, the C language provides the 
storage class register so that the programmer can ``suggest'' to the 
compiler that particular automatic variables should be allocated to CPU 
registers, if possible. Thus, register variables provide a certain 
control over efficiency of program execution. Variables which are used 
repeatedly or whose access times are critical, may be declared to be of 
storage class register."

> Hä? Bitte nimm Dir ein gutes C-Buch zur Hand und lies es gründlich
> durch! static hat ausschließlich einen Einfluss auf den
> Gültigkeitsbereich (Scope) einer Variablen. Es hat weder etwas mit
> "konstant" noch mit dem "Verändern" von Variablen zu tun! Außerdem trägt
> der Compiler nirgends etwas als "konstant" ein.
Sorry, habe schon zielich lange nicht mehr in C programmiert. Hatte C&R 
das auch schon so gesehen? Ich muß bei Zeiten meine C-Kenntnisse nochmal 
auffrischen.

Jaja, mann sollte keine Java-Konstrukte in C zurückführen und dann noch 
die Hälfte ("final") vergessen. Ich nehme alles zurück und behaupte das 
Gegenteil.

> Bei wenig Speicherressourcen sollte man auf lokale /static/-Variablen
> eher verzichten, weil die genau wie globale Variablen permanent den
> ihnen zugeteilten Speicher belegen!
Meist optimiert der Compiler nur einmalig benutzte und nicht veänderte 
Variablen sowieso weg.

Was ich eigentlich meinte, war ein "#define". Also statt "uint16_t LED1 
= 0x00C8;" schreibt man besser "#define LED1 0x00C8". Das ist dann aber 
nichts für den C-Compiler, sondern für den Präprozessor.

> Eine Variable, die sich nicht verändert, gehört übrigens in den
> Flash-Speicher und nicht ins RAM und erst recht nicht in ein Register...
Das habe ich auch nie gesagt. Ich wollte nur, dass der Compiler die 
konstanten "Variablen" wegoptimiert. Ins Register gehören natürlich alle 
kurzlebigen Variablen. Wenn diese knapp werden, muss man halt ins RAM 
auslagern (wenn vorhanden).

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.