PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Einfachst Datenübermittlung



Tux12Fun
02.06.2010, 23:41
Hallo Leute,

ich versuche gerade zwischen zwei Modulen einen einfachen Wert hin und her zu schicken.

Leider hat mein Code noch das Problem, dass ich erst ein wenig den PIN A0 anschalten muss damit es klappt. Vielleicht könnt ihr mir ja ein paar Tipps geben

Problemstellung ist dass das andere Modul am besten nur mit 2 Kabeln versorgt werden darf und die müssen ausgerechnet auch die Stromversorgung sein. Im Moment hantiere ich aber noch mit 3 Kabeln auf dem Steckbrett. One Wire / TWI ist für mich leider auch keine Lösung.

Die Controller (ATMEGA32) haben folgende Beschaltung
Sender PA0 --> Empfänger PC0
An A0 hängt zusätzlich zur Zeit eine LED

Später möchte ich den ATMEGA auch über die Datenleitung versorgen, deswegen habe ich es so eingerichtet dass PA0 fast immer Strom hat.

Die Logik ist folgende:

Eine 0 wird mit 100ms aus übertragen
Eine 1 wird mit 200ms aus übertragen
dazwischen gibt es 100ms Power.

Ist der Block fertig gibt es 1000ms Power auf jeden Fall Power


Hier ist mein Codeversuch für die Kommunikation.
Ich denke, ihr habt sicher Ideen zum optimieren.


#include <avr/io.h>
#include <stdlib.h>
#include <util/delay.h>

#define MCU = AVR_ATmega32
#define F_CPU 16000000

#define DEF_TIME_BIT0 100
#define DEF_TIME_BIT0_MIN 50
#define DEF_TIME_BIT0_MAX 150

#define DEF_TIME_BIT1 200
#define DEF_TIME_BIT1_MIN 150
#define DEF_TIME_BIT1_MAX 250

#define DEF_TIME_BIT_NONE 100

#define DEF_SLEEP_BETWEEN_SEND 1000
#define DEF_SLEEP_BETWEEN_SEND_DET 700

void my_sleep_ms(int val){
for (int i=0; i < val; i++){
_delay_ms(1);
}
}

void send_code(unsigned short int value){
// Hier wandeln wir den code in die Bitfolge um
unsigned short int code=value;
/*
#0 000
#1 001
#2 010
#3 011
#4 100
#5 101
#6 110
#7 111
*/
unsigned short bit[2];
if ((code / 4) > 0){
bit[0] = 1;
code = code - 4;
}
if ((code / 2) > 0){
bit[1] = 1;
code = code - 2;
}
if ((code / 1) > 0){
bit[2] = 1;
code = code - 1;
}

//Hier senden wir den Code
for (unsigned short int i=0; i <= 2; i++){
if (bit[i]==1){
PORTA &= ~(1<<PA0); //OFF
my_sleep_ms(DEF_TIME_BIT1);
PORTA |= (1<<PA0); //ON
my_sleep_ms(DEF_TIME_BIT_NONE);
}else{
PORTA &= ~(1<<PA0); //OFF
my_sleep_ms(DEF_TIME_BIT0);
PORTA |= (1<<PA0); //ON
my_sleep_ms(DEF_TIME_BIT_NONE);
}
}
my_sleep_ms(DEF_SLEEP_BETWEEN_SEND);
}

void listen_to_code(void){
PORTA &= ~(1<<PA0); //OFF
unsigned int duration=0;
unsigned int off_duration=0;
int bitnr=0;
int bit[2];
while (1){
if ( ( PINC & 0x01 ) != 0 ) {
off_duration++;
if (off_duration > DEF_SLEEP_BETWEEN_SEND_DET) {
//Reset
duration=0;
bitnr=0;
off_duration=0;
}

if ((duration > DEF_TIME_BIT1_MIN) && (duration < DEF_TIME_BIT1_MAX)){
bit[bitnr] = 1;
bitnr++;
}else if ((duration > DEF_TIME_BIT0_MIN) && (duration < DEF_TIME_BIT0_MAX)){
bit[bitnr] = 0;
bitnr++;
}
duration=0;

if (bitnr == 3){
bitnr=0;
//Auswerten
if ( (bit[0] == 0) && (bit[1] == 1) && (bit[2] == 0) ){
PORTA |= (1<<PA0); //ON
my_sleep_ms(1000);
PORTA &= ~(1<<PA0); //OFF
}
}

}else{
//Pin off
off_duration=0;
if (duration <= DEF_TIME_BIT1 + 1000){
duration++;
}

}
my_sleep_ms(1);
}
}

int main (void){


DDRA=0xff;
PORTA=0x00;

DDRC=0x00;
PORTC=0x00;

PORTA |= (1<<PA0); //ON

my_sleep_ms(3000);

//while (1){
send_code(2);
//send_code(2);
//listen_to_code();
//}
}

syn_error
03.06.2010, 00:33
andere Modul am besten nur mit 2 Kabeln versorgt werden darf.....
One Wire / TWI ist für mich leider auch keine Lösung.
Funk oder Ir.

