PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : mega8 oder tiny2313 oder tiny45 oder ... ?



Willa
04.12.2009, 12:04
Hallo!
Ich bin auf der suche nach einer Controllerempfehlung für ein kleines Teilprojekt. Was ich machen möchte:
Ich möchte einen Konverter bauen, der aus einem I²C Signal ein PWM Signal macht. Quadrocopter etc. werden oft mit Brushlessreglern betrieben die auf I²C umgebaut wurden (aufwändig) oder mit speziellen I²C Reglern (teuer). Jetzt möchte ich es gerne möglich machen ganz normale PWM Regler zu benutzen (billig), die durch meine I²C->PWM Konverter an Coptern betrieben werden können. Es gibt schon ein paar Leute die etwas ähnliches gemacht haben, allerdings finde ich die Lösungen meist nicht ganz optimal.
Ich möchte gerne drei getrennte Controller verwenden, für jeden Motorsteller einen eigenen. Dadurch verspreche ich mir ein sehr sauberes, schnelles PWM Signal, ohne monatelang meinen Code zu optimieren/ in Assembler zu schreiben etc. In Bascom ist es mir noch nicht geglückt drei wirklich saubere PWM Signal mit 400Hz zu erstellen. Aber welche Controller verwende ich nun dafür? Bascom nutzt anscheinend eh kein Hardware I²C, deswegen kommen die tiny2313/45 doch in Frage, oder? Ich will bei allen Controllern die ISP Schnittstelle benutzen, kann ich die dann doppelt belegen? D.h. kann ich beim tiny 45 den Pin B.2 als SCK benutzen fürs Programmieren und gleichzeitig z.b. als PWM Pin? Wie schnell kann bei den Tinys der interne Oszillator maximal schwingen? (Wenn mein Text euch konfus vorkommt, dann liegt das daran dass ich irgendwie Grippe oder so habe....)

Willa
04.12.2009, 16:06
Ich habe mal einen Schaltplan und ein Layout für den Tiny45 gemacht. Der µC wäre mein Favorit, wenn das denn so funktioniert wie ich mir das denke... Kann ich den Pin B.2 als ganz normalen Output Pin nutzen...? Mein Schaltplan könnte doch so funktionieren, oder? werde mir evtl. mal einen Tiny4 als DIP holen und das auf dem Steckbrett ausprobieren. Wie ich das Ganze programmiere (Bascom) weiss ich auch noch nicht so recht....

pyr0skull
04.12.2009, 17:05
Warum benutzt du für die PWM-Ausgabe nicht einen von den Hardware-PWM-Ports? Der Attiny45 hat soweit ich mich erinnere 3 davon, wobei einer auf 2 Pins jeweils normal und invertiert ausgegeben werden kann. Denn Software-I2C & Software-PWM zusammen braucht vermutlich einen Quarz, damit du auf brauchbare Frequenzen kommst.

Edit: Wenn du mit dem PWM einen Servo ansteuern willst, könnte eine Softwareansteuerung tatsächlich Sinn machen - dann würde ich aber den Hardware-I2C nutzen! Kann mir kaum vorstellen, dass Bascom nur Software-I2C kann :O

Besserwessi
04.12.2009, 17:14
Im prinzip sollte der Tiny45 gehen. Aller dings ist die Auswahl der Pins sehr ungünstig: PB2 ist so ziehmlich der einzige Pin der keinen Hardware PWM kann.

Wenn man die I2C Schnittstelle in Software machen will / muß, könnte es so gehen. Sonst sollte man für I2C besser die Dafür vorgesehenen Pins nehmen (PB2 und PB0 für Takt und Daten).
PB1 und PB4 könnte man dann als PWM Ausgänge nutzen.

Die ISP Pins kann man meistens auch für was anderes nutzen. Ausgänge sollten keine zu großen Lasten (< 1 K) treiben, Eingänge sollte man über etwa 2,2 K entkoppeln, so daß der ISP Mode ggf. der stärkere ist.

Willa
04.12.2009, 18:16
Hi!
Danke für eure Tipps. I²C und PWM habe ich nun an den richtigen Pins. Es scheint wirklich so zu sein, dass Bascom nur Software I²C macht wenn man nicht irgendeine zusätzliche Lib kauft. Das PWM ist für ein Modellbau Motorsteller (=Servo). Bisher habe ich das immer als Software PWM gelöst, wenns per Hardware geht (wie......?) macht das aber vielleicht auch Sinn...?

Vitis
04.12.2009, 18:27
Bascom kann I2C senden sowohl Hard- als auch Software.
Für den Empfang schauts da nicht so gut aus, da brauchts dann die
Lib dazu oder... es gab hier mal nen Thread mit nem Workaround
über die Register direkt.

Willa
04.12.2009, 18:39
Für den Empfang schauts da nicht so gut aus, da brauchts dann die
Lib dazu oder... es gab hier mal nen Thread mit nem Workaround
über die Register direkt.
Ich brauche für meinen Konverter den Empfang. Eigentlich ist mir (Software) I²C schon kompliziert genug, mal sehen ob ich das mit Hardware irgendwie hinbekomme....

