-         

Ergebnis 1 bis 3 von 3

Thema: RN Control - AVRStudio/AVRGCC - USART - Probleme :(

  1. #1

    RN Control - AVRStudio/AVRGCC - USART - Probleme :(

    Anzeige

    Hallo Leute,

    ich muss mich mal an euch wenden, da ich bei meiner RNControl nicht weiter komme. Folgendes versuche ich im Moment:

    ich habe ein Bacom-Programm für die RNControl, wleches funktioniert. An der RNControl angeschlossen ist eine Bluetooth-Karte, welche Daten über USART mit dem uC austauscht und diese an den PC schickt. Dort wird mittels USB-Stick ein Com-Port emuliert, welcher die Daten dann mittels Terminalprogramm anzeigt.
    Man steckt also den USB-Stick in den PC, dieser findet die Bluetooth-Karte am uC und added diesen als Bluetoothgerät. Dadurch erscheinen in der Systemsteuerung zwei Com-Ports (senden, empfangen). Nun kann man mit dem uC komunizieren, indem man über z.b. ein Terminalprogramm Daten an den uC sendet bzw. empfängt.

    Das ganze funktioniert auch mit dem Bascom-Programm ganz gut, jedoch versuche ich Momentan das ganze in AVRStudio mit C hinzubekommen.

    Folgendes Problem habe ich dabei: solange ich die Baudrate bei 9600 belasse, kann ich die Zeichen, die der uC sendet, problemlos im Terminalfenster empfangen, egal was ich bei der Schnittstelle in der Systemsteuerung für Baudrate einstelle und egal was ich beim Terminalprogramm einstelle. Ich bekomme die Daten immer korrekt angezeigt.
    Nun muss ich aber für zukünftige Anwendungen die Datenrate erhöhen, und wollte dazu mal höhere Baudraten testen. Also bin ich auf höhere Werte gagangen (ich habe mittlerweile alle ausprobiert). Das Ergebnis ist jedesmal, dass nur noch Mist im Terminalfenster ankommt. Ob das beim Bascomprogramm auch passiert kann ich im Moment nicht sagen, muss ich erst noch testen...
    Also dachte ich, es liegt an der CPU-Frequenz, da man ja bei 16Mhz einen Fehler in der Baudratenberechnung hat. Also hab ich die CPU-Frequenz umgestellt auf 14.7456 MHz. Das habe ich aber nur über F-CPU im Code gemacht. An dieser Stelle bin ich mir nicht sicher, ob der externe Quarz der RNControl (16Mhz) diese dann auch so genau einstellen kann, oder ob ich dazu noch etwas anderes tun muss oder gar den Quarz tauschen muss. Hintergedanke dabei war, dass bei dieser Frequenz kein Fehler in der Baudratenberechnung auftritt, siehe hier:
    http://www.kreatives-chaos.com/artik...elle-fuer-avrs

    Das Ganze hat dann aber auch nicht funktionierrt

    Hier mal der nötige Code aus meinem Programm, der für die Übertragung zuständig ist:

    Code:
    /*
    ###################################################
    rncontrol_imu.c
    
    Autor: xXx
    ###################################################
    */
    #ifndef F_CPU
    #define F_CPU 16000000UL  
    #endif
    
    
    #include "rncontrol.h"
    #include <avr/interrupt.h>
    
    
    
    /*-------------------------------### Variablen ###----------------------------*/
    volatile uint8_t befehl 	= 	60; 	//0x00;//0x33;
    
    uint8_t 	befehl_int 		=	0;
    uint16_t 	maxSpeed 		= 	1023;	//255;
    uint16_t 	sollSpeed 		= 	202;	//(40/100)*maxSpeed (40% * maxSpeed);
    uint32_t 	BAUD 			= 	9600;//38400;   // Baudrate,
    
    uint16_t 	UBRR_VAL 		= 	0;		//Registerwerte für USART
    uint32_t 	BAUD_REAL		= 	0;     	// Reale Baudrate
    float		BAUD_ERROR_FLAG	= 	0.1; 	// Fehler in Prozent
    
    
    /*-------------------------------### Interrupt-Routinen ###----------------------------*/
    
    ISR(USART_RXC_vect)   /* Zeichen wurde empfangen */ 
    {
    	befehl = (uint8_t) UDR;      /* Empfangener Wert wird gecastet und Übergeben */ 
    } 
    
    
    
    /*----------------------------### Hauptprogramm ###------------------------*/
    int main(void)
    {
    
    
    
    	/*------------------------------### Initialisierungsphase ###-------------------*/
    	UBRR_VAL 	= 	((F_CPU/(BAUD * 16)) - 1);
    	BAUD_REAL 	= 	(F_CPU/(16 * (UBRR_VAL + 1)));
    	//BAUD_ERROR 	= 	(( BAUD_REAL * 100)/BAUD - 100);
    
    	if ((BAUD_REAL - BAUD)!= 0) BAUD_ERROR_FLAG = 1;
    	//BAUD_ERROR_FLAG = 	(float)BAUD_REAL / BAUD * 100; //funktioniert nicht (?)
    
    	//Pins bzw. Ports als Ein-/Ausgänge konfigurieren
    	DDRA |= 0x00;			//00000000 -> alle Analogports als Eingänge
    	DDRB |= 0x03;			//00000011 -> PORTB.0 und PORTB.1 sind Kanäle des rechten Motors
    	DDRC |= 0xFF;			//11111111 -> PORTC.6 und PORTC.7 sind Kanäle des linken Motors, Rest sind LEDs für Lauflicht
    	DDRD |= 0xB0;			//10110000 -> PORTD.4 ist PWM-Kanal des linken Motors, PORTD.5 des rechten
    
    	//Initialisierungen
    	setportcon(0); setportcon(1); setportcon(2); setportcon(3); setportcon(4); setportcon(5); //LEDs ausschalten
    	setportdoff(7);			//Speaker aus
    	init_timer1();			//Initialisierung Timer für PWM
    	init_USART(UBRR_VAL);	//USART konfigurieren
    
    	/*--------------------------### Endlosschleife ###-------------------------*/
    	while(1)
    	{
    		sendUSART("\r\n\n\n"); //Sendet einen kleinen Begrüßungstext. "\r" setzt den Cursor wieder auf Zeilenanfag, "\n" beginnt dann die nächste Zeile
    		sendUSART("LPA-Vehikel activated");
    		sendUSART(" \r\n");
    
    
    		befehl_int = (uint8_t) befehl;  
    		if ((befehl_int) < 39) 
    		{
    			switch(befehl_int)
    			{
    			case 1: Batteriespannung(); befehl_int=101; break;
    			case 2: break;
    			case 3: Stopp(); 			befehl_int=101; break;
    			default: break;
    			}
    		}
    
    	}
    }
    Code:
    /*
    ###################################################
    rncontrol.h
    
    Diese Header-Datei stellt grundlegende Funktionen für das RN-Control 1.4 in C zur Verfügung.
    
    Autor: 
    #######################################################
    */
    
    
    #include <stdlib.h> 
    #include <avr/io.h>
    #include <util/delay.h>
    
    
    
    /*-------------------------------### Variablen ###----------------------------*/
    
    uint16_t analog;						//Variable für jeweils an einem Analogport gemessenen Wert, um nicht für eine Ausgabe mehrere Messungen durchführen zu müssen.
    char wort[5];
    const float referenzspannung = 5/1025;	//Referenzwert zur Multiplikation mit den Werten der Analogports (0...1023), um auf die Voltzahl zu kommen (0...5). Ergibt sich aus 5/1024.
    
    
    
    /*--------------### waitms - Programm pausieren lassen ###---------------*/
    
    /*Die Funktion lässt circa so viele Millisekunden verstreichen, wie angegeben werden.
    Angepasst auf das RN-Control 1.4 mit 16 MHz-Quarz!
    Vorsicht, Wert ist nur experimentell angenähert, nicht exakt berechnet!*/
    
    void waitms(uint16_t ms)
    {
    	for(; ms>0; ms--)
    	{
    		uint16_t __c = 4000;
    		__asm__ volatile (
    			"1: sbiw %0,1" "\n\t"
    			"brne 1b"
    			: "=w" (__c)
    			: "0" (__c)
    			);
    	}
    }
    
    
    
    /*----------------### Senden per USART - RS232-Kommunikation ###---------------------*/
    
    void init_USART(uint16_t UBRR_VAL)
    {
    
    	
    	UBRRL = (uint8_t) (UBRR_VAL & 0x0ff);
    	UCSRB = (1<<RXEN)|(1<<TXEN); 
    	UCSRC = (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0); 
    	/* //Alternativ:
    	// Baudrate einstellen (Normaler Modus)
    	UBRRH = (uint8_t) (UBRR_VAL>>8);
    	UBRRL = (uint8_t) (UBRR_VAL & 0x0ff);
    
    	// Aktivieren von receiver und transmitter
    	UCSRB = (1<<RXEN)|(1<<TXEN);
    
    	// Einstellen des Datenformats: 8 Datenbits, 1 Stoppbit
    	UCSRC = (1<<URSEL);
    	UCSRC|= (1<<UCSZ1)|(1<<UCSZ0);
    	*/
    
    
    }
    
    
    
    void sendchar(unsigned char c)
    {
    	while(!(UCSRA & (1<<UDRE))) //Warten, bis Senden möglich ist
    	{
    	}
    
    	UDR = c; //schreibt das Zeichen aus 'c' auf die Schnittstelle
    }
    
    
    void sendByte(uint8_t c)
    { 
    	while(!(UCSRA & (1<<UDRE))); 
    	UDR = c; 
    }
    
    
    
    void sendUSART(char *s) //*s funktiniert wie eine Art Array - auch bei einem String werden die Zeichen (char) einzeln ausgelesen - und hier dann auf die Sendeschnittstelle übertragen
    {
    	while(*s)
    	{
    		sendchar(*s);
    		s++;
    	}
    }
    
    
    uint8_t receiveUSART(void) //*s funktiniert wie eine Art Array - auch bei einem String werden die Zeichen (char) einzeln empfangen
    {
    	while (!(UCSRA & (1<<RXC)));
    
    	return UDR;                   // Zeichen aus UDR an Aufrufer zurueckgeben
    }
    
    
    /*--------------------------### ADC-Ansteuerung ###-------------------------*/
    /*### ADC-Ansteuerung ###*/
    
    uint16_t adcwert(uint8_t kanal)
    {
    	uint16_t wert = 0;										//Variable für Ergebnis deklarieren
    
    	ADCSRA = (1<<ADEN)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0);	//ADEN aktiviert überhaupt erst den internen ADC-Wandler, ADPS2 bis ADPS0 stellen den verwendeten Prescaler ein, denn die Wandlerfrequenz muss immer zwischen 50 und 200 kHz liegen! Der Prescaler muss bei 16MHz also zwischen 80 und 320 eingestellt werden, als einzige Möglichkeit bleibt hier 128 (=alle auf 1).   
    
    	ADMUX = kanal;
    	//ADMUX = (1<<REFS1)|(1<<REFS0);						//Einstellen der Referenzspannung auf "extern", also REFS1 und REFS0 auf "0" - daher auskommentierte Zeile
    
    	ADCSRA |= (1<<ADSC);									//nach Aktivierung des ADC wird ein "Dummy-Readout" empfohlen, man liest also einen Wert und verwirft diesen, um den ADC "warmlaufen zu lassen"      
    	while(ADCSRA & (1<<ADSC)) {}							//auf Abschluss der Konvertierung warten
    	wert = ADCW;											//ADCW muss einmal gelesen werden, sonst wird Ergebnis der nächsten Wandlung nicht übernommen.
    
    	/* Eigentliche Messung - Mittelwert aus 4 aufeinanderfolgenden Wandlungen */
    	wert = 0; 
    	for(uint8_t i=0; i<4; i++)
    	{
    		ADCSRA |= (1<<ADSC);				//eine Wandlung "single conversion" starten
    		while(ADCSRA & (1<<ADSC)) {}		//auf Abschluss der Konvertierung warten
    		wert = wert + ADCW;		    		//Wandlungsergebnisse aufaddieren
    	}
    
    	ADCSRA &= ~(1<<ADEN);					//ADC deaktivieren
    
    	wert = wert/4;							//Durchschnittswert bilden
    
    	return wert;
    }
    
    
    /*### PWM-Routinen zur Motoransteuerung ###*/
    
    void init_timer1(void)	//Initialisierung des Timers für Erzeugung des PWM-Signals
    {
    	/* normale 10-bit PWM aktivieren (nicht invertiert),
    	Das Bit WGM10 wird im Datenblatt auch als PWM10 (PWM, Phase Correct) bezeichnet */
    	TCCR1A = (1<<COM1A1)|(1<<COM1B1)|(1<<WGM10) |(1<<WGM11);
    
    	/* Einstellen der PWM-Frequenz auf 16Mhz/2/8/255 Mhz = 4 khz ( Prescaler = 8 ) */
    	TCCR1B = (1<<CS10);
    
    	/* Interrupts für Timer1 deaktivieren
    	Achtung : Auch die Interrupts für die anderen Timer stehen in diesem Register */
    	TIMSK &= ~0x3c;
    }
    
    
    /*-------------------------### Batteriespannung ###-----------------------*/
    void Batteriespannung(void)
    {
    	sendUSART("Analog6 = "); analog = adcwert(6);
    	utoa(analog, wort, 10);	sendUSART(wort); sendUSART(" = ");
    	dtostrf(analog*referenzspannung, 11, 8, wort);	sendUSART(wort); sendUSART(" Volt\r\n");
    	dtostrf(adcwert(6)*referenzspannung*5.66804, 11, 8, wort);
    	sendUSART("Batteriespannung = "); sendUSART(wort); sendUSART(" Volt\r\n\n\n\n");
    	waitms(300);
    }
    Was mir beim Simulieren noch aufgefallen ist:
    Wenn man URSEL auf eins setzt, soll laut Datenblatt nur das Register UCSRC geschrieben werden, und UBRRH davon nicht betroffen sein. Simuliert man nun aber mit dem Code von oben (egal ob man diesen hier oder den alternativ angegebenen nutzt), so wird URSEL auch schön gesetzt, nur wenn man dann die beiden anderen ((1<<UCSZ1)|(1<<UCSZ0)) setzt, wird UBRRH wieder überschrieben. Da dieser Code aber im Forum hier auch oft benutzt wird, wundert mich, dass er richtig sein soll, da das Register UBRRH ja ein Teil des Baudratenwertes ist, und dieser damit verändert wird, obwohl das laut Datenblatt mit UBSEL auf high nicht passieren sollte... Aber ob das meine Probleme mit der USART-Übertragung verursacht oder nicht, kann ich nicht sagen, ich komme im Moment damit nicht weiter :/

    Wo ich mir beim empfangen von Zeichen auch nicht sicher bin:
    Code:
    befehl=receiveUSART();
    Wenn man das im Main-Programm in jeder Schleife macht, un der uC aber nichts empfängt, geht das Programm dann trotzdem weiter, oder wartet es in der Funktion receiveUSART() auf jeden fall, bis ein Zeichen kommt? Falls das so ist, sollte doch meine Interrupt-Routine zum empfangen reichen oder?

    Vielleicht seht ihr ja einen Fehler an der ganzen Sache?

    Schönen Sonntag noch,
    Thomas

  2. #2
    Erfahrener Benutzer Robotik Visionär Avatar von Hubert.G
    Registriert seit
    14.10.2006
    Ort
    Pasching OÖ
    Beiträge
    6.186
    Wenn du einen 16MHz Quarz hast dann hast du bei diversen Baudraten, wie schon richtig erkannt, einen Fehler. Es nützt aber nichts nur die Baudrate im Programm zu ändern und eine andere Quarzfrequenz einzugeben, du musst auch den Quarz ändern.
    Grüsse Hubert
    ____________

    Meine Projekte findet ihr auf schorsch.at

  3. #3
    Hi Leute,

    also ich hab jetzt mal bissel rumprobiert:

    Jetzt funktioniert mein Programm komplett über Interrupt, ich kann also Zeichen mit dem Mega32 empfangen (momentan nur eins, da noch kein Buffer eingebaut ist), und ich kann mit dem PC Zeichen empfangen.

    Das alles funktioniert wunderbar bei 9600 Baudrate.
    Bei höheren Raten geht gar nix mehr, es kommt nur mist am PC an und es werden scheinbar keine Zeichen vom uC empfangen.

    Ich hab mir jetzt mal ein Kabel gemacht zur Überbrückung des Bluetooth-Chips. Vielleicht liegt ja dar Fehler.

    Falls noch jemand ne Idee hat: bitte melden

    Gruß
    Thomas

Berechtigungen

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