Vergesslicher, ungeduldiger atmega bei UART

OP #4702896
Lesenswert?

Moin,
ich will die Werte von 3 Hall Sensoren gerne über UART ausgeben. 
Allerdings nur dann, wenn sie sich auch ändern. Das mit dem Ausgeben 
funktioniert soweit. Das mit dem ändern allerdings nicht. Dafür hatte 
ich eine Variable   sensorold angelegt, die dann mit den aktuellen 
Sensorwerten verglichen wird. Leider wird sie immer wieder 0. In jedem 
Schleifendurchlauf! Ich versteh leider nicht warum. Auch das 
_delay_ms(500) wird scheinbar komplett ignoriert.
1
#include <avr/io.h>
2
#define F_CPU 20000000UL
3
#include <util/delay.h>
4
#define BAUD 9600L
5
#include <stdlib.h> 
6
#include <string.h>
7

8

9

10
int uart_putc(unsigned char character)
11
{  
12
  while (!(UCSR0A & (1<<UDRE0))){}    //warten bis Senden möglich
13
  UDR0 = character;
14
  return 0;
15
}
16
int main(void){
17
  
18
  //Initialisieren
19
  DDRD |=  0b11111100; //Phasen Ausgänge
20

21
  //Ausgangsverknüpfung (clear on compare match)
22
  TCCR1A |= (1<<COM1A1);
23
  
24
  //kein Vorteiler
25
  TCCR1B |= (1<<CS10);
26
  
27
  //Fast PWM, 10-bit
28
  TCCR1A |= (1<<WGM11) | (1<<WGM10);
29
  TCCR1B |= (1<<WGM12);
30
  
31
  //OCR1A = 500; //PWM Wert (MAX 1024)
32
  OCR1A = 300;
33

34
  DDRB |=  0b00000010; //PWM Ausgang
35

36
  //UART
37
  UCSR0B |= (1<<TXEN0);  // UART TX einschalten
38
  // Asynchron 8N1 ist bei mega 168 default
39
  UBRR0 = 129;
40

41
  // Pullups für Hall Sensoren
42
  PORTC|=  0b00111000;
43
  
44
  char sensor[200];
45
  uint8_t sensorold = 0;
46
  uint8_t sensorbin = 0;
47
  
48
  
49
  while (1){
50
      
51
    sensorbin = 0;
52
    
53
    if ( PINC & (1<<PINC5) ) {
54
      sensorbin += 1;
55
    }
56

57
    if ( PINC & (1<<PINC4) ) {
58
      sensorbin += 2;
59
    }
60

61
    if ( PINC & (1<<PINC3) ) {
62
      sensorbin += 4;
63
    }
64
    
65
    if(sensorbin != sensorold){
66
      if (sensorbin & 1){
67
        strcat( sensor, "A1\r\n" );
68
      }
69
      else{
70
        strcat( sensor, "A0\r\n" );  
71
      }
72
      
73
      if (sensorbin & 2){
74
        strcat( sensor, "B1\r\n" );
75
      }
76
      else{
77
        strcat( sensor, "B0\r\n" );
78
      }    
79
    
80
      if (sensorbin & 4){
81
        strcat( sensor, "C1\r\n" );
82
      }
83
      else{
84
        strcat( sensor, "C0\r\n" );
85
      }    
86
      
87
      uint8_t i = 0;
88
      uint8_t l = strlen (sensor);
89
    
90
      while (i <= l){
91
        uart_putc(sensor[i]);
92
        i++;
93
      };
94
        
95
      strcpy(sensor, "");// String leeren  
96
      _delay_ms(500);
97
      sensorold = sensorbin;
98
    }    
99
  }
100
}
OP #4702944
Lesenswert?

Lothar M. schrieb:
> Martin W. schrieb:
>> Auch das _delay_ms(500) wird scheinbar komplett ignoriert.
> Worauf begründest du den Schein? Schließ doch mal ein LED an einen Pin
> an, der mit jedem Zyklus getoggelt wird...