sternst
03.06.2010, 01:17
Leider hat mein Code noch das Problem, dass ich erst ein wenig den PIN A0 anschalten muss damit es klappt. Vielleicht könnt ihr mir ja ein paar Tipps gebenÄhm, was bitte soll "ein wenig anschalten" genau bedeuten?


Ich denke, ihr habt sicher Ideen zum optimieren. Ja, z.B. das "Umwandeln" von value in send_code ist völlig unsinnig. Das ist doch schon längst eine Bitfolge. Oder was denkst du, in welcher Form das im Controller bearbeitet/gespeichert wird?
Ich würde die Funktion so schreiben:

void send_code (uint8_t value) {

for (uint8_t mask = 1<<2; mask; mask >>= 1) {
PORTA &= ~(1<<PA0);
my_sleep_ms(value&mask?DEF_TIME_BIT1:DEF_TIME_BIT0);
PORTA |= (1<<PA0);
my_sleep_ms(DEF_TIME_BIT_NONE);
}

my_sleep_ms(DEF_SLEEP_BETWEEN_SEND);
}


PS: Rest vom Code habe ich mir nicht weiter angesehen.

Tux12Fun
03.06.2010, 12:12
Hallo,

schon mal danke für den Sendepart. Ich grüble zwar noch wie diese For Schleife genau arbeitet. Aber ich denke, da komme ich noch drauf.

Zu: ein wenig einschalten.

Die Funktion listen_to_code zählt ja wie lange der Pin ausgeschalten ist.
Da am Empfänger Modul am Anfang ja kein Strom an PC0 anliegt, zählt der Zähler natürlich gleich mal hoch. Aus diesem Grund schalte ich PA0 am Sender erst mal für 3 Sekunden ein, damit wird beim Empfänger ein Reset der Variablen ausgeführt. Gibt es dafür eine bessere Lösung ?

Hier noch der überarbeitete Listen Code. Jetzt mit richtigen Variablennamen:


void listen_to_code(void){
PORTA &= ~(1<<PA0); //OFF
unsigned int off_duration=0;
unsigned int on_duration=0;
int bitnr=0;
int bit[2];
while (1){
if ( ( PINC & 0x01 ) != 0 ) {
on_duration++;
if (on_duration > DEF_SLEEP_BETWEEN_SEND_DET) {
//Reset
off_duration=0;
bitnr=0;
on_duration=0;
}

if ((off_duration > DEF_TIME_BIT1_MIN) && (off_duration < DEF_TIME_BIT1_MAX)){
bit[bitnr] = 1;
bitnr++;
}else if ((off_duration > DEF_TIME_BIT0_MIN) && (off_duration < DEF_TIME_BIT0_MAX)){
bit[bitnr] = 0;
bitnr++;
}
off_duration=0;

if (bitnr == 3){
bitnr=0;
//Auswerten
if ( (bit[0] == 0) && (bit[1] == 1) && (bit[2] == 0) ){
PORTA |= (1<<PA0); //ON
my_sleep_ms(1000);
PORTA &= ~(1<<PA0); //OFF
}
}

}else{
//Pin off
on_duration=0;
if (off_duration <= DEF_TIME_BIT1 + 1000){
off_duration++;
}

}
my_sleep_ms(1);
}
}


PS: IR oder Funk ist dafür leider keine Lösungsmöglichkeit.

Später wird damit folgendes Abgebildet



===M1=====M2====M3======M4======M5=====M6=====
||
||
||
||


M1 ... M6 = ein Relai Modul in der Antenne.
== = Antenne
|| = Zuleitung zur Antenne.

sternst
03.06.2010, 13:18
Die Funktion listen_to_code zählt ja wie lange der Pin ausgeschalten ist.
Da am Empfänger Modul am Anfang ja kein Strom an PC0 anliegt, zählt der Zähler natürlich gleich mal hoch. Aus diesem Grund schalte ich PA0 am Sender erst mal für 3 Sekunden ein, damit wird beim Empfänger ein Reset der Variablen ausgeführt. Gibt es dafür eine bessere Lösung ?

Pull-Up benutzen.

Sehe ich das richtig, dass du über eine einzige Leitung die Versorgung und eine bidirektionale Kommunikation mit eigenem Protokoll machen willst?

Tux12Fun
03.06.2010, 18:42
Hallo,

ja das wäre mein Ziel, wobei mir eine eine Kommunikation in eine Richtung schon reicht. Die Pullups müsste ich mit PORTA=0xff aktivieren oder ?

021aet04
03.06.2010, 20:19
Die jeweiligen Ports müssen als Eingang definiert sein und dann kannst du mit z.B. PORTA=0xff die Pullups aktivieren.

Die Pins sind normalerweiße als Eingänge konfiguriert. Du kannst bei den AVRs die Pullups auch einzeln aktivieren (z.B. PORTA |= (1<<PA5)).

Das ist einer der Vorteile bei den AVRs. Wie es bei den PICs ist weiß ich nicht, bei den R8Ctiny (von Renesas) ist das nicht so (Pullups kann man nur in Gruppen aktivieren).

MfG Hannes