Hallo, ich habe letztes Jahr ja bereits begonnen mir Gedanken zur einer Terrariensteuerung zu machen: Beitrag "Erste Schaltung: Terrariensteuerung/DCF77/Dimmer/Schalter" Das Grundgerüstist von der Mikrocontroller-Seite her ist jetzt eigentlich fertig.* Was mir zur Zeit Sorgen macht ist das Auslesen der Temperatur via 1-wire Bus: Bisher basiert der ganze Ablauf, wie das DCF77-Projekt das ich als Grundlage genommen habe, darauf, dass jede Millisekunde ein Interrupt ausgelöst wird, dann passiert der ganze interessante Kram in der Interrupt-Routine und in der Hauptschleife setze ich dann einmal pro Sekunde den Inhalt vom Display und die Ausgänge neu. Wie kriege ich da jetzt die 1-wire-Kommunikation untergebracht? Meine bisher "beste" Idee ist das auch in der Interrupt-Routine zu machen, jede Millisekunde eine Aktion, z.B. ein Reset, ein Bit lesen oder ein Bit schreiben. Andererseits möchte ich die ISR nicht unnötig aufblähen. main.c im Anhang. Bitte nicht erschrecken, ich bin immernoch Anfänger ;-) Grüße, Andi M *Nachts um 2 oder 3 (Sommer/Winterzeit, so gewählt dass ich immer nur 1 mal syncen muss) geht die Funkuhr an, wenn das Signal 3 mal in Folge korrekte (Prüfbit) Werte geliefert hat die zueinander passen, wird die Uhr synchronisiert. Ein 4x16 Display zeigt die Infos an die ich haben möchte und ich kann mit FETs Relais schalten. Taktquelle ist ein 8 MHz Quarzoszillator. Die einfachen Funktionen sind somit fertig. Das Terrarium habe ich in der Zwischenzeit umgebaut, was einer der Gründe dafür ist dass das alles so lang gedauert hat. Vorteil: Für die Beleuchtung brauche ich erstmal keinen Dimmer mehr. Im Winter würde ich gerne eine Heizung (Heizkabel oder -Strahler) per Dimmer steuern, aber dafür brauche ich ja keine Mikrosekundengenaue Steuerung.
Andi M. schrieb: > Wie kriege ich da jetzt die 1-wire-Kommunikation untergebracht? > Meine bisher "beste" Idee ist das auch in der Interrupt-Routine zu > machen, jede Millisekunde eine Aktion, z.B. ein Reset, ein Bit lesen > oder ein Bit schreiben. Es gibt auch die Möglichkeit, das kritische 1-w Timing mit einem UART zu erzeugen. Hier ist das erklärt: http://www.maxim-ic.com/app-notes/index.mvp/id/214 Der Rest ist vom Timing her unkritisch und kann im Hauptprogramm gemacht werden. fchk
Ich habe bisher nichts mit dem UART gemacht aber eben schonmal etwas dazu gelesen. Sehe ich das richtg dass der U(S)ART "alleine" arbeitet? Also einfach einstellen wie schnell er was ausgeben/einlesen soll und den ganzen Timing-Kram macht der automatisch, ohne dass der sonstige Programmablauf unterbrochen wird?
Frank K. schrieb: [...] > http://www.maxim-ic.com/app-notes/index.mvp/id/214 [...] Ich habe eine Frage zu dem open-drain buffer circuit: Die benutzen da 2 2n7002, das Schaltzeichen entspricht einem "normalen" MOSFET mit einer parallelgeschalteten, in Sperrichtung gepolten Diode zwischen Drain und Source, was auch immer die tun soll. Ich hätte BS170 und 1N4148. Das sollte auch funktionieren, oder?
Andi M. schrieb: > Ich habe bisher nichts mit dem UART gemacht aber eben schonmal etwas > dazu gelesen. > > Sehe ich das richtg dass der U(S)ART "alleine" arbeitet? > Also einfach einstellen wie schnell er was ausgeben/einlesen soll und > den ganzen Timing-Kram macht der automatisch, ohne dass der sonstige > Programmablauf unterbrochen wird? Genau. Für den Reset/Presence Detect Puls wird der USART auf 9600bps eingestellt, für die Daten auf 115200bps. Das Teil empfängt bei Senden, und so bekommst Du die Rückmeldung des Slaves mit. Zeitkritisch ist nur der Teil beginnend von der fallenden Flanke des Startpulses, den der Master vorgibt, bis zur Antwort des Slaves auf den Reset bzw auf das jeweilige Bit. Das macht der USART. Die Zeit zwischen zwei Bits bzw zwischen Reset/Presence Detect und dem ersten Bit ist unkritisch, hier macht ein Interrupt nichts. Das nutzt man aus. fchk
Andi M. schrieb: > Ich habe eine Frage zu dem open-drain buffer circuit: > Die benutzen da 2 2n7002, das Schaltzeichen entspricht einem "normalen" > MOSFET mit einer parallelgeschalteten, in Sperrichtung gepolten Diode > zwischen Drain und Source, was auch immer die tun soll. Diese parasitäre Diode ist im MOSFET immer eingebaut und entsteht während der Fertigung. Dagegen kann man sich nicht wehren. > Ich hätte BS170 und 1N4148. Das sollte auch funktionieren, oder? Streiche die Diode. Ein BC548 sollte es auch tun. Siehe auch AppNote AVR318. Ich nehme immer einen 74HC1G125. !OE an TXD, Y(Ausgang) an RXD, A(Eingang) fest auf Ground. Wenn Du den nicht bekommst, ist ein ganzer HC125 das nächst einfache, wobei Du da ja nur ein von 4 Gattern brauchst. Die anderen kannst Du anderweitig verwenden. fchk
Hättest du nicht einfach gläserner Temperaturraum o.ä. schreiben können? Terrarium klingt so nach Tierquälerei.
Frank K. schrieb: > Diese parasitäre Diode ist im MOSFET immer eingebaut und entsteht > während der Fertigung. Dagegen kann man sich nicht wehren. Okay, ich war mir nicht sicher ob das ein Sondertyp ist bei dem man besonderen Wert auf diese Diode legt. Wenn die einfach den PN-Übergang vom Substrat zur Drain-Schicht meinen ist ja alles gut. >> Ich hätte BS170 und 1N4148. Das sollte auch funktionieren, oder? > Streiche die Diode. Ein BC548 sollte es auch tun. mh, ich hätte BS 170, BS 250, BD 135, 2SK 170, 2SJ 74, ZTX 450 und ZVP 3310 Frank K. schrieb: > Genau. Für den Reset/Presence Detect Puls wird der USART auf 9600bps > eingestellt, für die Daten auf 115200bps. Das Teil empfängt bei Senden, > und so bekommst Du die Rückmeldung des Slaves mit. > > Zeitkritisch ist nur der Teil beginnend von der fallenden Flanke des > Startpulses, den der Master vorgibt, bis zur Antwort des Slaves auf den > Reset bzw auf das jeweilige Bit. Das macht der USART. Die Zeit zwischen > zwei Bits bzw zwischen Reset/Presence Detect und dem ersten Bit ist > unkritisch, hier macht ein Interrupt nichts. Das nutzt man aus. > > fchk Ah, ja, sehr schön, dann habe ich Sonntag ja was zu tun :D Vielen Dank
Andi M. schrieb: > Bisher basiert der ganze Ablauf, wie das DCF77-Projekt das ich als > Grundlage genommen habe, darauf, dass jede Millisekunde ein Interrupt > ausgelöst wird Warum? Was muß denn unbedingt alle 1ms gemacht werden? Die kleinste Dauer bei DCF77 ist 100ms, Eine Abtastung alle 10 oder 20ms ist daher dicke ausreichend. Immer nur so schnell rechnen, wie nötig. Peter
Hallo Peter, das habe ich einfach so gelassen. Grundlage des Programms ist (wenn ich das gerade nicht verwechsel) das DCF-Projekt von hier: Beitrag "DCF-Uhr mit LCD in C" Zu dem 1-wire über UART-Problem: Ich habe heute erst mal das Display an einen andere Port verschieben müssen, was länger dauerte als ich gedacht hätte und dann habe ich angefangen Dinge für den UART zu basteln/programmieren, was bisher so mehr oder weniger erfolgreich war: Ich habe den open drain-Ausgang mit 2 BS170 aufgebaut (woran merke ich dass das funktioniert?) und ein paar Funktionen geschrieben, von denen ich hoffte dass sie den 1-wire-Baustein nach seiner ID fragen, kriege aber eine nicht endende Folge von Zweien und Fünfen. Demnächst werde ich wohl mal den Beispielquelltext ausprobieren den es zur Application Note AVR318 gibt.
Mh, ich kriege das nicht dazu zu funktionieren. Ich habe die zu dieser Appnote: http://www.atmel.com/Images/doc2579.pdf gehörende Software: http://www.atmel.com/Images/AVR318.zip genommen und folgende Anpassungen gemacht: - aus #include <ioavr.h> wurde <avr/io.h>, aus <inavr.h> wurde <avr/interrupt.h> - \ in Pfadnamen durch / ersetzt - ln -s OWIUARTBitFuntions.c OWIBitFunctions.c - ./common_files/OWIDeviceSpecific.h: "#define __ATmega8__" eingefügt - PORTB auf PORTC geändert (die Ausgabe soll auf LEDs landen, nicht auf dem Display das ich an PORTB hängen habe) - Versorgungsspannungspin des DS18S20 auf +5V gelegt, da im Quelltext irgendwo in einem Kommentar steht dass diese Funtkion(en) nur dann funktionieren würde(n). Ich übersetze es mit dem "üblichen" Makefile mit:
1 | MCU = atmega8 |
2 | F_CPU=8000000UL |
3 | F_OSC = 8.000MHz |
4 | FORMAT = ihex |
5 | TARGET = main |
6 | SRC = $(TARGET).c ../common_files/OWIcrc.c OWIUARTBitFunctions.c OWIHighLevelFunctions.c |
7 | ASRC = |
8 | OPT = s |
9 | DEBUG = dwarf-2 |
10 | EXTRAINCDIRS = |
11 | CSTANDARD = -std=gnu99 |
12 | CDEFS = -DF_CPU=$(F_CPU) |
13 | CINCS = |
14 | CFLAGS = -g$(DEBUG) |
15 | CFLAGS += $(CDEFS) $(CINCS) |
16 | CFLAGS += -O$(OPT) |
17 | CFLAGS += -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums |
18 | CFLAGS += -Wall -Wstrict-prototypes |
19 | CFLAGS += -Wa,-adhlns=$(<:.c=.lst) |
20 | CFLAGS += $(patsubst %,-I%,$(EXTRAINCDIRS)) |
21 | CFLAGS += $(CSTANDARD) |
22 | CFLAGS += -DF_OSC=$(F_OSC) |
23 | [...] |
Er meckert nicht allzu viel:
1 | In file included from OWIHighLevelFunctions.c:26:0: |
2 | OWIBitFunctions.h:38:1: warning: function declaration isn’t a prototype [-Wstrict-prototypes] |
3 | OWIBitFunctions.h:41:1: warning: function declaration isn’t a prototype [-Wstrict-prototypes] |
4 | OWIBitFunctions.h:44:1: warning: function declaration isn’t a prototype [-Wstrict-prototypes] |
5 | OWIBitFunctions.h:47:1: warning: function declaration isn’t a prototype [-Wstrict-prototypes] |
6 | OWIBitFunctions.h:50:1: warning: function declaration isn’t a prototype [-Wstrict-prototypes] |
7 | OWIHighLevelFunctions.c: In function ‘OWI_SearchRom’: |
8 | OWIHighLevelFunctions.c:199:13: warning: ‘return’ with no value, in function returning non-void [enabled by default] |
Aber das Teil scheint einfach nichts zu machen. Habe ich etwas wichtiges übersehen? Was hat es mit dem Makro BUSES auf sich? Wenn ich das richig sehe liefert das derzeit die beiden UART-Pins, ist das so richtig? Wie kriege ich raus ob der selbstgebaute open collector/drain-buffer richtig funktioniert? Ich habe ja nur 2 BS170 und 2 Widerstände so zusammengesteckt wie in der AppNote mit 2 BC547 gezeigt wird(das gab es woanders genauso, aber mit FETs).
Ich habe es jetzt so weit eingegrenzt:
1 | unsigned char OWI_TouchBit(unsigned char outValue) |
2 | {
|
3 | // Place the output value in the UART transmit buffer, and wait
|
4 | // until it is received by the UART receiver.
|
5 | OWI_UART_DATA_REGISTER = outValue; |
6 | lcd_setcursor(0,1);lcd_data('D'); |
7 | while(!(OWI_UART_STATCTRL_REG_A & (1 << OWI_RXC))) |
8 | {
|
9 | lcd_setcursor(0,1);lcd_data('F'); |
10 | }
|
11 | lcd_setcursor(0,1);lcd_data('G'); |
12 | // Set the UART Baud Rate back to 115200kbps when finished.
|
13 | OWI_UART_BAUD_RATE_REG_L = OWI_UBRR_115200; |
14 | return OWI_UART_DATA_REGISTER; |
15 | lcd_setcursor(0,1);lcd_data('H'); |
16 | }
|
Das Display zeigt "F" OWI_UART_STATCTRL_REG_A wird aufgelöst zu UCSRA OWI_RXC wird aufgelöst zu RXC Das ist also alles so wie es sein soll, Hier ist das nochmal mit Kommentar:
1 | OWI_UART_WRITE1 = 0xff; |
2 | |
3 | void OWI_WriteBit1() |
4 | {
|
5 | OWI_TouchBit(OWI_UART_WRITE1); |
6 | }
|
7 | |
8 | |
9 | /*! \brief Write and read one bit to/from the 1-Wire bus. (Polled UART driver)
|
10 | *
|
11 | * Writes one bit to the bus and returns the value read from the bus.
|
12 | *
|
13 | * \param outValue The value to transmit on the bus.
|
14 | *
|
15 | * \return The value received by the UART from the bus.
|
16 | */
|
17 | unsigned char OWI_TouchBit(unsigned char outValue) |
18 | {
|
19 | // Place the output value in the UART transmit buffer, and wait
|
20 | // until it is received by the UART receiver.
|
21 | OWI_UART_DATA_REGISTER = outValue; |
22 | while(!(OWI_UART_STATCTRL_REG_A & (1 << OWI_RXC))) |
23 | {
|
24 | }
|
25 | // Set the UART Baud Rate back to 115200kbps when finished.
|
26 | OWI_UART_BAUD_RATE_REG_L = OWI_UBRR_115200; |
27 | return OWI_UART_DATA_REGISTER; |
28 | }
|
Kann es sein dass das einfach konzeptionell falsch ist? Wenn ich ein Bit schreibe soll er beim 1wire-bus doch einfach eine Zeit lang warten, nicht bis er eine Rückmeldung bekommt, oder sehe ich das hier völlig falsch?
Ich hätte ja einfach die einfache Lösung genommen (Hochsetzen des Interrupts auf 20ms). Peter
Hallo Peter, leider sehe ich noch nicht wie das mein Problem lösen würde. Ich vermute du schlägst vor die Interrupts weiter auseinander zu ziehen damit ich eine reine Softwarelösung für die 1wire-Kommunikation nehmen kann, die nicht den UART benötigt sondern einfach irgendeinen I/O-Pin. Aber 1 Bit dauert ungefähr 500 µs, dann passen in 20 ms doch maximal 40 Bit, dann kommt wieder ein Interrupt. So weit ich weiß reicht das nicht, da ja schon die Geräteadressen 64Bit lang sind. Die UART-Lösung finde ich im Prinzip ganz gut, ich könnte ja sogar sicherstellen dass ich nur jede Millisekunde (oder alle x Millisekunden) ein Bit schreibe/lese*, indem ich am Anfang der Schleife den µC in einen sleepmode schicke, dann arbeitet er ja den Rest der Schleife erst ab wenn die ISR durchgelaufen ist. Grüße, Andi M *auch die Bit-Übertragung vom Slave zum Master wird ja vom Master initialisiert
Andi M. schrieb: > Aber 1 Bit dauert ungefähr 500 µs, dann passen in 20 ms doch maximal 40 > Bit, dann kommt wieder ein Interrupt. Nö. Das Reset dauert 480µs, ein Bit aber nur 60µs. Und man sperrt die Interrupts ja nicht für einen komplettes Datenpaket, sondern nur für einen Puls, also max für 480µs. Die High-Zeit zwischen den Pulsen ist nicht begrenzt, die kann auch Stunden dauern. Daher stört dort ein Interrupt nicht. Peter
Andi M. schrieb: >
1 | > OWI_UART_WRITE1 = 0xff; |
2 | >
|
3 | > void OWI_WriteBit1() |
4 | > { |
5 | > OWI_TouchBit(OWI_UART_WRITE1); |
6 | > } |
7 | >
|
8 | >
|
9 | > /*! \brief Write and read one bit to/from the 1-Wire bus. (Polled UART |
10 | > driver)
|
11 | > *
|
12 | > * Writes one bit to the bus and returns the value read from the bus.
|
13 | > *
|
14 | > * \param outValue The value to transmit on the bus.
|
15 | > *
|
16 | > * \return The value received by the UART from the bus.
|
17 | > */
|
18 | > unsigned char OWI_TouchBit(unsigned char outValue) |
19 | > { |
20 | > // Place the output value in the UART transmit buffer, and wait |
21 | > // until it is received by the UART receiver. |
22 | > OWI_UART_DATA_REGISTER = outValue; |
23 | > while(!(OWI_UART_STATCTRL_REG_A & (1 << OWI_RXC))) |
24 | > { |
25 | > } |
26 | > // Set the UART Baud Rate back to 115200kbps when finished. |
27 | > OWI_UART_BAUD_RATE_REG_L = OWI_UBRR_115200; |
28 | > return OWI_UART_DATA_REGISTER; |
29 | > } |
> > Kann es sein dass das einfach konzeptionell falsch ist? > Wenn ich ein Bit schreibe soll er beim 1wire-bus doch einfach eine Zeit > lang warten, nicht bis er eine Rückmeldung bekommt, oder sehe ich das > hier völlig falsch? Der Trick ist, dass TXD und RXD über den OC-Treiber (Deine beiden Transistoren) und den Pullup auf dem 1W-Bus miteinander verbunden sind. Wenn Du also etwas sendest, und es es nichts weiter am Bus angeschlossen, dann solltest Du genau das gleiche wieder empfangen. Wenn nicht, dann ist an der Hardware etwas faul. Das musst Du dann debuggen mit den üblichen Elektronik-Messmitteln... fchk
Oh, das hört sich sinnvoll an. Dann muss ich heute Nachmittag mal drüber nachdenken wie sich der Ausgang verhalten soll und durchmessen. Schnelltest: Temperatursensor abgezogen -> Funktion läuft durch. Eine andere Sache: Ich habe ganz übersehen dass in der Application Note sogar Hinweise stehen wie man die Software ans Laufen kriegt rotwerd Leider weiss ich nicht bei allen Punkten was sie damit meinen, ich habe das mal mit Fragezeichen an Stelle der Aufzählungszeichen markiert. Achja: Ich nutze den AVR-GCC unter Linux. To get started with the polled drivers, follow the steps below: • Create a new project in IAR embedded workbench. Depending on the version, this might require that a workspace is already created. • Add all *.c files from the “polled” and “common_files” directories. • Select the project from the project browser. Right click on the project and select options to bring up the project options dialog. ? Under “General/Target”, make sure that the correct device and memory model(?) is selected. ? Under “General/Library configuration”, check the “Enable bit definitions in I/O include files” option. (#include <avr/io.h>?) ? Under “General/System”, set the Data stack (CSTACK) to 0x40 and the Return stack (RSTACK) to 0x10. This is required to run the memory-intensive example code. Smaller stack sizes may be sufficient for other application utilizing this driver. • If AVRStudio is used for debugging, the output file format must be changed. Under XLINK/Output, select Format/Other, and then select “ubrof 8 (forced)” from the “Output format” drop-down box. • Open the file “OWIPolled.h” for editing and locate the section named “User defines”. • Choose between software only or UART driver by uncommenting one of the lines as described in the file. • Move down to the section corresponding to the selected driver. • Adjust the defines in the section according to the hardware setup as described in the file. • The project is now ready to be compiled.
Peter Dannegger schrieb: > Andi M. schrieb: >> Aber 1 Bit dauert ungefähr 500 µs, dann passen in 20 ms doch maximal 40 >> Bit, dann kommt wieder ein Interrupt. > > Nö. > Das Reset dauert 480µs, ein Bit aber nur 60µs. > > Und man sperrt die Interrupts ja nicht für einen komplettes Datenpaket, > sondern nur für einen Puls, also max für 480µs. > > Die High-Zeit zwischen den Pulsen ist nicht begrenzt, die kann auch > Stunden dauern. Daher stört dort ein Interrupt nicht. > > > Peter Diesen Post habe ich ganz übersehen da Frank direkt danach geantwortet hat. Mir ist eben eingefallen warum ich jede Millisekunde einen Interrupt haben möchte: Ich möchte die Temperatur auslesen um sie zu regeln, das Regeln soll per Phasenanschnitt erfolgen. Da eine Halbwelle nur 50 ms dauert hätte ich mit 20 ms etwas wenig Auflösung: Ich dachte daran den Nulldurchgang zu detektieren, entweder indem ich den Nulldurchgang zu einem Puls forme und als Interrupt annehme, sofern das nicht Konflikte mit dem Timer-Interrupt gibt oder den Nulldurchgang oder den Puls per Polling zu detektieren, dann einzustellen in welcher Millisekunde der TRIAC zünden soll und ihn dann in der ISR zur entsprechenden Millisekunde zu zünden. Aber: Wenn ich zwischen den Bits beliebig lang warten kann, kann ich ja einfach jedes Bit am Ende der ISR lesen/schreiben. Ich weiß nicht exakt wie lang die ISR läuft, aber eine LED die ich zu Beginn der ISR anmache und am Ende wieder ausschalte leuchtet kaum, da sollte also genug Zeit sein, auch mit 1 Interrupt pro Millisekunde. Deinen 1wire-Quelltext habe ich bereits, wenn ich das mit dem OC-Buffer nicht gefixt kriege probiere ich den nachher mal aus. Kriegt man den DS18S20 kaputt indem man ihn falsch anschließt? Höhere Spannungen als 5 Volt habe ich auf dem Steckbrett nicht...
Hallo. Ich habe etwas weiter gebaut: Ich habe Peters 1 wire-Code genommen und mit der Tempmeas.c aus diesem Post: Beitrag "Re: DS1820, DS18B20 in C" (das ist die Variante mit der Namenszuordnung) erweitert. Die Berechnung des Temperaturwerts habe ich neu gebaut, die kann jetzt 0,1°C-Schritte und negative Temperaturen. Was noch nicht so recht klappen will ist die parallele Kommunikation per 1-Wire und Auswertung des DCF-Signals wenn die ISR jede Millisekunde läuft. Jetzt habe ich ein paar "Design"-Fragen: - Sollte ich die ISR seltener laufenlassen? Peter hat das ja schon mehrfach vorgeschlagen, aber das würde die Genauigkeit der geplanten Temperaturregelung (über Triac) herabsetzen. Oder Kriegt man das "noch nebenbei" mit Timern hin? - Ich finde die Main-Schleife schon jetzt nicht hübsch. Kann da mal jemand draufgucken und mir einen Vorschlag machen wie ich das einfacher/übersichtlicher aufbauen könnte?
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.