Forum: Mikrocontroller und Digitale Elektronik Dip Schalter Abfrage


von Andreas B. (andybuett)


Lesenswert?

Hallo zusammen,

ich habe mit einem Kollegen eine kleine DMX Funk Schaltung um einen Dip 
Switch erweitert, um dabei die Frequenzen umschalten zu können. Leider 
sind wir beide nicht wirklich fit in C und haben jetzt das Problem, dass 
die Umschaltung nicht funktioniert. Die Platine an sich funktioniert und 
tut was sie soll aber wenn man die Dip Schalter betätigt ändert sich 
nichts.
Die PullUps sind gesetzt und funktionieren auch, kann man an der Platine 
nachmessen.
Ich denke es ist ein simples programmier Problem, auf das wir einfach 
nicht kommen.
Mir ist auch bewußt, dass man das schöner machen kann, allerdings könne 
wir es leider nicht!! ;-)

Über jegliche Hilfe sind wir dankbar!!!

Hier das Werk:
1
#define F_CPU 12000000
2
#define DMX_BAUD 250000
3
#define DMX_LOST_TIMEOUT 500
4
#define DMX_BAUD_BREAK 80000
5
6
#include <avr/io.h>
7
#include <avr/interrupt.h>
8
#include <avr/pgmspace.h>
9
#include <avr/eeprom.h>
10
#include <util/delay.h>
11
#include <stdlib.h>
12
#include <string.h>
13
#include "rf22.h"
14
15
volatile unsigned char dmx_buffer[514];
16
volatile unsigned char dmx_tmp_buffer[33];
17
volatile unsigned char new_dmx_data = 0;
18
19
volatile unsigned int dmx_lost = DMX_LOST_TIMEOUT;
20
 
