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
Lesezeichen