PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : 1 Servo mit 2 Tasten ansteuer, aber wie :-(



SimLock
07.11.2007, 19:27
Hi @ll,

Newbie braucht wieder hilfe ](*,)
Meine Überlegung ist folgende:

2 Taster, 1 Servo.
Taster 1 drehe Servo nach rechts solange taster gedrückt ist. Bei Max Servo Stop (nicht weiter nach rechts drehen!).

Das gleiche umgekehrt mit Taster 2 Servo drehe links bis min. Bei min.
Servo Stop (nicht weiter nach links drehen!).

Hab schon mal folgendem Code programmiert:



int main (void){

DDRD |= (1<<PD5); /* Pin D5 als Ausgang für Servo */


//*** Taster ***

DDRD &= ~ (1<<PD2); /* Pin D2 als Eingang */
PORTD |= (1<<PD2); /* Pull Up von PIN D2 aktivieren */
DDRD &= ~ (1<<PD3); /* Pin D3 als Eingang */
PORTD |= (1<<PD3); /* Pull Up von PIN D3 aktivieren */


while(1)
{
if (!( PIND & (1<<PIND2))) /* mache was wenn PinD2 low ist */
{
/* PWM +1 drehe nach rechts bis max, wenn max dann Servo stop */

}
else {
/* Servo Stop */

}

if (!( PIND & (1<<PIND3))) /* mache was wenn PinD3 low ist */
{
/* PWM -1 drehe nach links bis min, wenn min dann Servo stop */

}
else {
/* Servo Stop */

}

}
return 0;

}

wie binde ich da den PWM ein?
Habe schon stunde lang in Forum durchgeschaut und verstehe die codierung von PWM nicht. Wäre nett, wenn mir eine dabei helfen könnte!!!


Danke

P.s benutze ein atmega8

Zimble
08.11.2007, 10:38
Bist du dir sicher, dass du richtig geschaut hast? Die Frage wird hier fast täglich gestellt und auf verschiedenste Art und Weise beantwortet.

Im Grunde läuft es so:

PWM-Modus aussuchen (8,9,10Bit)
bei z.B. 8Bit: 2 x 2^8 = 512 -> passenden Prescaler wählen, damit die 512 Ticks/Increments in 20ms abgearbeitet werden
ins OCR Register Wert schreiben, so dass OCR/2 * ZeitProTick= 1 bis 2 ms


Wenn nun jemand einen Taster drückst, inkrementierst/dekrementierst du einfach den Wert in OCR und somit die "High-Zeit" deines PWM-Signals.


// initalize mega8 Timer1 with 9Bit, inverted, Prescaler 256
// this gives us a signal with 21.76ms at 12MHz
TCCR1A |= (1<<WGM11)|(1<<COM1A1)|(1<<COM1A0);
TCCR1B = (1<<CS12);

OCR1A = 476; // pulse of 1.5ms 512- 1500*(F_CPU/256/1000000)/2


Steht eigtl. alles hier: http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Die_PWM-Betriebsart

SimLock
08.11.2007, 11:16
Hi Zimble,

danke erstmal für deine Hilfe!

