PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : UART problem mega168



lionking
10.04.2006, 21:13
moin,
ich hab ein problem, und zwar versuche ich einen über adc eingelesenen wert über uart an den pc zu übertragen, das kabel hab ich mir gelötet und es scheint zu funzen, denn es kommt was an, aber nicht das was ich will.
es kommen immer C mit häkchen unten an...

ich benutze das terminal von Bascom.
Einen mega168, programmiert in avr-studio

hier der wichtige code (das mit dem ADC funzt, deswegen hab ichs weggelassen)


#include <avr/io.h>

int uart_putc(unsigned char d);
void uart_puts (char *s);

void init_uart(void)
{
UBRR0H = (unsigned char) (103>>8);
UBRR0L = (unsigned char) 103;
UCSR0B = (1<<RXEN0) | (1<<TXEN0);

}

int main(void)
{
init_uart();

uint8_t d = 231;

while (1)
{
while (!(UCSR0A & (1<<UDRE0))); // warten bis Senden moeglich
UDR0 = d; // sende Zeichen
}

return 0;
}

int uart_putc(unsigned char d)
{
while (!(UCSR0A & (1<<UDRE0))); /* warten bis Senden moeglich */
UDR0 = d; /* sende Zeichen */
return 0;
}

void uart_puts (char *s)
{
while (*s)
{ /* so lange *s != '\0' also ungleich dem "String-Endezeichen" */
uart_putc(*s);
s++;
}
}

kanal28
10.04.2006, 22:35
hallo lionking - ich mal wieder ;-)

also der code in main() und init_uart() sieht ok aus. Habe gerade gelernt, dass UCSR0C bereits vorinitialisiert ist...

Habe das Programm auf meinen mega168 geladen und es läuft mit Hyperterminal (Windows XP). Dein mega168 ist mit 4 MHz getaktet? Dann sollten die 103 wohl stimmen - habe es mit 207 getestet, weil meiner mit 8 MHz getaktet ist (außerdem habe ich es mit d = 83) getestet - Zeichen 231 ist etwas obskur. Hast Du das Terminal richtig eingestellt (2400, 8bit, no parity, 1 Stopbit)?

Dann könnte der Fehler ja doch am Kabel liegen?

Gruß
kanal28

lionking
10.04.2006, 22:35
soo ich hab mal die baudraten im terminal durchprobiert und tatsächlich funktioniert es bei 1200... wie kommt das??? ich hab doch im code 9600 eingestellt.
oder läuft mein mega168 etwa auf einer anderen frequenz? eigentlich sollen es 16Mhz sein... wie kann ich das testen?

lionking
10.04.2006, 22:46
sowas nenn ich timing :D wir warn gleichzeitig...

laut der formel F_CPU/(rate*16)-1 läuft mein avr mit ner frequenz von 2mhz
also liegt da der fehler.

achja, wo gibs das hyperterminal?

und ich hatte auch beim pwm das problem dass die frequenz nicht stimmte, jetzt weiss ich warum

also woher kommts, dass ich nur 2mhz hab?

kanal28
10.04.2006, 23:10
cool, aber eine ne Sekunde war ich vorn! :-)

also 2 MHz finde ich auch seltsam - original sollte es wohl 1 MHz sein. Hm, habe hier ein Tool zur Berechnung von http://www.rowalt.de/ - da gibts eine Berechnungsoption "double speed transmission" - dann wäre Deiner mit 1 MHz getaktet - aber das müsste man in UCSR0A aktivieren. Also Bascom kann ja die Fusebits auslesen - da kannst Du sehen, wie er getaktet ist.

Hyperterminal ist im Zubehör->Komm, wird aber nicht standardmäßig installiert. http://rowalt.de/ hat auch ein nettes kleines Terminalprogramm

kanal28

PS: welche Funktion erkundest Du als nächstes, dann kann ich mich schon mal vorbereiten ;-)

lionking
10.04.2006, 23:19
in bascom hab ich das entsprechende fusebit auf 1111:1111 external Xtal... und der hat 16Mhz

hyperterminal hab ich gefunden...danke

das nächste wird wohl die ansteuerung eines displays sein, aber da ich noch keins hab wird das wohl och nen paar tage dauern... vielleicht bis dahin schonmal interrupt und son kram :D

nochwas:
eher ein C problem, ich will ja den wert des adc per uart ausgeben...
jetzt wollte ich das so machen:

c = ReadChannel(1); //lese analogen wert aus channel 1 in c