Das leite ich daraus ab, das mir die Konsole innerhalb einer Sekunde 
bereits völlig zugeballert wird. Daher weiß ich ja auch, das der Rest 
funktioniert. Die ausgegebenen Sensorwerte sind richtig. Daher weiß ich 
auch, dass sensorold am ende der Schleife auf keinen Fall mit 0 
überschrieben wird. Trotzdem ist es beim Sprung in den Anfang der 
Schleife wieder 0.(hab ich mir über uart ausgeben lassen)

>
> BTW: der Watchdog ist ausgeschaltet?

Das klingt sehr spannend, aber wie finde ich das heraus? Die Fuse für 
Watchdog ist nicht gesetzt. Und von Hand hab ich da auch nix 
angeschaltet.
OP #4702960
Lesenswert?

jb schrieb:
>>>fake schrieb:
>>> Damit setzt Du doch bei jedem Schleifendurchlauf sensorold auf 0.
>
>>Nö.
>
> Wohle. Ganz sicher.
>
> Gruß J

Warum sollte das so sein ?

Zu beginn der Schleife wird meine Sensorspeicher (sensorbin) gelöscht. 
Dann werden die Sensoren in den Speicher geschrieben. Dass das 
funktioniert hat, weiß ich anhand der UART-Ausgabe. sensorbin ist also 
nun nicht mehr 0. Anschließend wird doch erst sensorold = sensorbin; 
ausgeführt.
OP #4702965
Lesenswert?

Joachim B. schrieb:
> kommst du denn überhaupt in diesen Programmteil?
>
> du nutzt strcat! ohne erstmalig sensor[] überhaupt zu initialisieren.
>
> vermutlich sollte es mal NULL sein aber wer weiss?
>
> Martin W. schrieb:
>> char sensor[200];
>
> sollte besser char sensor[200]={0}; sein bevor es mit strcat weitergeht!

Hab ich geändert. Hilft nur leider nicht. Die Ausgabe bleibt die selbe, 
also z.B.:
A1
B0
C1

Aushabe erfolgt geschätzt 10 mal pro Sekunde, oder öfter.
OP #4702975
Lesenswert?

BlaBla schrieb:
>
1
char sensor[200];
2
>   uint8_t sensorold = 0;
3
>   uint8_t sensorbin = 0;
>
> muss aus der main() heraus.

Warum ?

Peter II schrieb:
> Martin W. schrieb:
>> Aushabe erfolgt geschätzt 10 mal pro Sekunde, oder öfter.
>
> dann hast du ein viel größere Problem:
>
>> _delay_ms(500);
>
> dann sollte maximal 2mal in der sekunde etwas gesendet werden.

Ja davon sprach ich ja auch schon. Deswegen klang das mit dem Watchdog 
ja auch so gut. Aber wenn der nicht per default an ist, kanns das nicht 
sein.
Gast #4702987
Lesenswert?

Wie war das doch nochmal?

Lokale Variablen werden nicht automatisch initialisiert,
globale dagegen schon.

betrifft:
1
char sensor[200];

Eigentlich sollte der Compiler eine Warnung ausgeben ....
Moderator Persönliche Seite #4703005
Lesenswert?

Joachim B. schrieb:
> Martin W. schrieb:
>> char sensor[200];
>
> sollte besser char sensor[200]={0}; sein bevor es mit strcat weitergeht!

Das ist suboptimal. Damit werden sämtliche 200 Speicherstellen von 
sensor in einer Schleife genullt, obwohl das gar nicht notwendig ist.

Die erste Stelle reicht nämlich (wg. strcat):
1
char sensor[200];
2
sensor[0] = '\0';
Gast #4703012
Lesenswert?

BlaBla schrieb:
>
char sensor[200];
>   uint8_t sensorold = 0;
>   uint8_t sensorbin = 0;
>
> muss aus der main() heraus.

Warum ?

Das ist so! Bei jedem Durchlauf der while-Schleife werden die Variablen 
auf Null gesetzt. Mach daraus globale Variablen, dann werden die Inhalte 
beibehalten.
#4703021
Lesenswert?

Frank M. schrieb:
> Das ist suboptimal. Damit werden sämtliche 200 Speicherstellen von
> sensor in einer Schleife genullt,

