-         

Seite 1 von 5 123 ... LetzteLetzte
Ergebnis 1 bis 10 von 45

Thema: UART Interrupt und Time kommen sich in die Quere???

  1. #1
    Erfahrener Benutzer Roboter-Spezialist
    Registriert seit
    22.02.2005
    Beiträge
    385

    UART Interrupt und Time kommen sich in die Quere???

    Anzeige

    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

  2. #2
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    02.11.2005
    Alter
    42
    Beiträge
    1.140
    Hi!

    Zuerst mal wundere ich mich ein wenig über dieses Konstrukt:
    Code:
          //NUR AUFRUFEN, WENN EIN TIMER INTERUPT DA WAR 
          if(servo_flag == 1) { 
             cli(); 
             calc_steps(); 
             keep_moving(); 
             sei();
    Warum machst Du das über ein Flag und schreibst nicht den ganzen Kram in die Interrupt-Routine?

    Was Dein Empfangs-Problem angeht - das wird wohl ein Timing-Problem sein. Der Empfangs-Interrupt bekommt einfach nicht genügend Zeit zum arbeiten.

    Versuche doch mal
    - Den Timer langsamer laufen zu lassen
    - Die Interrupts während der Positionierung nicht global zu deaktivieren.

    askazo

  3. #3
    Erfahrener Benutzer Roboter-Spezialist
    Registriert seit
    22.02.2005
    Beiträge
    385
    Ich habe irgendwo gelesen, dass man größere Rechenoperationen nicht in die Interruptroutiene schreiben soll, sondern es mit so einem Flag in der Hauptschleife machen soll. Ich glaube es ging darum, dass während der eine Interrupt in Bearbeitung ist sonst alle anderen blockiert werden oder so ähnlich. Aber mit dem cli() und sei() hast du natürlich Recht wenn ich mir das jetzt so überlege. Dadurch ist ja nichts anders als wenn ich es direkt reinschreibe.
    Timer langsamer laufen lassen ist schlecht, weil sich sonst die Servos zu langsam bewegen. Dann müsste ich die Steps erhöhen was dann zu starkem rückeln führen würde.
    Ich werde das mal testen und dann bescheid sagen, was daraus geworden ist.
    Thx
    jagdfalke

  4. #4
    Erfahrener Benutzer Roboter-Spezialist
    Registriert seit
    22.02.2005
    Beiträge
    385
    Also ich habs jetzt mal so geschrieben (verkürzte Form):
    Code:
    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) {
    			calc_steps();
    			keep_moving();
    		}
    		if(char_flag == 1) {
    			input();
    		}
    	}
    	return 0;
    }
    
    void input(void) {
    	inStr[inCnt] = uart_readChar();
    	printf("\nCHAR RECEIVED: %c\n\r", inStr[inCnt]);
    	switch (inStr[inCnt])
    	{
    	case (stopsign):
    		//parseInput();
    		inCnt=0;
    		break;
    	case (startsign):
    		inCnt=0;
    		break;
    	default:
    		inCnt++;
    		break;
    	}
    	char_flag = 0;
    }
    
    SIGNAL (SIG_OVERFLOW0){
    	servo_flag = 1;
    }
    SIGNAL(SIG_USART_RECV) {
    	char_flag = 1;
    }
    Die keep_moving()-Methode ist noch fast die selbe. Ich habe nur mal statt dem CoController die Werte zu schicken eine Ausgabe über UART draus gemacht, die einem die momentanen Positionen der Servos angibt.
    Die bekomme jetzt auch immer schön regelmäßig Informationen zu den Servopositionen. Wenn ich jetzt ein Zeichen schicke kommt auch "CHAR RECEIVED" allerdings stimmt das Zeichen nie. Entweder piept der PC nur oder es kommt > oder + oder # (das dürften so sie gängigsten sein )

    Weiß jemand woran das liegt?


    mfg
    jagdfalke

  5. #5
    Super-Moderator Robotik Visionär Avatar von PicNick
    Registriert seit
    23.11.2004
    Ort
    Wien
    Beiträge
    6.836
    gönne den beiden ein "volatile", nutzt vielleicht nix, schad aber auch nicht
    volatile char inStr[500];
    volatile int inCnt = 0;
    mfg robert
    Wer glaubt zu wissen, muß wissen, er glaubt.

  6. #6
    Erfahrener Benutzer Roboter-Spezialist
    Registriert seit
    22.02.2005
    Beiträge
    385
    es hat sich nichts geändert. Was ich aber herausgefunden habe ist, dass Großbuchstaben zwar ankommen, aber immernoch der Piep-Ton vom PC ertönt.

  7. #7
    Super-Moderator Robotik Visionär Avatar von PicNick
    Registriert seit
    23.11.2004
    Ort
    Wien
    Beiträge
    6.836
    mmmhhh.
    In einer Uart-Receive ISR Routine ist das mindestens überflüssig
    loop_until_bit_is_set(UCSRA, RXC);
    du wirst ja aufgerufen WEIL ein Zeichen da ist.

    Sind die Zeichen, die du kriegst, überhaupt alle druckbar ? binäre Zeichen < 32 treiben ein Terminal in den Wahnsinn
    (bei 0x07 z.B. piepst er )

  8. #8
    Erfahrener Benutzer Roboter-Spezialist
    Registriert seit
    22.02.2005
    Beiträge
    385
    wenn ich die Zeile
    printf("CHAR RECEIVED: %c\n\r", inStr[inCnt]);
    in
    printf("CHAR RECEIVED: %i\n\r", (int)inStr[inCnt]);
    ändere kommt bei einem kleinen a die Zahl 97. Für b 98 für c 99 usw. Ein großes A bringt 65. Sollte doch stimmen oder?

  9. #9
    Super-Moderator Robotik Visionär Avatar von PicNick
    Registriert seit
    23.11.2004
    Ort
    Wien
    Beiträge
    6.836
    Ganz genau. passt eh alles.
    Zum test kannst du ja unterscheiden
    if (inStr[inCnt]) < 32)
    printf("CHAR RECEIVED: %i\n\r", (int)inStr[inCnt]);
    else
    printf("CHAR RECEIVED: %c\n\r", inStr[inCnt]);
    mfg robert
    Wer glaubt zu wissen, muß wissen, er glaubt.

  10. #10
    Erfahrener Benutzer Roboter-Spezialist
    Registriert seit
    22.02.2005
    Beiträge
    385
    aber kleine Buchstaben gehen überhaupt nicht.

Seite 1 von 5 123 ... LetzteLetzte

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •