Forum: Mikrocontroller und Digitale Elektronik Atmega88 Servo mit Poti steuern


von Christian (Gast)


Lesenswert?

Hallo zusammen,

ich hab mal wieder ne Frage.
Ich möchte einen Servomotor über ein Poti an meinem Atmega88 steuern.
Momentan habe ich ein Programm geschrieben, das über den Ausgang OC1A 
den Servomotor vom Linksanschlag zum Rechtsanschlag und zurück fahren 
lässt. Der Servo wird mit einem 50Hz Signal angesteuert. Jetzt wollte 
ich den Ausgang OC1A so lassen und den OC1B so programmieren, dass er 
ich den Motor über ein Poti steuern kann.
Nur leider bewegt sich der Servo nicht, wenn ich ihn an den OC1B Ausgang 
anschließe. Ich weis aber nicht warum.
Mein Atmega88 läuft mit 8MHz und der Timer1 wird mit 8fach Prescaler 
betrieben.
Der Wert ADC_C0 ist eine 16Bit Variable in der der Wert vom ADC 
gespeichert wird. Der ADC teil funktioniert, und der Wert wird mir auch 
auf einem LCD ausgegeben.

Hier mein Code:
1
int main(){
2
3
DDRB |= 1<<PINB1 | 1<<PINB2;
4
5
  TCCR1A |= 1<<WGM11 | 1<<COM1A1 | 1<<COM1A0 | 1<<COM1B0 | 1<<COM1B1;
6
  TCCR1B |= 1<<WGM12 | 1<<WGM13 | 1<<CS11;
7
  ICR1 = 19999;
8
9
10
while(1){
11
  OCR1A = ICR1 - 1000;
12
  OCR1B = ICR1 - (850 + (ADC_C0 * 1,26));
13
  _delay_ms(500);
14
  OCR1A = ICR1 -2000;
15
  OCR1B = ICR1 - (850 + (ADC_C0 * 1,26));
16
  _delay_ms(500);
17
}
18
19
}

von MWS (Gast)


Lesenswert?

Sollte da für die Floatkonstante statt dem Komma nicht ein Punkt rein 
gehören? Außerdem, bei einer Integermultiplikation mit einer 
Floatkonstante wird nur der Vorkommateil der Konstante berücksichtigt. 
Gab's da keine Warnungen?

von Christian (Gast)


Lesenswert?

Erstmal danke für die schnelle Antwort.
Das Atmelstudio 6 hat keine Fehlermeldung gebracht.
Dann müsste es doch funktionieren, wenn ich den Code so schreibe
1
OCR1B = ICR1 - (850 + ADC_C0);

von MWS (Gast)


Lesenswert?

Wie wird ADC gesampelt?

von Christian (Gast)


Lesenswert?

1
uint16_t ADC_C0;
2
3
4
5
6
ADMUX &= ~(1<<MUX0);
7
  ADCSRA |= (1<<ADSC);
8
  while (ADCSRA & (1<<ADSC)){}
9
    ADCL_C0 = ADCL;
10
    ADCH_C0 = ADCH;
11
  
12
  ADMUX |= (1<<MUX0);
13
  ADCSRA |= (1<<ADSC);
14
  while (ADCSRA & (1<<ADSC)){}
15
    ADCL_C1 = ADCL;
16
    ADCH_C1 = ADCH;
17
  
18
  ADC_C0 = ADCL_C0 + (ADCH_C0 * 256);
19
  ADC_C1 = ADCL_C1 + (ADCH_C1 * 256);

von Christian (Gast)


Lesenswert?

Ich habe mal ausprobiert mit einen normalen C++ compiler eine Berechnung 
mit einer int Variable zu machen. Es hat funktioniert. Allerdings nur 
wenn der Multiplikator so geschrieben wird 1.26 und nicht 1,26. Also 
müsste es so auch funktionieren.
1
OCR1B = ICR1 - (850 + (ADC_C0 * 1.26));

von MWS (Gast)


Lesenswert?

Ja, die Routine sieht brauchbar aus, aber wo rufst Du die in der >while< 
s.o. auf?

von Christian (Gast)


Lesenswert?