stimmt, wer packt das auch in eine Schleife im Code, das gehört sich 
anders!

Frank M. schrieb:
> Die erste Stelle reicht nämlich (wg. strcat):char sensor[200];
> sensor[0] = '\0';

auch das stimmt und ist effektiver wenn der sensor[] unbedingt im Code 
in der while stehen bleiben soll!
Moderator Persönliche Seite #4703040
Lesenswert?

BlaBla schrieb:
> Das ist so! Bei jedem Durchlauf der while-Schleife werden die Variablen
> auf Null gesetzt. Mach daraus globale Variablen, dann werden die Inhalte
> beibehalten.

Das ist blanker Unsinn. Die Variablen werden ausserhalb der 
while-Schleife definiert und auf Null gesetzt. Da main() auch nie 
verlassen wird, bleiben sie auch als lokale Variablen die ganze Laufzeit 
am Leben.

Sorry, aber Du scheinst wenig bis gar keine Ahnung von C zu haben. Ich 
wäre vorsichtig mit solchen Vorschlägen.
Moderator Persönliche Seite #4703042
Lesenswert?

Joachim B. schrieb:
> auch das stimmt und ist effektiver wenn der sensor[] unbedingt im Code
> in der while stehen bleiben soll!

Die Definition von sensor[] steht gar nicht in der while-Schleife, 
sondern darüber ;-)

Ausserdem ist eine lokale Variable hier sogar ressourcensparender:

Wenn Du sensor[200] nämlich global definierst, werden trotzdem wieder 
200 Speicherstellen gelöscht, obwohl die erste komplett reicht.

Martin W. schrieb:
> strcpy(sensor, "");// String leeren
1
sensor[0] = '\0'

ist hier etwas eleganter. Man muss nicht unbedingt immer mit Funktionen 
auf Variablen schießen - auch wenn sie in moderneren 
C-Compiler-Umgebungen intern abgebildet werden.
Gast #4703054
Lesenswert?

Martin W. schrieb:
> Ich versteh leider nicht warum. Auch das
> _delay_ms(500) wird scheinbar komplett ignoriert.

wenn dem so ist dann resetet der Controller.

mach doch einfach vor der while in der main eine uart Ausgabe. Sagen wir 
Ausgabe von "start".

Dann siehst Du auf jeden Fall ob ein Reset während des Programmablaufs 
stattfindet.
OP #4703078
Lesenswert?

BlaBla schrieb:
> Noch eine Idee: liegt die richtige Spannung für 20 MHz an.

Spannung sind 4,91V

Werner P. schrieb:
> Martin W. schrieb:
>> Ich versteh leider nicht warum. Auch das
>> _delay_ms(500) wird scheinbar komplett ignoriert.
>
> wenn dem so ist dann resetet der Controller.
>
> mach doch einfach vor der while in der main eine uart Ausgabe. Sagen wir
> Ausgabe von "start".
>
> Dann siehst Du auf jeden Fall ob ein Reset während des Programmablaufs
> stattfindet.

War ne gute Idee. Der Atmel scheint sich neu zu starten. Zumindest wird 
das Start ständig geschrieben. Der neustart erfolgt alle 16 UART Zeichen 
wenn ich mich nicht verzählt hab.
Aber woran kann das liegen ?
Gast #4703106
Lesenswert?

Noch eine Idee: AtmelStudio 7 zeigt mir die Variable "sensorbin" nicht 
im Debugger mit der Compiler-Option -Os an. Die wird scheinbar hinfort 
optimiert. Mit der folgenden Änderung wird sie wieder sichtbar.
1
volatile uint8_t sensorold = 0;
2
volatile uint8_t sensorbin = 0;
Gast #4703141
Lesenswert?

Frank M. schrieb:
>> sollte besser char sensor[200]={0}; sein bevor es mit strcat weitergeht!
>
> Damit werden sämtliche 200 Speicherstellen von
> sensor in einer Schleife genullt, obwohl das gar nicht notwendig ist.

Komisch, mein Compiler initialisiert mit dieser Art
1
char sensor[200]={0};

genau ein Element von sensor[], und zwar das erste. So war
ich es bisher auch gewohnt.