Besserwessi
04.12.2009, 18:47
Mit einem 16 Bit Timer kann man das PWM Signal sehr gut direkt vom Timer erzeugen, aber der Tiny44 hat nur einen 8 Bit Timer.
Es sollte auch mit dem 8 Bit timer gehen einen Puls definierter Länge zu erzeugen. Die lange Pause wird man dann wohl weiter in Software machen, nur den eigentlichen Puls könnte der Timer bestimmen. Wie genau wüßte ich jetzt aber auch noch nicht, da müßte man erstmal nachlesen ob die PWM Werte gepuffert werden.
Zumindestens sehe ich keinen Nachteil, wenn der Pin auch für Hardware PWM geht - die reine Softwarelösung kann man ja immernoch machen.

Wegen dem Timing wäre es schon besser wenn man nicht beides, I2C und das PWM Signal in Software macht. Die könnten sich schon etwas in die Quere kommen.

Bei der Software PWM Lösung sollte man auch mehr als einen PWM kanal machen könnten. Wenn das einmal klappt, dann spricht nichts dagen auch mehr Kanäl nacheinander zu machen.

pyr0skull
05.12.2009, 15:40
Imho würde es dann mehr Sinn machen, die PWM komplett in Software zu bauen, Hardware-PWM mit Software-Pause klingt nach einem ziemlichen Gekrampfe ohne Vorteile..

Besserwessi
05.12.2009, 22:01
Beim Servosignal ist nur die Pulsdauer wirklich wichtig, die Pause ist weniger kritisch. Per Hardware hat man den Vorteil, daß der Puls immer gleich ist, nur die Fehler des Oszillators hat man noch. Per Software hat man es schwer besser als etwa +-2 Zyklen zu werden. Es geht, ist aber nichte enfach. Außerdem hat man bei Software PWM eventuell ein kleinere Auflösung, da man ja für jeden Schritt einen Interrupt braucht.
Bei z.B. 1 MHz Taktfrequenz kommt man selbst in ASM für ein Software PWM im interrupt kaum unter etwa 15 µs Auflösung. Für den etwa 1 ms Steuerbereich den man bei den Servos hat, sind das nur etwa 6 Bit Auflösung. Wenn dann auch noch parallel I2C in Software laufen soll, wird es noch einiges schlechter, vermutlich sogar unbrauchbar.

Einen Puls durch den Hardware timer erzeugen zu lassen ist dagegen nicht so schwer:
Man setzt den Startwert des Timer und den Wert für die Vergleichereinheit so, das der Ausgang bei erreichen des Vergleichswertes zurückgesetzt wird. Dann setzt man den Ausgang auf high und startet den Timer. Um das Ende des Pulse kümmert sich dann die Hardware. Wenn man bei 1 MHz Takt noch einen Vorteiler von 8 nutzt, hat man 8 µs Auflösung für Zeiten bis etwa über 2 ms. Das geht auch in Basic, ohne zusätzliche Fehler und ohne die Gefahr, das einem irgendwo ein Interrupt dazwischenfunkt. Auch mit nur einem 8 Bit Timer kann man ohne den Vorteiler arbeiten. Es wird dann aber schon etwas komplizierter, weil man die Überläuft in Softwäre zählen muß. Den Feinabgleich macht man dann besser mit dem Startwert. Ist nicht ganz einfach aber das müßte gehen.

Willa
05.12.2009, 22:59
Wieso bekomme ich denn auf einmal keine Benachrichtigungen mehr zu disem Thema...?
Ich habe bisher schon 4 Servo PWMs mit ca. 300 Hz erzeugt, und das hat schon einigermaßen funktioniert, aber eben nur einigermaßen. Jetzt möchte ich es besser machen. Das mit der "SoftwarePause" ist gar nicht schlecht. Ich werde mal irgendwas in der Richtung probieren. Schade nur, dass ich kein Oszi habe und daher die Beurteilung der PWM Qualität nicht so richtig objektiv wird. Müsste ich evtl. im Flug testen... Das wird aber bei meinem Programmierstil (Trial + Error) ziemlich zeitaufwändig.

StevieL
06.12.2009, 11:44
Hallo William,

das was du vor hast, verwende ich schon länger, allerdings zu einem anderen Zweck. Ich habe ein paar ATMega8, welche als I2C-Slaves Befehle entgegennehmen und dementsprechend in PWM umsetzen. Sowohl I2C als auch PWM sind hardwaremäßig umgesetzt und alles in BASCOM programmiert. Die ATMega8 habe 3 PWM-Ausgänge und Hardware-TWI (I2C). Bei der Programmumsetzung kann ich dir helfen.

Willa
06.12.2009, 12:01
Hi Stefan,
das wäre natürlich fantastisch...! Sobald ich damit angefangen habe und die ersten Probleme auftauchen werde ich auf dich zukommen. Du benutzt PWM aber nicht um Servos anzusteuern, oder? Wie oft pro Sekunde reagieren die Mega8 auf Änderungen des I²C Sollwerts? Bei mir sollten das so ca. 400 Hz werden, ist das realistisch?

