PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Probleme bei Strukturen (Projekt Funkuhr)



Wasserkäfer
10.07.2008, 19:58
Hallo,

bin gerade dabei mir eine Funkuhr zu bauen. Das Signal empfange ich mittlerweile problemlos. Jetzt wollte ich das empfangene Signal umwandeln aber das klappt überhaupt nicht.

Ich speichere die ganzen 59 Bits in char dcf[60];
Nun wollte ich das aber über eine Struktur lösen. In meinem Programm zählt eine Variable dcf_ctr die einzelnen Bits des Signals hoch. Habe mal mit einer Struktur angefangen um die Wetterinformationen zu speichern aber habs nicht geschafft die ersten 15 bits in der Struktur zu speichern. Hier mal mein Code:


#include "avr/io.h"
#include "function.h"
#include <avr/interrupt.h>

volatile uint16_t dcf_time = 0; //Zählvariable DCF Pausen
uint8_t dcf_before = 1; //DCF Signal zuvor
uint8_t dcf_flag = 0; //DCF Signal aktuell
uint8_t dcf_ctr = 0; //DCF Bitzähler
char dcf[60]; //Codiertes DCF Signal 59 bit

int main (void)
{

//Port Konfiguration DCF77 Empfänger

dcf_ddr &= ~(1<<dcf_bit); //PinX als Eingang definieren
dcf_port |= (1<<dcf_bit); //Pullup Widerstand für diesen Pin aktivieren



//Debug Konfiguration, LED1, LED2


DDRC |= (1<<0) | (1<<1); //Bit0 PortC Ausgang
PORTC |= (1<<0) | (1<<1); //Led an PortC aus

//Timer 1 starten, Globale Interrups aktivieren
init_timer();
//USART initialisieren
init_USART();

/*###############################################
# #
# Hauptprogramm #
# #
################################################*/
while(1)
{

//##################### DEBUG ### LED1 zeigt DCF77 Signal#####################
if (dcf_pin & (1<<dcf_bit))
PORTC |= (1<<0); // Ausführen wenn HIGH
else
PORTC &= ~(1<<0); // Ausführen wenn LOW
}
return 0;
}





//Portzustand DCF77 einlesen und in dcf_flag schreiben
int get_dcf_bit()
{
if (dcf_pin & (1<<dcf_bit))
{
dcf_flag = 1;

}else{
dcf_flag = 0;
}
return(dcf_flag);
}

SIGNAL (SIG_OUTPUT_COMPARE1A)
{
PORTC ^= (1<<1); //DEBUG Zeige Frequenz vom Timer-Interrupt an LED2
get_dcf_bit(); //Pegel vom DCF Signal einlesen und in dcf_flag speichern

if(dcf_flag == 1) //Wenn DCF Signal HIGH > Zeit messen
{
if(dcf_flag == dcf_before) //Führe aus, wenn sich Pegel nicht geändert hat
{
dcf_time += 20; //Zeit +20ms
}else{ //Führe aus bei Pegeländerung
if(dcf_time > 770 && dcf_time < 830) //Erkenne Pause von 800 ms = logisch 1
{
dcf[dcf_ctr] = '1';
dcf_ctr++;
}
if(dcf_time > 870 && dcf_time < 930) //Erkenne Pause von 900 ms = logisch 0
{
dcf[dcf_ctr] = '0';
dcf_ctr++;
}
if(dcf_time > 1770 && dcf_time < 1830) //Erkenne Pause von 1800 ms = logisch 1, Ende der Übertragung
{
dcf[dcf_ctr] = '1';
sendUSART(dcf);
sendUSART("\r\n");
dcf_ctr = 0;
}
if(dcf_time > 1870 && dcf_time < 1930) //Erkenne Pause von 1900 ms = logisch 0, Ende der Übertragung
{
sendUSART(dcf);
sendUSART("\r\n");
dcf_ctr = 0;
}
dcf_time = 0; //Zeitvariable zurücksetzen
}
}
dcf_before = dcf_flag; //Alten Pegel in der Variable dcf_before speichern
}


Alles was mit der Struktur zu tun hatte wurde entfernt da das Programm sonst nimmer korrekt funktionierte.

Meine Struktur sah so aus:
Mit voran gestellten typedef hat mir AVR Studio gleich nen Fehler ausgespuckt. Kann mir einer sagen warum?

struct
{
weather[15];
}dcf_struct;