Wie schon gesagt, bin in C Newbie :-(

Was ich über PWM gelesen hab ist,

brauche eine Periodendauer von ca. 20 ms
(durch dein Code komme ich drauf), in dieser Zeit kommt dann ein Signal mit der länge:

1ms für links Drehung
oder
1,5ms für Mittelstellung
oder
2ms für rechts Drehung

Diese Signal schicke ich dann auf ein Pin wo mein Servo angeschlossen ist.
Kann ich jeden Pin dafür benutzten oder?

Wie inkrementierst/dekrementierst OCR?

Danke

Hubert.G
08.11.2007, 12:26
PWM-Ausgänge sind OC1A und OC1B.
Increment / decrement geht OCR1A++; oder OCR1A--; du musst dann einen min. / max. Wert vorgeben damit das Servo auch stehen bleibt. Du kannst auch gleich den Endwert eingeben.

SimLock
08.11.2007, 13:19
Kann ich PWM nicht über Software programieren?
Denn ich will 2 Servos steuern und auch noch 2 Getriebemotoren über L293D. Und dafür brauche ich ja 4 PWM oder nicht?

Hubert.G
08.11.2007, 16:55
Ja, kannst du, ich würde dann die Servos über Timer1 machen und die Motoren über die SW-PWM.

SimLock
08.11.2007, 21:29
Über Timer1, ist dass das Beispiel von Zimble mit OC1A und OC1B?

Hubert.G
08.11.2007, 21:42
Ja, genau das ist es.

SimLock
09.11.2007, 05:57
Ok,

also könnte das alle so aussehen, wenn ich nur Taster1 betätige dreht sich der Servo nach rechts (2ms) auf eine bestimte Position und danach geht der Server wieder in die Mittelstellung???




#include <avr/io.h>

// Timer1 initialisieren

void timer1_init(void)
{
TCCR1A |= (1<<WGM11)|(1<<COM1A1)|(1<<COM1A0); // initalize mega8 Timer1 with 9Bit, inverted, Prescaler 256
TCCR1B = (1<<CS12); // this gives us a signal with 21.76ms at 12MHz

OCR1A = 476; // pulse of 1.5ms 512- 1500*(F_CPU/256/1000000)/2
// Hier wieder der PWM auf mittelstellung gebracht oder?
}



int main (void){

DDRD |= (1<<PD5); /* Pin D5 als Ausgang für Servo */


//*** Taster ***

DDRD &= ~ (1<<PD2); /* Pin D2 als Eingang */
PORTD |= (1<<PD2); /* Pull Up von PIN D2 aktivieren */


while(1)
{
if (!( PIND & (1<<PIND2))) /* mache was wenn PinD2 low ist */
{
OCR1A =???; /* Servo dreht sich mit 2ms */

}
else {
OCR1A = 476; /* Servo Mittelstellung*/

}


}
return 0;

}
Könnte der Code so aussehen ist das inkrementierst/dekrementierst ?
Was für ein Wert schreibe ich in Zeile:
OCR1A = ???; /* Servo dreht sich mit 2ms */

Zimble
09.11.2007, 16:32
PIN PD5 als Ausgang fürs Servo sollte falsch sein.
Schau noch mal ins Datenblatt von deinem mega8. Die Ausgänge der Hardware-PWM sollten PB1-3 sein. In deinem Fall mit OCR1A also PB1.

Ansonsten sollte der Code soweit eigentlich funktionieren.
Bei mir hat der Servo einen max. Ausschlag bei 720us und bei 2520us.
Wenn du das umrechnest (s. erster codeschnippsel von mir)
kommst du auf OCR1A=495 bis 452.

Ich würde testweise noch ein delay einbauen, sonst dürfte er zu schnell runterzählen.


while(1){
if (!( PIND & (1<<PIND2))) /* mache was wenn PinD2 low ist */
{
if(OCR1A > 452){
OCR1A--; /* Pulsbreite verkürzen */
}
} else {
OCR1A = 476;
}
for(i=0;i<50;i++)
_delay_ms(10);
}

Sollte also so lange der Taster gedrückt ist aller 500ms die Pulsbreite reduzieren und so den Servo bis max in eine Richtung drehen und beim loslassen wieder resetten.

Zum testen sollte es reichen. Evtl. noch Taster entprellen.

oberallgeier
09.11.2007, 16:58
Hi @ll, ... 2 Taster, 1 Servo.
Taster 1 drehe Servo nach rechts solange taster gedrückt ist. Bei Max Servo Stop (nicht weiter nach rechts drehen!). ... Das gleiche umgekehrt mit Taster 2 Servo drehe links bis min.
Hi, SimLock,

also ich hatte das auch mal versucht (aber nicht mega8 und nicht C, sondern tiny13 und Assembler - hatte daher auch bisher nix beigetragen) - und fand das total unpraktisch. Das für mich Praktischste war ein Poti (25k lin) zum ADC und damit den Servo steuern. Dann habe ich Richtung, Anschlag und Drehgeschwindigkeit im Griff. Geht natürlich auch zwei Potis für zwei Servos.

SimLock
09.11.2007, 19:28
Servo dreht sich nicht :-(

musst noch unsigned char i; dazu schreiben, hattest du vergessen oder? <-- Weiß nicht ob die Zeile auch ok ist...
Beim Compilieren ist kein Fehler gewesen.
Servo ist mit gleicher masse verbunden.
Servo steuersignal ist auf PB1
Taster ist auf PD2

Mein aktueller Code:


#include <avr/io.h>
#include <stdbool.h>
#include <stdlib.h>
#include <avr/io.h>
#include <AVR/iom8.h>
#include <inttypes.h>
#include <util/delay.h>

#define F_CPU 12000000 // clock

// Timer1 initialisieren

void timer1_init(void)
{
TCCR1A |= (1<<WGM11)|(1<<COM1A1)|(1<<COM1A0); // initalize mega8 Timer1 with 9Bit, inverted, Prescaler 256
TCCR1B = (1<<CS12); // this gives us a signal with 21.76ms at 12MHz

OCR1A = 476; // pulse of 1.5ms 512- 1500*(F_CPU/256/1000000)/2
// Hier wieder der PWM auf mittelstellung gebracht oder?
}

int main (void)
{

unsigned char i; /* Variable i */

DDRB = ( 1 << PB1 ); /* Pin PB0 als Ausgang für Servo */

DDRD &= ~ (1<<PD2); /* Pin D2 als Eingang */
PORTD |= (1<<PD2); /* Pull Up von PIN D2 aktivieren */


while(1){
if (!( PIND & (1<<PIND2))) /* mache was wenn PinD2 low ist */
{
if(OCR1A > 452){
OCR1A--; /* Pulsbreite verkürzen */
}
} else {
OCR1A = 476;
}
for(i=0;i<50;i++)
_delay_ms(10);
}
}

vajk
09.11.2007, 23:12
... öhm wo in main() rufst DU denn die Funktion timer1_init() auf ?

Oder anders ausgedrückt, eine Funktion INIT() dient als separate Funktion nur der Übersicht und ist Bestandteil von main() bevor dieses sich in eine Endlosschleife begibt ....

Sauber geschrieben sollte das so aussehen - ich hab nur den Code etwas lesbarer gemacht und INIT() plaziert ... ich empfehlen "meine Ebenenstruktur" zu nutzen - also deutlich Einrücken und Leerzeichen zw. Anweisungen plazieren --- Funktional habe ich den Code nicht geprüf!:




#include <avr/io.h>
#include <stdbool.h>
#include <stdlib.h>
#include <avr/io.h>
#include <AVR/iom8.h>
#include <inttypes.h>
#include <util/delay.h>

#define F_CPU 12000000 // clock

// Timer1 initialisieren


void INIT(void)
{
// Portdefinitionen
DDRB = 0 | ( 1 << PB1 ); // Pin PB0 als Ausgang für Servo
DDRD &=~ (1<<PD2); // Pin D2 als Eingang
PORTD = 0 | (1<<PD2); // Pull Up von PIN D2 aktivieren

// timer1
// initalize mega8 Timer1 with 9Bit, inverted, Prescaler 256
TCCR1A |= (1 << WGM11 ) | ( 1 << COM1A1 ) | ( 1 << COM1A0 );
// this gives us a signal with 21.76ms at 12MHz
TCCR1B = (1 << CS12);
// pulse of 1.5ms 512- 1500*(F_CPU/256/1000000)/2
OCR1A = 476;
// Hier wieder der PWM auf mittelstellung gebracht oder? <= wie meinen


}

int main(void)
{
INIT();

unsigned char i; // Variable i [echt :-) ]

for(;;)
{
// mache was wenn PinD2 low ist
if (!( PIND & (1<<PIND2)))
{
if(OCR1A > 452)
{
OCR1A--; //Pulsbreite verkürzen
}
}
else
{
OCR1A = 476;
}
for(i = 0; i < 50; i++)
_delay_ms(10); // bei 16 MHz maximal 16 ms möglich !
}
}

SimLock
10.11.2007, 05:54
Hi,

danke! Aber Funktioniert trotzdem nicht :-(
Bei compilieren bekomme ich keine Fehlermeldung siehe Anhang:

-------- begin --------
avr-gcc (GCC) 4.1.2 (WinAVR 20070525)
Copyright (C) 2006 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.


Size before:
main.elf :
section size addr
.text 196 0
.stab 888 0
.stabstr 113 0
.debug_aranges 32 0
.debug_pubnames 43 0
.debug_info 330 0
.debug_abbrev 233 0
.debug_line 397 0
.debug_frame 48 0
.debug_str 196 0
.debug_loc 70 0
Total 2546




Compiling: main.c
avr-gcc -c -mmcu=atmega8 -I. -gdwarf-2 -Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -Wall -Wstrict-prototypes -Wa,-adhlns=main.lst -std=gnu99 -DF_OSC=12000000 -MD -MP -MF .dep/main.o.d main.c -o main.o

Linking: main.elf
avr-gcc -mmcu=atmega8 -I. -gdwarf-2 -Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -Wall -Wstrict-prototypes -Wa,-adhlns=main.o -std=gnu99 -DF_OSC=12000000 -MD -MP -MF .dep/main.elf.d main.o --output main.elf -Wl,-Map=main.map,--cref -lm

Creating load file for Flash: main.hex
avr-objcopy -O ihex -R .eeprom main.elf main.hex

Creating load file for EEPROM: main.eep
avr-objcopy -j .eeprom --set-section-flags=.eeprom="alloc,load" \
--change-section-lma .eeprom=0 -O ihex main.elf main.eep
c:\WinAVR-20070525\bin\avr-objcopy.exe: there are no sections to be copied!
c:\WinAVR-20070525\bin\avr-objcopy.exe: --change-section-lma .eeprom=0x00000000 never used
make.exe: [main.eep] Error 1 (ignored)

Creating Extended Listing: main.lss
avr-objdump -h -S main.elf > main.lss

Creating Symbol Table: main.sym
avr-nm -n main.elf > main.sym

Size after:
main.elf :
section size addr
.text 180 0
.stab 888 0
.stabstr 113 0
.debug_aranges 32 0
.debug_pubnames 36 0
.debug_info 309 0
.debug_abbrev 209 0
.debug_line 381 0
.debug_frame 48 0
.debug_str 189 0
.debug_loc 70 0
Total 2455



Errors: none
-------- end --------


> Process Exit Code: 0
> Time Taken: 00:04

Servo dreht sich nicht, ich stecke Pin PB1 rein raus... dann etwas
Sonst kann man glaube leicht hören, wie der Servo klick klick macht

Hubert.G
10.11.2007, 14:24
Ich habe das mal auf meinem Testboard probiert, mit dem timer1 init, der ja gefehlt hat, funktioniert das bei mir einwandfrei. Taste gedrückt, Servo läuft nach links, Taste aus, Servo läuft in die Mitte.
Hubert

SimLock
10.11.2007, 18:17
Also mein Servo dreht sich nicht :-( (nur wenn ich + pol rote leitung von servo an + pol "reibe")
Ist meine Mhz auch ok mit 12Mhz?
Wenn ich an PB1 eine LED anschliese blickt die LED. <-- das ist doch schon mal was.
Aber wenn ich Taster drücke, sieht man keine veränderung des blicken (wenn man das überhaubt sehen könnte.

Hubert.G
10.11.2007, 21:46
Dann stimmt mit deinem Servo etwas nicht. Oder du hast immer noch einen falschen Code.

#include <avr/io.h>
#include <stdbool.h>
#include <stdlib.h>
#include <avr/io.h>
#include <AVR/iom8.h>
#include <inttypes.h>
#include <util/delay.h>

#define F_CPU 12000000 // clock

// Timer1 initialisieren

void timer1_init(void)
{
TCCR1A |= (1<<WGM11)|(1<<COM1A1)|(1<<COM1A0); // initalize mega8 Timer1 with 9Bit, inverted, Prescaler 256
TCCR1B = (1<<CS12); // this gives us a signal with 21.76ms at 12MHz

OCR1A = 476; // pulse of 1.5ms 512- 1500*(F_CPU/256/1000000)/2
// Hier wieder der PWM auf mittelstellung gebracht oder?
}

int main (void)
{
timer1_init();
unsigned char i; /* Variable i */

DDRB = ( 1 << PB1 ); /* Pin PB0 als Ausgang für Servo */

DDRD &= (~ (1<<PD2)|(1<<PD3)); /* Pin D2 als Eingang */
PORTD |= (1<<PD2)|(1<<PD3); /* Pull Up von PIN D2 aktivieren */


while(1){
if (!( PIND & (1<<PIND2))) /* mache was wenn PinD2 low ist */
{
if(OCR1A > 452){
OCR1A--; /* Pulsbreite verkürzen */
}
}
if (!( PIND & (1<<PIND3))) /* mache was wenn PinD3 low ist */
{
if(OCR1A < 499){
OCR1A++; /* Pulsbreite verlängern */
}
}

if (( PIND & (1<<PIND2))&&(PIND & (1<<PIND3))) { /* Mitte wenn keine Taste */
OCR1A = 476;
}
for(i=0;i<50;i++)
_delay_ms(10);
}
}

Probiers mal damit, eine Taste für links- eine für rechstlauf.

SimLock
12.11.2007, 06:30
Hallo,

Danke erstmal für deinen Code!!!
Aber leider dreht sich bei mir kein Servo. Ich habe schon 4 verschiedene Servos angeschlossen!
Hier mal ein paar angaben zu meine Servos und Aufbau:


Servotyp: Standartservo von Conrad Carson 13375

http://images.google.com/imgres?imgurl=http://www.a1-modellbau.de/media/13375.jpg&imgrefurl=http://www.a1-modellbau.de/de/dept_428.html&h=200&w=267&sz=9&hl=de&start=1&um=1&tbnid=F7jGpGUlHBCpKM:&tbnh=85&tbnw=113&prev=/images%3Fq%3DCarson%2B13375%26svnum%3D10%26um%3D1% 26hl%3Dde%26rls%3Dcom.microsoft:en-US%26sa%3DN

Bord ist von MYAVR:

http://www.myavr.de/shop/article.php?artDataID=4 + Atmega8 µC

Angeschlossen:

Wie man in Link sehen kann, sieht man an Board, das dort unten die Steckleisten von PortD-B-C. Auf PortD 2 und 3 sind 2 Taster angeschlossen. An PortB1 habe ich die Steuerleitung von Servo angeschlossen. Die + - Anschlüsse von Servo habe ich sowie parallel als auch extern an einer Spannungsquelle angeschlossen. (Masse immer verbunden)
Der servo dreht nur etwas, wenn ich die Steuerleitung ab und wieder drauf lege an PB1!

Spannungswerte an den Port´s

Spannung gegen Masse gemessen!

PortD
D2 und D3 haben 5V (das liegt, weil ich die in Code auf „Low“ abfrage,
wenn ich Taster drücke, dann 0V)
Rest 0,7V

PortB
B1 wechseln ca. 1,7V zu 0V (schätzwerte, leider kein OZ.)
Rest 0,7V

PortC
Alle haben 0,8V

Wie gesagt, wenn ich eine LED an B1 anschließe, blinkt die LED!
Also gehe ich davon aus, dass das Board OK ist oder?
Wo könnte noch der Fehler liegen? :-(

Bin schon am verzeifeln....

Edit1:
Der Servo dreht immer einen Tacken nach den anderen sehr langsam nach links.

Edit2:
Hab mal was rumprobiert und umprogrammiert (Pulsimpulse verändert), der Servo läßt sich jetzt drehen! Zwar jetzt Taste1 eine festen werd und Taste2 einen Festen wert. (Zum Test erstmal) Mit den alten Code von H. funktionert es leider nicht trozt umprogrammieren der Zeitimpulse.
Wie mache ich das jetzt, das der nur schrittweiße sich dreht und nicht auf eine feste position?

SimLock
12.11.2007, 11:49
Edit3:
Jetzt Läuft es, es war noch Fehler in deinen Programm bei for schleife.
Danke an alle!

Hubert.G
12.11.2007, 12:08
Die for Schleife sollte doch ein langsames drehen bewirken, wenn du das rausnimmst dann dreht es gleich nach der max. Stellung. Das war von Anfang an drinnen und dachte daher es ist so gewollt.
Wenn du das nicht willst kannst du gleich nach if (!( PIND & (1<<PIND2))) OCRA==452; schreiben, da ersparst du dir die if-Schleife.

SimLock
12.11.2007, 13:43
Hi,

ich habe die for schleife komplett raus genommen und nur
OCRA++ mit 10 ms warten
Dazu oben noch die Impulszeiten geändert.

Wie bekomme ich jetzt 2 ansteuerungen von Servos hin?

habe schon Ausgänge und OCRB benutzt, aber klappt nicht.

radbruch
12.11.2007, 14:26
Hallo

Ich lese nun schon seit ein paar Tagen mit und verstehe nicht, warum ihr nicht einfach den Beispielcode aus dem RN-Wissen zu den Servos verwendet. Ein Timer im CTC-Mode und eine kleine ISR dazu steuert mehrere Servos, z.B. ein ATMega32 mit 8MHz und drei Servos:


#include <avr/io.h> // I/O Port definitions
#include <avr/interrupt.h> // Interrupt macros

uint8_t x, y, z;

void init(void)
{
DDRA |= 16; // E_INT1 als Ausgang
DDRC |= 3; // SCL und SDA als Ausgang

TCCR0 = (0 << WGM00) | (1 << WGM01); // CTC-Mode
TCCR0 |= (0 << COM00) | (0 << COM01); // ohne OCR-Pin
TCCR0 |= (0 << CS02) | (1 << CS01) | (0 << CS00); // prescaler /8
TIMSK = (1 << OCIE0); // Interrupt ein
OCR0 = 9; // 100kHz?
sei();
}
ISR(TIMER0_COMP_vect)
{
static uint16_t count=0;
if(count>z) PORTA &= ~16; else PORTA |= 16; // E_INT1 (Pin8)
if(count>y) PORTC &= ~1; else PORTC |= 1; // SCL (Pin10)
if(count>x) PORTC &= ~2; else PORTC |= 2; // SDA (Pin12)
if(count<2000)count++; else count=0;
}
int main(void)
{
init();
x=y=z=100;
while(1);
return 0;
}

Gruß

mic

SimLock
12.11.2007, 16:17
Hi Radbuch,

Danke für dein Beispielcode!!!
Ich habe es grade mal kopiert und compilliert.
Erhalte aber einige Fehlermeldung dazu:

Compiling: main.c
avr-gcc -c -mmcu=atmega8 -I. -gdwarf-2 -Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -Wall -Wstrict-prototypes -Wa,-adhlns=main.lst -std=gnu99 -DF_OSC=3686400 -MD -MP -MF .dep/main.o.d main.c -o main.o
main.c: In function 'init':
main.c:8: error: 'DDRA' undeclared (first use in this function)
main.c:8: error: (Each undeclared identifier is reported only once
main.c:8: error: for each function it appears in.)
main.c:11: error: 'WGM00' undeclared (first use in this function)
main.c:11: error: 'WGM01' undeclared (first use in this function)
main.c:12: error: 'COM00' undeclared (first use in this function)
main.c:12: error: 'COM01' undeclared (first use in this function)
main.c:14: error: 'OCIE0' undeclared (first use in this function)
main.c:15: error: 'OCR0' undeclared (first use in this function)
main.c: At top level:
main.c:18: warning: 'TIMER0_COMP_vect' appears to be a misspelled signal handler
main.c: In function 'TIMER0_COMP_vect':
main.c:21: error: 'PORTA' undeclared (first use in this function)
main.c:32:2: warning: no newline at end of file
make.exe: *** [main.o] Error 1

> Process Exit Code: 2
> Time Taken: 00:02


Mein altes Program läuft ja! Also mit 2 Taster 1 Servo.
Deswegen versuche ich mal das alte progamm zu erweitern.
Will aber jetzt 4 Taster und 2 Servos anschliesen.

Hab das hier mal versucht:


// Timer1 initialisieren

void timer1_init(void)
{
DDRB = ( 1 << PB1 )|( 1 << PB2 ); //PB1 und PB2 Als Ausgänge
TCCR1A |= (1<<WGM11)|(1<<WGM10)|(1<<COM1A1);
TCCR1B = (1<<CS11);
OCR1A = 75; // Servo1 auf Mittelposition vorstellen (40-120)
OCR1B = 75; // Servo2 auf Mittelposition vorstellen (40-120)
}

Und dachte mir das ich jetzt auf PinB2 den 2 Servo steuern könnte, tut sich aber nichts...

SimLock
12.11.2007, 19:34
Hi,

Danke für deinen Code!!!
Ich kriege aber mehrere Fehlermeldung beim compillieren:

main.c: In function 'init':
main.c:8: error: 'DDRA' undeclared (first use in this function)
main.c:8: error: (Each undeclared identifier is reported only once
main.c:8: error: for each function it appears in.)
main.c:11: error: 'WGM00' undeclared (first use in this function)
main.c:11: error: 'WGM01' undeclared (first use in this function)
main.c:12: error: 'COM00' undeclared (first use in this function)
main.c:12: error: 'COM01' undeclared (first use in this function)
main.c:14: error: 'OCIE0' undeclared (first use in this function)
main.c:15: error: 'OCR0' undeclared (first use in this function)
main.c: At top level:
main.c:18: warning: 'TIMER0_COMP_vect' appears to be a misspelled signal handler
main.c: In function 'TIMER0_COMP_vect':
main.c:21: error: 'PORTA' undeclared (first use in this function)
main.c:32:2: warning: no newline at end of file
make.exe: *** [main.o] Error 1

> Process Exit Code: 2
> Time Taken: 00:01


Wie schon gesagt, mein altes Programm mit 2 Taster und 1 Servo geht ja jetzt. Will es jetzt erweitern und zwar die gleiche funktion wie bei Servo1 an Servo2. Habe dafür folgendes geschreiben:


void timer1_init(void)
{

DDRB = (1<<PB1)|(1<<PB2); /* Pin PB1, PB2 als Ausgang für Servo1/Servo2 */

TCCR1A |= (1<<WGM11)|(1<<WGM10)|(1<<COM1A1);
TCCR1B = (1<<CS11);
OCR1A = 80; //Servo1
OCR1B = 80; //Servo2
}

Aber leider tut sich nichts an PB2

Frage, dieses PWM was ich erzeuge, kann ich nur 3 Servos damit an einen Atmega8 ansteuern? Oder kann ich dieses PWM für mehrere benutzten?
Mein Ziel, 2 Servos und noch eine L293D (mit 2 Gleichstrommotoren) zu betreiben.

Hubert.G
12.11.2007, 19:48
Die Fehler kommen da der Code für einen Mega32 geschrieben ist.

radbruch
12.11.2007, 20:08
Sorry, ich hätte auch dazuschreiben sollen, dass es ein Beispiel für einen ATMega32 ist. Wenn man aber irgendwo in diesem Thread auf ein blaues "Servo" klickt, kommt man direkt zur RN-Wissenseite. Dort ist das Beispiel zu finden, das als Vorlage zu meinem Code diente. 8-[


Wie schon gesagt, mein altes Programm mit 2 Taster und 1 Servo geht ja jetzt.
Ich dachte, du willst noch zwei Motoren per PWM ansteuern. Das wird aber schwierig, wenn du schon die Servos über PWM ansteuerst. Der ATMega8 hat nur 3 PWM-Kanäle...


TCCR1A |= (1<<WGM11)|(1<<WGM10)|(1<<COM1A1);
Für's Ansteuern von OC1B(PB2) muss im TCCR1A auch das COM1B1-Bit gesetzt sein, oder? Und um Probleme durch falsch gesetze Bits zu vermeiden sollte man TCCR1A hier nicht mit |= sondern besser nur mit = beschreiben.

mic

SimLock
12.11.2007, 20:26
Ich dachte man könnte die PWM für die 2 Gleichstrommotoren (über L293D) ansteuern und die 2 Servo dan über Software programmieren.
Geht überhaubt sowas?

Hubert.G
12.11.2007, 20:26
Hier mal der Code für 2 Servos

#include <avr/io.h>
#include <stdbool.h>
#include <stdlib.h>
#include <avr/io.h>
#include <AVR/iom8.h>
#include <inttypes.h>
//#include <util/delay.h>

#define F_CPU 12000000 // clock

// Timer1 initialisieren

void timer1_init(void)
{
TCCR1A |= (1<<WGM11)|(1<<COM1A1)|(1<<COM1A0)|(1<<COM1B1)|(1<<COM1B0); // initalize mega8 Timer1 with 9Bit, inverted, Prescaler 256
TCCR1B = (1<<CS12); // this gives us a signal with 21.76ms at 12MHz

OCR1A = 476; // pulse of 1.5ms 512- 1500*(F_CPU/256/1000000)/2

OCR1B = 476;
}

int main (void)
{
timer1_init();


DDRB = (1<<PB1)|(1<<PB2); /* Pin PB1 2 als Ausgang für Servo */

DDRD &= (~ (1<<PD2)|(1<<PD3)|(1<<PD0)|(1<<PD1)); /* Pin D als Eingang */
PORTD |= (1<<PD2)|(1<<PD3)|(1<<PD0)|(1<<PD1); /* Pull Up aktivieren */


while(1){
if (!( PIND & (1<<PIND2))) /* mache was wenn PinD2 low ist */
{
OCR1A=450;
}

if (!( PIND & (1<<PIND3))) /* mache was wenn PinD3 low ist */
{
OCR1A=499;
}

if (( PIND & (1<<PIND2))&&(PIND & (1<<PIND3))) { /* Mitte wenn keine Taste */
OCR1A = 476;
}
if (!( PIND & (1<<PIND0))) /* mache was wenn PinD0 low ist */
{
OCR1B=450;
}

if (!( PIND & (1<<PIND1))) /* mache was wenn PinD1 low ist */
{
OCR1B=499;
}

if (( PIND & (1<<PIND0))&&(PIND & (1<<PIND1))) { /* Mitte wenn keine Taste */
OCR1B=476;
}
}
}

Da auch noch SW-PWM dazumachen für die Motoren ist sicher auch noch eine knifflige Sache.

Edit: Welche Frequenz hast du dir für die PWM vorgestellt.

SimLock
12.11.2007, 21:04
Hi,

werde ich gleich mal testen. Ich habe 8Mhz eingestellt.

radbruch
12.11.2007, 21:56
Er meinte die Frequenz mit der die Spannung für die Motoren "zerkackt" werden soll. Hier ein (vielleicht) passernder Thread dazu:

https://www.roboternetz.de/phpBB2/zeigebeitrag.php?p=72521#72521

Ups, der Link zum Datenblatt in dem Thread funzt nimmer:
http://www.the-starbearer.de/Files/datenbl%E4tter/l293d.pdf

Man ist das zäh, auf Seite drei steht da:

NOTES: A. The pulse generator has the following characteristics: tr 3 10 ns, tf 3 10 ns, tw = 10 ms, PRR = 5 kHz, ZO = 50 W
PRR ist dann wohl die Max-Frequenz.

Gruß

mic

SimLock
13.11.2007, 06:47
Hi,

also dein Code geht bei mir leider nicht. Zwar kein Compilierungsfehler aber der Servo dreht nur schrittweise wenn ich PD3 betätige. Komisch

Mein Timer ist so eingestellt:

TCCR1A |= (1<<WGM11)|(1<<WGM10)|(1<<COM1A1); PWM, Phase Correct, 10-bit ; Clear OC1A/OC1B on Compare Match, set OC1A/OC1B at
BOTTOM, (non-inverting mode)

TCCR1B = (1<<CS11); clkI/O/8 (From prescaler)


kann ich da nicht mit:

OCR1A = 75; Servo1
OCR1B = 75; Servo2


Und Ausgang:

DDRB = (1<<PB1)|(1<<PB2); /* Pin PB1 und PB2 als Ausgang für Servo1/2 */

Nicht beide Bin benutzen? Also bei mir klappt das leider nicht

Edit:
Jetzt klappt auhc der 2 Servo, hatte vergessen OC1B on zu schalten.
Also kann ich jetzt 2 Servos ansteuern über PWM
Wie kann ich das aber über soft PWM realisieren?

Hubert.G
13.11.2007, 13:33
Wenn du mit den Servos immer nur rechts und links ohne Zwischenstufen fahren willst, kannst du das mit einem Timer ohne PWM auch machen. Für die Motoren nimmst du dann die HW-PWM. Mit welcher Frequenz willst du denn die Motoren ansteuern.

Hubert.G
13.11.2007, 13:59
Es stellen sich bei deiner Programmierung noch einige Fragen?
Womit steuerst du die Servos an, nur mit Taster.
Womit willst du die Drehzahl der Motoren verändern.
Das Programm ist jetzt noch recht klein und überschaubar. Es wäre gut sich das vorab zu überlegen. Man beginnt zumeist wieder von vorne wenn man sich die Frage stellen muss, wie kann ich auf die Hundehütte noch zwei Stockwerkt draufsetzen.

SimLock
13.11.2007, 14:53
Hi,

also mein Programm macht momentan folgendes:
Ich habe 4 Taster für 2 Servos. Damit bewege ich "später" eine kleine Cam hoch,runter,links,rechts. Die Funktion ist jetzt schon mal da. Die Servos bewegen sich, solange 1 Taster gedrückt ist 1 schritt z.B. nach rechts (max. drehen bis entwert erreicht ist, dann Stop).

Die Servos wolte ich wenn es geht über Soft-PWM steuern.
Weil ich für den L293D ja die PWM signal brauche oder?

Das L293D soll 2 Getriebemotoren steuern und zwar so:
Je Getriebe; Motor mit einer Drehrichtung 100% und die andere Drehrichtung mit 50% sonst Stop.

Mehr soll es erstmal nicht können.
1.Wenn das alles klappt, will ich das gern per PC steuern können (Kabel)
2.Dann kommt die Cam, die auch dann signal an PC schick (livestream)
3.Und wenn das auch "klappt", dann per Funk zum PC steuern.

Hubert.G
13.11.2007, 15:15
Wenn du für die Motoren nur 100% und 50% brauchst, dann genügt ein Timer der dir den Port-Pin toggled, da brauchst du kein HW-PWM. Verwende das besser für die Camerasteuerung.
Da hast du dir noch einiges vorgenommen.
Hubert

SimLock
13.11.2007, 21:10
Und wie mach ich das mit den Timer?
Genau so wie PWM programmieren?
Wie steuer man ein L293D an? <-- so wie das gelesen habe über PWM aber das wir es jetzt mit soft lösen wollen...

Hubert.G
14.11.2007, 09:40
Du musst einmal festlegen mit welcher PWM-Frequenz du arbeiten willst. Dann nimmst du einen freien Timer, z.B. Timer0 mit Prescaler 1024 und lässt bei jedem Überlauf ein Bit toggeln, damit hast du eine 50% PWM mit ca. 4kHz. Für eine andere Frequenz musst du den Timer entsprechend manipulieren.
Der L293D wird mit In1 In2 für Vorwärts- Rückwärtslauf und auf Enable1 mit PWM oder Dauer-high angesteuert. Du brauchst also für jeden Motor noch drei Pin.
Da ist jetzt einmal Pin-zählen angesagt, RXD und TXD für die Kommunikation, einen Quarz, da für RS232 der interne Oszillator nicht empfehlenswert ist, 6 Pin für die Motorsteuerung, 6 Pin für die Servos, viel bleibt da nicht mehr frei für eventuelle Sensoren oder so etwas.
Hubert

oberallgeier
14.11.2007, 10:03
Da ist jetzt einmal Pin-zählen angesagt, RXD und TXD ....... viel bleibt da nicht mehr frei für eventuelle Sensoren oder so etwas.
Hubert
Das war doch wohl genau die Situation, die der Anstoss für die Entwickler von TWI bzw. I2C war.

Also ein Hoch auf unsere Vorreiter/Vorväter und so.

Hubert.G
14.11.2007, 10:29
Das ist ein Grund die Pin-Belegung genau zu überdenken um sich nicht etwas selbst zu verbauen. Die weitere Frage stellt sich, ob die gewünschten Sensoren über so eine Schnittstelle verfügen.

SimLock
14.11.2007, 11:10
Hi,

vorab ein paar fragen noch zu Kommunikation zwischen PC und Board.
Brauche ich dazu nur ein RS232 IC und 2 Pin (PD0,PD1) von µC?

Pin Belegung:

Input PD0, PD1 (RXD, TXD Signal)

Input PD2 bis PD5 4 Taster für die Getriebemotoren
Output: PC0, PC2 für Getriebemotor 1
Output: PC3, PC5 für Getriebemotor 2

Output: PB1, PB2 für die Servos
Input PB4 bis PB7 4 Taster für die Servos

So bleibt noch paar über 4-5 das müsste doch reichen für Cam Signal und Funk.
Oder brauche ich dazu noch mehr Signale?

Hubert.G
14.11.2007, 11:48
Für eine Kabel- RS232 Übertragung ist ein MAX232 oder dergleichen notwendig. Ein Quarz ebenfalls da der interne Oszillator nicht genau genug ist.
Es bleiben daher nur 20 Pin übrig.
2 RX/TX
4 Taster Motor
6 Steuerung Motor
4 Taster Servo
2 Ansteuerung Servo

Macht 18 Pin, Funk kannst du über RX/TX machen da du ja dann kein Kabel hast, ob zwei Pin für die Kamera reichen musst du selbst wissen.

SimLock
14.11.2007, 12:17
Kannst du mir einen Link geben wie der RS232 mit den µC aufgebaut/verbunden wird?

So wie ich das gelesen habe braucht man nur ein 9polg. Stecker und 3 Kontakte (RXD, GND, TXD) um Daten von PC hin und her schicken.
Oder ist damit nur das schicken von Daten; von PC zum Borad gemeint?

Cam braucht nur 1 Videosignal denke ich mal, hab noch nicht gesucht nach einer Cam.

Hubert.G
14.11.2007, 12:26
Das geht in beide Richtungen. Link habe ich gerade keinen.
µC - TXD - TxIN (MAX)TxOUT - Pin2 9PolSubD
µC - RXD - RxOUT(MAX)RxIN - Pin3 9PolSubD
und GND auf Pin5

SimLock
14.11.2007, 12:59
Dann brauche ich den RS232 nicht oder?
Ich habe ja ein Borad zum Brennen, dann stecke ich µC auf den bot.
Von da werden die Daten von PC zum Board verschickt,
dafür brauche ich nur die 3 Adern oder muss da noch ein RS232 hin?

Was für ein Quarz nimmt man, ich weiß nicht genau wie meine Frequenz ist.

TCCR1A |= (1<<WGM11)|(1<<WGM10)|(1<<COM1A1); PWM, Phase Correct, 10-bit ; Clear OC1A/OC1B on Compare Match, set OC1A/OC1B at
BOTTOM, (non-inverting mode)
TCCR1B = (1<<CS11); clkI/O/8 (From prescaler)

Wie rechnet man die F?

Hubert.G
14.11.2007, 14:03
Wenn du über Kabel zum PC gehst brauchst du einen MAX232. Wenn du es über Funk machst dann nicht.
Ein 8MHz Quarz geht mit Einschränkungen, steht im Datenblatt unter USART/Example of Baudrate Settings
PWM-Frequenz steht im Datenblatt Seite 91
Für die Servos sollte die PWM-Frequenz 50Hz sein für die Motoren etwa 3kHz

SimLock
15.11.2007, 05:59
Was soll ich deiner Meinung erst machen, die Daten sofort per Funkt rüberschicken oder erst über Kabel?
Was ist einfacher zu Programmieren?
Per Funk brauche ich da auch einen Quarz?

Werde erstmal gleich versuchen die Frequenz zu erreichnen was ich benötige und welche ich monetan für die Servos benütze

Edit:

ich blicke leider nicht durch, wie man die Frequenz ausrechnet :-(
Also habe ja
CPU = 8Mhz
Bit = 10
Prescaler = 8

Hubert.G
15.11.2007, 10:08
Für RS232 egal ob Kabel oder Funk brauchst du eine Quarz, es kann auch ohne gehen, ist aber eine wackelige Angelegenheit. Kabel ist sicher einfacher.

SimLock
15.11.2007, 13:16
Ok,

dann Fangen wir mal lieber klein an und lassen alles bei seite und versuchen jetzt estmal das vorhandene Programm mit 2 Servos erweitern.
Also mit Karbel und RS232 verbinund aufbauen.
Da ich ein Board schon ein RS232 ist das schon mal vorhanden.

Wie kann ich jetzt von PC aus sagen z.b. wenn ich die Peiltaste hoch drücke an Pin D0 ein high Signal anliegt?

Habe schon gelesen, dass es über HyperTerminal geht.
Und folgenden Code. Wo sage ich das Programm das mit Pfeiltaste/Pin D5?


/* UART-Init beim AT90S2313 */

#include <avr/io.h>
#include <inttypes.h>
#include <util/delay.h>

#define F_CPU 8000000 // clock
#define BAUD 9600L // Baudrate, das L am Ende ist wichtig, NICHT UL verwenden!

// Berechnungen
#define UBRR_VAL ((F_CPU+BAUD*8)/(BAUD*16)-1) // clever runden
#define BAUD_REAL (F_CPU/(16*(UBRR_VAL+1))) // Reale Baudrate
#define BAUD_ERROR ((BAUD_REAL*1000)/BAUD-1000) // Fehler in Promille

#if ((BAUD_ERROR>10) || (BAUD_ERROR<-10))
#error Systematischer Fehler der Baudrate grösser 1% und damit zu hoch!
#endif

int main(void)
{
UBRRH = UBRR_VAL >> 8;
UBRRL = UBRR_VAL & 0xFF;

UCSRB = (1<<RXEN)|(1<<TXEN)|(1<<RXCIE);
UCSRC |= (1<<URSEL)|(3<<UCSZ0);



while (!(UCSRA & (1<<UDRE))) /* warten bis Senden moeglich */
{}


return 0;
}

SimLock
15.11.2007, 15:31
Ok,

dann Fangen wir mal lieber klein an und lassen alles bei Seite und versuchen jetzt erstmal das vorhandene Programm mit 2 Servos zu erweitern.
Also mit den Karbel und den RS232 IC eine verbinung über Hyperterminal aufbauen.
Da in meinen Board schon ein RS232 vorhanden ist, fehlt nur das Programm.

Wie kann ich jetzt von PC aus sagen z.b. wenn ich die Peiltaste "hoch" drücke an µC Pin D0 ein high Signal anliegt?

Habe schon gelesen, dass es über HyperTerminal geht.
Und folgenden Code. Wo sage ich das Programm das mit Pfeiltaste/Pin D5?


/* UART-Init beim AT90S2313 */

#include <avr/io.h>
#include <inttypes.h>
#include <util/delay.h>

#define F_CPU 8000000 // clock
#define BAUD 9600L // Baudrate, das L am Ende ist wichtig, NICHT UL verwenden!

// Berechnungen
#define UBRR_VAL ((F_CPU+BAUD*8)/(BAUD*16)-1) // clever runden
#define BAUD_REAL (F_CPU/(16*(UBRR_VAL+1))) // Reale Baudrate
#define BAUD_ERROR ((BAUD_REAL*1000)/BAUD-1000) // Fehler in Promille

#if ((BAUD_ERROR>10) || (BAUD_ERROR<-10))
#error Systematischer Fehler der Baudrate grösser 1% und damit zu hoch!
#endif

int main(void)
{
UBRRH = UBRR_VAL >> 8;
UBRRL = UBRR_VAL & 0xFF;

UCSRB = (1<<RXEN)|(1<<TXEN)|(1<<RXCIE);
UCSRC |= (1<<URSEL)|(3<<UCSZ0);



while (!(UCSRA & (1<<UDRE))) /* warten bis Senden moeglich */
{}


return 0;
}

Hubert.G
15.11.2007, 16:04
Der PC sendet den Wert des ASCII-Zeichen von der Taste, diesen Wert musst du dann im µC einen Bedeutung zuweisen. Willst du auch was zum PC zurücksenden. Das Empfangen von Zeichen würde ich Interruptgesteuert machen.

SimLock
15.11.2007, 16:49
Hi,

ich will nur Befehle (High Signal) zum Input Pin´s des µC Schicken.
Später (viel Später) soll nur der Livestream von der Cam zum PC geschickt werden.

Interruptgesteuert... , muss mal nachlesen oder hast du ein Beispiel dazu?

Hubert.G
15.11.2007, 17:04
Ein Beispiel habe ich nicht bei der Hand, ich verwende sonst die Lib von Fleury

SimLock
15.11.2007, 17:23
Sag mal, hast du icq? Dann könne wir gern gezielt/schnell miteinander komunizieren.

Lib von Fleury sagt mir jetzt nichts, wie ist die aufgebaut?

Hubert.G
15.11.2007, 17:51
http://jump.to/fleury
Unter AVR GCC Librarys gibt es diese.
ICQ oder so was habe ich nicht.

SimLock
15.11.2007, 19:42
Danke für diesem Link, aber mein englisch ist nicht so toll und verstehe daher nicht viel :-(

das Programm in uartlibrary ist ja groß...
Kannst du oder ein andere der sich mit UART auskennt mir es besser beschreiben, wie das so funktioniert oder einen kleine Beispiel dazu?

War mein code falsch oder bin ich auf den richtigen Weg?

Hubert.G
15.11.2007, 20:01
Du bist grundsätzlich auf dem richtigen Weg, die while Schleife ist aber für senden.

SimLock
16.11.2007, 08:10
So müsste der Code aussehen oder?:


int main(void)
{
/* UART einstellungen */
UBRRH = UBRR_VAL >> 8;
UBRRL = UBRR_VAL & 0xFF;
UCSRB = (1<<RXEN)|(1<<TXEN)|(1<<RXCIE); // UART TX,RX einschalten
UCSRC |= (1<<URSEL)|(3<<UCSZ0); // Asynchron 8N1

/* Output einstellen */
DDRB = (1<<PB1); /* Pin PB1 als Ausgang für Led */

/* Zeichen empfangen */
uint8_t Usart_Rx(void)
{
while (!(UCSRA & (1<<RXC))) // warten bis Zeichen verfuegbar
; /* Hier muss jetzt der Befehl rein wenn ich z.b. W drücke PB1 auf high */
return UDR; // Zeichen aus UDR an Aufrufer zurueckgeben
}
}

Wie programmiere ich, dass z.B. "W" in ASCII ungewandelt wird und mir PB1 auf high stellt?

vajk
16.11.2007, 10:38
@SimLock
>So müsste der Code aussehen oder?:
NEIN

Anmerkung: main() ist genauso eine Funktion, wie auch Usart_Rx() - diese können nicht verschachtelt werden! Wobei so der "UART-Empfang" nicht funktioniert. Das Geht über Interrupt und füllt dann globalen Puffer. Da implementiert man auch Verhalten gegen Pufferüberlauf und (Übertragungs-)Fehlerkontrolle.

> dass z.B. "W" in ASCII ungewandelt wird
char x = 'W';

PB1 = "high"; // diese Zeile ist ein Joke!
[PortB |= (1 << 0x01); heißt es richtig - nur verstehst Du auch, was hier passiert, warum ein |-Operator benutzt wird, was der '<<'-Operator bewirkt - das sind Grundlagen!]

> Wie programmiere ich,
Kleiner Tipp, frag Dr. Google - "C für Anfänger" wäre so ein Suchkriterium.
Sorry, meine Meinung ist, Du kannst hier im Forum gerne fragen bei Problemen, aber die Grundzüge von C kannst Du besser aus Büchern lernen.

Und irgendwelche Libs zu nehmen, wenn man von den Grundzügen keine Ahnung hat, ist der falsche Weg - das macht dann Dir auf Dauer keinen Spaß.
Kleiner Tipp, schau die Codeschnippsel im Netz an, wie es andere gelöst haben, daraus kann man auch gut lernen.

SimLock
16.11.2007, 11:04
Danke für dein Tip!

Das mit der Funktion () verstehe ich.
Ich habe mich beim Markieren, einfügen verklickt.

Frage zu deinen Code:
PortB |= (1 << 0x01);

Der Code was ich geschrieben habe, macht doch die gleiche funktion:
DDRB = (1<<PB1);

Ich bin ja grade erst paar Tage hierbei und lerne fleißig :-)

Hubert.G
16.11.2007, 12:14
Ich habe mal schnell was zusammengeschrieben. Die Timerwerte und OCRx-Werte mussst du für dich anpassen. Es geht mit den Zahlen am Tastenblock 2,4,6,8,0.

#include <avr/io.h>
#include <stdbool.h>
#include <stdlib.h>
#include <avr/io.h>
#include <AVR/iom8.h>
#include <inttypes.h>
#include <avr/interrupt.h>

#define F_CPU 8000000 // clock
#define BAUD 9600
#define bauddivider (unsigned int)(F_CPU / BAUD / 16 - 0.5)
volatile unsigned char rxwert=0x30;

ISR(USART_RXC_vect){
rxwert= UDR;
PORTB=(1<<PB0);
}

void timer1_init(void)
{
TCCR1A = (1<<WGM11)|(1<<COM1A1)|(1<<COM1A0)|(1<<COM1B1)|(1<<COM1B0); // initalize mega8 Timer1 with 9Bit, inverted, Prescaler 256
TCCR1B = (1<<CS12); // this gives us a signal with 21.76ms at 12MHz

OCR1A = 486; // pulse of 1.5ms 512- 1500*(F_CPU/256/1000000)/2

OCR1B = 486;
}
void usart_init(void){
UBRRL = bauddivider; //set baud rate
UBRRH = bauddivider >> 8;
UCSRB = (1<<RXCIE)|(1<<RXEN);
UCSRC = (1<<URSEL)|(3<<UCSZ0);
}
int main (void)
{
timer1_init();
usart_init();

DDRB = (1<<PB0)|(1<<PB1)|(1<<PB2); /* Pin PB1 2 als Ausgang für Servo */

DDRD &= (~ (1<<PD2)|(1<<PD3)|(1<<PD0)|(1<<PD1)); /* Pin D als Eingang */
PORTD |= (1<<PD2)|(1<<PD3)|(1<<PD0)|(1<<PD1); /* Pull Up aktivieren */
sei();

while(1){
if(rxwert==0x30){
if (!( PIND & (1<<PIND2))) /* mache was wenn PinD2 low ist */
{
OCR1A=470;
}

if (!( PIND & (1<<PIND3))) /* mache was wenn PinD3 low ist */
{
OCR1A=499;
}

if (( PIND & (1<<PIND2))&&(PIND & (1<<PIND3))) { /* Mitte wenn keine Taste */
OCR1A = 486;
}
if (!( PIND & (1<<PIND0))) /* mache was wenn PinD0 low ist */
{
OCR1B=470;
}

if (!( PIND & (1<<PIND1))) /* mache was wenn PinD1 low ist */
{
OCR1B=499;
}

if (( PIND & (1<<PIND0))&&(PIND & (1<<PIND1))) { /* Mitte wenn keine Taste */
OCR1B=486;
}
}
switch(rxwert){
case 0x38 :
OCR1A=470;
break;
case 0x32 :
OCR1A=499;
break;
case 0x34 :
OCR1B=470;
break;
case 0x36 :
OCR1B=499;
break;
}
}
}


Ein gutes C-Tutorial ist auch das hier: www.mikrocontroller.net/articles/AVR-GCC-Tutorial

Hubert

vajk
16.11.2007, 13:29
@SimLock :-)

Lernen ist immer gut

>Ich habe mich beim Markieren, einfügen verklickt.
ja, hier gibts keinen precompiler

Grundsätzlich C ist eine mächtige Sprache, lesbar wird sie nur - auch für einen selbst - wenn man klar strukturiert und akribisch Ordnung hält. In meinen Augen sollte eine Initalisierung in eine entsp. Funktion z.B. AvrINIT(void) und eben alle Initialisierung oder weitere Aufrufe. Die Portdefinitionen stehen bei mir immer am Anfang, das Ende meist ein sei();


hiermit setzt Du nur ein Bit von PortB
> PortB |= (1 << BIT2);
Löschen wäre
PortB &=~ (1 << BIT2);

hiermit setzt Du den gesamten Port ...
> DDRB = (1 << PB1);

... wenn Du das später im Code auch so machst, wirst Du irgendwann lange nach Fehlern suchen.
Setze lieber immer nur die BIts, die Du wirklich verändern willst.

SimLock
17.11.2007, 11:41
Hi Hubert,

danke für dein Code, aber funktioniert nicht bei mir trotz OCRA anpassung :-(

Mal paar fragen dazu:

1. Hier wird der Ausgang für UART Signale gewählt oder?


ISR(USART_RXC_vect){
rxwert= UDR;
PORTB=(1<<PB0);
}


2. Mit "break" wird doch das Programm angehalten und springt nicht wieder zur Hauptschleife oder?


switch(rxwert){
case 0x38 :
OCR1A=470;
break;


Ich hab dein Programm mal geändert für eine Led ansteuerrung.
Siehe Code. Wenn ich Taster PD2 drücke geht Lampe PD5 an und aus.
Wenn ich jetzt über Hyberterminal Taste stücke, geht an PB0 eine Led dauernt an und die funktion über normalen Taster PD2 funktioniert nicht mehr. Hängt sich das Programm jetzt auf vielleicht wegen "break" oder stimmt die einstellungen von UART nicht?


#include <avr/io.h>
#include <stdbool.h>
#include <stdlib.h>
#include <avr/io.h>
#include <AVR/iom8.h>
#include <inttypes.h>
#include <avr/interrupt.h>

#define F_CPU 8000000 // clock
#define BAUD 9600
#define bauddivider (unsigned int)(F_CPU / BAUD / 16 - 0.5)
volatile unsigned char rxwert=0x30;

ISR(USART_RXC_vect){
rxwert= UDR;
PORTB=(1<<PB0);
}
void usart_init(void){
UBRRL = bauddivider; //set baud rate
UBRRH = bauddivider >> 8;
UCSRB = (1<<RXCIE)|(1<<RXEN);
UCSRC = (1<<URSEL)|(3<<UCSZ0);
}
int main (void)
{

usart_init();



//*** LED ***

DDRB |= (1<<PB0); /* Pin PB0 als Ausgang für UART */
DDRD |= (1<<PD5); /* Pin PD5 als Ausgang für Led */


//*** Taster ***

DDRD &= ~ (1<<PD2); /* Pin D2 als Eingang */
PORTD |= (1<<PD2); /* Pull Up von PIN D2 aktivieren */

sei();

while(1){
if(rxwert==0x30){
if (!( PIND & (1<<PIND2))) /* mache was wenn PinD2 low ist */
{
PORTD |= (1<<PD5); /* Setzt Pin PD5 auf High */

}
else {
PORTD &= ~ (1<<PD5); /* Setzt Pin PD5 wieder auf low */

}
}
switch(rxwert){
case 0x38 :
PORTD |= (1<<PD5); /* Setzt Pin PD5 auf High */
break;
case 0x32 :
PORTD &= ~ (1<<PD5); /* Setzt Pin PD5 wieder auf low */
break;
}
}
}


vajk, danke für dein Hinweiß. Hab es mir aufgeschrieben :-)

Hubert.G
17.11.2007, 12:17
1. Das ist der Interrupt den ausgelöst wird wenn ein Zeichen Empfangen wurde, es wird unter rxwert gespeichert.
2. mit break verlässt du die switch-Schleife
3. wenn die Led aufleuchtet dann funktioniert die ISR , die Tasten funktionieren erst wieder wenn du einen 0 drückst.
Die UART-Einstellungen sind für einen 8MHz Takt, es könnte nur Probleme geben wenn du mit dem internen Oszillator arbeitest, der ist nicht sehr genau. Sonstige Einstellung 8bit, no parity, 1 Stoppbit.

SimLock
17.11.2007, 13:10
Mein Programm, das müsste ja ok sein oder?
Wenn ich über Hyperterminal geal welche Taste ich drücke dann leutete dauernt die Led an PB0 und die PD5 tut sich nichts, kann die auch nicht über den Taster ansteuern. Wenn ich 0 drücke leutet die Led immer noch und nichts verändert sich.

Einstellungen sind genau wie du gesagt hast. Benutze den internen Quarz. Wenn ich den externen Quarz von 3,6Mhz benutze, passiert genau das gleiche.

sieht so aus, das er diesen Wert nicht erreicht, weil das ist ja die Funktion des Taster drin, und solange dieses Signal nicht da ist..
if(rxwert==0x30)

Hubert.G
17.11.2007, 14:56
Du musst schon einen Quarz mit 8MHz verwenden, sonst stimmt die Baudrate nicht und du bekommst irgend einen Unsinn übertragen. Der interne Oszillator kann zu ungenau sein.
Die PB0 leuchtet beim ersten Interrupt auf und geht nicht mehr aus. Das sich mit PD5 dann nichts tut ist klar, im rxwert steht irgend ein Blödsinn und solange da nicht 0x30 drinnen steht geht nichts.

SimLock
17.11.2007, 15:22
Dann muss ich mir mal einen 8 Mhz Quarz besorgen.
Heißt das jetzt, wenn es Funktioniert muss ich jedesmal 0x30 drücken, also 0 damit die Tasterfunktionschleife funktioniert?

Also ich habe mal ein Testprogramm mit Senden geschrieben, wenn ich einen Taster drücke, soll dann 'W' rüber geschickt werden. Im Terminal kommt auch was an, aber nicht W sonder a~ und noch ein symbol.
Das liegt jetzt daran wegen des Quarz?

Hubert.G
17.11.2007, 15:46
Richtig, wenn du 0 drückst laufen die Servos in Mittelstellung und die Taster sind wieder aktiv. Das kann man durch ändern des Programms natürlich ganz anders gestalten, hier sollte es ja nur eine Demo des UART sein.
Du kannst diesen 3,6864 MHz Quarz auch nehmen, allerdings musst du F_CPU ändern und den PWM-Timer anpassen damit die Servos funktionieren.

SimLock
17.11.2007, 16:16
Die Servos lassen wir erstmal weg. Will nur die Led von PC aus an und aus machen. Also dann F_CPU auf 3,6864 MHz und externen Quarz einstellen.

Somit klappt es! <-- Thx.

Frage noch zu UART, der Signal bei PB0 kann ich dann nicht mehr benutzen oder? Der wird dann für die Empfangen genutz...

Und noch eine Frage zu case:
case 0x38 :
PORTD |= (1<<PD5); /* Setzt Pin PB3 auf High */
break;

kann man da auch else mit einbauen?
Dacht da so an:
case 0x38 :
PORTD |= (1<<PD5); /* Setzt Pin PB3 auf High */
Else
PORTD &= ~ (1<<PD5); /* Setzt Pin PB3 wieder auf low */
break;

oder geht das nur mit einer If/Else?

Hubert.G
17.11.2007, 16:27
In den Fuses den externen Quarz einstellen.
Das PB0 in der ISR kannst du weglassen, war für mich nur eine Indikator ob die ISR funktioniert, wenn du es änderst auf PORTB^=(1<<PB0); dann geht die Led an und aus.

SimLock
17.11.2007, 16:38
Also das mit Empfangen geht schon mal, F_CPU umgestellt.
Das PB0 in der ISR ist weg, geht auch und leutet nicht mehr.

1000 Danke schon mal dafür!!!

Hast du meine letzt Frage gelesen mit If/Else oder case?

Hubert.G
17.11.2007, 18:20
Die letzte Frage habe ich übersehen.
Es geht auch

if(rxwert==0x38){
tu was
}
else if(rxwert==0x32){
tu was anderes
}
else if.........


ich kann nur nicht sagen was den kleineren Code erzeugt, aber switch case ist für mich übersichtlicher

vajk
17.11.2007, 19:40
typedef unsigned char byte;
byte rx = 'a';
switch(rx)
{
case '0' : tuewas(); break;
case '5' : tuewasanderse(); break;
case '6': // wie bei 'b' - absichtlichkein break;
case 'b': nochwasanderes(); break;
case 0x38:
{
waslosbei8();
mach();
egal();
}
break;
default: nixlos(); // <- da haste Dein "else" sprich
// wenn sonst nix gewählt wurde
}


switch/case ist mächtig aber geht nur für konstante Wertabfragen, if kann auch variablen vergleichen.

SimLock
17.11.2007, 22:59
Danke euch beiden!!!

Habe mal folgendes geschrieben:


while(1){

switch(rxwert){

case 0x38 :
PORTD |= (1<<PD5);/* Setzt Pin PB3 auf High */
break;
default:
PORTD &= ~ (1<<PD5);/* Setzt Pin PB3 wieder auf low */
break;
}
}
return(0);
}

Jetzt bleibt die Led dauernt an, wenn ich Ziffer8 1-mal drücke.
Will aber die Led nur solange an sein wie auch der Taster gedrückt wird!
Wenn ich Ziffer8 gedrückt halte, geht die Led in intervall an uns aus.
Dachte, das mit default würde auch gehen. Oder habe ich da einen Denkfehler?

Hubert.G
18.11.2007, 08:49
Da hast du einen Denkfehler. Wenn du am PC die 8 drückst, wird diese nur einmal übertragen. Bleibst du aber auf der Taste, dann wird die 8 im, auf dem PC eingestellten Rythmus wiederholt.
Wenn du das so willst wie geschildert, dann brauchst du eine Zeitschleife die sagt, Taste gedrückt, gewisse Zeit warten, Taste wieder gedrückt, weiterwarten, Taste nicht mehr gedrückt, Zeit abgelaufen, rücksetzen.
Das Steuern eines Bot über den PC ist für mich ohne entsprechenden PC-Programm nicht sehr sinnvoll. Speziell wenn man über das Hyper-Terminal steuern muss. Eine IR-Fernbedienung ist da sicher Sinnvoller, aber natürlich auch etwas aufwendiger.

vajk
18.11.2007, 10:51
Wie sieht jetzt Deine USART-RX-funktion aus - wird da auch noch auf den Port zugegriffen?

Ist Dir bewusst, daß die Datenübertragung zum uC langsamer als die Abarbeitungsgeschwindigkeit im uC ist?

Ist Dir bewusst, daß wenn Du kein Zeichen sendet, auch kein Zeichen übertragen wird?

Typischerweise, würde ich ein WindoofProgramm dann so schreiben, daß ein Steuerzeichen gesendet wenn "Taste gedrückt" und ein weiteres, wenn Taste wieder losgelassen wird.

Sprich im uC den Port nicht im switch.default löschen, sondern eben durch einen anderen Steuercode.

Je nachdem welche Daten Du noch übertrage willst, gehen Dir die Steuerzeichen irgendwann aus ;-) Also sollte aus den Steuerzeichen einen Befehlssequenz werden, typ. weise inkl. prüfsumme.

Auf uC-Seite würde ich nicht das vorhandensein von Zeichen im Puffer via Timer prüfen. Sondern ein flag setzen, wenn die Empfangssequenz vollständig ist ....

SimLock
18.11.2007, 19:28
Hi,

danke euch beiden für die Antwort!

Also, mein bot soll alle input´s über den PC bekommen.
Dachte da an einen Visualbasic Programm zu erstellen, wo ich dann Daten über den Hyperterminal zum µC sende. (Später wenn diese Funktion funktioniert, dann die Daten per Funk schicken)

Wenn das so realisierbar ist mit VB und HT?
Oder gibt es eine andere Methode, die einfacher wäre?

Zu Hubert:
…auf dem PC eingestellten Rhythmus wiederholt.
- Was wäre, wenn man den Stoppit auf 0 setzten würde?

…Zeitschleife…
- meinst du die mit _delay_ms(10); ?

…ohne entsprechenden PC-Programm nicht sehr sinnvoll.
- Welches Programm meinst du?



Zu vajk:

…noch auf den Port zugegriffen?
- Nein wird es nicht, meinst das hier oder?
ISR(USART_RXC_vect){
rxwert= UDR;
}

…Befehlssequenz werden, typ. weise inkl. prüfsumme.
- Wie meinst du das?

vajk
18.11.2007, 19:45
@SimLock

> Wenn das so realisierbar ist mit VB und HT?

entweder - oder ! Nur eines der Programm kann auf die serielle Schnittstelle zugreifen ...

> …auf dem PC eingestellten Rhythmus wiederholt.
hä?

> - Was wäre, wenn man den Stoppit auf 0 setzten würde?
nonsense

> …Zeitschleife…
> - meinst du die mit _delay_ms(10); ?

ohhh neiiiinnnn ... ganz falscher Weg!

>…ohne entsprechenden PC-Programm nicht sehr sinnvoll.
> - Welches Programm meinst du?
na das was Du in VB schreiben willst .. menno


> …Befehlssequenz werden, typ. weise inkl. prüfsumme.
> - Wie meinst du das?[/quote]
aua²
sorry.

Also ... Du sprechen mit uns, nutzen nicht nur Buchstaben sondern Sätze und Wörter ...

.. Du sprechen mit Robby, Du nutzen nicht nur Einzelzeichen sondern Steuerbefehle die aus mehr "Zeichen" bestehen .. = Befehlssequenzen

... und die eben - besonders, wenn Du das per Funk machen willst - muß auch geprüft werden .. typisch ist hier zumindest einen Prüfsumme / CRC über das was übertragen wird angehängt ...

z.B. <34><234><fr434wdae>[crc] ...
- die 34 ist zb. ein Ausführungsbefehl, auf den eine Antwort erwartet wird
- die 234 der Befehl
- fr.. die Daten, die zum Befehl gehören

z.B: 234 = fahren, fr... = vorwärte 27 cm ....

Besonders wenn Du per funk steuerst, solltest Du auch Rückmeldungen an den PC liefern können, ob ein Befehl auch ausgeführt wird oder wurde, oder auch Abfragen, wie die Motortemperatur ist die Betriebsspannung ...

Dazu reichen nicht 0.255 Bit = 1 Byte !!!!

Kapischi?

Hubert.G
18.11.2007, 20:54
> …auf dem PC eingestellten Rhythmus wiederholt.
hä?
Damit meinte ich die Zeichenwiederholung wenn man auf der Taste bleibt.

Aber auf den PC bin ich nicht so zuhause, da bin ich nur Anwender und werde mich daher aus der Diskussion ausklinken.

Hubert

SimLock
19.11.2007, 05:43
Hi, danke euch beiden!!!

Werde erstmal fleißig weiter lesen uns später zurück kommen mit gezielten fragen. Bring ja nichts, wenn ich dauernt frage :-)

Edit:

Eine Frage hätte ich noch:
...eins verstehe ich nicht so ganz, wenn ich diesem Code benutzt und Daten zum PC schicke, funktioniert es, an PC wird ein W angezeigt + solange ich den Taster drücke leuchtet die Led. Warum kann man das nicht genau so einfach umgekehrt realisieren. Dann müsste es doch auch gehen, nur wenn ich statt Taster drücke, eine PC Taste drücke.




while (1)
{

if (!( PIND & (1<<PIND2))) /* mache was wenn PinD2 low ist */
{
PORTB |= (1<<PB1); /* Led auf hig setzten */
x = 'W';
UDR = x;
_delay_ms(20);
PORTB &= ~ (1<<PB1); /* Led auf low setzten */
}
}
return 0;
}

Werde erstmal weiter lesen und in paar Tagen, wenn ich wieder Fragen habe, die Fragen aufteilen und in Forum neue Themen erstellen.

Danke alle die mir bis jetzt geholfen haben!

Hubert.G
19.11.2007, 08:58
Die PC-Tastatur ist zu schreiben ausgelegt, jeder Tastendruck ein Zeichen. Wenn du das so willst wie du geschrieben hast, dann musst du dir ein PC-Programm schreiben das den Tastendruck in deinem Sinne auswertet. Du musst dem Kontroller mitteilen: jetzt Taste gedrückt, jetzt Taste nicht mehr gedrückt.
In meinem Programm wird das "Taste nicht mehr gedrückt" durch das drücken der Taste 0 signalisiert.

SimLock
19.11.2007, 09:55
Also verstehe ich das so, das der PC bei 1 Tastendrück ein Wert rüberschickt und ich erst nochmal drücken muss damit der µC den ersten Wert löscht?

vajk
19.11.2007, 10:47
Eine Taste am PC-Keyboard ist nunmal keine am uC .. die Logic ist drauf ausgelegt, Zeichen zu schreiben ... ganz vergleichbar einer Schreibmaschine ... wenn ich mich richtig erinnere, genieriert Windows nur zwei Messages: WM_KEYDOWN und WM_KEYUP - eine "KEYISPRESSED" mußt Du Dir selber bauen ...
Dazu kommt die Repeatfunktionalität der Tastatur, bei längerem Tastendruck.
Also nix, was Du direkt zur Fernschlatung nutzen kannst.

Wie oben schon erklärt, brauchst Du zwei Steuerwerte, die ausgewertet werden AN und AUS ... und wenn Du gut bist, implementierst Du noch ein Timeout, wenn das AUS nicht ankommt ... oder keine Steuerinformationen mehr ankommen. Eine Bidirektionale Kommunikation zur Steuerung wäre Vorteilhaft.

Tipp: gewöhne Dir delays ganz schnell wieder ab im uC-Code - insbesondere solange Du nicht mehr Erfahrung hast!

Überlege lieber, wie Du Timer geschickt einsetzen kannst ...
geschickt heißt z.B. daß Du mit Timern eine Tastenentprellung durchführst, gleichzeit auch erkennen kannst, daß eine Taste kurz oder lang gedrückt wurde ... bei Tastern am uC wohlmerkt.

Viel Erfolg weiterhin.

SimLock
19.11.2007, 12:18
Das hört sich alles richtig an bei euch, leider bin ich nicht so weit und verstehe einige sachen noch nicht :-(

Aber warum funktioniert nicht sowas mit continue?
Dachte, solange die Taste nicht gedrückt wird, muss die Led aus sein und wenn ich die drücke müsste die leuten... <-- meine Logik ist voll falsch.
Ist doch schwierieger als ich dachte.


while(1){

switch(rxwert){
if(rxwert!=0x38){
PORTB &= (~ (1<<PB1));
continue;
}

if(rxwert==0x38){
PORTB |= (1<<PB1);
break;
}
}
}

Hab ihr irgendwo links wo ich das genau durchlesen könnte?

Hubert.G
19.11.2007, 12:30
Wenn du die Taste die direkt am µC angeschlossen ist drückst, dann ist es richtig. Du Fragst die Taste aber auch kontinuierlich ab.
Über den UART bekommst du aber nur ein "diese Taste wurde gedrückt" aber kein "diese Taste wurde wieder losgelassen". Wenn du das willst musst du dir ein PC-Programm schreiben das genau das macht und es über den UART an den µC weitergibt.
Dein Codeschnippsel scheitert genau daran. Du sagst zwar unten "wenn 0x38 leuchtet Led" aber wie bekommst du das "wenn nicht 0x38". Ohne PC-Programm geht das nur durch drücken einer anderen Taste oder wie in meinem Programm durch drücken der Taste 0. Also der µC braucht das Kommando " Taste nicht mehr gedrückt", wie du das realisierst ist deine Sache.

vajk
19.11.2007, 13:43
Schreib doch mal den Code lesbarer!



int main(void)
{
InitAVR();

for(;;)
{
switch(rxwert)
{
if(rxwert == 0x11) // löschcode z.b.
{
PORTB &=~ (1 << PB1);
continue; // nicht unbedingt nötig
}
if(rxwert == 0x38)
{
PORTB |= (1 << PB1);
// break; wieso soll hier die Hauptschleife gelöscht werden
}
}
}
return(0);
}


Ich schließ mich meine Vorredner an, der PC muß beides senden,
Taste gedrückt - Taste losgelassen ...

So wie Du es bisher verwendest, weiß der uC nix davon, daß Taste losgelassen wird.

.. ist doch einfach zu verstehen !

SimLock
19.11.2007, 14:59
Vielen Danke erstmal!

Kann erst morgen weiter testen. Heute leider keien Zeit...

SimLock
20.11.2007, 05:57
So habe grade dein Code getestet, leider tut sich nicht bei mir...
InitAVR(); diese Zeile hab ich raus gelassen.
Trotzdem tut sich nichts, ist zwar eine forever schleife wie ich gesehen…
Theoretisch müsste das doch gehen mit deinen Code, komisch.

vajk
20.11.2007, 09:49
> Schreib doch mal den Code lesbarer!
das hatte ich mit Deinem Code gemacht .. ihn lesbarer gemacht und um einen Aus-Steuerbefehl ergänzt - mehr nicht (doch, kommentiert und das sinnlose break entfernt).

Und natürlich eine for(;;) - so weit ich mich erinnere macht der compiler draus einen jump - ein while(1) beinhaltet eine abfrage und dann einen jump - auch wenn das ein Befehl sein wird .. aber das ist assembler und hier nicht wirklich wichtig.


InitAVR(); << da gehören ALLE Initialisierungen rein. Und wenn Du das in Unterfunktionen aufgliedern willst, dann eben die Aufrufe dieser.

Wenn Du keine Initialisierungen machst, sind alle Ports Eingänge - menno!

Natürlich ändert sich nichts - Du mußt vom PC aus eben eine "mach-an" - Sequenz definieren und schicken UND Du mußt vom PC aus eine "mach aus"-Sequenz definieren und schicken ... Trichter aufn Kopf, reinkippen, verstehen oder hinnehmen!

Wen Du so weiter machst, biete ich Dir noch eine Sprechstunde am Telefon an :-)

SimLock
20.11.2007, 10:39
Das mit der Sprechstunde am Telefon finde ich gut!
Ich übernehme auch die Kosten :-)

Bin grade paralle in VB Forum um ein Sende Formular zu erstellen.