Hallo,
ich möchte einen DS18S20 an einem ATTINY 2313 betreiben. Habe mir
verschiedene Codes aus dem Forum angeschaut. Diese sind für mich leider
viel zu kompliziert vom Programmieraufwand. Mit anderen Worten, ich kann
sie nicht nachvollziehen. Zum einen hatte ich den Code von Peter
Dannegger.
Hat vielleicht jemand einen funktionierenden C-Code für den ATTINY 2313,
bei dem ich eventuell nur den Clock und die Ports anpassen muss?
main.h hab ich folgend abgeändert. Der Sensor liegt bei mir auch an Pin
D6. Beschaltung hab ich folgende:
DS18s20
GND --> GND
DQ --> auf ATTINY PortD6 und über 4k7 auf 5V
Vdd --> 5V
Der µC läuft auf 1Mhz
TCCR1B|=((1<<WGM12)|(1<<CS11)|(1<<CS10));// Modus 4 CTC, Prescaler 64
28
TIMSK|=(1<<OCIE1A);
29
OCR1A=1250;
30
31
//Sleep_Mode Init
32
set_sleep_mode(SLEEP_MODE_IDLE);//Init Sleep-Modus auf IDLE
33
34
//Anzeige init
35
lcd_init();
36
37
//3x Minus-Zeichen am Anfang
38
array[0]='-';
39
array[1]='-';
40
array[2]='-';
41
array[3]='C';//°C zeichen
42
43
44
lcd_setcursor(0,1);
45
lcd_string("################");
46
lcd_setcursor(0,2);
47
lcd_string(array);
48
49
sei();
50
51
for(;;)
52
{
53
uint8_tdigit;
54
cli();
55
switch(tick)
56
{
57
case1:
58
{
59
if(therm_reset())
60
error=1;
61
else
62
error=0;
63
if(!(error))
64
{
65
therm_write_byte(THERM_CMD_SKIPROM);
66
therm_write_byte(THERM_CMD_CONVERTTEMP);
67
}
68
break;
69
}
70
// case 20: //nach 200msek.
71
// {
72
// if ( light_port & (1 << light_pin) )
73
// light = 1;
74
// else
75
// {
76
// light = 0;
77
// OCR0B = 255; //max. Helligkeit
78
// }
79
// break;
80
// }
81
// case 40: //nach weiteren 200msek.
82
// {
83
// if (light)
84
// {
85
// if ( light_port & (1 << light_pin) )
86
// OCR0B = 80; //Helligkeit abdunkeln
87
// }
88
// else
89
// {
90
// light = 0;
91
// OCR0B = 255; //max. Helligkeit
92
// }
93
// break;
94
// }
95
case81://nach 800msek.
96
{
97
if(!(error))
98
{
99
therm_reset();
100
therm_write_byte(THERM_CMD_SKIPROM);
101
therm_write_byte(THERM_CMD_RSCRATCHPAD);
102
scratchpad[0]=therm_read_byte();
103
scratchpad[1]=therm_read_byte();
104
}
105
break;
106
}
107
case82:
108
{
109
if(!(error))
110
{
111
if(scratchpad[1]!=0)//negative Temperatur
112
{
113
digit=((0xff-scratchpad[0])+1)>>1;
114
if(digit<10)
115
{
116
array[0]=' ';
117
array[1]='-';//Minus-Zeichen setzen
118
array[2]=(digit%10)+'0';
119
array[3]='C';
120
}
121
else
122
{
123
array[0]='-';//Minus-Zeichen setzen
124
array[1]=((digit/10)%10)+'0';//zehner Stelle
125
array[2]=(digit%10)+'0';//einer stelle
126
array[3]='C';
127
}
128
129
}
130
else
131
{
132
digit=scratchpad[0]>>1;
133
if(digit<10)
134
{
135
array[0]=' ';
136
array[1]=' ';//vorstellen-Null ausblenden
137
array[2]=(digit%10)+'0';
138
array[3]='C';
139
}
140
else
141
{
142
array[0]=' ';
143
array[1]=((digit/10)%10)+'0';//zehner Stelle
144
array[2]=(digit%10)+'0';//einer stelle
145
array[3]='C';
146
}
147
}
148
}
149
else
150
{
151
if(!(flash))
152
{
153
array[0]='E';
154
array[1]='r';
155
array[2]='r';
156
array[3]=' ';
157
flash=1;
158
}
159
else
160
{
161
array[0]='S';
162
array[1]='e';
163
array[2]='n';
164
array[3]='s';
165
flash=0;
166
}
167
}
168
break;
169
}
170
case83:
171
{
172
lcd_setcursor(0,2);
173
lcd_string(array);
174
tick=0;
175
break;
176
}
177
}
178
sei();
179
sleep_mode();
180
}
181
}
Das Display zeigt mir in Zeile 1 alles wie gewünscht an. In Zeile 2 im
ersten Moment auch "---C", dann allerdings kommen Err und Sens und
irgendwann dann wilde Zeichenkombinationen, die sich im Verlauf der Zeit
auch auf Zeile 1 ausweiten.
Tja Dein µC läuft mit 1MHz, meiner mit 8MHz. Damit mußt Du die TIMER1
Initialisierung auch anpassen.
1
//Timer1 aller 10ms bei 1MHz Taktfrequenz
2
TCCR1B|=((1<<WGM12)|(1<<CS11));// Modus 4 CTC, Prescaler 8
3
TIMSK|=(1<<OCIE1A);
4
OCR1A=1250;
Dann ist die Frage wie lang ist das Anschlußkabel zum Sensor. Je länger
desto kleiner der Pull-UP an DQ.
Die wilden Zeichenkombinatinen deuten auch auf falsches Timing des LCD
hin. Versuche doch erstmal eine stehende LCD-Anzeige in beiden Zeilen
hinzubekommen. Kannst ja in Zeile 2 eine Variable hochzählen lassen
(Variable bei case 81 z.B. hochzählen lassen). Wen das klappt wendest Du
Dich dem Sensor zu.
Hallo Ronny,
also auf dem LCD bekomm ich eigentlich eine stabile Anzeige. Es wechselt
halt immer zwischen Err Sens und wilden Zeichen. Das mit dem Takt hab
ich mir schon fast gedacht. Habe leider noch nie was mit Timern gemacht
und versteh den Code von dir dazu auch nicht. Um die Zeiten des Sensors
einzuhalten verwendest du den Timer?
Ich hab eine Vermutung, ich hab den Sensor an PD6 hängen und das LCD an
D0-D5. Kann es sein, das die im Laufe des Programms auch verändert
werden und das Display dewegen manchmal springt?
Also folgendes, wenn ich den Sensor nicht mit dem µC verbinde, dann
zählt er wunderbar meine int test=0; im case 81 hoch und stellt sie in
der 2. zeile des lcd dar. Sobald ich den Sensor anschließe, würfelt er
das ganze lcd durcheinander und er zählt an allen beliebigen
cursorpositionen hoch.
So ich hab jetzt das Display an Port B gehangen und an Port D hängt nur
am D6 der Sensor. Ich lass in case 81 eine int hochzählen und die auf
dem lcd in zeile 2 ausgeben. Die Ausgabe zählt auch hoch. Daneben lass
ich array ausgeben, was immer zwischen Sens und Err wechselt. Damit hab
ich die Zeitbedingungen wohl verletzt laut Flussdiagramm. Wie lös ich
das Problem?
Beks schrieb:> Daneben lass> ich array ausgeben, was immer zwischen Sens und Err wechselt. Damit hab> ich die Zeitbedingungen wohl verletzt laut Flussdiagramm. Wie lös ich> das Problem?
Wie du im Flußdiagramm sehen kannst, bedeutet die wechselnde Anzeige,
dass die Initialisierung des Sensors nicht funktioniert hat.
Guck dir die Signale, die zu Sensor geschickt werden an und vergleich
das mit den Angaben im Datenblatt. Um die Taktfrequenz zu prüfen, kannst
du auch auf einem anderen Port-Pin über Vorwiderstand eine LED
anschließen und parallel zur Sensorabfrage blinken lassen. Wenn die LED
nicht ungefähr im Sekundentakt blinkt, stimmt das Timing für die
Sensorabfrage noch nicht.
mfg Martin
Martin schrieb:> Wenn die LED> nicht ungefähr im Sekundentakt blinkt, stimmt das Timing für die> Sensorabfrage noch nicht.
Ich lass ja in der Case 81 eine int inkrementieren und dann am Ende auch
ausgeben. Die zählt auch ungefähr im Sekundentakt hoch. Im gleichen Takt
wechselt auch das array von Err auf Sens. Ja irgendwas passt da mit der
Initialisierung nicht. Aber was?
Nochmal den Quellcode:
main.c
1
#include"main.h"
2
#include"temp_eigen.h"
3
#include"lcd-routines.h"
4
5
6
chararray[4];
7
volatileuint8_ttick;
8
9
uint8_tscratchpad[2];
10
uint8_terror;
11
uint8_tlight;
12
uint8_tflash;
13
14
inttest=0;
15
chartesta[3];
16
17
ISR(TIMER1_COMPA_vect)//aller 10msek.
18
{
19
tick++;
20
}
21
22
intmain(void)
23
{
24
25
//Timer1 aller 10ms bei 1MHz Taktfrequenz
26
TCCR1B|=((1<<WGM12)|(1<<CS11));// Modus 4 CTC, Prescaler 8
27
TIMSK|=(1<<OCIE1A);
28
OCR1A=1250;
29
30
31
//Sleep_Mode Init
32
set_sleep_mode(SLEEP_MODE_IDLE);//Init Sleep-Modus auf IDLE
Oder Dein Sensor ist futsch. Schau Dir mal die Leitung wo Dein Sensor
dran hängt (PIN DQ) mit dem Oszi an, Zuerst ohne Sensor und dann mit. Da
muß ein Unterschied zu sehen sein.
Die Timings für die 1-Wire-Kommunikation mache ich mit der
delay-Funktion. Bei mir funktioniert das System seit mehreren Monaten
perfekt.
Im Quellcode ist kein Problem? Also ich hab die Verdrahtung auf einen
Steckboard und ein Oszi hab ich leider noch nichr. Der Sensor könnte
natûrlich hin sein, glaub aber eher das im Quellcode was nicht stimmt.
Das mit.dem Timer und case versteh ich noch nicht, kann daher nicht
erkennen ob ich nicht die Zeitbedingungen verletze.
Im Quellcode ist kein Problem? Also ich hab die Verdrahtung auf einen
Steckboard und ein Oszi hab ich leider noch nichr. Der Sensor könnte
natûrlich hin sein, glaub aber eher das im Quellcode was nicht stimmt.
Das mit.dem Timer und case versteh ich noch nicht, kann daher nicht
erkennen ob ich nicht die Zeitbedingungen verletze.
Nein im Quellcode ist kein Problem, bei mir funktionierts ja auch. Ich
habe das Ganze einmal auf dem Steckbrett aufgebaut gehabt und dann auf
der Platine. Beides hat funktioniert mit verschiedenen DS18S20-Sensoren
Zum Timer:
Der Timer-Interrupt erfolgt aller 10ms. In der Interrupt-Routine wird
nur die variable "tick" hochgezählt. in der int main(void) wird mit case
die variable "tick" ausgewertet, d.h. nach 10ms wird der DS18S20
resettet, alle Adressen angesprochen da nur ein Sensor am Bus hängt und
eine Messung gestartet. Bei 810ms (case 81) wird wieder ein Reset
ausgelöst, alle Adressen angesprochen und der Speicher des DS18S20
ausgelesen. Bei 820ms erfolgt dann die Konvertierung des
Temperaturwertes für die Anzeige. Das alles geschieht aber nur wenn der
1.Reset erfolgreich war.
Näheres dazu hier:
http://www.teslabs.com/openplayer/docs/docs/other/ds18b20_pre1.pdf
Und mein Controller läuft ja unverändert auf den Default Clock Source,
also 1Mhz. Muss ich dann in folgender Zeile nicht ein no prescaling
einstellen?
Also CS10 setzen?
1
TCCR1B|=((1<<WGM12)|(1<<CS11));// Modus 4 CTC, Prescaler 8
beschäftige Dich erstmal mit den Timer-Möglichkeiten die die
AVR-Controller bieten, siehe hier:
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/Die_Timer_und_Z%C3%A4hler_des_AVR
Dort ist auch erklärt was die Variable OCR1A bewirkt. Der
Timer1-Interrupt wird nicht als Overflow sondern als Compare ausgelöst.
Gut korrekterweise müßte es noch heißen:
OCR1A = 1250-1; //Compare bei 10ms
Nein nein, ich bin beruflich nur gerade ziemlich eingebunden und bin
noch nicht dazu gekommen. Das die Variable für einen Vergleich zuständig
ist hab ich auch schon gelesen, aber noch nicht tiefergehend. Es ist
auch sehr mühseelig sich in das Thema einzuarbeiten, wenn man keine
Nachrichtentechnik studiert hat :)
So ich hab mir jetzt den Text mal durchgelesen zu den Timern und weiß
leider immernoch nicht mehr bescheid.
1
TCCR1B|=((1<<WGM12)|(1<<CS11));// Modus 4 CTC, Prescaler 8
Warum wähl ich als Vorteiler 8 bei einen Clock von 1Mhz? Damit hab ich
eine reduzierten Takt von 125 Khz. Dann wird das WGM12 (CTC1) Bit
gesetzt, damit wird der Wert OCR1A = 1250; mit dem aktuellen Zählwert
verglichen und bei Gleichheit der aktuelle Zählwert Null gesetzt. Dabei
seh ich aber irgendwie immer noch nicht in welchen Zeittakt der Timer
nun zählt? Mit 125 kHz? Das heißt die Periode wäre 1/125kHz = 8µs. Dann
zählt er aller 8µs einen Wert hoch?
beks schrieb:> So ich hab mir jetzt den Text mal durchgelesen zu den Timern und weiß> leider immernoch nicht mehr bescheid.>>
1
>TCCR1B|=((1<<WGM12)|(1<<CS11));// Modus 4 CTC, Prescaler 8
2
>
> Warum wähl ich als Vorteiler 8 bei einen Clock von 1Mhz? Damit hab ich> eine reduzierten Takt von 125 Khz. Dann wird das WGM12 (CTC1) Bit> gesetzt, damit wird der Wert OCR1A = 1250; mit dem aktuellen Zählwert> verglichen und bei Gleichheit der aktuelle Zählwert Null gesetzt. Dabei> seh ich aber irgendwie immer noch nicht in welchen Zeittakt der Timer> nun zählt? Mit 125 kHz? Das heißt die Periode wäre 1/125kHz = 8µs. Dann> zählt er aller 8µs einen Wert hoch?
Bis hier her alles richtig.
Und wenn der Timer jetz mit diesem "alle 8µs 1 weiter zählen" bei 1250
angelangt ist, löst er einen Compare Match aus und fängt wieder bei 0
an.
WIe oft kommt daher dieser Comapre Match?
(Du bist am Compare Match interessiert! Das ist der Teil mit dem du
arbeiten kannst indem du zb eine ISR anhängst)
... schrieb:> Rechne mal nach: Wenn der Timer mit 125 kHz zählt und bei Zählerstand> 1250 ein ISR ausgelöst wird, in welchen Zeitabständen passiert das dann?
125 Khz --> 8 µs zwischen den Zählsignalen und wenn er bis 1250 zählt,
sind das 1250 * 8 µs = 10 ms
Karl Heinz Buchegger schrieb:> Bis hier her alles richtig.> Und wenn der Timer jetz mit diesem "alle 8µs 1 weiter zählen" bei 1250> angelangt ist, löst er einen Compare Match aus und fängt wieder bei 0> an.> WIe oft kommt daher dieser Comapre Match?
Ich glaub ich versteh es. Dann kommt aller 10 ms dieser "compare match"
und bei dem Quellcode oben wird in der ISR die Variable tick
inkrementiert. Nach 10ms ist die 1, dann nochmal 10ms und tick = 2 und
zeit war 20ms, ... , nach 80 mal 10ms ist tick=80 und die verstrichene
Zeit war 800 ms.
Gratuliere. Du hast gerade den Rechengang nachvollzogen, mit dem die
Verbdindung von hier
Beitrag "Re: DS18S20 und ATTINY 2313"> "The OCR1A or ICR1 define the top value for the counter,> hence also its resolution." Auszug Datenblatt.>> Warum wird OCR1A auf 1250 gesetzt?
zu hier
Beitrag "Re: DS18S20 und ATTINY 2313"> Zum Timer:> Der Timer-Interrupt erfolgt aller 10ms.
hergestellt wird.
Karl Heinz Buchegger schrieb:> Gratuliere.
Danke :) Leider hängt der Sensor aber dennoch irgendwie im Errormodus
fest. Er zeigt immer nur Err und Sens im Wechsel an.
schön das Du am Ball bleibst... Und ich habe auch nicht studiert.
es wird auch nicht an der Timer-Auswertung liegen. Die Zeiten für den
Sensor werden mit der delay-Funktion erzeugt. Was noch möglich ist das
die 1MHz zu langsam sind. Du kannst auch den ATTINY2313 mit 8MHz laufen
lassen ohne externen Quarz. Dazu die Clockdiv. Variable in den Fuse-Bits
deaktivieren.
siehe hierzu: http://www.mikrocontroller.net/articles/AVR_Fuses und
hier:
http://www.ladyada.net/learn/avr/fuses.html
Ich hab den jetzt auf internen 8 Mhz Takt umgestellt (siehe dazu
Anhang). In meinen Quellcode hab ich natürlich in meiner Lcd-header-file
die Freq. auf 8 Mhz angepasst und nun zeigt er mir nur noch wilde Sachen
in der zweiten Zeile an. Die erste Zeile ist komplett leer, wobei dort
auch etwas stehen sollte. Also ist dabei wohl etwas schief gegangen.
Ich schäm mich, ich hatte den Sensor verpolt. Das mit den 8 Mhz versteh
ich aber dennoch nicht. Der Sensor läuft jetzt aber Klasse auf 1 Mhz und
so soll das auch bleiben!
Ronny, auf meinen LCD bekomm ich die Ausgabe für °C nicht hin. Das
Datenblatt gibt eigentlich kaum was dazu her. Auf deine Art hab ich es
auch schon versucht über den ASCII Code. Und mit '°C' nimmt er auch
nicht. Hab ein LCD-Modul TC1602E-01.
Gratulation,
warum es mit 8MHz nicht funktioniert kann ich Dir nicht sagen, wird aber
an der LCD-Routine liegen. Das ASCII-Zeichen von mir ist dem Datenblatt
meiner Anzeige entnommen. Für Dein LCD ist aber nicht viel zu finden.
Nach langer Suche habe ich es hier im Forum gefunden:
http://www.mikrocontroller.net/attachment/72821/SPLC780D001BC.pdf
Das "°C"-Zeichen gibt es auf Deinem LCD nicht, also setzt Du es aus 2
Symbolen zusammen. Zuerst das "°"-Symbol mit
1
array[3]=0xB2;
und dann der Buchstabe "C"
1
array[4]='C';
Die Größe des Arrays muß natürlich am Anfang auch noch angepasst werden:
ronnysc schrieb:> ...und har es funktioniert?
War das Wochenende über nicht da. Habs gerade getestet und leider klappt
es nicht. Das ° hatte ich auch schon versucht über '°' dazustellen, was
natürlich nicht funktionierte. Deine Variante über 0xB2 klappt leider
auch nicht. Hab mir grad bei den Link mal die ganzen möglichen Zeichen
angeschaut und leider das dargestellt nicht gefunden. Weiterhin hab ich
etwas komisches festgestellt. Wenn ich den µC von Spannung nehme und
dann wieder anlege, wird in der ersten Zeile mein Text kurz angezeigt
und dann in wilde Zeichen gewandelt. Wenn ich dann das Programm wieder
neu aufspiele, dann bleibt der Text in der ersten Zeile korrekt stehen.
Nehm ich den µC wieder von Spannung und leg wieder an, gleicher Effekt.
Also ich gehe immer noch davon aus das die Ansteuerung des LCD falsch
ist bzw. das Timing nicht stimmt. Packe mal Dein komplettes Programm in
eine ZIP-Datei und poste das mal hier.
Ich muss zugeben, die LCD Routine wurde nicht selbst geschrieben,
funktioniert aber eigentlich ganz gut. Ich hab den Quellcode mal gepackt
und er befindet sich im Anhang.
Ein kleinen Fehler hab ich schonmal, das array sollte char array[5]
sein! Dennoch löscht er mir den Text aus der ersten Zeile, wenn ich das
System stromlos schalte.
Tja das liegt an was anderem. Du hast den Fehler in Deiner Ansteuerung
des LCD, siehe:
http://www.mikrocontroller.net/articles/String-Verarbeitung_in_C
Die Routine ist in Ordnung, Du mußt nur das String-Ende auch setzen.
Ansonsten läuft die Routine "lcd_string" ewig. Der Quellcode im Anhang
ist dahingehend von mir korrigiert und noch ein paar Extras :).
Probiere das mal aus.
Ich vermute es liegt hier irgendwo der Fehler. Für diesen Code wird nach
dem wegnehmen der Spannung und wieder zuschalten, die erste Zeile
richtig dargestellt. Allerdings aktualisiert die zweite Zeile nicht
mehr, was sich darin äußert, dass die Temperaturanzeige nur durch einen
µC-Reset aktualisiert.
1
case83:
2
{
3
//Ausgabe GrundLCD
4
lcd_setcursor(0,2);
5
lcd_string("Temperatur:");
6
lcd_setcursor(11,2);
7
lcd_string(array);
8
lcd_home();
9
lcd_string(" HAPPY BIRTHDAY ");
10
tick=0;
11
break;
Im folgenden Fall, aktualisiert der µC nach dem stromlos schalten die
zweite Zeile (Temperaturanzeige), allerdings wird die Zeile durch wilde
Zeichen dargestellt.
Ach mist, das Backslash 0 :) Ja so ist das wenn man zu wenig übt. Ja das
hab ich natürlich vergessen bei dem char array. Danke dir - es
funktioniert so wunderbar. Vielleicht sollten wir mal icq nummern
tauschen ;)
Du setzt den Sensor ja in den sleep mode idle. Könnte ich den auch in
den Power Save Modus schalten und anstelle des Timer 1, den Timer 2
benutzen? Die Stromaufnahme reduziert sich dann ja schonmal erheblich.
Na dann schick mir mal Deine per PN.
Power Safe Mode nützt sicher nicht so viel, da das Programm aller 10ms
wieder aus dem Schlaf geweckt wird. Ich nutzt den Sleepmode eigentlich
nur um das Programm am Ende der for-Schleife anzuhalten. Damit habe ich
immer einen definierten Einstieg.
Könnte man sicher auch mit dem Watchdog hinbekommen. Den aller 10ms
anschlagen lassen und den Controller in den Power Down Modus am Ende der
Schleife schicken. Ist zwar mit der Brechstange, ginge aber. Fraglich
ist aber was das an Strom wirklich spart...
aber freut mich das es jetzt funktioniert. Für die endgültige Version
empfehle ich Dir aber einen Quarz. Der interne Oszillator ist nicht
unbedingt frequenzstabil bei unterschiedlichen Temperaturen.