Hier mal der ganze Code:
1
#define F_CPU 8000000
2
3
4
#include <avr/io.h>
5
#include <util/delay.h>
6
#include <lcd-routines.h>
7
#include <lcd-routines.c>
8
#include <stdint.h>
9
10
11
12
13
uint16_t ADC_C0;
14
uint16_t ADC_C1;
15
uint8_t ADCL_C0;
16
uint8_t ADCH_C0;
17
uint8_t ADCL_C1;
18
uint8_t ADCH_C1;
19
char ADC_StringC0 [16];
20
char ADC_StringC1 [16];
21
22
23
24
void ADC_Init (void)
25
{
26
  
27
  ADMUX |= (1<<REFS0);
28
  ADCSRA |= (1<<ADPS2) | (1<<ADPS1) | (1<<ADEN) | (1<<ADSC);
29
  
30
  while (ADCSRA & (1<<ADSC));
31
  ADCL_C0 = ADCL;
32
  ADCH_C0 = ADCH;
33
  
34
}
35
36
37
void ADC_Read (void)
38
{
39
  
40
  ADMUX &= ~(1<<MUX0);
41
  ADCSRA |= (1<<ADSC);
42
  while (ADCSRA & (1<<ADSC)){}
43
    ADCL_C0 = ADCL;
44
    ADCH_C0 = ADCH;
45
  
46
  ADMUX |= (1<<MUX0);
47
  ADCSRA |= (1<<ADSC);
48
  while (ADCSRA & (1<<ADSC)){}
49
    ADCL_C1 = ADCL;
50
    ADCH_C1 = ADCH;
51
  
52
  ADC_C0 = ADCL_C0 + (ADCH_C0 * 256);
53
  ADC_C1 = ADCL_C1 + (ADCH_C1 * 256);
54
  
55
}
56
57
58
59
void LCD_Write (void)
60
{
61
  lcd_clear();
62
  
63
  itoa (ADC_C0, ADC_StringC0, 10);
64
  itoa (ADC_C1, ADC_StringC1, 10);
65
  
66
  lcd_setcursor(0,1);
67
  lcd_string("ADC0      ADC1");
68
  lcd_setcursor(0,2);
69
  lcd_string(ADC_StringC0);
70
  lcd_setcursor(9,2);
71
  lcd_string(ADC_StringC1);
72
  
73
  
74
  
75
  
76
}
77
78
79
void AVR_init (void)
80
{
81
  DDRC |= 1<<PINC4 | 1<<PINC5;
82
  PORTC |= 1<<PINC2 | 1<<PINC3;
83
  DDRB |= 1<<PINB1 | 1<<PINB2;
84
  
85
}
86
87
88
void PWM_init (void)
89
{
90
91
  TCCR1A |= 1<<WGM11 | 1<<COM1A1 | 1<<COM1A0 | 1<<COM1B0 | 1<<COM1B1;
92
  TCCR1B |= 1<<WGM12 | 1<<WGM13 | 1<<CS11;
93
  ICR1 = 19999;
94
  
95
  
96
}
97
98
99
void PWM_Funktion (void)
100
{
101
  OCR1A = ICR1 - 1000;
102
  OCR1B = ICR1 - (850 + (ADC_C0 * 1.26));
103
  _delay_ms(500);
104
  OCR1A = ICR1 -2000;
105
  OCR1B = ICR1 - (850 + (ADC_C0 * 1.26));
106
  _delay_ms(500);
107
  
108
  
109
}
110
111
112
int main(void)
113
{  
114
  AVR_init();
115
  ADC_Init();
116
  lcd_init();
117
  PWM_init();
118
   
119
  
120
  
121
  
122
    while(1)
123
    {
124
        ADC_Read();
125
    LCD_Write();
126
    PWM_Funktion();
127
    
128
      
129
    
130
    
131
    }
132
}

von MWS (Gast)


Lesenswert?

Christian schrieb:
> Ich habe mal ausprobiert mit einen normalen C++ compiler eine
> Berechnung
> mit einer int Variable zu machen. Es hat funktioniert. Allerdings nur
> wenn der Multiplikator so geschrieben wird 1.26 und nicht 1,26. Also
> müsste es so auch funktionieren.
> OCR1B = ICR1 - (850 + (ADC_C0 * 1.26));

Beim AVR GCC ist der Default für die Berechnung ein Integer, damit wird 
sich das so verhalten, wie von mir oben beschrieben.

Im AVR-Studio kannst Du Deinen Code auch simulieren und die Variablen 
untersuchen, stell dafür auf keine Optimierung, -O0.

von Magnus M. (magnetus) Benutzerseite


Lesenswert?

Nimms mir bitte nicht übel, aber hast du schon mal was von kommentiertem 
Code gehört?

: Bearbeitet durch User
von Christian (Gast)


Lesenswert?

Wie ganau mache ich das?

von MWS (Gast)


Lesenswert?

Ich gehe davon aus, dass Du OCR1B genauso wie ..A getestet hast, lass 
doch mal die Floatkonstante völlig weg, Du müsstest trotzdem irgendeine 
Reaktion bekommen.

von Christian (Gast)


Lesenswert?

Normalerweise kommentiere ich den Code, aber das ist eigentlich nur ein 
Testprogramm, daher habe ich die Kommis weggelassen.

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
Noch kein Account? Hier anmelden.