Hi,
ich brauche Hilfe bei meinem AVR-C Code fuer einen ATmega8. Um Kontext
zu schaffen: Dieser Code soll mithilfe des ADCs die Spannung eines
Spannungsteilers einlesen. Diese value wird an die Funktion
'Update_CtrlCntr1' uebergen, welche sie so umrechnet, dass ich fuer den
Counter 1 eine Compare-value bekomme, die die ON-Time eines von diesem
Counter generiertem 50-Hz Signal bestimmt.
Wie man im Code unten sieht, wird der character cmd als 'f' gesetzt. In
diesem Mode liest der ADC bei jedem Durchlauf der while Schleife eine
neue value von dem Spannungsteiler ein und updated so die ON-Time des
PWM-Signals.
Nun, ich moechte diesen ATmega mithilfe eines Arduinos steuern, heisst,
ich sende ueber Serial die characters 'A', 'B', 'C', ... und moechte,
dass die in der Switch Case Anweisung spezifizierte mot_control value
benutzt wird und solange cmd nicht 'f' ist, der ADC nicht aktiv ist (Die
mot_control value also fest ist). Mithilfe der 'Serial_avail()'
Funktion wird, wie es der Name verratet, gecheckt, ob das 'RXC' (Receive
Complete) Bit gesetzt ist, bzw. etwas empfangen wurde, also etwas im
'UDR' Register ist. Nur falls diese Funktion eine '1' zurueckgibt, soll
der command eingelesen und verarbeitet werden.
Mein Problem ist, dass der ATmega zwar das PWM-Signal richtig generiert
und den ADC richtig einliest, aber nicht auf die vom Arduino gesendeten
Bytes reagiert. Generell, wenn ich in der 'default' Sektion der Switch
Case Anweisung NICHT den cmd direkt wieder auf 'f' setze, die anfangs
anliegende Spannung eingelesen wird und gesetzt BLEIBT, egal ob ich die
Spannung veraendere. Also wird sofort in die Switch Case Anweisung
geleitet und die Variable cmd geaendert. Ein Senden von commands bringt
nichts. Ich hab mir das jetzt schon ziemlich oft durchgeschaut, etwas
veraendert, komm jedoch nicht auf den Fehler. Kann sein, dass es etwas
offensichtliches ist, wer weiss.
Unten hier liegen die Codes fuer die Main-Funktion, Serial_init
Funktion, Serial_avail Funktion und Serial_read Funktion.
Vielen Dank im Voraus!
1
intmain(void)
2
{
3
Serial_init(MYUBRR);
4
Init_CtrlCntr1();// Control Counter 1
5
Init_ADC();
6
7
intmot_ctrl;// motor control value (10-bit because ADC)
8
charcmd='f';//cmd = 'command' received by Arduino
9
10
while(1)
11
{
12
if(cmd=='f')mot_ctrl=ADC_read(ADC_INPUT);
13
Update_CtrlCntr1(mot_ctrl);
14
15
if(Serial_avail()==1){
16
cmd=Serial_readChr();
17
switch(cmd){
18
case'A':mot_ctrl=0;break;
19
case'B':mot_ctrl=114;break;
20
case'C':mot_ctrl=228;break;
21
case'D':mot_ctrl=341;break;
22
case'E':mot_ctrl=455;break;
23
case'F':mot_ctrl=569;break;
24
case'G':mot_ctrl=683;break;
25
case'H':mot_ctrl=796;break;
26
case'I':mot_ctrl=910;break;
27
case'J':mot_ctrl=1024;break;
28
default:cmd='f';break;
29
}
30
}
31
}
32
}
1
voidSerial_init(intubrr){
2
UBRRH=0;
3
UBRRL=0;
4
UCSRA=0;
5
UCSRB=0;
6
UCSRC=0;
7
8
// Set UBRR for BAUD
9
UBRRH=ubrr>>8;
10
UBRRL=ubrr&0xFF;
11
// Enable Receiver and/or Transmitter (Here only RX)
12
UCSRB|=(1<<RXEN);
13
// Set Modes (Here Asynchronous modes, no parity, 8 data bits, 1 stop bit)
14
UCSRC|=(1<<UCSZ1)|(1<<UCSZ0);
15
}
1
intSerial_avail(){
2
if(UCSRA&(1<<RXC))return1;
3
elsereturn0;
4
}
1
charSerial_readChr(){
2
// Return Value currently in the Data Register
3
returnUDR;
4
}
Hier auch noch die Berechnung der UBRR-value mit der Baudrate und dem
Clock-Speed.
War mir zuviel Text, habe ich nicht gelesen. Aber:
1. Es wird MYUBRR definiert, aber ubrr zugewiesen.
2. Es handelt sich doch um C, warum also dieser Klimmzug mit UBRRH und
UBRRL statt gleich UBRR=MYUBRR;?
3. und vor allem:
1
UCSRC|=(1<<UCSZ1)|(1<<UCSZ0);
aus dem Datenblatt:
"• Bit 7 – URSEL: Register Select
This bit selects between accessing the UCSRC or the UBRRH Register. ...
The URSEL must be one when writing the UCSRC."
Am besten UCSRC gar nicht anfassen, der Reset-Wert passt schon.
Vielen Dank, hab dies versucht, jedoch keinen Erfolg mit der Formel
erzielen koennen.
Hab deinen Vorschlag das empfangene direkt wieder an den Arduino
zurueckzusenden versucht, bekomme aber gar nichts zurueck. Bekomme, wie
man in der angehaengten Datei sieht, nur am Anfang, wenn ich den Arduino
(mit dem der ATmega versorgt wird) einstecke und den Serial Monitor
oeffne etwas zurueck... und zwar anscheinend nichts.
Hier auch noch meine Veraenderungen im AVR-Code, will nicht was
offensichtliches wieder stundenlang suchen...
1
intmain(void)
2
{
3
Serial_init(MYUBRR);
4
Init_CtrlCntr1();// Control Counter 1
5
Init_ADC();
6
7
intmot_ctrl;// motor control value (10-bit because ADC)
8
charcmd='f';//cmd = 'command' received by Arduino
9
10
while(1)
11
{
12
if(cmd=='f')mot_ctrl=ADC_read(ADC_INPUT);
13
Update_CtrlCntr1(mot_ctrl);
14
15
if(Serial_avail()==1){
16
cmd=Serial_readChr();
17
Serial_sendChr(cmd);
18
switch(cmd){
19
case'A':mot_ctrl=0;break;
20
case'B':mot_ctrl=114;break;
21
case'C':mot_ctrl=228;break;
22
case'D':mot_ctrl=341;break;
23
case'E':mot_ctrl=455;break;
24
case'F':mot_ctrl=569;break;
25
case'G':mot_ctrl=683;break;
26
case'H':mot_ctrl=796;break;
27
case'I':mot_ctrl=910;break;
28
case'J':mot_ctrl=1024;break;
29
default:cmd='f';break;
30
}
31
}
32
}
33
}
1
voidSerial_init(intubrr){
2
UBRRH=0;
3
UBRRL=0;
4
UCSRA=0;
5
UCSRB=0;
6
UCSRC=0;
7
8
// Set UBRR for BAUD
9
UBRRH=ubrr>>8;
10
UBRRL=ubrr&0xFF;
11
// Enable Receiver and/or Transmitter (Here only RX)
12
UCSRB|=(1<<RXEN)|(1<<TXEN);
13
// Set Modes (Here Asynchronous modes, no parity, 8 data bits, 1 stop bit)
14
UCSRC|=(1<<UCSZ1)|(1<<UCSZ0);
15
}
1
voidSerial_sendChr(charcsend){
2
while(!(UCSRA&(1<<UDRE)))/* warten bis Senden moeglich */
UBRRH und UCSRC haben beim Atmega8 dieselbe Adresse. Damit die Daten ins
UCSRC geschrieben werden, muß das URSEL-Bit gesetzt werden. Sonst
überschreibst du UBRRH und deine Baudrate stimmt nicht mehr.
Das ist das, was dir S. Landolt mit seinem Punkt 3 sagen wollte.
Also: RTFM, Seite 146.
S. Landolt schrieb:> Und was ist nun mit dem UCSRC im geänderten Programm?
Sorry, hab erstmal das oben versucht, hab das erst gelesen.
Hab jetzt das URSEL Bit gesetzt und siehe da -> geht!
Vielen Dank! Tja, da lohnt es sich halt wirklich genau im Datenblatt zu
lesen anstatt Code von einem anderen ATmega zu nehmen ;)
Falls irgendwer den Thread findet und das gleiche Problem hat:
Wenn man irgendwas beim USCRS Register beim ATMega 8 (vielleicht auch
anderen ATmegas, muss man nachschauen) aendern will, z.B. die Anzahl an
zu empfangenen Bits zu setzen usw. muss auch unbedingt das URSEL Bit in
dem USCRS Bit gesetzt sein, sonst wird das UBRRH Register verwendet.
Natuerlich wenn man aufs UBRRH Register schreiben will das Bit wieder
auf 0 setzen.
S. Landolt schrieb:> So wie ich das sehe, betreiben Sie die Schnittstelle mit 5 bit und 40> Bd.
Falsch gesehen, das ist ärgerlich.
Also nochmal (und damit Thomas Eckmann bestätigen): das
1
UCSRC=0;
läuft ja in UBRRH, folglich bleibt UCSRC auf 8 bit; mit
1
UCSRC|=(1<<UCSZ1)|(1<<UCSZ0);
wird UBRRH auf 6 gesetzt und somit die Übertragungsrate auf rund 40 Bd.