unsigned char y[] = "der Wert ist: %i \r\n", c;

uart_puts(y); // sende Zeichen

nur kommt beim terminal
der Wert ist: %i
an... wie mache ich das, dass dann da
der Wert ist:
und dann der wert steht?

kanal28
10.04.2006, 23:48
Also die Taktfrequenz verbuche ich erstmal als rätselhaft - keine Ahnung was da ist.

Du musst den Zahlenwert in einen String umwandeln. Eine formatierte Ausgabe kriegst Du mit sprintf() hin (http://www.elook.org/programming/c/sprintf.html). Leider wird der Code dann ziemlich groß. Etwas sparsamer, aber ohne Formatierung sind itoa() und dtostrf() - sind wohl beide nicht Standard-C; google sollte weiterhelfen.

kanal28

PS: Wenn Du schon mal LCD üben willst - mit der großartigen Sim-Seite hier habe ich mein LCD verstanden http://www.geocities.com/dinceraydin/djlcdsim/djlcdsim.html

lionking
10.04.2006, 23:58
hab rausgefunden woran das mit dem tackt lag... da war noch nen fusebit gesetzt, nähmlich "divide Clock by 8" :D daher die 2Mhz
naja jetzt hab ich die 16Mhz, aber muss nun die teiler neu einstellen vom adc und pwm

es funzt mit itoa()... so:



...
c = ReadChannel(1); //lese analogen wert aus channel 1 in c

OCR1A = c; //sende wert zum PWM

unsigned char y[] = "Der Wert ist: ";

unsigned char z[3];

itoa(c, z, 10);

uart_puts(y); // sende Zeichen
uart_puts(z);
uart_puts("\r\n");
...

lionking
16.04.2006, 02:01
so neues problem, dismal mit der ansteuerung eines servos...
noch ohne interrupt... sollte ich mir glaubich mal angucken...
naja hier mal der code, er sollte denke ich genug kommtentiert sein.

#include <avr/io.h>
#include <my.h>

int main(void)
{
DDRD |= (1<<PD2); //PORTD2 wird als ausgang gesetzt

uint16_t a = 0; //wert des adc
uint32_t a32 = 0; //wert des adc in 32bit, zum berechnen

uint8_t ar = 0; //Statuswerte: ob der ADC ausgelesen wurde
uint8_t t = 0; //und in welchem Abschnitt wir sind

while(1)
{
if(t==0) //wenn wir im zweiten zyklus sind...
{
if(!ar) //wenn der ADC noch nicht ausgelesen wurde wird das getan
{
a32 = ReadChannel(0)*125/8+16000; //ADC wird ausgelesen und "normiert" auf 16000-32000 (1-2ms)
a = (uint16_t) a32;
ar = 1; //ADC wurde ausgelesen
}

if(TCNT1 >= 20000) //wenn der Timer bei 20000 ist (10ms) wird:
{
t = 1; //sind wir als nächstes im ersten Zyklus, also wird:
TCCR1B |= (1<<CS10); //PORTD2 gesetzt,
PORTD |= (1<<PD2); //der Taktteiler auf 1 gestellt
TCNT1 = 0; //und der Timer zurückgesetzt
}
}

if(t==1) //wenn wir im ersten Zyklus sind...
{
if(TCNT1 >= a) //...und der Timer den ausgerechneten Wert erreicht hat
{
t = 0; //sind wir als nächstes im zweiten Zyklus, also:
ar = 0; //ist der ADC-Wert verbraucht
TCCR1B |= (2<<CS10); //und der Taktteiler wird auf 8 gestellt,
PORTD &= ~(1<<PD2); //PORTD2 wird nicht gesetzt
TCNT1 = 0; //und der Timer wird zurückgesetzt
}
}
}

return 0;
}

leider funzt es nicht, wahrscheinlich irgend ne blöde sache drin...
naja an PD2 kommt jedenfalls nix an
ReadChannel is von mir und funzt auf jeden Fall.

edit, blöder fehler,, hab ich grad gemerkt, der timer sollte vielleicht gestartet werden :D
naja er macht trotzdem noch nicht was er soll, es ist einfach ne rechteckspannung am ausgang

lionking
16.04.2006, 18:45
so es funzt... irgendwie hat das mit der umrechnung auf 16-32k nich geklappt... jetzt gehts
hab folgendes geändert:

a32 = ReadChannel(0); //ADC wird ausgelesen und "normiert" auf 16000-32000
a32 = a32*125/8+16000;
a = (uint16_t) a32;