Temperatur Messen mit dem Attiny13

GreenArrow

Neues Mitglied
26. Aug. 2008
23
0
0
Sprachen
Hey Leute, ich habe mich jetzt ein bißchen mit dem Attiny13 und Assembler befasst und kann jetzt ganz tolle Sachen mit LED ´s machen :D . Das wird aber auf dauer ein bißchen langweilig. Man möchte ja nicht ewig bei "Hello World" stehen bleiben. Also hab ich mir vorgenommen ein Thermometer zu basteln. Das kann man schließlich immer gebrauchen.
Leider brauch ich da glaub ich ne Menge Hilfe. Ich erklär erstmal wie ich mir das vorgestellt hab und vielleicht haperts ja da schon. Und zwar wollte ich nen Temperatur Sensor an den ADC Eingang des uC anschließen, dann im uC gucken welchen Wert (0..1023) ADC hat und das dann in die Temperatur umrechnen. Bei 5Volt müsste doch volle Spannung 1023 sein und keine Spannung 0, oder???.
Dann wollte ich nen Sieben Segment Treiber an Ausgang 0-4 des Attiny anschließen und damit die Temperatur auf ner Sieben Seg. Anzeige ausgeben. Ich weiß das ich dann natürlich nur eine Zahl habe,aber mir fehlen beim Attiny13 halt die Ports für mehr anzeigen. Damit lebe ich dann halt erstmal. Reicht ja wenn ich weiß das ne 1 für zehn grad steht und ne 2 für zwanzig etc. Das müsste doch soweit alles klappen oder hab ich da bis jetzt Denkfehler drin?
Edit: hab grad gesehen das nen Max7219 Baustein gibt. Da brauch ich nur drei Ports und kann zig 7Seg Anzeigen steuern. Aber das wär für den Anfang ein bißchen zuviel. Ich möchte erstmal nur die eine Anzeige ans laufen kriegen.

Leider fehlt mir der Plan wie ich das mit dem ADC in Assembler Programmiere. Hat vielleicht jemand von euch nen Beispiel-Code oder so rumfliegen den er mir kopieren könnte. Ich versuch dann durchzusteigen und wenns nicht klappt frag ich nochmal nach. Vielen Dank schonmal, Mfg GreenArrow
 
Hallo,
Bei 5Volt müsste doch volle Spannung 1023 sein und keine Spannung 0, oder???.

ja, wenn man VCC (5V) als die analoge Referenzspannung verwendet.

Hat vielleicht jemand von euch nen Beispiel-Code oder so rumfliegen den er mir kopieren könnte

Ja, das untere Beispiel initiiert eine AD-Wandlung im Mode SingleConversion. Ausgewählt ist der ADC-Eingang ADC0, das ist PB5 beim ATtiny13. Der Prescaler ist auf 128 eingestellt, du kannst einen kleineren Wert wählen, die höchste Frequenz für den ADC sollte bei <= 200kHz liegen, wenn du volle 10bit Auflösung brauchst. Das 10bit Ergebnis steht rechtsbündig in den Registern ADCL und ADCH.


Code:
AnalogDigitalConvert:

   ldi r16, 0b00000000
   out ADMUX, r16                 ; VCC is analog reference, ADC0 (PB5)

   ldi r16, 0b10000111            ; ADC Enable, prescaler 128 (Bei 10bit sollte 
   out ADCSR, r16                 ; der Takt des ADC <= 200kHz sein)

   sbi ADCSR, ADSC                ; Start conversion

adc_wait: sbic ADCSR, ADSC        ; Conversion ready ?
   rjmp adc_wait
   
   in r16, ADCL                   ; Ergebnis in die Register r16, r17
   in r17, ADCH
   
   ; ...

ret
Grüße
Dirk
 
@ Dirk,
das ist super. Vielen Dank. Werd ich direkt testen und dann erstmal was rum probieren.
Mfg GreenArrow
 