Und zum speichern habe ich bei jeder Pausenerkennung eine if-Abfrage eingebaut. Hier das Beispiel für ne 1 erkannt.

if(dcf_ctr <=14){
dcf_struct.weather |= (1<<dcf_ctr);
}

Der richtig Emfpangene DCF String hat nie mit dcf_struct.weather übereingestimmt. Hab auch Probleme dcf_struct.weather über USART auszugeben. Sendet nur wirres Zeug und itoa geht auch nicht.
Das man USART nicht in Interrupts aufruft ist mir klar, ist nur zum Debuggen drinn :)

Wäre um jede Hilfe froh wie ich das mit Strukturen lösen kann.
Vielen Dank schonmal

sternst
10.07.2008, 20:10
Mit voran gestellten typedef hat mir AVR Studio gleich nen Fehler ausgespuckt.
Und wie lautete der?


struct
{
weather[15];
}dcf_struct;
Und poste bitte nochmal die tatsächliche Definition von dcf_struct, denn diese wirst du wohl kaum benutzt haben, schließlich hat weather da gar keinen Typ.

Wasserkäfer
10.07.2008, 20:59
Sorry hat sich wohl ein Fehler eingeschlichen O:) Um mich mit Strukturen vertraut zu machen hab ich am Anfang ne ganz einfache genommen. Hier klappts mit typedef nicht:

typedef struct
{
uint16_t weather:15;
}dcf_s;

+

dcf_s.weather = 3;

ergibt den Fehler : ../dcf77.c:51: error: expected identifier or '(' before '.' token
Lass ich das typedef weg funktionierts

Da fällt mir gerade auf: Wo liegt der Unterschied wenn ich bei struct einmal uint16_t weather:15; schreibe oder uint16_t weather[15];?

Leider klappts da nicht viel bis jetzt, Tutorial hab ich das von RN-Wissen

Danke
lg

the_Ghost666
10.07.2008, 22:22
Ich wüsste jetzt auhc keine konkrete Antwort, hatte aber mal ähnliche Fragen, vielleicht findest du hier noch ein paar Antworten auf deine: https://www.roboternetz.de/phpBB2/viewtopic.php?t=40386

sternst
10.07.2008, 22:24
Lass ich das typedef weg funktionierts
Mit typedef erzeugst du einen neuen Typ "dcf_s". Du musst dann erstmal eine Variable dieses neuen Typs erstellen, also z.B.:

dcf_s SomeVar;
SomeVar.weather = 3;

Ohne das typedef erzeugst du eine Variable mit Namen "dcf_s", die du dann direkt verwenden kannst.


Wo liegt der Unterschied wenn ich bei struct einmal uint16_t weather:15; schreibe oder uint16_t weather[15];?

Das erste ist ein Bit-Field, das zweite ein Array.

Nimm es mir bitte nicht krumm, aber bei dir fehlen ja noch essentielle Grundlagen der Programmiersprache C. Bitte nimm dir mal ein C Buch zur Hand und lese dich da etwas ein. Man lernt C nicht mal so eben nebenbei durch Try&Error oder durch ein paar Fragen in einem Forum.

Wasserkäfer
11.07.2008, 12:18
Vielen Dank

typedef hab ich einfach falsch im Wiki verstanden aber nu klappts. Bitfelder kannte ich bis jetzt einfach nicht da ich sie noch nicht verwenden musste. Bis jetzt immer Arrays verwendet die mir hier auch sinnvoller erscheinen.

Wie will man denn was neues lernen ausser durch LearningByDoing? Wenn ich ein Buch gelesen habe werd ichs auch nicht gleich perfekt können. Der Code der bis jetzt steht funktioniert ja einwandfrei (vlt nicht besonders schön und gecodet aber funktioniert) und ist auch nur durch LerningByDoing entstanden.

Die Werte in struct_s.weather schreiben hab ich nun hinbekommen. Hab vergessen das die Werte dabei ja rechts mit dem LSB anfangen :)
Ist die Methode so i.O oder gibt es schönere um die Werte in die Struktur zu übernehmen?


#include "avr/io.h"
#include "function.h"
#include <avr/interrupt.h>

volatile uint16_t dcf_time = 0; //Zählvariable DCF Pausen
uint8_t dcf_before = 1; //DCF Signal zuvor
uint8_t dcf_flag = 0; //DCF Signal aktuell
uint8_t dcf_ctr = 0; //DCF Bitzähler
char dcf[60]; //Codiertes DCF Signal 59 bit
int temp;
int temp2[15];