Frank M. scheint einen neuartigen Compiler zu haben oder einen
der einen anderen Standard verfolgt ..... vielleicht M$?
#4703179
Lesenswert?

CRätsel schrieb:
> Frank M. scheint einen neuartigen Compiler zu haben

kann nicht sein, der Frank weiss es immer besser als ich.....

Ich glaube fast ich muss das wirklich auf meinem Compiler untersuchen 
was da genau passiert obwohl es mir total schnurz ist ob

Joachim B. schrieb:
> char sensor[200]={0};

200 Byte auf 0 setzt oder nur das erste Byte

aber da Frank mir wieder mal widersprach:

Frank M. schrieb:
> Das ist suboptimal. Damit werden sämtliche 200 Speicherstellen von
> sensor in einer Schleife genullt

interessiert es mich schon ob mit Recht oder nur weil er ein 
Widerspruchsgeist ist.

CRätsel schrieb:
> Komisch, mein Compiler initialisiert mit dieser Art
> char sensor[200]={0};
> genau ein Element von sensor[], und zwar das erste. So war
> ich es bisher auch gewohnt.

dafür spricht:

http://www.tutorials.at/c/09-arrays-strings.html
Ein wichtiger Punkt bei lokal deklarierten Arrays ist deren 
Initialisierung. Ein Beispiel:

int daten[3] = { 0, 0, 0 };

Hier wird das Array daten mit 3 Elementen vom Typ int deklariert und 
zugleich definiert. Alle drei Elemente werden auf 0 gesetzt 
(initialisiert). Die einzelnen Werte werden dabei der Reihe nach 
zwischen geschwungenen Klammern { } angegeben.

int daten[] = { 4, 10, -20 };

Hier wurde die Anzahl der Elemente in eckigen Klammern weggelassen. Das 
ist immer dann möglich, wenn ein Array gleich initialisiert wird. Denn 
es geht für den Compiler aus der Initialisierungsliste ohnehin hervor, 
wieviel Speicher und Elemente reserviert werden müssen.

Das erste Element (daten[0]) wird mit 4 initialisiert, das zweite 
(daten[1]) mit 10 und das dritte (daten[2]) und zugleich letzte mit -20.
OP #4703196
Lesenswert?

Werner P. schrieb:
> Martin W. schrieb:
>> Aber woran kann das liegen ?
>
> Wenn der Code in deinem Eingangspost alles ist dann kann es eigentlich
> nur noch ein Hardwarefehler sein.
>
> Schaltplan?
>
> Edit: Was passiert wenn Du in der while mal alles ausdokumentierst?

Also ich hab alles im While auskommentiert. Ergebnis: Der Kontroller 
startet permanent neu, statt in der while schleife zu verharren. :'( 
Lass ich ihn etwas Ausgeben, schafft er vor dem Absturz etwa 16 Zeichen. 
Am Reset Pin hab ich mal mit dem Oszi gemessen und konnte nix sehen was 
einen Restart rechtfertigen würde.

Schaltplan hab ich mal angehängt. Ich denke aber mal nicht, dass ich da 
etwas total verkackt habe.
Angehängte Dateien:
Gast #4703206
Lesenswert?

Martin W. schrieb:
> Leider stürzt er immer noch ab.

Aufbau zeigen ....

Die 27pF am Quarz kommen mir etwas hoch vor, könnte die
Betriebssicherheit beeinträchtigen. 18pF müssten reichen.

Ein 78L05 als Spannungsregler ..... ob der Strom ausreicht
um alles zu speisen .... ich weiss nicht was die IRS2184
an Strom ziehen ....

... und wieviel Oberspannung hast du auf der Primärseite
des Reglers?
OP #4703228
Lesenswert?

Frickelfritze schrieb:
> Martin W. schrieb:
>> Leider stürzt er immer noch ab.
>
> Aufbau zeigen ....
>
> Die 27pF am Quarz kommen mir etwas hoch vor, könnte die
> Betriebssicherheit beeinträchtigen. 18pF müssten reichen.
>
> Ein 78L05 als Spannungsregler ..... ob der Strom ausreicht
> um alles zu speisen .... ich weiss nicht was die IRS2184
> an Strom ziehen ....

