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
Lesezeichen