21
22
#define TRANSMIT_BLOCKS 16  //1 Block 32Channels max.16 Blocks 512Channels
23
#define TRANSMIT_REPEAT  64
24
25
//############################################################################
26
//DMX Senderoutine
27
ISR (USART_TX_vect)
28
//############################################################################
29
{
30
  static unsigned int  dmx_channel_tx_count = 1;
31
  static unsigned char dmx_tx_state = 0;
32
  
33
  switch (dmx_tx_state)
34
  {
35
    case (0):
36
      UBRR0   = (F_CPU / (DMX_BAUD_BREAK * 16L) - 1);
37
      UDR0 = 0; //RESET Frame
38
      dmx_tx_state = 1;
39
      break;
40
41
    case (1):
42
      UBRR0   = (F_CPU / (DMX_BAUD * 16L) - 1);
43
      UDR0 = 0; //Start Byte
44
      dmx_tx_state = 2;
45
      break;
46
47
    case (2):
48
      _delay_us(10);
49
      //Ausgabe des Zeichens
50
      UDR0 = dmx_buffer[dmx_channel_tx_count];
51
      dmx_channel_tx_count++;
52
      
53
      if(dmx_channel_tx_count == 512)
54
      {
55
        dmx_channel_tx_count = 1;
56
        dmx_tx_state = 0;
57
      }
58
      break;
59
  }
60
}
61
62
63
//############################################################################
64
//DMX Empfangsroutine (RS485)
65
ISR (USART_RX_vect)
66
//############################################################################
67
{
68
  static unsigned int dmx_channel_rx_count = 0;
69
  static unsigned char dmx_valid = 0;
70
  unsigned char tmp = 0;
71
  
72
  tmp =  UDR0;
73
  
74
  if(UCSR0A&(1<<FE0))
75
  {
76
    if(dmx_channel_rx_count > 1)
77
    {
78
      dmx_lost = 0;
79
    }
80
    dmx_channel_rx_count = 0;  
81
    dmx_buffer[0] = tmp;
82
    
83
    if(dmx_buffer[0] == 0)
84
    {
85
      dmx_valid = 1;
86
      dmx_channel_rx_count++;
87
    }
88
    else
89
    {
90
      dmx_valid = 0;
91
    }
92
    return;
93
  }
94
  
95
  if(dmx_valid)
96
  {
97
    if(dmx_buffer[dmx_channel_rx_count] != tmp)
98
    {
99
      dmx_buffer[dmx_channel_rx_count] = tmp;  
100
      new_dmx_data = TRANSMIT_REPEAT;
101
    }
102
  
103
    if(dmx_channel_rx_count < 514)
104
    {
105
      dmx_channel_rx_count++;
106
    }
107
    return;
108
  }
109
}
110
111
//############################################################################
112
//Hier wird die Zeit gez‰hlt (Tick 1ms)
113
ISR (TIMER2_COMPA_vect)
114
//############################################################################
115
{
116
  if(dmx_lost<DMX_LOST_TIMEOUT)
117
  {
118
    dmx_lost++;
119
  }
120
}
121
122
//############################################################################
123
//Hauptprogramm DMX FUNK ‹BERTRAGUNG
124
int main(void)
125
//############################################################################
126
{  
127
  unsigned int tmp;
128
  unsigned char packet_cnt = 0;
129
  unsigned long counter = 0;
130
  DDRB |= (1<<PB0); //LED PORT Output
131
  DDRD |= (1<<PD3); //Direction RS485 RX/TX
132
  
133
  PORTB |= (1<<0); //LED ON
134
  
135
//#############################################################  
136
  DDRC &= ~(1<<PC2); //M‰useklavier PINs als Eingang
137
  DDRC &= ~(1<<PC3);
138
  DDRC &= ~(1<<PC4);
139
  DDRC &= ~(1<<PC5);
140
  
141
  PORTC |= (1<<PC2); //M‰useklavier PULL UP einschalten
142
  PORTC |= (1<<PC3);
143
  PORTC |= (1<<PC4);
144
  PORTC |= (1<<PC5);
145
//#############################################################
146
147
  
148
  PORTC |= (1<<PC0);  //Pullup (Receiver/Transmitter)
149
  for(unsigned long b = 0;b<100000;b++){;asm("nop");};
150
  
151
  rf22_init();
152
  
153
//___________________________________________    
154
// Hier könnte das Problem liegen!!
155
156
157
  if ( ( !(PINC & (1<<PC2)) ) && (PINC & (1<<PC3)) && (PINC & (1<<PC4)) && (PINC & (1<<PC5)) )  // PINC2 eingeschaltet, 3, 4, 5 = 1; nicht eingeschaltet
158
    {
159
    rf22_setfreq(RF22FREQ(430.0));  // Frequenz z.B. jetzt 430 MHz
160
    }
161
    
162
  if ( (PINC & (1<<PC2)) && ( !(PINC & (1<<PC3)) ) && (PINC & (1<<PC4)) && (PINC & (1<<PC5)) )  // PINC3 eingeschaltet, 2, 4, 5 = 1; nicht eingeschaltet
163
  {
164
    rf22_setfreq(RF22FREQ(440.0));  // Frequenz z.B. jetzt 440 MHz
165
    }
166
  
167
//___________________________________________  
168
    
169
  
170
  
171
  rf22_rxmode();  
172
  
173
  
174
  if(PINC & (1<<PC0)) //Module als Sender oder Empf‰nger
175
  {
176
    PORTD &= ~(1<<PD3); //TX RS485
177
  
178
    //Init usart DMX-BUS
179
    UBRR0   = (F_CPU / (DMX_BAUD * 16L) - 1);
180
    UCSR0B|=(1 << RXEN0 | 1<< RXCIE0);
181
    UCSR0C|=(1<<USBS0); //USBS0 2 Stop bits  
182
    sei();//Globale Interrupts Enable
183
  
184
    //Timer2 Timecounter f¸r DMX Ausfall Kabel
185
    TCCR2A |= (1<<WGM21);
186
    TCCR2B |= (1<<CS22|1<<CS21|1<<CS20);
187
    TIMSK2 |= (1<<OCIE2A);
188
    OCR2A = F_CPU/1024/1000 - 1; //Tick Time
189
  
190
    while(1)
191
    {
192
      if(new_dmx_data > 0)
193
      {
194
        new_dmx_data--;  
195
        //512 Kan‰le werden zu je 32Bytes a 16 Packete versendet
196
        memcpy((unsigned char*)&dmx_tmp_buffer[1],(unsigned char *)&dmx_buffer[(packet_cnt*32)],32);
197
        dmx_tmp_buffer[0] = packet_cnt;
198
        packet_cnt++;
199
        
200
        if(packet_cnt == TRANSMIT_BLOCKS)
201
        {
202
          packet_cnt = 0;
203
        }
204
        
205
        rf22_sendpacket(dmx_tmp_buffer,33); //Packetcounter und 32DMX Bytes
206
      }
207
      
208
      //Abfrage ob DMX Packete via Kabel empfangen wurden
209
      if(dmx_lost==DMX_LOST_TIMEOUT)
210
      {
211
        PORTB &=~(1<<0); //LED AUS NO DMX
212
      }
213
      else
214
      {
215
        PORTB |= (1<<0); //LED AN DMX OK
216
      }  
217
    }
218
  }
219
  else
220
  {
221
    PORTD |= (1<<PD3); //RX RS485
222
    
223
    //Timer2 Timecounter f¸r DMX Ausfall Funk
224
    TCCR2A |= (1<<WGM21);
225
    TCCR2B |= (1<<CS22|1<<CS21|1<<CS20);
226
    TIMSK2 |= (1<<OCIE2A);  
227
    OCR2A = F_CPU/1024/1000 - 1; //Tick Time
228
    
229
    //Init usart DMX-BUS
230
    UBRR0   = (F_CPU / (DMX_BAUD * 16L) - 1);
231
    DDRD |= (1<<PD1); //Output TXD Pin ATmega88
232
    UCSR0B|=(1<<TXEN0)|(1<<TXCIE0); // TXEN0 Transmitter enable / TXCIE0 TX complete interrupt enable 
233
    UCSR0C|=(1<<USBS0); //USBS0 2 Stop bits  
234
    sei();//Globale Interrupts Enable
235
    UDR0 = 0;//Start DMX
236
    
237
    while(1)
238
    {  
239
      //Warte bis Packet empfangen wurde
240
      while(PIND&(1<<2))
241
      {
242
        if(dmx_lost == DMX_LOST_TIMEOUT)
243
        {
244
          PORTB &= ~(1<<0); //Status LED aus
245
          counter++;
246
          if(counter >1000000)
247
          {
248
            PORTB |= (1<<0);
249
            for(unsigned a = 0;a<5000;a++){;asm("nop");};
250
            PORTB &= ~(1<<0);
251
            counter = 0;
252
          }
253
        }
254
        else
255
        {
256
          PORTB |= (1<<0); //Status LED an
257
          counter = 0;
258
        }
259
      }
260
261
      tmp = rf22_getpacket(dmx_tmp_buffer); //Packetcounter und 32DMX Bytes
262
    
263
      //wurden alle Bytes empfangen?
264
      if(tmp == 33)
265
      {
266
        dmx_lost= 0;
267
        //512 Kan‰le werden zu je 32Bytes a 16 Packete empfangen
268
        packet_cnt = dmx_tmp_buffer[0];
269
        memcpy((unsigned char*)&dmx_buffer[(packet_cnt*32)],(unsigned char *)&dmx_tmp_buffer[1],32);
270
      }
271
    }
272
  }
273
}