Der 78L05 versorgt ausschließelich die MCU.

> ... und wieviel Oberspannung hast du auf der Primärseite
> des Reglers?

12V. Die Frage hat das Problem gelöst. Von sowas hab ich noch nie 
gehört, und es ist mir echt peinlich, das die Quasi 1.Frage jeder 
Telefonhotline mein Problem löst. Auf die Frage hin, hab ich das 
Netzteil einmal aus der Steckdose gezogen um nochmal auf die 
Beschriftung zu gucken. 12V DC 800mA. Also eigentlich ok. Nach dem 
wieder reinstecken ging alles.

Ist irgendwem sowas schon mal passiert ? Ich finde das sehr Skuril. Ich 
dachte spätestens nach dem Programmieren und dem damit verbundenen Reset 
müsste ein Absturz des Prozis behoben sein... aber offensichtlich war 
das hier nicht der Fall.

Vielen Dank an alle die geholfen haben und die vielen Tipps nebenbei. 
Der Thread ist damit gelöst.
OP #4703249
Lesenswert?

Frickelfritze schrieb:
> Martin W. schrieb:
>> Also eigentlich ok. Nach dem wieder reinstecken ging alles.
>
> Vielleicht wird es dem 78L05 doch etwas ungemütlich wenn er
> 7 Volt verarbeiten und xx mA liefern muss.

Jup. Also gut anfassen kann man ihn nicht. Ich denke ich werde ihn 
tatsächlich tauschen, zumal in der Endfassung 16,88V anliegen können 
sollen.

Das sind dann 11,88V drop. Bei den erlaubten 100mA wären das dann schon 
Rund 1,2 Watt. Andererseits darf das Ding laut Datenblatt 70°C heiß 
werden.
Moderator Persönliche Seite #4703559
Lesenswert?

CRätsel schrieb:
> Komisch, mein Compiler initialisiert mit dieser Art
> char sensor[200]={0};
> genau ein Element von sensor[], und zwar das erste. So war
> ich es bisher auch gewohnt.
>
> Frank M. scheint einen neuartigen Compiler zu haben oder einen
> der einen anderen Standard verfolgt ..... vielleicht M$?

Der "neuartige" Compiler ist ein stinknormaler avr-gcc.
Testcode:
1
#include <string.h>
2

3
int
4
main ()
5
{
6
    char sensor[200] = { 0 };
7
    strcat (sensor, "Hello World");
8
}

lss-Output:
1
00000096 <main>:
2
  96:  cf 93         push  r28
3
  98:  df 93         push  r29
4
  9a:  cd b7         in  r28, 0x3d  ; 61
5
  9c:  de b7         in  r29, 0x3e  ; 62
6
  9e:  c8 5c         subi  r28, 0xC8  ; 200
7
  a0:  d1 09         sbc  r29, r1
8
  a2:  0f b6         in  r0, 0x3f  ; 63
9
  a4:  f8 94         cli
10
  a6:  de bf         out  0x3e, r29  ; 62
11
  a8:  0f be         out  0x3f, r0  ; 63
12
  aa:  cd bf         out  0x3d, r28  ; 61
13
  ac:  ce 01         movw  r24, r28
14
  ae:  01 96         adiw  r24, 0x01  ; 1
15
  b0:  28 ec         ldi  r18, 0xC8  ; 200
16
  b2:  fc 01         movw  r30, r24
17
  b4:  11 92         st  Z+, r1
18
  b6:  2a 95         dec  r18
19
  b8:  e9 f7         brne  .-6        ; 0xb4 <main+0x1e>
20
  ba:  60 e0         ldi  r22, 0x00  ; 0
21
  bc:  71 e0         ldi  r23, 0x01  ; 1
22
  be:  0e 94 6d 00   call  0xda  ; 0xda <strcat>

Die Initialisierungsroutine geht von 0xac bis 0xb8. Hier werden 200 
Bytes in einer Schleife genullt.

Und jetzt noch die Literatur dazu, dass der avr-gcc das richtig macht, 
während Du entweder irgendetwas dahingeschwätzt oder einen defekten 
Compiler hast:

  http://www.c-howto.de/tutorial-arrays-felder-initialisierung.html