StevieL
06.12.2009, 12:50
Hallo William,

ich lasse den Prozessor bei einer Taktfrequenz von 8 MHz einfach eine Schleife laufen, die das TWCR-Register abfragt. Von da aus wird dann einfach verzweigt. 400 Hz sollte also kein Problem sein.

StevieL
06.12.2009, 14:09
Hallo William,

ich habe mal kurz eines meiner Programme zurechtgestutzt:



$regfile = "m8def.dat"
$crystal = 8000000
$lib "i2c_twi.lbx"

$hwstack = 256
$swstack = 256
$framesize = 64


'Subs deklarieren
Declare Sub Twi_init_slave
Enable Interrupts

'Ports setzen
Ddrb = &B0000111
Portb = &B11111000
Ddrd = &B11101111
Portd = &B00010000

'SDA und SCL definieren
Config Sda = Portc.4
Config Scl = Portc.5
I2cinit

Config Timer1 = Pwm , Pwm = 8 , Compare A Pwm = Clear Up , Compare B Pwm = Clear Up , Prescale = 1
'PWM1a auf Pinb.1; PWM1b auf Pinb.2
Config Timer2 = Pwm , Compare Pwm = Clear Up
'PWM2 auf Pinb.3

Waitms 100

Call Twi_init_slave ' TWI aktivieren

Dim I As Byte
Dim J As Byte

Const Maxanzahlbyte = 2 ' Wenn mehr Zeichen kommen werden diese verworfen !
Dim Messagebuf(maxanzahlbyte) As Byte
Dim Anzahlbuf As Byte ' Anzahl Zeichen die gesendet wurden
Dim Neuemsg As Byte ' zeigt an wenn eine neue Message gültig ist

Dim Twi_control As Byte ' Controlregister lokale kopie
Dim Twi_status As Byte
Dim Twi_data As Byte
Const Slaveid = &H82 'Adresse für I2C

Twi_data = 0
Anzahlbuf = 0
Neuemsg = 0

Do

' schauen ob TWINT gesetzt ist
Twi_control = Twcr And &H80 ' Bit7 von Controlregister auslesen

If Twi_control = &H80 Then
Twi_status = Twsr And &HF8 ' Status ->Bit3 bis Bit7

Select Case Twi_status

' Slave Adress received, wir sind gemeint !
Case &H60 :
Twcr = &B11000100 ' TWINT löschen, erzeugt ACK
Anzahlbuf = 0
Neuemsg = 0 ' Flag für Message ungültig
' Byte mit ACK
Case &H80 :
If Anzahlbuf < Maxanzahlbyte Then
Incr Anzahlbuf ' zähler +1
Messagebuf(anzahlbuf) = Twdr
End If
Twcr = &B11000100 ' TWINT löschen, erzeugt ACK

' Stop oder restart empfangen
Case &HA0 :
Twcr = &B11000100 ' TWINT löschen, erzeugt ACK
' es müssen 2 Byte sein, damit das Paket OK ist
If Anzahlbuf = Maxanzahlbyte Then
Neuemsg = 1 ' Flag für Message gültig
Else
Neuemsg = 0 ' Flag für Message ungültig
End If
' was anderes empfangen
Case Else :
Twcr = &B11000100 ' TWINT löschen, erzeugt ACK

End Select
End If

' ein gültiges Paket angekommen
If Neuemsg = 1 Then
Neuemsg = 0 ' Flag wieder löschen
Select Case Messagebuf(1)
'Erster Wert
Case 1:
Pwm1a = Messagebuf(2)
Case 2:
Pwm1b = Messagebuf(2)
Case 3:
Compare2 = Messagebuf(2)
Case Else:
End Select
'Waitms 250
End If
Loop
End


' TWI als slave aktivieren
Sub Twi_init_slave
Twsr = 0 ' status und Prescaler auf 0
Twdr = &HFF ' default
Twar = Slaveid ' Slaveadresse setzen
Twcr = &B01000100 ' TWI aktivieren, ACK einschalten
End Sub


Ich habe es nicht getestet, aber wenn man 2 Bytes nacheinander schickt (erstes 1, 2 oder 3) sollte der zweite Wert auf den entsprechenen PWM-Kanal ausgegeben werden.
Das Grundprogramm stammt übrigens aus dem RN-Wissen Artikelbereich.

Willa
18.12.2009, 17:46
Hi,
@stevie, ich konnte dein Programm noch nicht übersetzen und testen, als erstes möchte ich aber sowieso erstmal erfolgreich ein Servo ansteuern (wenn irgendwie möglich per hardware PWM).
Dazu habe mir mal die Grundlagen angeschaut, aber anscheinend einen Denkfehler, den die Theorie passt nicht zu meinen Beobachtungen...:
Ich habe einen tiny45 mit 8MHz int. Takt. Clock divide by 8 ist erstmal an.
den Timer0 habe ich als PWM konfiguriert:

Config Timer0 = Pwm , Compare B Pwm = Clear Up , Prescale = 1024
Enable timer0
Das PWM Signal soll auf PB.1 "herauskommen"

Config Portb.1 = Output
Ocr0b = 128
Angenommen, der Code oben wäre richtig, so sollte doch folgendes passieren:
µC Frequenz=1MHz, Prescaler = 1024 ==> PWM frametime = 976,56 Hz
Wenn Ocr0b jetzt auf 128 gesetzt ist, sollte Portb.1 doch eigentlich abwechselnd 1/(972,56/2) Sekunden an und aus sein. Tatsächlich blinkt die angeschlossene LED aber mit ca. 2 Hz. Was habe ich da falsch gedacht....? So wie es aussieht schaffe ich es eh nicht ein Servo per Hardware anzusteuern, da werde ich wohl oder übel auf software umsteigen müssen...

Besserwessi
18.12.2009, 19:58
Wenn man bei 1 MHz Takt den Teiler auf 1024 setzt, hat man pro zeitschritt ca. 1 ms. Bei einem 8 Bit timer und 128 als PWM Wert sollte man dann 128 ms an und 128 ms aus bekommen, bei phasenrichtigem PWM sogar noch doppelt so lange.
So direkt mit der Unterstützung von bascom aus wird das mit dem PWM auch kaum gehen. Da wird man schon die register von hand Programmieren müssen.


Für die Servo steuerung sollte auch der Code aus dem Wiki-bereich gehen:
http://www.rn-wissen.de/index.php/Servoansteuerung.

So schlecht ist das Beispiel nicht. Mit nur einem 8 Bit timer müßte man aber überlegen die Auflösung des Timers noch etwas erweitern, den man braucht ja pulse von 1-2 ms. Für 2 ms würde ein Timer Takt von 1/8 MHz noch gerade reichen. Wenn man mehr auflösung haben will, müßte man noch zusätzlich die Zahl der Überläufe runterzählen, und erst wenn man da 0 erreicht hat den Code zum umschalten der Pins ausführen.

Ein Problem kann da nur ein weiterer Interrupt für I2C sein. Da sollte man sehen, dass man wenigsten I2C per hardware und ohne Interrupt hinkriegt. So kompliziert sollte das nicht sein, denn man muß ja nur Daten empfangen, nicht senden. Bei 100 kHz I2C Takt hat man ja immerhin 80 µs für eine Byte. So lange sollte die ISR fürs PWM Signal hoffentlich nicht brauchen. Notfalls muß man doch mit mehr als 1 MHz Takt arbeiten.