von Hmmm (Gast)


Lesenswert?

Andreas B. schrieb:
> rf22_setfreq(RF22FREQ(430.0));  // Frequenz z.B. jetzt 430 MHz
> rf22_setfreq(RF22FREQ(440.0));  // Frequenz z.B. jetzt 440 MHz

Da darfst Du nicht senden, und das Modul wird es Dir vermutlich auch 
nicht erlauben.

von Patrick J. (ho-bit-hun-ter)


Lesenswert?

Hi

Ich sehe nicht Mal, wo Ihr die DIP-Schalter zum Programm-Start abfragt.

Ok, könnte damit zusammen hängen, daß mir C nicht viel sagt :)

Dann sehe ich weiter nicht, daß Ihr per Timer-Interrupt (oder bei dem 
DMX-lost) diese Schalter erneut abfragt und darauf reagiert.
Oder per PC-Interrupt auf Änderungen der DIP-Schalter reagiert.

MfG

von Stefan F. (Gast)


Lesenswert?

> Ich sehe nicht Mal, wo Ihr die DIP-Schalter zum Programm-Start abfragt.

Direkt unter dem Kommentar "Hier könnte das Problem liegen"

Der Code zur Initialisierung von Port C und der Code zur Abfrage sehen 
Ok aus. Um ganz sicher zu sein, könntest du mit einer LED anzeiogen, ob 
und welche der beiden IF Bedingungen zutrifft. Oder du gibst 
Log-meldungen auf einem seriellen Port (wahlweise auf einem I/O Pin per 
Software Emulation) aus.

Genrell sollte man sich immer wenigstens einen I/O Pin für 
Statusanzeigen und zum Debugging frei halten. Ich hoffe, das ist bei 
Deiner Anwendung der Fall.

von Andreas B. (andybuett)


Lesenswert?

Hmmm schrieb:
> Andreas B. schrieb:
>> rf22_setfreq(RF22FREQ(430.0));  // Frequenz z.B. jetzt 430 MHz
>> rf22_setfreq(RF22FREQ(440.0));  // Frequenz z.B. jetzt 440 MHz
>
> Da darfst Du nicht senden, und das Modul wird es Dir vermutlich auch
> nicht erlauben.

Das funktioniert aber ohne die Dip Schalter mit der original Schaltung 
so perfekt. Daran kann es nicht liegen.

Mit dem was Patrick schreibt kann ich auch nicht viel anfangen. 
Allerdings hört sich das schon schlüssig an. Müsste es dann aber nicht 
wenigstens teilweiße funktionieren??

von Andreas B. (andybuett)


Lesenswert?