struct
{
int weather:15;
}dcf_s;

int main (void)
{

//Port Konfiguration DCF77 Empfänger

dcf_ddr &= ~(1<<dcf_bit); //PinX als Eingang definieren
dcf_port |= (1<<dcf_bit); //Pullup Widerstand für diesen Pin aktivieren



//Debug Konfiguration, LED1, LED2


DDRC |= (1<<0) | (1<<1); //Bit0 PortC Ausgang
PORTC |= (1<<0) | (1<<1); //Led an PortC aus

//Timer 1 starten, Globale Interrups aktivieren
init_timer();
//USART initialisieren
init_USART();

/*###############################################
# #
# Hauptprogramm #
# #
################################################*/
while(1)
{

//##################### DEBUG ### LED1 zeigt DCF77 Signal#####################
if (dcf_pin & (1<<dcf_bit))
PORTC |= (1<<0); // Ausführen wenn HIGH
else
PORTC &= ~(1<<0); // Ausführen wenn LOW
}
return 0;
}





//Portzustand DCF77 einlesen und in dcf_flag schreiben
int get_dcf_bit()
{
if (dcf_pin & (1<<dcf_bit))
{
dcf_flag = 1;

}else{
dcf_flag = 0;
}
return(dcf_flag);
}

SIGNAL (SIG_OUTPUT_COMPARE1A)
{
PORTC ^= (1<<1); //DEBUG Zeige Frequenz vom Timer-Interrupt an LED2
get_dcf_bit(); //Pegel vom DCF Signal einlesen und in dcf_flag speichern

if(dcf_flag == 1) //Wenn DCF Signal HIGH > Zeit messen
{
if(dcf_flag == dcf_before) //Führe aus, wenn sich Pegel nicht geändert hat
{
dcf_time += 20; //Zeit +20ms
}else{ //Führe aus bei Pegeländerung
if(dcf_time > 770 && dcf_time < 830) //Erkenne Pause von 800 ms = logisch 1
{
if(dcf_ctr <= 14)
{
dcf_s.weather |= (1<<dcf_ctr);
}
dcf[dcf_ctr] = '1';
dcf_ctr++;
}
if(dcf_time > 870 && dcf_time < 930) //Erkenne Pause von 900 ms = logisch 0
{
if(dcf_ctr <= 14)
{
dcf_s.weather &= ~(1<<dcf_ctr);
}
dcf[dcf_ctr] = '0';
dcf_ctr++;
}
if(dcf_time > 1770 && dcf_time < 1830) //Erkenne Pause von 1800 ms = logisch 1, Ende der Übertragung
{
if(dcf_ctr <= 14)
{
dcf_s.weather |= (1<<dcf_ctr);
}
dcf[dcf_ctr] = '1';
temp = dcf_s.weather;
itoa(temp,temp2,2);
//sendUSART(dcf);
//sendUSART("\r\n");
sendUSART("Wetter: ");
sendUSART(temp2);
sendUSART("\r\n");
dcf_ctr = 0;
}
if(dcf_time > 1870 && dcf_time < 1930) //Erkenne Pause von 1900 ms = logisch 0, Ende der Übertragung
{
if(dcf_ctr <= 14)
{
dcf_s.weather &= ~(1<<dcf_ctr);
}
dcf[dcf_ctr] = '0';
temp = dcf_s.weather;
itoa(temp,temp2,2);
//sendUSART(dcf);
//sendUSART("\r\n");
sendUSART("Wetter: ");
sendUSART(temp2);
sendUSART("\r\n");
dcf_ctr = 0;
}
dcf_time = 0; //Zeitvariable zurücksetzen
}
}
dcf_before = dcf_flag; //Alten Pegel in der Variable dcf_before speichern
}

Dirk
11.07.2008, 18:23
Hallo Wasserkäfer,

bei meinem DCF77-Decoder für den RP6 ...
https://www.roboternetz.de/phpBB2/viewtopic.php?t=34240
... habe ich z.B. diesen uint64_t Typ für DCF77 genommen:

typedef union {
uint64_t bits; // All DCF77 bits
struct {
unsigned weather : 15; // Bits 0..14: Coded weather info
unsigned flags : 6; // R: Call bit 15 for PTB employees
// A1: Announcement of a time zone change
// Z1: Time zone 1 [0 = MEZ, 1 = MESZ]
// Z2: Time zone 2 [1 = MEZ, 0 = MESZ]
// A2: Announcement of a leap second
// S: Start bit 20 (always 1)
unsigned minute : 7; // 7 bits for the minute (BCD)
unsigned bit_P1 : 1; // P1: Minute parity bit 28
unsigned hour : 6; // 6 bits for the hour (BCD)
unsigned bit_P2 : 1; // P2: Hour parity bit 35
unsigned day : 6; // 6 bits for the day (BCD)
unsigned weekday : 3; // 3 bits for the weekday
unsigned month : 5; // 5 bits for the month (BCD)
unsigned year : 8; // 8 bits for the year (BCD)
unsigned bit_P3 : 1; // P3: Date parity bit 58
unsigned bit_59 : 1; // Leap second bit 59 (always 0)
unsigned notused : 4; // Bits 60..63: Not used
};
} dcf77_t;
Da schiebe ich dann alle Bits des DCF-Telegramms rein und kann mir dann die einzelnen Werte (f. Stunde, Minute ...) da wieder rausziehen.

Vielleicht wäre das auch was für dich. Sieh dir die Libs doch 'mal an.

Gruß Dirk

Wasserkäfer
12.07.2008, 20:18
Hi,

hab mir deine Libs jetzt mal angeschaut und teilweise versteh ichs auch.
Nur zum Verständniss: Du kannst dir da die einzelnen Werte aus der Union wieder rausziehen weil bei einer Union ja die einzelnen Werte übereinander auf dem selben Speicherplatz liegen. Somit ist dcf77_t.bits und die geschachtelte Struktur übereinander. Stimmt das so?

Aber leider ist mir nicht ganz klar, wie du die empfangenen Informationen in dcf77_t.bits reinschiebst.

Das hier müsste ja eine Pausenerkennung sein:

if ((duration > (PAUSE_900MS - PAUSE_DEVIATION))
&& (duration < (PAUSE_900MS + PAUSE_DEVIATION))) {
dcfbit = BIT_0;
dcfstream.bits &= ~bitstream_mask;
bitstream_mask <<= 1;

Wird eine 0 erkannt weist du dcfbit = 0b00000000 zu. (Warum? dcfbit hat doch nichts mit dcf77_t.bits zu tun)
Die nächsten zwei Zeilen mit dcfstream.bits und bitstream_mask sind mir vollkommen unklar. Woher kommen die 2 Variablen?
Was die zwei Zeilen ausführen hoff ich verstanden zu haben:

dcfstream.bits &= ~bitstream_mask;
UND - Verknüpfung von dcfstream.bits und invertiertem bitstream_mask

bitstream_mask <<= 1;
bitstream_mask um 1 nach links schieben und in bitstream_mask speichern


Danke schonmal für die Hilfe

Wasserkäfer
16.07.2008, 16:40
So nach einem Tag intensiven Lib anschaun habe ich den Teil soweit verstanden. Es sind nur 3 kleine Fragen geblieben ^^

1. Für was benötigt man dcfbit = Bit_0; bzw. Bit_1;?
2. Warum reicht static uint64_t bitstream_mask;?
Müsste man die Variable nicht mit 1 vorladen da diese ja nach links
durchgeschoben wird?
3. Braucht man unbedingt static für die Variablen?

Vielen Dank schonmal

Dirk
19.07.2008, 15:10
Sorry, war im Urlaub, daher erst jetzt:

Zu 1:
Mit dcfbit = ... werden die 4 Bit-Varianten (0/1-Bit und 0/1-Lastbit, d.h. Telegrammende) bezeichnet.

Verwendet wird das dann später in 2 Abfragen:
if (dcfbit != BIT_ERROR) {...
Dieser Teil wird nur ausgeführt, wenn eine der 4 Varianten erkannt wurde.
... und ...
if (dcfbit & LASTBIT_0) {...
Da wird getestet, ob ein Lastbit (also Telegrammende) vorliegt.

Zu 2:
Stimmt: Immer wenn ein Lastbit erkannt wurde (Pause 1800 oder 1900ms), wird mit ...
bitstream_mask = 1;
... diese Variable wieder mit 1 vorgeladen, sonst um eine Stelle nach links geschoben.

Zu 3:
Ja.

Gruß Dirk