Forum: Mikrocontroller und Digitale Elektronik Display Ulrich Radig Software erweitern [C]


von Andreas A. (elw-2)


Lesenswert?

Hallo!

Ich wollte ganz gerne das Anzeigemodul von Ulrich Radigs Labornetzteil 
für meines Verwenden. Das funktioniert auch im Test richtig gut!

Nur habe ich jetzt das Problem, dass ich auch ganz gerne die 
Wicklungsumschaltung von dem µC steuern lassen wollte. Hier für ist auch 
schon PD7 vorgesehen, aber noch nicht Programmiert.


Nun dachte mich mir, dass kann ja nicht so schwere sein!
Da ich gerade anfange mich mit µC Programmierung in C zu beschäftigen, 
musste ich mich erstmal einlesen, das hat auch so ganz gut geklappt.

Aber wenn ich nun die if/else Abfrage mit einbau, fängt die Anzeige an 
zu flackern, nur warum weiß ich leider nicht :(

Ich hoffe ihr könnt mir helfen, im Anhang ist meine Code und die 
Original teil:

Meiner mit PD7
1
#include <avr/interrupt.h>
2
#include <avr/io.h>
3
4
#include "multiplex.h"
5
#include "adc.h"
6
7
//---------------------------------------------------------------------------
8
int main (void) 
9
{
10
11
  DDRD |= (1<<PD0)|(1<<PD1)|(1<<PD2)|(1<<PD3)|(1<<PD4)|(1<<PD5)|(1<<PD6)|(1<<PD7);
12
  DDRB |= (1<<PB0)|(1<<PB1)|(1<<PB2)|(1<<PB3)|(1<<PB4)|(1<<PB5);
13
  
14
  adc_init();
15
  
16
  sei();
17
  
18
  init_multiplex();
19
  
20
  while(1)
21
  {    
22
    if (adc_count > 400)
23
    {
24
      //ADC_OFF;
25
      display1 = (display_value_1 / adc_count);
26
      display2 = (display_value_2 / adc_count);
27
      adc_count = 0;
28
      display_value_1 = 0;
29
      display_value_2 = 0;
30
      //ADC_ON;
31
    }      
32
    {
33
      if (display1 > 200)
34
        PORTD |= (1 << PD7);
35
      else
36
        PORTD &= ~(1 << PD7);
37
    }
38
  }
39
}

Original von Radig:
1
#include <avr/interrupt.h>
2
#include <avr/io.h>
3
4
#include "multiplex.h"
5
#include "adc.h"
6
7
//---------------------------------------------------------------------------
8
int main (void) 
9
{
10
11
  DDRD |= (1<<PD0)|(1<<PD1)|(1<<PD2)|(1<<PD3)|(1<<PD4)|(1<<PD5)|(1<<PD6);
12
  DDRB |= (1<<PB0)|(1<<PB1)|(1<<PB2)|(1<<PB3)|(1<<PB4)|(1<<PB5);
13
  
14
  adc_init();
15
  
16
  sei();
17
  
18
  init_multiplex();
19
  
20
  while(1)
21
  {    
22
    if (adc_count > 400)
23
    {
24
      //ADC_OFF;
25
      display1 = (display_value_1 / adc_count);
26
      display2 = (display_value_2 / adc_count);
27
      adc_count = 0;
28
      display_value_1 = 0;
29
      display_value_2 = 0;
30
      //ADC_ON;
31
    }
32
  }
33
}

VG
Andreas

PS:
Der Link im Forum zum Projekt
Beitrag "Netzteil, LM317, Strombegrenzung und Anzeige!"

von Andreas A. (elw-2)


Lesenswert?

Push it :(

von Fabian (Gast)


Lesenswert?

Ich glaube nicht, dass es an deiner zusätzlichen IF-Abfrage liegt. Das 
muss andere Gründe haben. Benutzt Du ein Relais um die Wicklung 
umzuschalten? Freilaufdiode?! ....
Außerdem musst Du noch eine Hysterese einbauen. Ungefähr so:

      if (display1 > 200)
        PORTD |= (1 << PD7);
      else if (display 1 < 180)
        PORTD &= ~(1 << PD7);

von Andreas A. (elw-2)


Lesenswert?

Stimmt, die Hysterese fehlt, danke die habe ich noch ganz vergessen :)

Aber das ändert nicht am Phänomen.

Es noch auf einem Steckbrett aufgebaut. An dem Anschluss für das Relais 
(mit Treibertransistor später) ist aktuell nur eine LED mit 
Vorwiderstand, also Simulation.

Mit dem Original Code ist alles super (aus dem AVR Studio 5 heraus 
Programmiert, mit selbst erzeugter hex), aber sobald ich die Änderung 
mit eine Programmiere fängt alles an zu flackern, also ob dir 
Multiplexabfolge nicht mehr richtig ausgeführt werden würde.

=> Also kann es auch nicht am Steckbrettaufbau liegen, den mit dem 
Originalcode flackert es nicht, nur mit dem angepassten :(

von Andreas A. (elw-2)


Lesenswert?

Gerade ist mir was ganz kurioses aufgefallen. Sobald ich mich in der if 
Funktion befinde, hört das Flimmern auf, was komisch er verhaften...

von Sascha W. (sascha-w)


Lesenswert?

Hallo,

soweit ich das sehe, hängt an PortD auch die Anzeige. Der Multiplex 
läuft in einem TimerInt. Wenn du in Main PortD auch veränderst, dann 
muss das atomar sein, sonst gibts diesen lustigen Effekt.
Wenn du die richtige Optimierung hat, sollte zwar aus der 
1-Bit-Portoperation in asm ein sbi/cbi werden - das währe dann atomar.

an sonsten so...
1
cli();
2
PORTD |= (1 << PD7);
3
sei();

aber mach das so, das der Portzustand nur dann neu ausgegeben wird, wenn 
er sich ändern soll.

Sascha

von Andreas A. (elw-2)


Lesenswert?

>aber mach das so, das der Portzustand nur dann neu ausgegeben wird, wenn
>er sich ändern soll.

ÖÖÖÖ, jetzt noch mal in LOGO! oder S7 FUP bitte!

Wie soll ich das jetzt machen???

Sollte evtl. ne Logo oder S7 in meien NT einbauen, dass kann ich besser 
Programmieren :D :D

von Andreas A. (elw-2)


Lesenswert?

Jetzt mal Spaß bei Seite :)

Ich bekomme es nicht hin, habe des jetzt mal in die multiplx.c gepackt.
Das funktioniert jetzt auch so weite, das Flackern ist weg, nur jetzt 
schaltet der Pin natürlich im Takt ein und aus => was somit eine 
Mischspannung ist und eine DC Relais mag das net so.
Gut mit einer Diode und einem Kondensator funktioniert das auch so, aber 
das ich wohl nicht Sinn und Zweck des ganzen.

Hoffe es kann mir eine Helfen!

von Sascha W. (sascha-w)


Lesenswert?

also z.B. so ...

main.c
1
...
2
volatile char supply=0;
3
4
...
5
  while(1)
6
  {    
7
    if (adc_count > 400)
8
    {
9
      //ADC_OFF;
10
      display1 = (display_value_1 / adc_count);
11
      display2 = (display_value_2 / adc_count);
12
      adc_count = 0;
13
      display_value_1 = 0;
14
      display_value_2 = 0;
15
      //ADC_ON;
16
    }      
17
    if (display1 > 200) {
18
       supply=1;
19
    }
20
    if (display1 < 180) {
21
       supply=0;
22
    }
23
24
  }
25
...

multiplex.c
1
ISR (TIMER2_OVF_vect)
2
//############################################################################
3
{  
4
  PORTD = 0;
5
  PORTB = (1<<segcounter);
6
  
7
  switch (segcounter)
8
  {  
9
    case 0:
10
      PORTD = SEGMENTE[(display1 % 1000 / 100)];
11
      break;  
12
    case 1:
13
      PORTD = SEGMENTE[(display1 % 100 / 10)];
14
      break;    
15
    case 2:
16
      PORTD = SEGMENTE[(display1 % 10)];
17
      break;
18
    case 3:
19
      PORTD = SEGMENTE[(display2 % 1000 / 100)];
20
      break;
21
    case 4:
22
      PORTD = SEGMENTE[(display2 % 100 / 10)];
23
      break;  
24
    case 5:
25
      PORTD = SEGMENTE[(display2 % 10)];
26
      break;
27
  }
28
  if ((segcounter++)>5) segcounter = 0;  
29
30
        if (supply=1) {
31
           PORTD |= (1 << PD7);
32
        } else {
33
           PORTD &= ~(1 << PD7);
34
        }
35
}

oder so ...

main.c
1
...
2
char supply=0;
3
  while(1)
4
  {    
5
    if (adc_count > 400)
6
    {
7
      //ADC_OFF;
8
      display1 = (display_value_1 / adc_count);
9
      display2 = (display_value_2 / adc_count);
10
      adc_count = 0;
11
      display_value_1 = 0;
12
      display_value_2 = 0;
13
      //ADC_ON;
14
    }      
15
    if (display1 > 200 && supply=0) {
16
        cli();
17
        PORTD |= (1 << PD7);
18
        sei();
19
        supply=1;
20
    }
21
    if (display1 < 180 && supply=1) {
22
        cli();
23
        PORTD &= ~(1 << PD7);
24
        sei();
25
        supply=0;
26
    }
27
  }

Sascha

von Karl H. (kbuchegg)


Lesenswert?

Sascha Weber schrieb:

> oder so ...

(2. Variante)

Das hilft letzten Endes auch nichts. Denn in der Multiplex Routine wird 
der PortD als Ganzes neu gesetzt. D.h. in dem Fall würde dann eben das 
Relais flackern.

Das könnte man zwar auch abstellen, aber deine erste Variante ist 
wharscheinlich die Einfachere.

von Sascha W. (sascha-w)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Sascha Weber schrieb:
>
>> oder so ...
>
> (2. Variante)
>
> Das hilft letzten Endes auch nichts. Denn in der Multiplex Routine wird
> der PortD als Ganzes neu gesetzt. D.h. in dem Fall würde dann eben das
> Relais flackern.
>
> Das könnte man zwar auch abstellen, aber deine erste Variante ist
> wharscheinlich die Einfachere.

hmm... stimmt - hab ich übersehen, müsste man noch maskieren, damit 
wirklich nur die Segmentbits geändert werden.
Ist sowiso mist, da die ISR mit PORTD=0 anfängt.

also so für Var. 1
1
ISR (TIMER2_OVF_vect)
2
//############################################################################
3
{  
4
uint8 portdata;
5
  PORTB = (1<<segcounter);
6
  
7
  switch (segcounter)
8
  {  
9
    case 0:
10
      portdata= SEGMENTE[(display1 % 1000 / 100)];
11
      break;  
12
    case 1:
13
      portdata= SEGMENTE[(display1 % 100 / 10)];
14
      break;    
15
    case 2:
16
      portdata= SEGMENTE[(display1 % 10)];
17
      break;
18
    case 3:
19
      portdata= SEGMENTE[(display2 % 1000 / 100)];
20
      break;
21
    case 4:
22
      portdata= SEGMENTE[(display2 % 100 / 10)];
23
      break;  
24
    case 5:
25
      portdata= SEGMENTE[(display2 % 10)];
26
      break;
27
  }
28
  if ((segcounter++)>5) segcounter = 0;  
29
30
        if (supply=1) {
31
           portdata |= (1 << PD7);
32
        }
33
  PORTD = portdata;
34
}

oder so für Var. 2
1
ISR (TIMER2_OVF_vect)
2
//############################################################################
3
{  
4
uint8 portdata;
5
  PORTB = (1<<segcounter);
6
  
7
  switch (segcounter)
8
  {  
9
    case 0:
10
      portdata= SEGMENTE[(display1 % 1000 / 100)];
11
      break;  
12
    case 1:
13
      portdata= SEGMENTE[(display1 % 100 / 10)];
14
      break;    
15
    case 2:
16
      portdata= SEGMENTE[(display1 % 10)];
17
      break;
18
    case 3:
19
      portdata= SEGMENTE[(display2 % 1000 / 100)];
20
      break;
21
    case 4:
22
      portdata= SEGMENTE[(display2 % 100 / 10)];
23
      break;  
24
    case 5:
25
      portdata= SEGMENTE[(display2 % 10)];
26
      break;
27
  }
28
  if ((segcounter++)>5) segcounter = 0; 
29
 
30
  portdata |= (PORTD & PD7);
31
  PORTD = portdata;
32
}

Sascha

von Andreas A. (elw-2)


Lesenswert?

Hallo!

Erstmal dank für die Antworten!!

@Sascha
Bei deiner Variante 2 bekomme ich in der Main diesen Fehler für deine 
beiden if Abfragen:

"lvalue required as left operand of assignment"
1
...
2
#include <avr/interrupt.h>
3
#include <avr/io.h>
4
5
#include "multiplex.h"
6
#include "adc.h"
7
8
volatile char supply=0;
9
10
//---------------------------------------------------------------------------
11
int main (void) 
12
{
13
14
  DDRD |= (1<<PD0)|(1<<PD1)|(1<<PD2)|(1<<PD3)|(1<<PD4)|(1<<PD5)|(1<<PD6)|(1<<PD7);
15
  DDRB |= (1<<PB0)|(1<<PB1)|(1<<PB2)|(1<<PB3)|(1<<PB4)|(1<<PB5);
16
  
17
  adc_init();
18
  
19
  init_multiplex();
20
  
21
  while(1)
22
  {    
23
    if (adc_count > 200)
24
    {
25
      //ADC_OFF;
26
      display1 = (display_value_1 / adc_count);
27
      display2 = (display_value_2 / adc_count);
28
      adc_count = 0;
29
      display_value_1 = 0;
30
      display_value_2 = 0;
31
      //ADC_ON;
32
    }  
33
        
34
      if (display1 > 200 && supply=0) 
35
      {
36
       cli();
37
       PORTD |= (1 << PD7);
38
       sei();
39
        supply=1;
40
      }
41
      
42
      if (display1 < 180 && supply=1)
43
      {
44
      cli();
45
      PORTD &= ~(1 << PD7);
46
      sei();
47
        supply=0;
48
      }
49
      
50
  }
51
}

Bei Variante 1 sind es 6 Errors in der multiplex

Kann das sein, dass es am Compiler liegen, ich verwende das AVR Studio 
5.

@ Karl Heinz Buchegger
>Das könnte man zwar auch abstellen, aber deine erste Variante ist
>wahrscheinlich die Einfachere.

Vermute mal du meinst meine Gleichrichtung, das ist wahrscheinlich 
wirklich nicht die schönste, aber wirkungsvollste Methode.

von Sascha W. (sascha-w)


Lesenswert?

Andreas A. schrieb:

> Kann das sein, dass es am Compiler liegen, ich verwende das AVR Studio
> 5.
nein wohl eher weil du in C programmierst und ich eigentlich in ASM

das erste Problem sollte sich wohl so lösen lassen

statt:
1
if (display1 < 180 && supply=1)
eher so:
1
if ((display1 < 180) && (supply=1))

zu Var. 1
wenn es 6 Fehler sind dann ja warscheinlich in switch(), da wird wohl 
der Typ von SEGMENTE nicht zum Typ von portdata [uint8] passen - einfach 
mal entsprechend anpassen!

Sascha

von holger (Gast)


Lesenswert?

>eher so:
>
>if ((display1 < 180) && (supply=1))

eher so:

if ((display1 < 180) && (supply==1))

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.