UART Interrupt und Time kommen sich in die Quere???
Hi,
ich will nun beide meine Testprogramme vereinen. Das eine Bewegt 4 Servos gleichzeitig. Das ganze ist Timer-Interrupt-gesteuert. Der andere Teil in ein RX-Complete Interrupt, der Eingaben speichert bis das Stoppzeichen kommt und dann den String an eine Methode weitergibt, die ihn verarbeitet.. Es sollen z.B. Strings wie "s1100" empfangen werden, was bedeutet "Bewege Servo 1 (s1) zur Position 100".
Das ganze klappt aber nicht so. Wenn ich die Befehle zum Bewegen der Servos auskommentiere funktioniert der Empfang, ansonstem eben nicht.
Das Prinzip soll folgendes sein: Der Controller vergleicht ständig die aktuelle Position und die Soll-Position. Wenn sie nicht übereinstimmen bewegt er sie. Durch den Empfang des Befehls sollen neue Positionen vergeben werden können. Der Controller bewegt dann automatisch die Servos in die gewünschte Position.
Hier ist der Code für das ganze:
Code:
#define F_CPU 8000000
#define BAUD_RATE 9600
#include <avr/delay.h>
#include <avr/interrupt.h>
#include <avr/signal.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <avr/io.h>
#include <avr/sfr_defs.h>
#define stopsign '!'
#define startsign '&'
char inStr[500];
int inCnt = 0;
// -- METHODEN DEKLARATIONEN
void keep_moving(void);
void move(int servo, int pos);
void calc_steps(void);
int putChar(char c);
int signum(int val);
void uart_init(int tx, int rx);
uint8_t uart_readChar(void);
void parseInput(void);
// -- SERVO VARIABLES
volatile uint8_t servo_flag = 0;
volatile float shoulder_pos = 127.0;
volatile float elbow_pos = 127.0;
volatile float wrist_pos = 127.0;
volatile float gripper_pos = 127.0;
volatile uint8_t shoulder_dest = 255;
volatile uint8_t elbow_dest = 1;
volatile uint8_t wrist_dest = 127;
volatile uint8_t gripper_dest = 250;
volatile float shoulder_step = 0;
volatile float elbow_step = 0;
volatile float wrist_step = 0;
volatile float gripper_step = 0;
int main (void) {
//TIMER-IINTERRUPT AN
TCCR0 |= (1<<CS01) | (1<<CS00);
TIMSK |= (1<<TOIE0);
//UART-INTERRUPT AN
UCSRB |= (1<<RXCIE);
//UART INITIALISIEREN (RX UND TX ANSCHALTEN)
uart_init(1, 1);
//GLOBAL INTERRUPT AN
sei();
//PRINTF FÜR AUSGABE KONFIGURIEREN
fdevopen(putChar,NULL,0);
printf("\n\n\rSTART !!!\n\r");
//HAUPTSCHLEIFE
while(1)
{
//NUR AUFRUFEN, WENN EIN TIMER INTERUPT DA WAR
if(servo_flag == 1) {
cli();
calc_steps();
keep_moving();
sei();
}
}
return 0;
}
// -- METHODEN ZUM BEWEGEN DER SERVOS
void keep_moving() {
//CALCULATE NEW POSITIONS
shoulder_pos = shoulder_pos + shoulder_step;
elbow_pos = elbow_pos + elbow_step;
wrist_pos = wrist_pos + wrist_step;
gripper_pos = gripper_pos + gripper_step;
//SET STEP=0 IF DEST. POSITION WAS REACHED
if( (int)(shoulder_pos) == shoulder_dest){ shoulder_step = 0; }
if( (int)(elbow_pos) == elbow_dest) { elbow_step = 0; }
if( (int)(wrist_pos) == wrist_dest) { wrist_step = 0; }
if( (int)(gripper_pos) == gripper_dest) { gripper_step = 0; }
//POSITIONEN SCHICKEN
move(1, (int)shoulder_pos);
move(2, (int)shoulder_pos);
move(3, (int)elbow_pos);
move(4, (int)wrist_pos);
move(5, (int)gripper_pos);
servo_flag = 0;
}
void calc_steps(void) {
float shoulder_to_go = shoulder_dest - shoulder_pos;
float elbow_to_go = elbow_dest - elbow_pos;
float wrist_to_go = wrist_dest - wrist_pos;
float gripper_to_go = gripper_dest - gripper_pos;
float shoulder_absolute = abs(shoulder_to_go);
float elbow_absolute = abs(elbow_to_go);
float wrist_absolute = abs(wrist_to_go);
float gripper_absolute = abs(gripper_to_go);
shoulder_step = 1;
elbow_step = 1;
wrist_step = 1;
gripper_step = 1;
//GET GREATEST VALUE
uint8_t largest_way_servo = shoulder_absolute;
if(elbow_absolute > largest_way_servo) { largest_way_servo = elbow_absolute; }
if(wrist_absolute > largest_way_servo) { largest_way_servo = wrist_absolute; }
if(gripper_absolute > largest_way_servo) { largest_way_servo = gripper_absolute; }
//SET STEP DEPENDING ON GREATEST VALUE (BIGGEST STEP=1)
shoulder_step = (shoulder_absolute/largest_way_servo) * signum(shoulder_to_go);
elbow_step = (elbow_absolute/largest_way_servo) * signum(elbow_to_go);
wrist_step = (wrist_absolute/largest_way_servo) * signum(wrist_to_go);
gripper_step = (gripper_absolute/largest_way_servo) * signum(gripper_to_go);
}
void move(int servo, int pos){
loop_until_bit_is_set(UCSRA, UDRE);
UDR = '#';
loop_until_bit_is_set(UCSRA, UDRE);
UDR = 's';
loop_until_bit_is_set(UCSRA, UDRE);
UDR = servo;
loop_until_bit_is_set(UCSRA, UDRE);
UDR = pos;
}
// INPUT PARSEN
void parseInput(void) {
if(inStr[0] == 's') {
if(inStr[1] == '1') {
int hundred = 100 * ((int)inStr[2] - 48);
int ten = 10 * ((int)inStr[3] - 48);
int one = (int)inStr[4] - 48;
int pos = hundred + ten + one;
elbow_dest = pos;
}
}
}
//SIGNUM WIRD NUR IN calc_steps BENÖTIGT
int signum(int val) {
if(val != 0) {
return val/abs(val);
} else {
return 0;
}
}
//INTERRUPTS
SIGNAL (SIG_OVERFLOW0){
servo_flag = 1;
}
SIGNAL(SIG_USART_RECV) {
cli();
inStr[inCnt] = uart_readChar();
switch (inStr[inCnt])
{
case (stopsign):
parseInput();
inCnt=0;
break;
case (startsign):
inCnt=0;
break;
default:
inCnt++;
break;
}
sei();
}
// -- UART METHODEN
void uart_init(int tx, int rx) {
UBRRL = (F_CPU/(BAUD_RATE*16l)-1);
if(tx == 1) {
UCSRB |= (1<<TXEN);
}
if(rx == 1) {
UCSRB |= (1<<RXEN);
}
}
int putChar(char c){
while ( !( UCSRA & (1<<UDRE)) );
UDR=c;
return 0;
}
uint8_t uart_readChar(void) {
loop_until_bit_is_set(UCSRA, RXC);
return UDR;
}
Aber irgendwas stimmt nicht.. Er reagiert nicht auf Eingaben. Wenn ich die Zeilen mit move() auskommentiere klappt der Empfang.
Wäre super nett wenn sich das jemand anschauen würde. Es ist viel weniger als es aussieht. Ihr könnt ja die methoden keep_moving() und calc_steps komplett auslassen. Sie funktionieren ja einwandfrei.
mfg
jagdfalke
Liste der Anhänge anzeigen (Anzahl: 1)
hallo, spät, aber doch !
Leider bin ich in der Vorweihnachtszeit nicht Herr meiner selbst, tut leid.
Anbei gezippt das Projekt. Vorsicht: ich hab mega32 mit 8 MHZ also ev. ausbessern.
Das tut jetzt, was es soll.
Damit ich was sehen kann, hab ich ein paar Terminal steuerungen eingebaut, du mußt etweder dein terminal auf VT100-Mode einstellen oder das Zeugs rauslöschen.
Ein paar sachen hab ich hin- und hergeschoben, aber du solltest dein Programm noch erkennen können
Liste der Anhänge anzeigen (Anzahl: 1)
Zu dem Zeitpunkt als der gepostetet output gekommen ist hatte ich schon alle printfs entfernt.
Dieses "#sOA<#soA<" zeigt doch eigentlich, dass irgendwas dazwischen gefprintet wird wärend er die Servoposition übermittelt, oder? Soll ich da einfach cli()-sei() drum rum machen? Aber dann könnte es wieder sein, dass er Eingaben nicht registriert. Damn.
Zur Geschwindigkeit: Wenn ich das printf, das die Positionen ausgibt weglasse, ist er mind. doppelt so schnell. Naja, wäre trotzdem gut wenn wir ne andere Möglichkeit finden würden das schneller zu machen, denn irgendwann sollen die Daten vom PC empfangen werden.
Im Anhang nochmal der modifizierte Code
Liste der Anhänge anzeigen (Anzahl: 1)
So, ich hab ein wenig umgerührt und "streamlined"
Was auf jeden Fall den Schirm stört, ist das Echo vom Inky. Hab ich mal auskommentiert, wir wissen ja, daß es geht.
Die Input-Prüfung und verteilung hab ich gleich in die ISR reingegeben, is einfacher und man muß bei der Position nicht mehr führende Nullen eingeben.
Ich kann es im Moment hier mangels AVR zwar kompilieren, aber nicht testen.
Liste der Anhänge anzeigen (Anzahl: 1)
Na ich hab kompiliert und inzwischen schon getestet
Geht pipifein ! kein problem mit make ??????
nimm einfach den ganzen projektkrempel aus der Zip, ist alles aktuell
Man muß zwar blind eingeben, weil kein Echo mehr da ist.
Ich hab' drei Servos angehängt, die bewegen sich auch.
Lad einfach das Hex !