Zitat:
-----------------------------
Ist die Anzahl der Werte bei der Initialisierung kleiner als die 
Feldgröße, werden die restlichen Werte auf Null gesetzt. [...]
Dadurch lässt sich ein Feld auch einfach komplett mit Null-Werten 
initialisieren:

int punkte[5] = { 0 };
-----------------------------

Weitere Links dazu:

  http://stackoverflow.com/questions/2589749/how-to-initialize-array-to-0-in-c
  http://stackoverflow.com/questions/201101/how-to-initialize-all-members-of-an-array-to-the-same-value

Es gibt noch tausende andere Links zu diesem Thema, meinst Du, die lügen 
alle?
Moderator Persönliche Seite #4703572
Lesenswert?

Joachim B. schrieb:
> dafür spricht:
>
> http://www.tutorials.at/c/09-arrays-strings.html
> Ein wichtiger Punkt bei lokal deklarierten Arrays ist deren
> Initialisierung. Ein Beispiel:
>
> int daten[3] = { 0, 0, 0 };
>
> Hier wird das Array daten mit 3 Elementen vom Typ int deklariert und
> zugleich definiert.

Ich muss Dir leider widersprechen: Das spricht überhaupt nicht dafür. 
Das ist der normale Ansatz eines Tutorial-Schreibers, wenn er dem Leser 
die Initialisierung beibringen will.

Der Autor dieses Tutorials kennt lediglich die folgende Regel nicht:

"Wenn eine Initialisierung angegeben wird und diese unvollständig(!) 
ist, wird der Rest automatisch mit Nullen gefüllt".

Die wenigsten kennen diese, obwohl sie steinalt, also keine irgendwelche 
komische "Neuerung" irgendeines Standards ist. Im Gegenteil: Das war 
schon immer so.
Moderator Persönliche Seite #4703619
Lesenswert?

Joachim B. schrieb:
> machst du ja gerne,

:-)

> aber ich räume ein eine Fundstelle ist naturgemäß wenig aussagekräftig.

Was Du da zitiert hast, ist ja nicht falsch - höchstens unvollständig. 
Der Autor hätte auf die zusätzliche Möglichkeit der 
Komplettinitialisierung eines Array ruhig hinweisen können.

Bei
1
int daten[2048] = { 0 };

hätte er nämlich sonst eine ziemliche Schreibarbeit :-)
OP #4703765
Lesenswert?

guest schrieb:
> Frickelfritze schrieb:
>>> dass ich da etwas total verkackt habe.
>>
>> Naja, total nicht aber bisschen schon.
>
> L1 an AREF ist auch eher daneben, die würde eher an AVCC Sinn ergeben.
> Wenn man die Versorgungsspannung als Referenz will setzt man einfach die
> REFSn Bits in ADMUX passend.

Du hast vollkommen recht, da hab ich kacke gebaut! Wird natürlich 
korrigiert.
Moderator Persönliche Seite #4703792
Lesenswert?

Joachim B. schrieb:
> QC hält sich nicht an die automatische Arraygröße wenn Werte vorgegeben
> sind

Die früheren C-Compiler für Windows aus den 80ern haben jede Menge 
falsch bzw. "anders" gemacht als das UNIX-Original. Wirf das QuickC-Buch 
am besten wech oder verfeuere es im Kamin, aber verschenke es 
keinesfalls. Der andere könnte darin lesen und einiges lernen, was 
schlicht und einfach falsch ist. ;-)
#4703795
Lesenswert?

Frank M. schrieb:
> Die früheren C-Compiler für Windows

sorry das war DOS! (alles weisst du auch nicht gelle :)

und das M$ immer alles anders macht weiss man ja, wieso wurde 
dennFAT16(!?) auf int 32k Cluster reglementiert? wenn es auch locker 
uint 64k Cluster sein könnten? denn negative Cluster will ja keiner.

Ich muss noch mal nach meinem Sybex Buch suchen, nur das hier fiel mir 
gerade beim Werkstattumzug in die Hände.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren