Hallo,
ein weiteres Machwerk auf dem Weg zum Servotester mit Pulsweitenanzeige. Noch nicht ganz ausgereift und die Auflösung ist noch verbesserungswürdig. Aber damit hab ich hoffentlich schon ein paar Hürden zum Verstehen des ATtiny45 überwunden.
Mit dem CONFIG SERVO Befehl des BASCOM-AVR kam ich überhaupt nicht klar. Nach meinen Erfahrungen zu ungenau, abhängig von $CRYSTAL und sobald ISR laufen, nicht mehr kalkulierbar.
Deshalb den Timer1 "per Hand" für PWM konfiguriert. Da der Servo ein Impuls alle 20ms braucht, der zwischen 1 bis 2 ms lang sein soll und dieser Impuls auch noch möglichst fein einstellbar sein soll und auch noch sehr konstant sein muß, hab ich folgende Lösung versucht:
Kleinste Auflösung für Servopulseinstellung=16µs. Da man bei dem 8bit Timer damit nicht auf die 20ms Pulsabstand kommt - den Timer dann alle 5 Mal mit der Pulsweite als "Monoflop" Interrupt gesteuert auf den Ausgang wirken lassen - funktioniert.
Pulsweite einstellbar mit 10k Poti am ADC.
Code:'################################################### 'File: Servotester mit Display.bas 'IDE: BASCOM-AVR Version 1.11.9.8 'HW circuit: ATtiny45_4_X_7_Segment_SPI (ADC- & Servoanschluß nicht eingezeichnet) 'Multiplexing und Servosignal via Timer1 'Servo an PB4. 10k Poti für Servopulseinstellung an PB3 '4 x 7 Segment zeigt Servopuls in ms an. Bereich 0,720ms bis 2,304ms in 16µs steps '####################################################### $regfile = "attiny45.dat" $eepleave $framesize = 32 $swstack = 32 $hwstack = 96 'hwstack reichlich wg Interruptroutine $crystal = 8000000 Dim X As Byte Dim Y As Byte Dim Z As Byte Dim Init7segment As Byte Dim Displaydigitaddress(4) As Word Dim Displaydigit(17) As Byte 'darzustellende Zeichen (hex 0..F) '0gfedcba (segmente, msb immer 0) Displaydigit(1) = &B01000000 'Ziffer "0", 0 = segment ein, 1 = aus Displaydigit(2) = &B01111001 'Ziffer "1" Displaydigit(3) = &B00100100 'Ziffer "2" Displaydigit(4) = &B00110000 Displaydigit(5) = &B00011001 Displaydigit(6) = &B00010010 Displaydigit(7) = &B00000010 Displaydigit(8) = &B01111000 Displaydigit(9) = &B00000000 Displaydigit(10) = &B00010000 Displaydigit(11) = &B00001000 Displaydigit(12) = &B00000011 Displaydigit(13) = &B01000110 Displaydigit(14) = &B00100001 Displaydigit(15) = &B00000110 Displaydigit(16) = &B00001110 Displaydigit(17) = &B01111111 'Wert um eine Ziffer dunkel zu schalten Displaydigitaddress(1) = 16 'Wenn noch keine Ziffer eingegeben -> dunkel Displaydigitaddress(2) = 16 Displaydigitaddress(3) = 16 Displaydigitaddress(4) = 16 X = 0 'Initialisierung von Zählvariablen Y = 0 'Initialisierung von Zählvariablen Z = 0 'Initialisierung von Zählvariablen 'Nutzung von Software SPI - nur Output Config Spi = Soft , Dout = Portb.0 , Ss = Portb.1 , Clock = Portb.2 Spiinit 'mit Senden von acht high bits sicherstellen, daß über Q7 des Schieberegisters 'der HEF4017 erste Ziffer der 4 X 7 Segmentanzeige adressiert -> reset des 4017 Init7segment = &B11111111 Spiout Init7segment , 1 Config Portb.4 = Output 'PB4 as output Gtccr = Gtccr Or &B01100000 'set PWM1B & OC1B (PB4) to clear on compare Ocr1b = 94 'set pulse to 1504µs (on 8Mhz, prescaler = 128) Ocr1c = 254 'set min pwm frequency (8Mhz / 128 / 255 =~ 245 Hz Tccr1 = Tccr1 Or &B00001000 'set prescaler (128) switches timer on On Ovf1 Isr_timer1 Enable Timer1 Config Adc = Single , Prescaler = Auto , Reference = Avcc Dim Comparematchvalue_ocr1b As Byte Dim Adc_readout As Integer Dim Adc_str As String * 5 Dim Char As String * 1 Dim Channel As Byte Channel = 3 'ADC3 (auf Pin PB3) Enable Interrupts Do Adc_readout = Getadc(channel) If Adc_readout < 10 Then Adc_readout = 10 Elseif Adc_readout > 1000 Then Adc_readout = 1000 End If Adc_readout = Adc_readout / 10 Adc_readout = Adc_readout + 43 Comparematchvalue_ocr1b = Adc_readout Adc_readout = Adc_readout * 16 Adc_readout = Adc_readout + 10016 Adc_str = Str(adc_readout) Char = Mid(adc_str , 2 , 1) Displaydigitaddress(1) = Val(char) Char = Mid(adc_str , 3 , 1) Displaydigitaddress(2) = Val(char) Char = Mid(adc_str , 4 , 1) Displaydigitaddress(3) = Val(char) Char = Mid(adc_str , 5 , 1) Displaydigitaddress(4) = Val(char) Loop End Isr_timer1: X = X And &B00000011 X = X + 1 Y = Displaydigitaddress(x) + 1 Spiout Displaydigit(y) , 1 If Z >= 4 Then Ocr1b = CompareMatchValue_OCR1B Bitwait Pinb.4 , Set Bitwait Pinb.4 , Reset Ocr1b = 0 Z = 0 Else Z = Z + 1 End If Return
Praxistest mit echtem Servo steht noch aus (nur mit Oszi und 10k Pulldown probiert)
Anzeige flimmert leicht - warum auch immer - mal sehen...
EDIT: wg. Flimmern siehe verbessertes Listing im Beitrag vom 12.02.2011 weiter hinten im thread
Fazit - ich glaub ich hab den "nicht phasen korrekten PWM Timer" verstanden
Bitte um Aufzeigen möglicher Probleme, Kommentare, Fragen, etc. willkommen.
(hab mir vorgenommen, den Code demnächst noch ein bißchen besser zu kommentieren)
Gruß
Searcher






Hoffentlich liegt das Ziel auch am Weg
Zitieren
Die Experimente sind jedoch sehr aufschlußreich.

Lesezeichen