@ Dirk,
ich sitz jetzt seit zwei Wochen an dem Projekt und es will einfach nicht klappen. Ich hab mir gedacht ich poste mal den Quelltext und du guckst vielleicht mal drüber. Vielleicht hab ich ja auch nen denkfehler. Ich nutze den ADC Wandler im 8Bit modus damit ich nur ein Byte hab und so schonmal fehler ausschließen kann. Eigentlich möchte ich den ADC wandler nur starten,gucken ob ne spannung anliegt (welche ist mir fürs erste egal) und als anzeige ne LED verwenden. Quasi so:
0 Volt = Wert 0
5 Volt = Wert 255
kopiere den Wert in R16 und gucke ob er größer oder kleiner als 128 ist. Ich hab die LED an Pb3 angeschlossen und der ADC Wandler soll auf Pb4 laufen. Die Schaltung hab ich aufs Wesentliche Reduziert. Nur der uC und ne LED. mit ner Steckverbindung verbinde ich dann VCC und PB4. Aber wie gesagt die LED leuchtet nicht und langsam weiß ich nich mehr weiter. Hier der (von mir zusammengeschnippelte) Quelltext:

Code:
.include "tn13def.inc"

ldi r16,2
out ADMUX, r16                 ; VCC is analog reference, ADC2 (PB4)

sbi ddrb,3

   ldi r16,3            ; ADC Enable, prescaler 128 (Bei 10bit sollte 
   out ADCSRA, r16                 ; der Takt des ADC <= 200kHz sein)

   sbi ADCSRA, ADEN                ; Start conversion
   sbi ADMUX, ADLAR					; 8 bit nur highbyte 
adc_wait: sbic ADCSRA, ADSC        ; Conversion ready ?
   rjmp adc_wait
   
   schleife:
   in r16, ADCH                   ; Ergebnis in die Register r16
   

    
	
	cpi r16,128
	brlo kleiner
	cpi r16,128
	brsh größer
	

	
  rjmp schleife 


kleiner:
cbi portb,3
ret

größer:
sbi portb,3
ret

ende: rjmp ende

Schonmal vielen Dank im Vorraus für die Mühe, Mfg GreenArrow
 
Hallo,

du startest den ADC nicht und zum Schluss stürzt dein Progremm ab, da du ret verwendest, ohne dass zuvor eine Rücksprungadresse durch rcall auf dem Stack abgelegt wurde.

Probiere mal folgenden Code (nicht getestet und nur so aus dem Kopf heraus geschrieben):
Code:
.include "tn13def.inc"


.org 0
rjmp Main

; hier ist der Bereich für die Interrupt-Einsprungadressen


Main:

  ; *** Initialisierungen ***

  ; PB3 ist Ausgang, LED aus
  sbi PORTB, PB3
  sbi DDRB, PB3              

  ; VCC is analog reference, ADC2 (PB4)
  ; Ergenbis ist Left Adjusted
  ldi r16, (1<<MUX1) | (1<<ADLAR)
  out ADMUX, r16                
  
  ; ADC Enable, prescaler 8
  ldi r16, (1<<ADEN) | (1<<ADPS1) | (1<<ADPS0)
  out ADCSRA, r16


  ; *** Hauptprogramm ***
Main_loop:

  rcall Convert

rjmp Main_loop



Convert:

  sbi ADCSRA, ADSC               ; Start conversion
convert_adc_wait: sbic ADCSRA, ADSC        ; Conversion ready ?
  rjmp convert_adc_wait
   
  in r16, ADCH                   ; Ergebnis in die Register r16
   
  cpi r16, 128
  brlo convert_led_an
  sbi PORTB, PB3                 ; LED aus
  ret

convert_led_an:
  cbi PORTB, PB3                 ; LED an
ret
Grüße,
Dirk
 
@Dirk:
Klasse. Funktioniert. Musste nur
Code:
sbi portb,pb3
durch
Code:
sbi portb,3
ersetzen und dein Prog läuft. Wahnsinn. Jetzt hab ich endlich ne Grundlage mit der ich was Anfangen kann und jetzt komm ich endlich weiter. Vielen Vielen Dank GreenArrow
 
Hey Dirk, das Prog läuft Prima, aber ich habe noch ein paar Fragen auf die ich im Netz keine oder unzureichende Antworten gefunden habe. Und zwar wofür ist .org 0 ?
Du hast das Rcall und das Ret nur verwendet um mir zu zeigen wie es geht,oder? Ich mein,mann könnte es in diesem Fall auch einfach weglassen,weil sich main_loop ja eh wiederholt wenn ich den
Code:
 rjmp main_loop
