Endlich einer der sich traut zu überlegen damit einen Versuch zu wagen . Der Code enthält, wie vermutlich alle Codes, immer noch einen kleinen mir bekannten Bug. Falls der Übergang von einer Betriebsart in eine andere etwas hakelt könnte es der sein Viel Erfolg
Danke für Deine Arbeit und den Code! Werde ich bei Gelegenheit aus probieren! Alte Laufwerke hat man ja zur Genüge im Keller liegen! ^^ Viele Grüße, p@
Im RampenTest.bas.txt gab es einen Bug (fehlende Initialisierung einer Variablen). Programm ist gegen berichtigte Version ausgetauscht.
Hallo Marcus, danke für Erläuterung zur knick- und ruckelfreien Kurve. Hab ich echt zum erstenmal gehört. Gegoogelt und gleich Lust bekommen so eine Linie zu konstruieren. Es könnte aber sein, daß mein Problem damit verschwunden wäre und ich meine Meßapparatur gar nicht mehr ausnützen müßte. Nein, Quatsch. Es ist nicht soooo wichtig für mich, eine Teststrecke mit Höchstgeschwindigkeit zu durchfahren; da ist sowieso bei den Voraussetzungen von Motor, Getriebeübersetzung wg Höchstgeschwindigkeit und differentieller Lenkung, einfache Elektronik des TT bald Schluß. Es interessiert mich, wie ich auftretende Probleme in den Griff bekommen kann (ohne die Strecke zu verändern - das käme mir dann gemogelt vor). Falls mir das in diesem Fall für die gegenwärtige Strecke gelingt, könnte es sein, daß ich danach auch andere Streckenkonstruktionen ausprobiere. In der letzten Zeit habe ich weniger experimentiert und bin deshalb kaum weitergekommen. Allerdings habe ich schon einige Meßwerte bekommen können und es lassen sich daraus die Schlingerbewegungen schon erkennen. Die muß ich noch aufbereiten, genauer analysieren hinsichtlich Frequenz und Stärke und sicher noch ein paar Messungen mit unterschiedlichen Geschwindigkeiten machen. Werd dann mal sehen, wie ich Deinen Input in Gegenmaßnahmen praktisch verwerten kann. Gruß Searcher
Hi Knick und Ruckfrei haben wir damals im Mathe-LK gemacht, meint: DIe FUnktion, auf die der Roboter fährt, sowie die erste und zweite Ableitung sind stetig. Die erste Ableitung gibt an, wie die Lenkposition ist. Die zweite ABleitung gibt an, wie schnell die Lenkposition verändert wird. am Ende des Kreisen, wo du in die Gerade übergehst, muss der Robotor sehr schnell von der Lenkposition eingeschlagen auf neutral wechseln. Für diesen Wechsel hast du nur begrenzte Zeit zur Verfügung, die davon abhängt wie lange man noch die Linie sieht und natürlich wie schnell man ist. Bist du also zu schnell verliert man die Linie. SOweit die Theorie, hätte nie gedacht, dass mir Mathe so in der Praxis etgegen kommt^^
Zitat von Marcus Blesius Hast du mal probiert, wie dein Robo auf Knick und Ruckfreie Strecken reagiert? Hallo Marcus, mein Robo ist sehr einfach aufgebaut. Er kann nur vorwärts fahren und ich kann ihn nicht aktiv bremsen. Deshalb sind alle meine Teststrecken Knick- und "Ruckfrei"? d.h. keine Winkel drin. Winkel würd er nur mit geringer Geschwindigkeit schaffen. Für Messungen habe ich einen kleinen Rundkurs und eine Acht "aufgebaut". Die Kurven sind mit Zirkel gezogen, also Kreisbögen mit kleinstem Durchmesser von 22 cm. Im Prinzip wie im Video in diesem Blogeintrag zu sehen: http://www.roboternetz.de/community/...s-Linienfolger Ich bin eigentlich sehr zufrieden mit dem Fahrverhalten unter den Voraussetzungen auf den Teststrecken. Das Schlingern tritt nur sichtbar bei hoher Geschwindigkeit am Ausgang einer engen Kurve auf und das möchte ich versuchen zu verbessern. Liegt wahrscheinlich an den schwachen Motoren, die es nicht schaffen, rechtzeitig kräftig genug auf die Steuerimpulse zu reagieren und den TT auf Spur zu bringen, und ich hoffe durch Messungen Aufschlüsse über Gegenmaßnahmen zu bekommen. Gruß Searcher
Hast du mal probiert, wie dein Robo auf Knick und Ruckfreie Strecken reagiert?
Hier noch der hingefrickelte Code Code: '############################################################################### 'File: Messprogramm_08.bas ' 'Funktionen: 'Meßprogramm zum Abfahren einer geraden weißen Meßstrecke mit 100 schwarzen Strichen 'Die Striche sind im Abstand von 0,5cm aufgetragen und werden von einem CNY70 abgetastet 'Die verstrichenen Zeiteinheiten seit Start werden für jeden Strich im eeprom gesichert 'Nachbereitung der Meßwerte in externen Programmen auf PC 'Linienfolgefunktion sorgt für das Nichtabweichen von der Meßstrecke 'Meßfahrt wird mit RC5 Infrarotfernbedienung gestartet und nach Zählen von 100 Strichen gestoppt ' 'IDE: BASCOM-AVR Demoversion 1.11.9.8 ' 'HW circuit: Linienfolger_mit_FB.aac plus angeflanschtem CNY70 mit Schmittrigger an PB0 'Timer1 für PWM Erzeugung, Timeticks und Start der ADC Messungen für Linienfolgung 'TSOP für FB an PB3. BASCOM Kommando Getrc5 nutzt Timer0 !!! '############################################################################### $regfile = "attiny45.dat" $eepleave $framesize = 4 $swstack = 4 $hwstack = 34 $crystal = 8000000 $lib "mcsbyteint.lbx" 'only byte and word operations Dim Address As Byte , Command As Byte 'variables for getrc5 Dim Sr_tick(101) As Word 'Zwischenspeicher für Meßwerte Dim Ee_tick(101) As Eram Word At &H02 'eeprom Speicher wird am Ende der Meßfahrt gefüllt Dim Time_tick As Word Dim Toggle_bit As Bit Dim Index As Byte Dim Average_speed As Byte Average_speed = 0 'Durchschittsgeschwindigkeit mit 0 initialisieren Dim Adc_low As Byte 'variable for adc result Config Portb = Input 'ports initialisieren Portb = Portb Or &H1F 'ports mit pullups auf definierten Pegel Config Rc5 = Pinb.3 'TSOP at PB3 Config Portb.4 = Output 'PB4 as output, OC1B, MotorX Config Portb.1 = Output 'PB1 as output, OC1A, MotorY Tccr1 = Tccr1 Or &B01100000 'set PWM1A & OC1A (PB1) Gtccr = Gtccr Or &B01100000 'set PWM1B & OC1B (PB4) clear TCNT1 on OCR1C match Ocr1a = 0 'initialise OCR1A -> low, no pulses at OC1A Ocr1b = 0 'initialise OCR1B -> low, no pulses at OC1B Ocr1c = 249 'set pwm frq. 8Mhz / 4 / (249 + 1)= 8kHz Tccr1 = Tccr1 Or &B00000011 'Einschalten TIMER1 - prescaler = 4 Didr0 = &B00110100 'ADC power save PB2,4,5. PB3 (TSOP) nicht abschalten Admux = &B10101011 '1,1V internal reference, ADLAR=1 (left adjusted), PB5 PB2 gain 20 Adcsrb.7 = 1 'bipolar mode Adcsra = Adcsra Or &B00001111 'ADC Int. enable, ADC prescaler auf 128 (62500Hz at 8MHz systemclock) 'Messung braucht 13 Takte -> 13 * 16µs = 208µs Adcsra.7 = 1 'turn on ADC Pcmsk.pcint3 = 1 'Pin Change Interrupt PCINT3 auf Pin PB3 für FB TSOP erlauben Enable Pcint0 'Pin Change Interrupts erlauben On Adc Adcmessung_to_pwm 'Wenn ADC Messung fertig -> Interrupt zum PWM Tastverh. setzen On Pcint0 Get_time_tick 'Zeitnahme wenn Pin Change Interrupt vom CNY70 On Ovf1 Set_time_tick 'Timer1 Overflow INT -> ISR zum Timeticks hochzählen Enable Interrupts 'Interrupts generell erlauben Do 'Hauptschleife While Pcmsk.pcint0 <> 1 'Schleife für Startbefehl von Fernbedienung, 'nur wenn PCINT auf PB0 für CNY70 NICHT zugelassen Getrc5(address , Command) 'procedure returns FF FF if no RC5 message If Address <> &HFF Then 'RC5 Nachricht empfangen then... Command = Command And &B01111111 'toggle bit auf Null Select Case Command Case &H1D : Average_speed = 0 'stop bei home taste Tccr1 = Tccr1 And &B11011111 'OC1A (PB1) output abschalten Gtccr = Gtccr And &B11011111 'OC1B (PB4) output abschalten Portb.1 = 0 'OC1A auf low (Motor abschalten) Portb.4 = 0 'OC1B auf low (Motor abschalten) Ocr1a = 0 Ocr1b = 0 Case &H01 : Average_speed = 60 'verschiedene Fahrstufen Case &H02 : Average_speed = 70 Case &H03 : Average_speed = 80 Case &H04 : Average_speed = 100 Case &H05 : Average_speed = 120 Case &H06 : Average_speed = 140 Case &H07 : Average_speed = 160 Case &H08 : Average_speed = 180 Case &H09 : Average_speed = 200 End Select If Average_speed <> 0 Then 'FB Befehl zum Losfahren/Messen erkannt Incr Index Time_tick = &HFF00 + Average_speed 'Fahrstufe mit highbyte HFF versehen Sr_tick(index) = Time_tick 'Fahrstufe speichern Time_tick = 0 Pcmsk.pcint3 = 0 'Disable weitere interrupts von FB TSOP an PB3 Pcmsk.pcint0 = 1 'Enable Interrupts vom CNY70 an PB0 Tccr1 = Tccr1 Or &B01100000 'set PWM1A & OC1A (PB1) -Motor an PWM Generator anschalten Gtccr = Gtccr Or &B01100000 'set PWM1B & OC1B (PB4) clear TCNT1 on OCR1C match, Motor an PWM-Gen. Enable Ovf1 'Timer1 Overflow Int enable (8kHz für Timetick hochz.) End If End If Wend If Index = 101 Then 'Teststrecke bewältigt - 100 Striche gezählt plus Fahrstufe gespeichert Disable Ovf1 Average_speed = 0 Tccr1 = Tccr1 And &B11011111 'OC1A (PB1) output abschalten Gtccr = Gtccr And &B11011111 'OC1B (PB4) output abschalten Portb.1 = 0 'OC1A auf low (Motor abschalten) Portb.4 = 0 'OC1B auf low (Motor abschalten) Ocr1a = 0 Ocr1b = 0 Pcmsk.pcint0 = 0 Pcmsk.pcint3 = 1 Time_tick = 0 Toggle_bit = 0 For Index = 1 To 101 Ee_tick(index) = Sr_tick(index) 'sram array zum eeprom array übertragen Next Index Index = 0 End If Loop Set_time_tick: 'wird alle 125µs aufgerufen (8kHz PWM freq.) Incr Time_tick 'Zeiteinheiten hochzählen Adcsra.6 = 1 'ADC Messung für Liniensensoren starten, benötigt ca 208µs 'damit wird eine Messung jeden zweiten ISR Aufruf gestartet 'und somit die PWM zum Lenken mit 4kHz aktualisiert Return Adcmessung_to_pwm: 'ISR f. ADC Auslesen und Setzen der PWM (Aufruf alle 250µs) Adc_low = Adch 'nur 8 bit der Messung nutzen If Adc_low.7 = 1 Then 'negativer Wert vom ADC Adc_low = Not Adc_low 'umsetzen des 2er Komplements Adc_low = Adc_low + 1 'umsetzen des 2er Komplements Shift Adc_low , Right , 1 'Trimmen des Meßwertes/Abschneiden Meßschwankungen Ocr1a = Average_speed - Adc_low 'PWM Pulsweite setzen Ocr1b = Average_speed + Adc_low 'PWM Pulsweite setzen Else 'Meßwert positiv - keine Umwandlung Shift Adc_low , Right , 1 'Trimmen Ocr1a = Average_speed + Adc_low 'PWM Pulsweite setzen Ocr1b = Average_speed - Adc_low 'PWM Pulsweite setzen End If Return Get_time_tick: 'ISR Aufruf durch PCINT If Pcmsk.pcint0 = 1 Then 'Gilt nur, wenn CNY70 Interrupt verursacht If Toggle_bit = 0 Then 'Nur jeder zweite Interrupt zählt, da PCINT nicht nur bei 'schwarzen Strichen sondern auch bei weißen auftritt Incr Index If Index = 102 Then Index = 101 'Arrayindexüberlauf verhindern Sr_tick(index) = Time_tick 'Zeiteinheit in den Zwischenspeicher If Index = 50 Then Average_speed = Average_speed + 40 'Während Fahrt speed erhöhen End If Toggle Toggle_bit End If Return Gruß Searcher
'############################################################################### 'File: Messprogramm_08.bas ' 'Funktionen: 'Meßprogramm zum Abfahren einer geraden weißen Meßstrecke mit 100 schwarzen Strichen 'Die Striche sind im Abstand von 0,5cm aufgetragen und werden von einem CNY70 abgetastet 'Die verstrichenen Zeiteinheiten seit Start werden für jeden Strich im eeprom gesichert 'Nachbereitung der Meßwerte in externen Programmen auf PC 'Linienfolgefunktion sorgt für das Nichtabweichen von der Meßstrecke 'Meßfahrt wird mit RC5 Infrarotfernbedienung gestartet und nach Zählen von 100 Strichen gestoppt ' 'IDE: BASCOM-AVR Demoversion 1.11.9.8 ' 'HW circuit: Linienfolger_mit_FB.aac plus angeflanschtem CNY70 mit Schmittrigger an PB0 'Timer1 für PWM Erzeugung, Timeticks und Start der ADC Messungen für Linienfolgung 'TSOP für FB an PB3. BASCOM Kommando Getrc5 nutzt Timer0 !!! '############################################################################### $regfile = "attiny45.dat" $eepleave $framesize = 4 $swstack = 4 $hwstack = 34 $crystal = 8000000 $lib "mcsbyteint.lbx" 'only byte and word operations Dim Address As Byte , Command As Byte 'variables for getrc5 Dim Sr_tick(101) As Word 'Zwischenspeicher für Meßwerte Dim Ee_tick(101) As Eram Word At &H02 'eeprom Speicher wird am Ende der Meßfahrt gefüllt Dim Time_tick As Word Dim Toggle_bit As Bit Dim Index As Byte Dim Average_speed As Byte Average_speed = 0 'Durchschittsgeschwindigkeit mit 0 initialisieren Dim Adc_low As Byte 'variable for adc result Config Portb = Input 'ports initialisieren Portb = Portb Or &H1F 'ports mit pullups auf definierten Pegel Config Rc5 = Pinb.3 'TSOP at PB3 Config Portb.4 = Output 'PB4 as output, OC1B, MotorX Config Portb.1 = Output 'PB1 as output, OC1A, MotorY Tccr1 = Tccr1 Or &B01100000 'set PWM1A & OC1A (PB1) Gtccr = Gtccr Or &B01100000 'set PWM1B & OC1B (PB4) clear TCNT1 on OCR1C match Ocr1a = 0 'initialise OCR1A -> low, no pulses at OC1A Ocr1b = 0 'initialise OCR1B -> low, no pulses at OC1B Ocr1c = 249 'set pwm frq. 8Mhz / 4 / (249 + 1)= 8kHz Tccr1 = Tccr1 Or &B00000011 'Einschalten TIMER1 - prescaler = 4 Didr0 = &B00110100 'ADC power save PB2,4,5. PB3 (TSOP) nicht abschalten Admux = &B10101011 '1,1V internal reference, ADLAR=1 (left adjusted), PB5 PB2 gain 20 Adcsrb.7 = 1 'bipolar mode Adcsra = Adcsra Or &B00001111 'ADC Int. enable, ADC prescaler auf 128 (62500Hz at 8MHz systemclock) 'Messung braucht 13 Takte -> 13 * 16µs = 208µs Adcsra.7 = 1 'turn on ADC Pcmsk.pcint3 = 1 'Pin Change Interrupt PCINT3 auf Pin PB3 für FB TSOP erlauben Enable Pcint0 'Pin Change Interrupts erlauben On Adc Adcmessung_to_pwm 'Wenn ADC Messung fertig -> Interrupt zum PWM Tastverh. setzen On Pcint0 Get_time_tick 'Zeitnahme wenn Pin Change Interrupt vom CNY70 On Ovf1 Set_time_tick 'Timer1 Overflow INT -> ISR zum Timeticks hochzählen Enable Interrupts 'Interrupts generell erlauben Do 'Hauptschleife While Pcmsk.pcint0 <> 1 'Schleife für Startbefehl von Fernbedienung, 'nur wenn PCINT auf PB0 für CNY70 NICHT zugelassen Getrc5(address , Command) 'procedure returns FF FF if no RC5 message If Address <> &HFF Then 'RC5 Nachricht empfangen then... Command = Command And &B01111111 'toggle bit auf Null Select Case Command Case &H1D : Average_speed = 0 'stop bei home taste Tccr1 = Tccr1 And &B11011111 'OC1A (PB1) output abschalten Gtccr = Gtccr And &B11011111 'OC1B (PB4) output abschalten Portb.1 = 0 'OC1A auf low (Motor abschalten) Portb.4 = 0 'OC1B auf low (Motor abschalten) Ocr1a = 0 Ocr1b = 0 Case &H01 : Average_speed = 60 'verschiedene Fahrstufen Case &H02 : Average_speed = 70 Case &H03 : Average_speed = 80 Case &H04 : Average_speed = 100 Case &H05 : Average_speed = 120 Case &H06 : Average_speed = 140 Case &H07 : Average_speed = 160 Case &H08 : Average_speed = 180 Case &H09 : Average_speed = 200 End Select If Average_speed <> 0 Then 'FB Befehl zum Losfahren/Messen erkannt Incr Index Time_tick = &HFF00 + Average_speed 'Fahrstufe mit highbyte HFF versehen Sr_tick(index) = Time_tick 'Fahrstufe speichern Time_tick = 0 Pcmsk.pcint3 = 0 'Disable weitere interrupts von FB TSOP an PB3 Pcmsk.pcint0 = 1 'Enable Interrupts vom CNY70 an PB0 Tccr1 = Tccr1 Or &B01100000 'set PWM1A & OC1A (PB1) -Motor an PWM Generator anschalten Gtccr = Gtccr Or &B01100000 'set PWM1B & OC1B (PB4) clear TCNT1 on OCR1C match, Motor an PWM-Gen. Enable Ovf1 'Timer1 Overflow Int enable (8kHz für Timetick hochz.) End If End If Wend If Index = 101 Then 'Teststrecke bewältigt - 100 Striche gezählt plus Fahrstufe gespeichert Disable Ovf1 Average_speed = 0 Tccr1 = Tccr1 And &B11011111 'OC1A (PB1) output abschalten Gtccr = Gtccr And &B11011111 'OC1B (PB4) output abschalten Portb.1 = 0 'OC1A auf low (Motor abschalten) Portb.4 = 0 'OC1B auf low (Motor abschalten) Ocr1a = 0 Ocr1b = 0 Pcmsk.pcint0 = 0 Pcmsk.pcint3 = 1 Time_tick = 0 Toggle_bit = 0 For Index = 1 To 101 Ee_tick(index) = Sr_tick(index) 'sram array zum eeprom array übertragen Next Index Index = 0 End If Loop Set_time_tick: 'wird alle 125µs aufgerufen (8kHz PWM freq.) Incr Time_tick 'Zeiteinheiten hochzählen Adcsra.6 = 1 'ADC Messung für Liniensensoren starten, benötigt ca 208µs 'damit wird eine Messung jeden zweiten ISR Aufruf gestartet 'und somit die PWM zum Lenken mit 4kHz aktualisiert Return Adcmessung_to_pwm: 'ISR f. ADC Auslesen und Setzen der PWM (Aufruf alle 250µs) Adc_low = Adch 'nur 8 bit der Messung nutzen If Adc_low.7 = 1 Then 'negativer Wert vom ADC Adc_low = Not Adc_low 'umsetzen des 2er Komplements Adc_low = Adc_low + 1 'umsetzen des 2er Komplements Shift Adc_low , Right , 1 'Trimmen des Meßwertes/Abschneiden Meßschwankungen Ocr1a = Average_speed - Adc_low 'PWM Pulsweite setzen Ocr1b = Average_speed + Adc_low 'PWM Pulsweite setzen Else 'Meßwert positiv - keine Umwandlung Shift Adc_low , Right , 1 'Trimmen Ocr1a = Average_speed + Adc_low 'PWM Pulsweite setzen Ocr1b = Average_speed - Adc_low 'PWM Pulsweite setzen End If Return Get_time_tick: 'ISR Aufruf durch PCINT If Pcmsk.pcint0 = 1 Then 'Gilt nur, wenn CNY70 Interrupt verursacht If Toggle_bit = 0 Then 'Nur jeder zweite Interrupt zählt, da PCINT nicht nur bei 'schwarzen Strichen sondern auch bei weißen auftritt Incr Index If Index = 102 Then Index = 101 'Arrayindexüberlauf verhindern Sr_tick(index) = Time_tick 'Zeiteinheit in den Zwischenspeicher If Index = 50 Then Average_speed = Average_speed + 40 'Während Fahrt speed erhöhen End If Toggle Toggle_bit End If Return
@radbruch: Ein etwas spätes Danke für die Erläuterung. Sieht so aus, als wenn die email Nachricht bei Kommentaren auf ältere oder nicht letzte Blogeinträge nicht geht. Hab mich in der letzten Zeit mit, im weiteren Sinne, Odometrie Messungen beschäftigt. Komme sicher nochmal auf Deine Untersuchungen bezüglich LED-Entladekurve zurück. Gruß Searcher
... ich habe damals nicht wirklich verstanden, was Du da genau mißt. In Sperrrichtung geschaltet bilden LEDs eine kleine Kapazität die man aufladen kann. Abhängig von der Beleuchtungsstärke stellt sich zusätzlich ein Entladestrom ein. Die Entladungskurve ist deshalb proportional zur Beleuchtungsstärke und kann sogar mit einem digitalen Eingang erfasst werden.
@radbruch: Hallo, jetzt hab ich endlich mal in die Links von Dir geschaut. Die kamen mir sehr bekannt vor und ich habe damala, als ich sie gelesen hatte, nicht wirklich verstanden, was Du da genau mißt. Es gibt bei der differential conversion auch den unipolar mode. Den kann man verwenden, wenn die Polarität der angelegten Spannung bekannt ist. Mißt man da keine gegeneinander geschalteten LEDs, sondern nur eine LED, könnte die sogar genug Spannung liefern um ein brauchbares Meßergebnis mit 10Bit Auflösung zu bekommen. Dann hat man nicht die Last des 2er Komplements und liest den ADC "normal" aus. ADC_PIN1---->|------ADC_PIN2 Gruß Searcher
Hallo, Warum du zum Invertieren "Not" verwendest kann ich nicht nachvollziehen (bin Bascom-Laie). In C würde das der logischen Verküpfung "!" entsprechen: Na ja. Wahrscheinlich geht das auch viel eleganter. Ich wollte doch einfach nur das 2er Komplement als "normale" Zahl vorliegen haben. Zu C kann ich da gar nix sagen. Weis auch nicht mehr, wie ich Folgendes gefunden habe und warum dann auch noch in den Code aufgenommen habe http://de.wikipedia.org/wiki/Zweierk..._Dezimalsystem "Zahl ist negativ: Man subtrahiert 1 und negiert die einzelnen Ziffern. (Dieser Schritt lässt sich für den Menschen vereinfachen: Man negiert zuerst die einzelnen Ziffern und addiert hinterher 1, was zum selben Ergebnis führt.)" Den Zusatz in den Klammern hab ich einfach 1:1 in Code übernommen. Aus der BASCOM help (Language Fundamentals) http://avrhelp.mcselec.com/language_fundamentals.htm : "Logical Operators Logical operators perform tests on relations, bit manipulations, or Boolean operators. There four operators in BASCOM are : NOT - Logical complement ..." NOT Invertiert alle Bits in der Variablen. Diesen Hinweis fand ich auch irgendwo, kann ihn aber nicht wiederfinden. Vor Anwendung auch in Simulator ausprobiert. NOT testet also nicht nur sondern man kann auch bits damit manipulieren/invertieren. Code: Helperbyte2 = Adc_low And &B10000000 Wenn in Adc_low höchstwertiges Bit gesetzt ist wird es in Helperbyte2 übernommen If Helperbyte2 = &B10000000 Then Ist höchstwertiges Bit gesetzt, dann Zahl negativ Adc_result = Not Adc_result Alle Bits in Adc_result invertieren Adc_result = Adc_result And &B0000000011111111 wg WORD Variable die "oberen", nicht benötigten Bits auf Null setzten Adc_result = Adc_result + 1 zum Schluß noch laut Wiki 1 addieren . . Wann liefert der ADC negative Werte? Da muß ich doch mal aus dem Datenblatt des ATtiny45 (doc2586) zitieren:Kapitel 17.11.3 </pre> "...In the bipolar input mode two sided voltage differences are allowed and thus the voltage on the negative input pin can also be larger than the voltage on the positive input pin... ...The result is presented in two’s complement form, from 0x200 (-512d) through 0x000 (+0d) to 0x1FF (+511d). The GAIN is either 1x or 20x...." Frei mit Interpretation übersetzt: Die Polarität an dem positiven und negativen Anschluß des Gain Amplifier darf auch umgedreht sein. Falls verpolt, dann negativer Meßwert in ADCH/ADCL, oder anders ausgedrückt: Bekommt man einen positiven Wert, braucht man nur die beiden gemessenen Pole vertauschen und bekommt dann einen negativen Wert; Werte werden im 2er Komplement dargestellt. (sollte die gleiche Größe besitzen - das ist aber noch ein anderes Thema im Datenblatt bezüglich Kalibrierung) Auf dem Blockschaltbild (Figure 17-1) kann man den "Gain Amplifier" finden, der den negativen und positiven Eingang hat. Die Pins des µC werden nach Table "17-4. Input Channel Selections" im ADMUX Register mit den MUX[3:0] Bits ausgewählt. (Einstellung der vor dem Gain Amplifier liegenden MUXe) In meinem Fall: Code: Bitkombination pos.diff.Input neg.diff.Input gain 1011 ADC0 (PB5) ADC1 (PB2) 20x Die Summenspannung der Dioden ist sicher kleiner als VCC, deshalb ist die an Pin7 gemessene Spannung immer größer als GND. Die Spannung im bipolar mode wird nicht nur an einem PIN gemessen! Also nicht von einem PIN gegen GND oder VCC oder sonsitge Ref. Es wird gegen den zweiten mit MUX[3:0] ausgewählten PIN gemessen und mit der 1,1V Ref verglichen / Die 1,1V Ref Spannung wird benutzt um den gemessenen Wert in den 10Bit für ADCH ADCL zu wandeln. Etwas rückwärts erklärt, aber ich kenne die Innereien des µC ja auch nicht genau, so stellt sich das für mich zunächst mal dar. (Vielleicht ist hier der Vergleich mit einem DMM angebracht - messen -> positive Anzeige - Meßspitzen vertauschen -> negative Anzeige) Warum sind die Fotodioden an Pin1 und nicht an GND angeschlossen? Liegt daran, das ich die Herbieverwendung der Fotodioden auf den µC umsetzen wollte. Fand den bipolar mode und war glücklich Falls ich versuchen würde, die Dioden "herkömmlich" zu messen, müßte ich beide Dioden jeweils zB gegen GND schalten. Im Programm müßte man zwei Messungen durchführen und die Differenz SW-mäßig behandeln. So hab ich mit einer Messung das Ergebnis (mal abgesehen von der Nachbereitung) Ist also eine Wahl zwischen den Möglichkeiten gewesen. EDIT: Kann mich wage erinnern, daß wenn man die Reihenschaltung der gegeneinander geschalteten Dioden an einen PIN und zB GND schaltet, sich die Störeinstrahlungen zB Netzbrumm sehr stark bemerkbar machen. Bei differentieller Messung heben die sich auf. Hab dazu jedoch keine weiteren Versuche gemacht, war einfach eine Beobachtung; ohne Gewähr. Hoffe hab keine Deiner Fragen übersehen. Wie gesagt: Einfach weiterfragen, das hilft mir auch besser durchzublicken. PS wg Overlay: Hab schon früher ein wenig programmiert. BASCOM und µC sind neu und Overlay threads gibt es im Forum und im RN-Wissen steht auch was. Ob es hier notwendig ist - ich hab es einfach mal ausprobiert. noch ein EDIT: Weshalb beginnt dann der Wertebereich bei -63? Auf was beziehst Du Dich da? Falls es der Hauptblogeintrag ist, habe ich da in meiner Euphorie eine Ungenauigkeit reingebracht. Durch die Shifterei ist es genauer -64 bis 63 wie in meinem anderen Kommentar vorher schonmal durchgerechnet. Mit dem Meßwert 0 wären es dann schon 128 virtuelle Fotodioden (nicht sooo ernst gemeint) Gruß Searcher
Helperbyte2 = Adc_low And &B10000000 Wenn in Adc_low höchstwertiges Bit gesetzt ist wird es in Helperbyte2 übernommen If Helperbyte2 = &B10000000 Then Ist höchstwertiges Bit gesetzt, dann Zahl negativ Adc_result = Not Adc_result Alle Bits in Adc_result invertieren Adc_result = Adc_result And &B0000000011111111 wg WORD Variable die "oberen", nicht benötigten Bits auf Null setzten Adc_result = Adc_result + 1 zum Schluß noch laut Wiki 1 addieren
Bitkombination pos.diff.Input neg.diff.Input gain 1011 ADC0 (PB5) ADC1 (PB2) 20x
Puhh, kann nur hoffen, daß ich mich jetzt nicht blamiert habe. Grundsätzlich paßt es aber. Soweit ich es beurteilen kann ist das alles richtig. Der ADC ist ja für mich kein Neuland, lediglich der "Bipolar Differential Conversion Mode" irritiert mich. Die Summenspannung der Dioden ist sicher kleiner als VCC, deshalb ist die an Pin7 gemessene Spannung immer größer als GND. Weshalb beginnt dann der Wertebereich bei -63? Wann liefert der ADC negative Werte? Wenn die Spannung an Pin7 kleiner als die Referenzspannung ist oder wenn sie negativer als GND ist? Warum sind die Fotodioden an Pin1 und nicht an GND angeschlossen? (Ich könnte es ja selbst testen, aber mein Equipment ist zur Zeit "eingemottet" wegen anstehender Sommerprojekte.) Nochmals Danke für die Infos. Gruß mic [Edit] Noch 'ne kleine Anmerkung zum Thema "blamieren": Das ist mir ins Auge gesprungen: " Adc_result = Not Adc_result 'umsetzen des 2er Komplements" Nach über einer Stunde Programmanalyse weis ich jetzt, das Adc_result als Overlay definiert ist und deshalb über "Adc_low = Adch" gefüllt wird. Wer als Microkontrollereinsteiger solche Programme schreibt kann sich nicht blamieren! Warum du zum Invertieren "Not" verwendest kann ich nicht nachvollziehen (bin Bascom-Laie). In C würde das der logischen Verküpfung "!" entsprechen: Wenn Adc-result true ist wird es False sonst wird es True. Bitweises Invertieren in C ist die Tilde "~". ("Logical Operators" in Kapitel "Language Fundamentals" der Bascomhilfe.)
Hallo, Es sind +-63 des Auslesewertes des ADCH Registers. Hab jetzt kaum Zeit. Genauere Erklärung später. Die Summe der Diodenspannung wird gegen 1,1V verglichen und auf den Wertebereich -512 bis +511 ?? umgerechnet und in ADCH und ADCL Register abgelegt. Bis später, muß weg. auch *lol* (war wohl etwas in Druck ) Noch mal ansetzen. Im bipolar differential conversion mode liefert der ADC, der ja generell eine 10bit Auflösung hat, einen Wertebereich von -512 bis +511. (512 + 511 = 1023 -> max Wert mit 10bit darstellbar) Der Meßwert wird in den beiden Registern ADCH und ADCL als high und low Byte abgelegt und ist normalerweise "right adjusted" - niederwertigstes Bit in ADCL an der Bit 0 Stelle. Ist es ein negativer Wert, erkennt man das an dem höchstwertigen Bit, das dann 1 ist und man muß die Zahl als 2er Komplement behandeln. Positive kann man direkt verwenden. In den ADC Einstellungen im Programm stelle ich aber "left adjusted" ein. Bewirkt, das das höchstwertige Bit des 10 stelligen Meßergebnisses an Bitposition 7 des ADCH registers geshiftet wird und natürlich alle anderen Bits mitgeshiftet werden. Ich lese nur ADCH aus und bekomme einen 8 Bit Wert (Vorzeichen plus 7 höchstwertige Bits des Meßwertes) also einen Wertebereich von -128 bis 127. Verliere da schon mal an Auflösung, die ich aber sowieso nicht nutzen könnte bzw störend wären Negative Werte werden im Programm in positive gewandelt; die positiven werden dann zweimal nach rechts geshiftet (Bereich (-)32 bis 31 ) und einmal wieder nach links. (-)64 bis 63. Warum gerade diesen Bereich? Paßte gerade zu dem PWM Einstellungen und Geschwindigkeit um den Kurs zu bewältigen. OK, hier muß ich auch noch was tun, da die Auflösung durch das links shiften gelitten hat. Vielleicht reicht nur einmal statt zweimal nach rechts shiften - wie gesagt ist auf die Schnelle und durch zusammenfrickeln aus anderen Programmen entstanden. Puhh, kann nur hoffen, daß ich mich jetzt nicht blamiert habe. Grundsätzlich paßt es aber. "-->|-->|---|<--|<--"? Weis nicht, ob ich das beim Herbie nicht schon mal probiert hatte. Jetzt war ich zu sehr mit dem ADC und Linienherstellung beschäftigt Danke, ist auf jeden Fall ein Versuch wert. Sollte man auch einfach mit DMM messen können. Wär das die Lösung der Energieprobleme? Nur weiter fragen oder kommentieren. Sattelfest bin ich da sicher nicht. Gruß Searcher
Hab jetzt kaum Zeit ... Bis später, muß weg. *lol* "-->|-->|---|<--|<--"?
In deiner Schaltung wird aber die Summe der Spannungen gemessen, die die Leds selbst aktiv erzeugen. Das ist genial! Leider nicht von mir sondern abgekupfert von hier: http://www.beam-wiki.org/wiki/Herbie_line_follower Ist das letzlich auch der Grund warum die "moderneren" AVRs 1,1V anstelle von 2,56V als interne Referenz verwenden? Genau, sonst bekäm ich den TT nicht als Linienfolger zum laufen Funktioniert das nur mit Fotodioden oder auch mit normalen LEDs? Wie groß sind eigentlich die Spannungen die von den Dioden erzeugt werden? LEDs gehen im Prinzip auch, bringen aber eine zu geringe Spannung. Habe gerade den TT über die Linie wie im Video gefahren, die Zuleitungen zu den gegeneinander geschalteten Fotodioden abgezogen und an Oszi geklemmt - ein Anschluß Meßspitze, der andere an Masse. Die IR LEDs eingeschaltet und gemessen. Bei guter Ausrichtung über der Linie - 0 Volt. Über der Linie verschieben -> größter Unterschied = 28 mV. Es kommt sehr auf den Untergrund an. Gleiche Messung mit weißer Linie auf schwarzem Teppichboden - größter Unterschied = 98 mV. Die Spannung liegt dann an den ADC Pins an und mit der im Datenblatt verwendeten Formel 0,098V * 512 / 1,1V *20 = 912 wäre der im bipolaren Mode maximal anzeigbare Wert überschritten. Meßergebnis deshalb nur 511 ADC-Einheiten. Verwendete IR-LEDs: L_934SF4BT Verwendete Fotodioden: SFH203FA Warum sind es +-63 von 1,1V? SummeDerDiodenspannungen gegen GND/Pin1/Pin7/VCC/VREF? Es sind +-63 des Auslesewertes des ADCH Registers. Hab jetzt kaum Zeit. Genauere Erklärung später. Die Summe der Diodenspannung wird gegen 1,1V verglichen und auf den Wertebereich -512 bis +511 ?? umgerechnet und in ADCH und ADCL Register abgelegt. Bis später, muß weg. Gruß Searcher
Danke für die umfangreiche und sehr ausführliche Antwort. Aber bitte entschuldige, dass hier klingt, auf den ersten Blick, für mich wie ein verspäteter Aprilscherz: Schaltet man zwei (Leuchtdioden) wie im Schaltbild gegeneinander, überwiegt die Spannung der am hellsten beschienenen Fotodiode. Die Gesamtspannung kann man an den Enden der Reihenschaltung messen. Auf den zweiten Blick wird mir klar, dass ich vom falschen Ansatz ausging. Meine Versuche mit der Lichtempfindlichkeit von LEDs verwendeten immer den kapazitiven Effekt der Beleuchtungsstärke: http://www.roboternetz.de/community/...-Sensor-am-RP6 http://www.roboternetz.de/community/...l=1#post495721 In deiner Schaltung wird aber die Summe der Spannungen gemessen, die die Leds selbst aktiv erzeugen. Das ist genial! Ist das letzlich auch der Grund warum die "moderneren" AVRs 1,1V anstelle von 2,56V als interne Referenz verwenden? 1,1V internal reference, ADLAR=1 (left adjusted) Wieder was gelernt. Danke :) Gruß mic [Edit]Ähm, so wirklich verstehe ich es trotzdem noch nicht. Funktioniert das nur mit Fotodioden oder auch mit normalen LEDs? Wie groß sind eigentlich die Spannungen die von den Dioden erzeugt werden? Warum sind es +-63 von 1,1V? SummeDerDiodenspannungen gegen GND/Pin1/Pin7/VCC/VREF?
Code zum "Proof of Concept" Erklärungen: siehe meinen vorherigen Kommentar Code: '############################################################################### 'File: RC5_Linie_01.bas 'noch nicht ausgereifte Funktionen: '1. Fernbedienung eines Dreirades mit RC5 Fernbedienung '2. Linienfolgung 'IDE: BASCOM-AVR Demoversion 1.11.9.8 ' 'HW circuit: Linienfolger_mit_FB.aac 'PWM Erzeugung mit Timer1 'TSOP an PB3. BASCOM Kommando Getrc5 nutzt Timer0 !!! '############################################################################### $regfile = "attiny45.dat" $eepleave $framesize = 32 'default? $swstack = 32 'default? $hwstack = 32 'default? $crystal = 8000000 $lib "mcsbyteint.lbx" 'only byte and word operations Dim Address As Byte , Command As Byte 'variables for getrc5 Dim Helperbyte1 As Byte Dim Dummy As Byte Dim Helperword As Word At Helperbyte1 Overlay Dim Top As Byte Dim Helperbyte2 As Byte Dim Limit_slower As Byte Dim Limit_faster As Byte Dim Limit_low_curve As Byte Dim Limit_high_curve As Byte Dim Quarter_power As Byte Dim Half_power As Byte Dim Prescaler As Byte Prescaler = 3 'preset for 8kHz PWM freq Dim Adc_low As Byte 'variables for adc result Dim Adc_high As Byte 'variables for adc result Dim Adc_result As Word At Adc_low Overlay 'variables for adc result Config Portb = Input 'ports initialisieren Portb = Portb Or &H1F 'ports mit pullups auf definierten Pegel Config Rc5 = Pinb.3 'TSOP at PB3 Config Portb.4 = Output 'PB4 as output, OC1B Config Portb.1 = Output 'PB1 as output, OC1A Top = 249 'OCR1C wert für PWM Frequenz Half_power = Top Shift Half_power , Right , 1 Quarter_power = Half_power Shift Quarter_power , Right , 1 Quarter_power = 0 Limit_slower = 7 Limit_faster = Top - 8 Limit_low_curve = 3 Limit_high_curve = Top - 4 Tccr1 = Tccr1 Or &B01100000 'set PWM1A & OC1A (PB1) Gtccr = Gtccr Or &B01100000 'set PWM1B & OC1B (PB4) clear TCNT1 on OCR1C match Ocr1a = 0 'initialise OCR1A -> low, no pulses at OC1A Ocr1b = 0 'initialise OCR1B -> low, no pulses at OC1B Ocr1c = Top 'set pwm frq. 8Mhz / 4 / (Top + 1)= 8kHz Tccr1 = Tccr1 Or Prescaler '#### ADC Setup begin Admux = &B10101011 '010 1,1V internal reference, ADLAR=1 (left adjusted), PB5 PB2 gain 20 'REFS bits f. Vref im Register ein bißchen durcheiander! Adcsra.3 = 1 'ADIE ADC Interrupt enable Adcsra.2 = 1 'ADC prescaler auf 128 (62500Hz at 8MHz systemclock) Adcsra.1 = 0 'ADC prescaler auf 128 (62500Hz at 8MHz systemclock) Adcsra.0 = 1 'ADC prescaler auf 128 (62500Hz at 8MHz systemclock) Adcsrb.7 = 1 'bipolar mode Didr0.2 = 1 'power save 'Didr0.3 = 1 'TSOP darf nicht abgeschaltet werden Didr0.4 = 1 Didr0.5 = 1 Adcsra.7 = 1 'turn on ADC On Adc Adcmessung_to_pwm 'Wenn Messung fertig -> Interrupt Enable Interrupts 'nötig für RC5 Empfang und ADC auslesen Do If Quarter_power <> 0 Then Adcsra.6 = 1 'start conversion '####### folgende Zeilen für RC5 Fernbedienungsempfang ########## Getrc5(address , Command) 'procedure returns FF FF if no RC5 message If Address <> &HFF Then 'RC5 Nachricht empfangen then... Command = Command And &B01111111 'toggle bit auf Null Select Case Command Case &H17 : Helperword = Ocr1a + Ocr1b 'OK Taste - geradeaus Shift Helperword , Right , 1 'durch zwei teilen Ocr1a = Helperbyte1 Ocr1b = Helperbyte1 Case &H0F : If Ocr1a > Limit_slower And Ocr1b > Limit_slower Then Ocr1a = Ocr1a - 8 'langsamer bei Pfeil nach unten Ocr1b = Ocr1b - 8 Else Ocr1a = 0 'bei Reg.überläufen Notstop Ocr1b = 0 End If Case &H0E : If Ocr1a < Limit_faster And Ocr1b < Limit_faster Then Ocr1a = Ocr1a + 8 'schneller bei Pfeil nach oben Ocr1b = Ocr1b + 8 Else Ocr1a = Top 'schneller geht's nicht Ocr1b = Top End If Case &H13 : If Ocr1a > Limit_low_curve And Ocr1b < Limit_high_curve Then Ocr1a = Ocr1a - 4 'rechts bei Pfeil nach rechts Ocr1b = Ocr1b + 4 Else Ocr1a = 0 Ocr1b = 0 End If Case &H0B : If Ocr1a < Limit_high_curve And Ocr1b > Limit_low_curve Then Ocr1a = Ocr1a + 4 'links bei Pfeil nach links Ocr1b = Ocr1b - 4 Else Ocr1a = 0 'bei Reg.überläufen Notstop Ocr1b = 0 End If Case &H1D : Quarter_power = 0 Ocr1a = Quarter_power 'stop bei home Taste Ocr1b = Quarter_power Case &H01 : Quarter_power = 62 Ocr1a = Quarter_power '1/4 Gas mit Taste 1 Ocr1b = Quarter_power Case &H02 : Ocr1a = 187 '3/4'Half_power '1/2 Gas mit Taste 2 Ocr1b = 187 '3/4'Half_power Case &H03 : Ocr1a = Top 'Vollgas mit Taste 3 Ocr1b = Top Case &H04 : Ocr1a = Half_power Ocr1b = 80 'Kurve links ' Case &H05 : Gosub Testprogram Case &H06 : Ocr1a = 80 'Kurve rechts Ocr1b = Half_power Case &H37 : Ocr1a = 0 'Pirouette rechts mit Taste Audio Ocr1b = Top Case &H36 : Ocr1a = Top 'Pirouette links mit Taste View Ocr1b = 0 Case &H07 : 'Gtccr = Gtccr Or &B00000010 Prescaler = Prescaler + 1 If Prescaler = 8 Then Prescaler = 7 Tccr1 = Tccr1 And &B11111000 Tccr1 = Tccr1 Or Prescaler Waitms 300 Case &H08 : 'Gtccr = Gtccr Or &B00000010 Prescaler = 4 '4kHz Tccr1 = Tccr1 And &B11111000 Tccr1 = Tccr1 Or Prescaler Waitms 300 Case &H09 : 'Gtccr = Gtccr Or &B00000010 Prescaler = Prescaler - 1 If Prescaler = 0 Then Prescaler = 1 Tccr1 = Tccr1 And &B11111000 Tccr1 = Tccr1 Or Prescaler Waitms 300 End Select Waitms 30 'Änderungen nicht zu schnell bei gehaltener Taste End If '############# ENDE RC5 FB Emfang ############## Loop Adcmessung_to_pwm: 'ISR f. ADC Auslesen und Setzen der PWM Adc_result = 0 'irgendwelche Reste beseitigen Adc_low = Adch 'nur 8 bit der Messung nutzen 'Adc_low variable wg overlay mit Adc_result Helperbyte2 = Adc_low And &B10000000 If Helperbyte2 = &B10000000 Then 'negativer Wert vom ADC Adc_result = Not Adc_result 'umsetzen des 2er Komplements Adc_result = Adc_result And &B0000000011111111 Adc_result = Adc_result + 1 Shift Adc_result , Right , 2 'Trimmen des Meßwertes/Abschneiden Meßschwankungen Shift Adc_result , Left , 1 'Trimmen des Meßwertes/Abschneiden Meßschwankungen Ocr1a = Quarter_power + Adc_result Ocr1b = Quarter_power - Adc_result Else 'Meßwert positiv - keine Umwandlung Shift Adc_result , Right , 2 'Trimmen Shift Adc_result , Left , 1 Ocr1a = Quarter_power - Adc_result Ocr1b = Quarter_power + Adc_result End If Return Gruß Searcher
'############################################################################### 'File: RC5_Linie_01.bas 'noch nicht ausgereifte Funktionen: '1. Fernbedienung eines Dreirades mit RC5 Fernbedienung '2. Linienfolgung 'IDE: BASCOM-AVR Demoversion 1.11.9.8 ' 'HW circuit: Linienfolger_mit_FB.aac 'PWM Erzeugung mit Timer1 'TSOP an PB3. BASCOM Kommando Getrc5 nutzt Timer0 !!! '############################################################################### $regfile = "attiny45.dat" $eepleave $framesize = 32 'default? $swstack = 32 'default? $hwstack = 32 'default? $crystal = 8000000 $lib "mcsbyteint.lbx" 'only byte and word operations Dim Address As Byte , Command As Byte 'variables for getrc5 Dim Helperbyte1 As Byte Dim Dummy As Byte Dim Helperword As Word At Helperbyte1 Overlay Dim Top As Byte Dim Helperbyte2 As Byte Dim Limit_slower As Byte Dim Limit_faster As Byte Dim Limit_low_curve As Byte Dim Limit_high_curve As Byte Dim Quarter_power As Byte Dim Half_power As Byte Dim Prescaler As Byte Prescaler = 3 'preset for 8kHz PWM freq Dim Adc_low As Byte 'variables for adc result Dim Adc_high As Byte 'variables for adc result Dim Adc_result As Word At Adc_low Overlay 'variables for adc result Config Portb = Input 'ports initialisieren Portb = Portb Or &H1F 'ports mit pullups auf definierten Pegel Config Rc5 = Pinb.3 'TSOP at PB3 Config Portb.4 = Output 'PB4 as output, OC1B Config Portb.1 = Output 'PB1 as output, OC1A Top = 249 'OCR1C wert für PWM Frequenz Half_power = Top Shift Half_power , Right , 1 Quarter_power = Half_power Shift Quarter_power , Right , 1 Quarter_power = 0 Limit_slower = 7 Limit_faster = Top - 8 Limit_low_curve = 3 Limit_high_curve = Top - 4 Tccr1 = Tccr1 Or &B01100000 'set PWM1A & OC1A (PB1) Gtccr = Gtccr Or &B01100000 'set PWM1B & OC1B (PB4) clear TCNT1 on OCR1C match Ocr1a = 0 'initialise OCR1A -> low, no pulses at OC1A Ocr1b = 0 'initialise OCR1B -> low, no pulses at OC1B Ocr1c = Top 'set pwm frq. 8Mhz / 4 / (Top + 1)= 8kHz Tccr1 = Tccr1 Or Prescaler '#### ADC Setup begin Admux = &B10101011 '010 1,1V internal reference, ADLAR=1 (left adjusted), PB5 PB2 gain 20 'REFS bits f. Vref im Register ein bißchen durcheiander! Adcsra.3 = 1 'ADIE ADC Interrupt enable Adcsra.2 = 1 'ADC prescaler auf 128 (62500Hz at 8MHz systemclock) Adcsra.1 = 0 'ADC prescaler auf 128 (62500Hz at 8MHz systemclock) Adcsra.0 = 1 'ADC prescaler auf 128 (62500Hz at 8MHz systemclock) Adcsrb.7 = 1 'bipolar mode Didr0.2 = 1 'power save 'Didr0.3 = 1 'TSOP darf nicht abgeschaltet werden Didr0.4 = 1 Didr0.5 = 1 Adcsra.7 = 1 'turn on ADC On Adc Adcmessung_to_pwm 'Wenn Messung fertig -> Interrupt Enable Interrupts 'nötig für RC5 Empfang und ADC auslesen Do If Quarter_power <> 0 Then Adcsra.6 = 1 'start conversion '####### folgende Zeilen für RC5 Fernbedienungsempfang ########## Getrc5(address , Command) 'procedure returns FF FF if no RC5 message If Address <> &HFF Then 'RC5 Nachricht empfangen then... Command = Command And &B01111111 'toggle bit auf Null Select Case Command Case &H17 : Helperword = Ocr1a + Ocr1b 'OK Taste - geradeaus Shift Helperword , Right , 1 'durch zwei teilen Ocr1a = Helperbyte1 Ocr1b = Helperbyte1 Case &H0F : If Ocr1a > Limit_slower And Ocr1b > Limit_slower Then Ocr1a = Ocr1a - 8 'langsamer bei Pfeil nach unten Ocr1b = Ocr1b - 8 Else Ocr1a = 0 'bei Reg.überläufen Notstop Ocr1b = 0 End If Case &H0E : If Ocr1a < Limit_faster And Ocr1b < Limit_faster Then Ocr1a = Ocr1a + 8 'schneller bei Pfeil nach oben Ocr1b = Ocr1b + 8 Else Ocr1a = Top 'schneller geht's nicht Ocr1b = Top End If Case &H13 : If Ocr1a > Limit_low_curve And Ocr1b < Limit_high_curve Then Ocr1a = Ocr1a - 4 'rechts bei Pfeil nach rechts Ocr1b = Ocr1b + 4 Else Ocr1a = 0 Ocr1b = 0 End If Case &H0B : If Ocr1a < Limit_high_curve And Ocr1b > Limit_low_curve Then Ocr1a = Ocr1a + 4 'links bei Pfeil nach links Ocr1b = Ocr1b - 4 Else Ocr1a = 0 'bei Reg.überläufen Notstop Ocr1b = 0 End If Case &H1D : Quarter_power = 0 Ocr1a = Quarter_power 'stop bei home Taste Ocr1b = Quarter_power Case &H01 : Quarter_power = 62 Ocr1a = Quarter_power '1/4 Gas mit Taste 1 Ocr1b = Quarter_power Case &H02 : Ocr1a = 187 '3/4'Half_power '1/2 Gas mit Taste 2 Ocr1b = 187 '3/4'Half_power Case &H03 : Ocr1a = Top 'Vollgas mit Taste 3 Ocr1b = Top Case &H04 : Ocr1a = Half_power Ocr1b = 80 'Kurve links ' Case &H05 : Gosub Testprogram Case &H06 : Ocr1a = 80 'Kurve rechts Ocr1b = Half_power Case &H37 : Ocr1a = 0 'Pirouette rechts mit Taste Audio Ocr1b = Top Case &H36 : Ocr1a = Top 'Pirouette links mit Taste View Ocr1b = 0 Case &H07 : 'Gtccr = Gtccr Or &B00000010 Prescaler = Prescaler + 1 If Prescaler = 8 Then Prescaler = 7 Tccr1 = Tccr1 And &B11111000 Tccr1 = Tccr1 Or Prescaler Waitms 300 Case &H08 : 'Gtccr = Gtccr Or &B00000010 Prescaler = 4 '4kHz Tccr1 = Tccr1 And &B11111000 Tccr1 = Tccr1 Or Prescaler Waitms 300 Case &H09 : 'Gtccr = Gtccr Or &B00000010 Prescaler = Prescaler - 1 If Prescaler = 0 Then Prescaler = 1 Tccr1 = Tccr1 And &B11111000 Tccr1 = Tccr1 Or Prescaler Waitms 300 End Select Waitms 30 'Änderungen nicht zu schnell bei gehaltener Taste End If '############# ENDE RC5 FB Emfang ############## Loop Adcmessung_to_pwm: 'ISR f. ADC Auslesen und Setzen der PWM Adc_result = 0 'irgendwelche Reste beseitigen Adc_low = Adch 'nur 8 bit der Messung nutzen 'Adc_low variable wg overlay mit Adc_result Helperbyte2 = Adc_low And &B10000000 If Helperbyte2 = &B10000000 Then 'negativer Wert vom ADC Adc_result = Not Adc_result 'umsetzen des 2er Komplements Adc_result = Adc_result And &B0000000011111111 Adc_result = Adc_result + 1 Shift Adc_result , Right , 2 'Trimmen des Meßwertes/Abschneiden Meßschwankungen Shift Adc_result , Left , 1 'Trimmen des Meßwertes/Abschneiden Meßschwankungen Ocr1a = Quarter_power + Adc_result Ocr1b = Quarter_power - Adc_result Else 'Meßwert positiv - keine Umwandlung Shift Adc_result , Right , 2 'Trimmen Shift Adc_result , Left , 1 Ocr1a = Quarter_power - Adc_result Ocr1b = Quarter_power + Adc_result End If Return
Hallo radbruch, danke für Dein Intresse. Ich habe das Programm vom Video gerade noch ein bißchen mehr kommentiert und werd es in einem weiteren Kommentar einfügen (Hier geht's nicht, nur 10000 Zeichen erlaubt und im Hauptblogeintrag aus gleichem Grund auch nicht). Ist ein bißchen zurechtgestrickt zur Linienfolgung aus Programmstücken, die ich vorher schon gemacht hatte. Einfach nur nachfragen, wenn da was unklar ist. Da geht bestimmt noch was eleganter zu machen - wollte eben nur schnell fahren Grober Programmablauf: 1. Initialisieren (Timer und ADC Einstellungen) 2. Messung in der Endlosschleife starten 3. Wenn Messung fertig ist, wird vom ADC ein Flag gesetzt, das zum Interrupt führt. 4. In der ISR den Meßwert auslesen und die PWM entsprechend einstellen. 4.a Ist der ADC auf bipolar gestellt, wird die Spannung zwischen den beiden ausgewählten Anschlüssen gemessen. Wird die verpolt, können da auch nagative Werte rauskommen, die im 2er Komplement dargestellt werden. 4.b Zum Losfahren stelle ich einfach mit FB die PWM Werte auf 62 versteckt in "Case &H01 : Quarter_power = 62". Dazu addiere oder subtrahiere ich einfach in den Compareregistern die auf +-63 getrimmten Meßwerte (ich weiß, da ist noch was nicht ganz sauber und muß sowieso überarbeitet werden) Im Prinzip ist der Gedanke: Beide Dioden mittig über der Linie -> Meßwert = 0 -> nix addieren, fährt gerade weiter Kurve -> Meßwert zb = (-33) -> PWM wird leicht korrigiert Kurve -> Meßwert zb = (+33) -> PWM wird in andere Richtung korrigiert etc. Wie funktionieren die Fotodioden Wenn man eine Fotodiode beleuchtet, kann man an ihren Anschlüssen eine Spannung messen. Schaltet man zwei wie im Schaltbild gegeneiander, überwiegt die Spannung der am hellsten beschienenen Fotodiode. Die Gesamtspannung kann man an den Enden der Reihenschaltung messen. Werden beide gleichhell beleuchtet ist die Spannung Null. Je nach Beleuchtung wird die gemessenen Gesamtspannung über der Reihenschaltung auch positiv oder negativ. (Soweit meine laienhafte Erklärung) Das gleich Prinzip wird beim Herbie mit einem LM386 genutzt, den ich auch mal modifiziert nachgebaut hatte. Jetzt messe ich mit dem ADC die Spannung und war überrascht, daß das geht. Ist der Pin1 des Tiny45 aktiv? Ja, RESET ist aktiv - hab da nichts geändert, weil ich ISP verwenden möchte. Hat mich auch gewundert, weil ich da auch noch den externen 10k Widerstand dran hab. Ich werde nochmal die Meßwerte genau unter die Lupe nehmen müssen um zu sehen, ob da nicht doch irgenwas und wenn ja wieviel verfälscht wird. Läuft aber wie im Video zu sehen. Bei Vortests auf dem Steckbrett lief es auch gut. So hab ich noch einen Pin frei. Wenn es jedoch eine nicht mehr tolerierbare Grenze gibt, kann man noch ein zweites Paar Pins für die differenzielle Messung nutzen - dann stehen aber größere Umordnungsarbeiten an EDIT: RESET war wg Aufbaufehler NICHT mit dem 10k Pullup beschaltet. Der Widerstand hing "in der Luft" Schaltplan wurde berichtigt. Siehe auch über- übernächsten Blogeintrag. Gruß Searcher
Die Richtung ist super! Die Fotodioden werden vom ADC mittels "Bipolar Differential Conversion" gemessen. Diese Funktion des ADCs habe ich noch nicht verwendet. Mit meinen kläglichen Englischkenntnissen steige ich auch bei der Beschreibung im Datenblatt nicht ganz durch. Könnest du vielleicht das Setup und die Abfrage des ADC zeigen? Wie funktionieren die Fotodioden, bzw. wie erkennst du mit dieser spartanischen Schaltung die Linie? Ist der Pin1 des Tiny45 aktiv? Es ist immer wieder interessant deinen Projekten zu folgen. Danke für den Blog ;) Gruß mic