Willa
18.12.2009, 20:10
Für die Servo steuerung sollte auch der Code aus dem Wiki-bereich gehen:
http://www.rn-wissen.de/index.php/Servoansteuerung
Der ist ja auch von mir ;-D. Ich habe ein Beispiel für I²C bekommen (vom RN-User Bammel), soweit ich das verstanden habe ist der in Hardware ausgeführt. Ich dachte, ich lasse den tiny mit 8 MHz laufen, nehme den 8bit Timer und einen prescaler von 8. Dann dauert ein Overflow 0,255 ms. Ich teile meinen Puls (Länge 1 bis 2 ms) dann einfach in mehrere Overflows auf, wie von dir vorgeschlagen. Also erst vier komplette Überlaufe (~1ms), dann variabel nochmal ca. 4 Überläufe (legen die Servoposition fest) und dann nochmal ca. 70 Überläufe (bzw. weniger, da ich ein "schnelles" signal für meine Regelung brauche.

Willa
06.01.2010, 17:33
Jetzt stehe ich schon wieder auf dem Schlauch.... Entweder, der timer0 eines tiny45 hat einen versteckten prescaler von dem ich nichts weiss, oder ich überfordere den controller total mit meinem timer0 interrupt...
Was ich versuche: Timer0 soll alle 4µs überlaufen. D.h. nach 250 overflows sind 1ms verstrichen, nach 500 overflows sind 2ms verstrichen. Das ist dann die Zeit in der mein Pin auf high geschaltet wird. Danach warte ich nochmal 5000 overflows ab (=20ms), das ist die typische Pause im Servo PWM Signal.
Ich dachte, ich probiere es mal auf diese einfache Art und Weise, aber anscheinend haut da was überhaupt nicht hin. Alle Zeiten scheinen 10mal so lange zu dauern wie geplant. Fuse divideby8 ist aus, interner Oszillator ist auf 8MHz eingestellt und auch so im Code angegeben. Was läuft hier falsch...? Ist 4µs viiiiiiiel zu kurz für den µC?


'Settings
$regfile = "attiny45.dat"
$framesize = 32
$swstack = 32
$hwstack = 64
$crystal = 8000000

Dim Count As Word
Dim Setcount As Word
Dim Servopos As Word
Dim Longpause As Bit
Const Timervorgabe = 224

Config Portb.1 = Output
Portb.1 = 1
Config Timer0 = Timer , Prescale = 1
On Timer0 Timer0isr
Timer0 = Timervorgabe
Enable Interrupts
Enable Timer0

Do
Servopos = 126 'ca. Mittelstellung (werte können zw 0 und 250 sein)
Setcount = Servopos + 250 '==> setcount ist zwischen 250 und 500
Waitms 2000 'einfach mal nichts tun
Loop
End


Timer0isr:
Timer0 = Timervorgabe 'Vorgabe=224 ==> frequenz von 250000Hz oder 1/f = 4µs
Incr Count 'zähle wie oft 4µs verstrichen sind
If Longpause = 0 Then 'longpause ist die pause von ca. 20ms beim servosignal
If Count >= Setcount Then '==> 1 bis 2 ms verstrichen
Count = 0 'wieder bei null anfangen
Portb.1 = 0 'pin auf low setzen
Longpause = 1 '20 ms warten
End If
Else 'longpause=1
If Count >= 5000 Then '==> 20 ms warten
Count = 0 'nach 20 ms wieder bei null anfangen
Longpause = 0 'das flag zurücksetzen
Portb.1 = 1 'pin auf high setzen
End If
End If
Return

Rone
06.01.2010, 18:36
Hallo!

Welche Bascom Version verwendest Du?
Unter Vorbehalt:
Bascom hatte ein Problem mit dem richtigen Initieren der Timer
bei den Tiny 25/45/85

Entweder Timerregister per Hand setzen oder auf 1.11.9.8
updaten.

Hoffe, ich konnte helfen.

MfG
Rone

oberallgeier
06.01.2010, 18:37
Hi Willa,

Du weißt ja, dass ich in Bascom ein absoluter Nobody bin. Aber gerade habe ich einen tiny85 auf dem Breadbord - der im Wesentlichen von seinem Timer "lebt". Du weißt sicher, dass der tiny85 ein Bruder vom t45 ist. Läuft mit 8 MHz+CKDIV8 - also mit 1 MHz vom internen Oszillator. Daraus mache ich mit dem Timer0 einen Takt von 1 ms => 1 kHz. WENN ich den Prescaler (CLK/ 8 ) nicht nehmen würde und WENN ich die fuse CKDIV8 nicht nehmen würde - könnte ich also ohne Änderung auf einen Takt von 64 kHz kommen - 15 µs/Takt bei 8 MHz. Und hätte keinerlei interne Taktprobleme zu erwarten. Mit einem schnelleren (Quarz-)Takt ist entsprechend mehr möglich.

... nach 250 overflows ... nach 500 overflows ... warte ich nochmal 5000 overflows ab (=20ms) ...Dürfte also auch Deinen Ansprüchen genügen.

Obs Dir hilft weiß ich nun nicht, aber ich habe mal Initialisierung und ISR rausgeschippselt - hier ist der code. Wünsch Dir alles Gute:

/* >>
Sicherung 03Jan10 1630 ...C2..\PCR_80\PCR_80_tmr_x31.c
.............
================================================== ============================== */
// ================================================== ==============================


// ================================================== ==============================
// === Initialisierung fuer Timer0 tiny85 bei 1 MHz (IntOsz) =====================
void TC0TMR_init(void) // Init Tmr/Cntr0, ca. 1,00 kHz = 1000µs = 1ms
{ // COM0A1=COM0A0=0 => OC0A disconnected
TCCR0A |= (1<<WGM01); // Timer im CTC-Mode, Top=OCRA doc S 82
TCCR0B |= (1<<CS01); // Prescaler 1/8 / Clock = 1/8 CPU-Takt doc S 83
OCR0A = 122; // Preset/Preload 121 => ca. 1,00 ms @ 1,0Mhz
TIMSK |= (1<<OCIE0A); // Tmr/Cntr0 CompareA interrupt enabled
}
// ================================================== ==============================


// ================================================== ==============================
// === Nicht unterbrechbare ISR für timer0 =======================================
// zählt hoch mit 1 kHz/1,0 ms. Zählerwert (=Zeitwert) wird für Zeitmessung benutzt
ISR(TIM0_COMPA_vect) // Vektor 11 (0 ... 2 !!!) doc S 50
{
//### Izeit_0 = Zähler für Zeithorizont hochzählen. Izthrznt wird im main definiert
// durch die erforderliche Interruptzahl für EINE Sekunde
// Durch Izhrznt kann eine Feinjustage der "BoardUhr" erreicht werden

Izeit_0 ++; // Mit 1 kHz hochzählen
if (Izeit_0 >= Izthrznt) // Interrupt-Timer = "Zeithorizont" begrenzen auf
// Izthrznt = Zeit für EINE Sekunde
{ // Izeit_0 gleich oder größer als Izthrznt ==>
Izeit_0 = 0; // ...Sekundenzähler zurückstellen auf Null
// ..... Hier folgen noch weitere Zeitvariablen (sec, min, etc).
}
return;
}
// ================================================== ==============================


// ================================================== ==============================
// ===== ENDE Subroutinen ================================================== ==
// ================================================== ==============================

Anmerkung:

volatile uint16_t Izthrznt; // Der zeitliche Horizont, z.B. 1000 für 1 sec
// Möglich wäre 60 000 <=> 1 min
volatile uint16_t Izeit_0; // Timertakt in timer0 <=> siehe dort

Izthrznt = 996; // Zeithorizont Timer0/1MHz / 1,00 ms => ergibt EINE Sekunde
// Abweichung im Test: 600 sec = 599,86 sec real
// bzw. 600,00 sec +/- 0,5 sec

Besserwessi
06.01.2010, 18:50
Mit einem Interrupt alle 4 µs oder 32 Zyklen wird das in BASCOM nicht so ohneweiteres gehen. Wenn der Interrupt nicht viel zu tun hat, könnte es in ASM gehen, aber auch dann ist der µC fast nur in der ISR.

Der Tiny45 hat auch für timer0 einen Prescaler ( /8 , /64, /256, /1024), im Datenblatt unter (13.3.1).

Edit:
Das erweitern der Timerauflösung sollte man anders machen. Meine Idee dazu:
Die Zeit setzt sich zusammen aus einer kurzen Zeit bis zum ersten Überlauf, und dann einer Zahl weiterer Überläufe. In der Overflow ISR wird ein Zähler runtergezählt, und wenn man 0 erreicht hat ist das Ende der Zeit erreicht.
Die Ungenauigkeit kommt so nur durch die Interruts Latenz (im Idealfall bis 3 oder 4 Zykeln). Und man hat nur einen Interrupt alle 256 Zyklen oder ggf. noch etwas seltener mit einem Vorteiler von 2...8.

Willa
07.01.2010, 14:16
Hi! Danke für eure Tipps! ich glaube 4 µs ist aber tatsächlich etwas knapp... Habe versucht die Zeit mit meiner mechanischen Eieruhr zu stoppen, und das hat nicht geklappt :-s :^o
Jetzt bin ich wieder bei der Methode die ich ursprünglich machen wollte und die auch Besserwessi vorschlägt. Auf einem Mega32 mit 16MHz und dem 8bit timer hat es jetzt auch endlich geklappt. Das Oszi zeigt ein sehr sauberes Signal mit genau der Länge und der Pause die ich einstelle.


$regfile = "m32def.dat"
$framesize = 32
$swstack = 32
$hwstack = 64
$crystal = 16000000
$baud = 38400

Config Pinb.1 = Output 'servo output
Config Pina.0 = Output 'statusLED

Config Timer0 = Timer , Prescale = 8
On Timer0 T0isr

Dim I As Byte
Dim Pulse As Single
Dim Pulsetemp As Single
Dim Fullrun As Single
Dim Lastrun As Single
Dim Fullrunfix As Byte
Dim Lastrunfix As Byte
Dim Currun As Byte
Dim Pause As Byte

Enable Timer0
Enable Interrupts

Do
Pulse = 1.5 'in ms
'_______________
'1 increment des timer0 dauert 16M / 8 = 0.0005 ms (=2000 milliHz)
'1 ms pulse benötigt daher 1*2000 increments
'2 ms pulse benötigt 2*2000 increments
Fullrun = Pulse * 2000
Shift Fullrun , Right , 8
Lastrun = Frac(fullrun)
Shift Lastrun , Left , 8
Lastrun = 256 - Lastrun
Lastrunfix = Round(lastrun)
Fullrunfix = Int(fullrun)
'________________

Waitms 333 'nichts tun


Loop

End

T0isr:
If Pause = 0 Then
If Currun < Fullrunfix Then
If Portb.1 = 0 Then
Portb.1 = 1
End If
Incr Currun
End If
If Currun = Fullrunfix Then 'wird direkt nach dem voherigen aufgerufen...
Timer0 = Lastrunfix
Incr Currun
Elseif Currun > Fullrunfix Then
Currun = 0
Pause = 1
Portb.1 = 0
End If
Else 'pause=1
'20ms pause sind ca 150 volle überläufe
If Pause < 150 Then ' 75~10ms 37~5ms
Incr Pause 'pause +1.5ms = frequenz
Else
Pause = 0
End If
End If

Return

Um diesen Code auf meinen tiny zu übertragen muss ich eigentlich nur den Wert 2000 durch eine 1000 ersetzen. Das werde ich heute abend mal ausprobieren.

Willa
07.01.2010, 16:36
Okay, der code funktioniert auf nem tiny45. Leider funktioniert aber der Code für den I²C Slave nicht... Dieser wurde mal für nen Mega8 geschrieben, auf nem Tiny45 bekomme ich eine Fehlermeldung beim kompilieren...:

$regfile = "attiny45.dat"
$framesize = 16
$swstack = 16
$hwstack = 32
$crystal = 8000000

'TWI
'====

Declare Sub Twi_init_slave
Dim Twi_control As Byte
Dim Twi_status As Byte
Dim Command As Byte
Dim Einwert As Byte
Dim Newbyte As Byte


Enable Interrupts


'Init
'=====
Command = 0

Call Twi_init_slave

'-------------------------------------------------------------------------------
'***| Hauptprogramm |************************************************* **********
'-------------------------------------------------------------------------------
Do
Newbyte = 0

'schauen ob TWINT gesetzt ist
Twi_control = Twcr And &H80 ' Bit7 von Controlregister
If Twi_control = &H80 Then
Twi_status = Twsr And &HF8 ' Status
'wurde ein Byte geschickt?
If Twi_status = &H80 Or Twi_status = &H88 Then
Command = Twdr ' neue Daten merken
Newbyte = 1 ' merken das ein neues Byte da ist
End If
'TWINT muss immer gelöscht werden, damit es auf dem Bus weiter geht
Twcr = &B11000100 ' TWINT löschen, erzeugt ACK
End If

'wenn ein neues Byte gekommen ist verarbeiten
If Newbyte <> 0 Then

'Register zuordnen -> Befehl
Einwert = Command
End If
Loop
End

'-------------------------------------------------------------------------------
'***| TWI: Slavekonfiguration |*************************************************
'-------------------------------------------------------------------------------

Sub Twi_init_slave
Twsr = 0 ' status und Prescaler auf 0
Twdr = &HFF ' default
Twar = &H22 ' Slaveadresse setzen I2C-RX-Adr:Hex22
Twcr = &B01000100 ' TWI aktivieren, ACK einschalten
End Sub

bei dieser Zeile
Twi_control = Twcr And &H80
kommt die Beschwerde
Source variable does not match target variable [__BTMPA = TWCR]
und bei dieser
Twi_status = Twsr And &HF8
kommt
Source variable does not match target variable [__BTMPA = TWSR]
Was läuft hier falsch...? Funktioniert der I2C Code gar nicht mit nem tiny45...?

Besserwessi
07.01.2010, 17:01
Es ist besser bei der Pause mit dem angebrochen Zyklus anzufangen. Sonst hat man bei einem kleinen Rest Probleme mit der Laufzeit der ISR. Eine ganz kurze Verzögerung von unter etwa 40 Zyklen kann man mit der ISR nicht erreichen, so lange braucht etwa die ISR selber. Den verkürzeten teil am Anfang: dann wird ggf. der aufruf der 2 ten ISR etwas verzögert, was aber noch nicht weiter stört. Hauptsage die letzte ISR wird schnell aufgerufen.


Der Tiny44 hat kein extra TWI interface, sondern eine USI.

Willa
07.01.2010, 17:25
Der Tiny44 hat kein extra TWI interface, sondern eine USI.
och mensch, langsam macht das kein Spaß mehr... Von einem Problem direkt zum nächsten... Habe Google befragt aber nichts brauchbares zu Bascom & I2C & Tiny45 gefunden.
Es gibt zwar hier (https://www.roboternetz.de/phpBB2/viewtopic.php?t=25058) einen Thread der evtl. das behandelt was ich suche, aber ich verstehe nicht genug davon. Mir fehlt jetzt echt die Motivation da weiter dran zu arbeiten. Den I2C -> PWM Adapter den ich versuche zu bauen brauche ich selber überhaupt nicht. Der ist nur für die Leute gedacht die meinen Copter nachbauen und dabei Geld für teure I2C Regler sparen wollen. Vielleicht versuche ich es nochmal mit einem Mega8, evtl. bekomme ich ja dort PWM und I2C gleichzeitig hin.

Besserwessi
07.01.2010, 17:42
Im Wiki Bereich steht etwas zu I2C mit der USI unter BASCOM. Das Beispiel ist da zwiar für den 2313, aber da kein Unterschiede zum Tiny45 sein.

Mit einen Mega8 oder alternativ Mega48 wäre es einfacher, denn man hat einen 16 Bit timer, und 2 Servosignale kann man da direkt über Hardware PWM erzeugen.

Willa
10.01.2010, 13:15
Hi,
ich habe es nun mit einem mega8 hinbekommen. Auf dem Steckbrett funktioniert die Schaltung und die i2c/ pwm Konvertierung. Jetzt habe ich noch eine kurze, kleine Frage...:
Mit Lötjumpern kann ich später die Refreshrate und die i2c Adresse einstellen ohne das Programm zu verändern. Dazu werden Pins des Megas mit GND verbunden und am Anfang des Programms wird der Pin status abgefragt. Aus Layoutgründen würde ich gerne einen Pin nicht auf GND sondern auf +5V ziehen. Geht das überhaupt...? Mir scheint dass es nicht geht...
So ist die Einstellung für die Pins die auf GND gezogen werden:

Config Pinc.0 = Input 'rate_bit1
Portc.0 = 1
If Pinc.0 = 0 Then ...


Für +5V dachte ich an folgendes

Config Pinc.1 = Input 'rate_bit2
Portc.1 = 0
If Pinc.0 = 1 Then ...


Aber das geht nicht... Hätte es aber für logisch gealten wenn es gehen würde... :-D

Besserwessi
10.01.2010, 14:07
Mit schalten nach GND geht, da hat man interne Pullups. Für Schalter gegen +5V geht es nicht, denn da Fehlen Pulldownwiderstände.

Wenn es sein muß fürs Layput, ggf. einen PIN auf low setzen und als hilftweise GND Pin nutzen, wenn man genug Pins frei hat.

Willa
10.01.2010, 14:23
Du hast aber auch immer schlaue Einfälle..... Funktioniert, vielen Dank!

Willa
24.01.2010, 13:44
Hallo,
ich habe schon wieder eine Frage, diesmal eine prinzipielle....:
Ein Modellbauregler wird mit einem PWM Signal versorgt. Normalerweise ist dieses Signal 1 bis 2 ms high (gibt die Sollgeschwindigkeit vor) und danach ca. 20 ms low.
Viele Regler benötigen die 20ms lange Pause nicht. Mein billig-Chinaregler hier funktioniert sogar noch bei einer Pause von nur 1ms einwandfrei.
Die allermeisten Modellbauregler basieren auf einem Mega8 als Prozessor. Wie wird dieser µC wohl die Länge des High-Signals messen? Misst er die Zeit von steigender zu fallender Flanke? Anders geht es wohl nicht.
Jetzt zu meiner Frage:
Mein PWM Signal ist also 1-2 ms high, danach immer 1ms low. Ist das so optimal, oder wäre es besser, wenn die Pause nicht fix ist, sondern von der Länge des vorhergehenden High-Pegels abhängt?
So wie ich es jetzt habe, ist die Stellfrequenz nicht konstant, sondern sie hängt vom Sollwert ab. Je höher dieser ist, desto geringer ist die Stellfrequenz (2+1ms ist länger als 1+1ms). Mache ich mir am Ende Gedanken um etwas, was den Mega8 im Regler überhaupt nicht interessiert? Hat jemand eine Idee dazu (auch philosophische Gedanken helfen)?

Besserwessi
25.01.2010, 21:11
Die Wiederhohlfrequenz für das PWM Signal sollte nicht so kritisch sein. So schnell, d.h. auf 2-3 ms Basis, kann der Motor ohnehin kaum reagieren. Der µC im Regler wird vermutlich jeden Puls vermessen und so dann halt ggf. den Sollwert für die Geschwindigkeit etwas häufiger aktualisieren. Etwas weniger als die sonst üblichen 20 ms könnten schon sinnvoll sein. Eventuell wird dadurch die Implementierung ja sogar einfacher.

Willa
25.01.2010, 21:30
Die Wiederhohlfrequenz für das PWM Signal sollte nicht so kritisch sein. So schnell, d.h. auf 2-3 ms Basis, kann der Motor ohnehin kaum reagieren.
Hallo Besserwessi. Dieses Argument höre ich relativ oft wenn begründet werden soll warum so schnelles PWM nichts bringt. Ich finde aber dieses Argument ist so nicht korrekt. Ich möchte dir gerne mal meine Gedanken aufschreiben, dann kannst du diese vielleicht widerlegen...:
Angenommen ein Motor braucht immer 80ms (aufgrund von Massenträgheit, Wagner Effekt etc.) um einen neuen Sollwert in aerodyn. Kraft umzusetzen.
Gedankenexperiment (alles vereinfacht und abstrahiert):
Irgendein Sensor misst mit unendlich hoher Frequenz den Ist-Zustand und errechnet gleichzeitig den neuen Sollwert. Dieser Sollwert wird sofort rausgeschickt. Dann braucht das System von der "Störung" bis zur Kompensation der Störung genau 80 ms.
Zweite Version: Gleicher Zustand wie oben, aber der neue Sollwert wird nur alle 20 ms rausgeschickt. Fangen wir auf einer Zeitskala bei 0ms an: Bei 0ms ist alles in Ordnung, Ist- und Sollwert stimmen überein. An den Motor wird ein Sollwert geschickt der nicht vom vorherigen abweicht. Bei 1ms wird aber plötzlich eine Störung gemessen. Es wird aber erst 20ms später wieder ein neuer Sollwert an den Motor geschickt. Daher dauert es in diesem Fall nun 80ms + 20 ms bis der Motor die aerodyn. Kraft erzeugt hat.
Meiner Meinung nach führt man mit einer niedrigen PWM Frequenz eine Art Totzeit ein in der der Sensor quasi hilflos ist, denn er darf keinen neuen Wert an den Motor rausschicken obwohl es nötig wäre.
Ich bin leider ganz und gar kein Regelungstechniker, deswegen sind meine Annahmen vielleicht etwas naiv. Aber ich finde das so wie ich es erklärt habe intuitiv richtig.....

Besserwessi
25.01.2010, 21:37
So etwa sehe ich das auch. Wenn der Motor die Oben genannten 80 ms braucht, hat man im System ein Totzeit von halt 80 ms plus die Periodendauer vom PWM. Da würden 20 ms schon etwas stören, bei 1-2 ms extra Totzeit hält sich der Verlust an Geschwindigkeit aber in Grenzen.