ganz ans Ende setze, oder?
Und noch eine Frage die mich schon länger quält. Und zwar seh ich ganz oft das man ne LED mit cbi einschaltet. Das heißt ihr schließt die LED an den uC und an VCC an. Ich schließe die aber an den uC und an GND an und benutze dann halt sbi um sie einzuschalten. Weil mir sbi und einschalten halt irgendwie sinnvoller vorkommt. Aber es wird ja nen Grund haben warum fast alle anderen cbi nehmen. Kannst du mir vielleicht sagen wo da die Vorteile sind? Sind ne ganze Menge Fragen... Vielen dank, GreenArrow
 
Hallo GreenArrow,

.org 0 ist eine Anweisung an den Assembler, den Adresszeiger zu setzen, in diesem Fall wird er auf die Adresse 0x0000 gesetzt, was der Resetadresse entspricht.

Nach der Resetadresse 0x0000 folgen die Einsprungadressen für die Interrupts. Wenn du zum Beispiel den Timer0Overflow-Interrupt nutzen möchtest, musst du beim ATtiny13 folgenddermassen vorgehen:

Code:
.org 0
   rjmp main
.org 0x0003
   rjmp MeinTimer0OverflowInterrupt
;... ggf weitere Einsprungadressen

main:

;...
rjmp main

MeinTimer0OverflowInterrupt:
;...
reti
.org verwendet man im Codesegment (.cseg) wie oben, im Datensegment (.dseg, SRAM) und für das EEPROM (.eseg).

Die Routine habe ich nur verwendet, um dir zu seigen, wie man das mit rcall und ret macht. Du kannst natürlich den ganzen Programmcode in die Endlosschleife von Main einbauen. Bei größeren Programmen wird es aber unübersichtlich. Ich habe mir angewöhnt möglichst viel in Routinen zu erledigen, mit definierten Eingangs- und Ausgangsparametern, so kann ich die Routinen auch in anderen Programmen schnell einbauen und muss diese nicht neu schreiben.

Die LED schließt man oft an VCC (mit Vorwiderstand) an und schaltet diese dann invertiert, weil der Mikrocontroller einen höheren Strom nach GND verträgt (Stromsenke), wird der Pin nach VCC geschaltet, leifert er nicht so einen hohen Strom (Stromquelle). ABER: Allerdings können oft die neueren Mikrocontroller in beiden Fällen genauso viel Strom liefern. Siehe dir einmal das Datenblatt des ATtiny13 an, Kapitel DC Electrical Characteristics, Voh und Vol. Vielleicht gibt es aber auch noch andere Gründe, warum man eine LED invertiert schaltet ?!

:ciao:

Grüße,
Dirk
 

Über uns

  • Makerconnect ist ein Forum, welches wir ausschließlich für einen Gedankenaustausch und als Diskussionsplattform für Interessierte bereitstellen, welche sich privat, durch das Studium oder beruflich mit Mikrocontroller- und Kleinstrechnersystemen beschäftigen wollen oder müssen ;-)
  • Dirk
  • Du bist noch kein Mitglied in unserer freundlichen Community? Werde Teil von uns und registriere dich in unserem Forum.
  •  Registriere dich

User Menu

 Kaffeezeit

  • Wir arbeiten hart daran sicherzustellen, dass unser Forum permanent online und schnell erreichbar ist, unsere Forensoftware auf dem aktuellsten Stand ist und der Server regelmäßig gewartet wird. Auch die Themen Datensicherheit und Datenschutz sind uns wichtig und hier sind wir auch ständig aktiv. Alles in allem, sorgen wir uns darum, dass alles Drumherum stimmt :-)

    Dir gefällt das Forum und unsere Arbeit und du möchtest uns unterstützen? Unterstütze uns durch deine Premium-Mitgliedschaft!
    Wir freuen uns auch über eine Spende für unsere Kaffeekasse :-)
    Vielen Dank! :ciao:


     Spende uns! (Paypal)