Stefan U. schrieb:
>> Ich sehe nicht Mal, wo Ihr die DIP-Schalter zum Programm-Start abfragt.
>
> Direkt unter dem Kommentar "Hier könnte das Problem liegen"
>
> Der Code zur Initialisierung von Port C und der Code zur Abfrage sehen
> Ok aus. Um ganz sicher zu sein, könntest du mit einer LED anzeiogen, ob
> und welche der beiden IF Bedingungen zutrifft. Oder du gibst
> Log-meldungen auf einem seriellen Port (wahlweise auf einem I/O Pin per
> Software Emulation) aus.
>
> Genrell sollte man sich immer wenigstens einen I/O Pin für
> Statusanzeigen und zum Debugging frei halten. Ich hoffe, das ist bei
> Deiner Anwendung der Fall.

Hört ich gut an. Daran habe ich auch schon gedacht! Aber wie ich das 
umsetzen soll weiß ich nicht!?
Könnte man nicht die LED an PB0 dafür nehmen?

Wie könnte denn ein Code Schnipsel dafür aussehen?

von Stefan F. (Gast)


Lesenswert?

> Könnte man nicht die LED an PB0 dafür nehmen?

Sicher.

> Wie könnte denn ein Code Schnipsel dafür aussehen?

Sorry, aber DAS kannst du alleine herausfinden. LED's einschalten ist in 
sämtlichen Tutorials immer die allererste Übungsaufgabe.

von Andreas B. (andybuett)


Lesenswert?

Stefan U. schrieb:
> Sorry, aber DAS kannst du alleine herausfinden. LED's einschalten ist in
> sämtlichen Tutorials immer die allererste Übungsaufgabe.

Das ist schon richtig und an sich auch nicht das Problem. Hatte das auch 
schon versucht, bin aber nicht weitergekommen. Evtl. weil das Problem 
schon davor lag! Werde es aber nochmal testen.

Falls sonst noch jemand einen Tip bzw. Vorschlag hat, wäre ich sehr 
dankbar!

von Andreas B. (andybuett)


Lesenswert?

Habe Stefans Vorschlag beherzigt und nochmal mit der LED an PB0 
getestet. Hatte da beim ersten mal zu kompliziert gedacht Habe jetzt 
alles was die Frequenz Umschaltung angeht mal auskommentiert und 
wirklich nur mit der IF Abfrage versucht die LED an bzw. auch mal 
auszumachen. Leider ohne Erfolg!

Sprich der Fehler muss irgendwo dort, bei der Abfrage des Dips liegen! 
Aber wo?

von Stefan F. (Gast)


Lesenswert?

Dann schalte die LED mal vor den IF Abfragen ein um zu sehen, ob dieser 
Block Code überhaupt ausgeführt wird.

von Peter D. (peda)


Lesenswert?

Die Abfrage ist viel zu unleserlich und damit fehlerträchtig.
Definier erstmal ne Maske für die Inputs und dann entscheide per 
switch/case:
1
#include <avr/io.h>
2
#include <util/delay.h>
3
4
#define SWITCH_MASK (1<<2 | 1<<3 | 1<<4 | 1<<5)
5
6
void read_switch( void )
7
{
8
  DDRC &= ~SWITCH_MASK;
9
  PORTC |= SWITCH_MASK;
10
  DDRB |= 1<<0;
11
  _delay_us( 100 );               // time to tie open inputs high
12
  switch( PINC & SWITCH_MASK ){
13
    case 0b111000: PORTB |= 1<<0; break;
14
    case 0b110100: PORTB &= ~(1<<0); break;
15
  }
16
}

: Bearbeitet durch User
von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Peter D. schrieb:
> Die Abfrage ist viel zu unleserlich und damit fehlerträchtig.

Die Mischung aus Konstanten-Bitschieberei und des nicht-portablen 
0b-Präfixes findest Du leserlicher und weniger fehlerträchtig?

Insbesondere, da Du die Konstantenbitschieberei genau andersherum 
anstellst als die 0b-Konstanten schreibst ...
1
#include <avr/io.h>
2
#include <util/delay.h>
3
4
#define SWITCH_MASK (1<<5 | 1<<4 | 1<<3 | 1<<2)
5
6
#define SWITCH_A (1<<5 | 1<<4 | 1<<3)
7
#define SWITCH_B (1<<5 | 1<<4        | 1<<2)
8
9
10
11
void read_switch( void )
12
{
13
  DDRC &= ~SWITCH_MASK;
14
  PORTC |= SWITCH_MASK;
15
  DDRB |= 1<<0;
16
  _delay_us( 100 );               // time to tie open inputs high
17
  switch( PINC & SWITCH_MASK ){
18
    case SWITCH_A: PORTB |= 1<<0; break;
19
    case SWITCH_B: PORTB &= ~(1<<0); break;
20
  }

Hier sind natürlich sinnvollere Namen für die verschiedenen 
Schalterzustände zu wählen als "SWITCH_A", "SWITCH_B" etc.



}

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.