Forum: Mikrocontroller und Digitale Elektronik MSP430G2553 PWM LED-Dimmer verhalten


von Mathias Z. (matziz198)


Lesenswert?

Hallo schon wieder,

ich versuch einen, per Drehgeber einstellbaren, PWM LED-Dimmer zu 
basteln. Drehgeber funktioniert. Die PWM läuft, lässt sich jedoch nicht 
einstellen. Der Initialwert von CCR1 liegt beim Starten an, die LED 
leuchtet leicht. Wenn ich am Encoder drehe geht die LED für ca. 1s auf 
volle Helligkeit und danach bleibt sie aus bis ich wieder drehe.
Ich habe schon etliche Varianten versucht das CCR1 während der Laufzeit 
zu ändern. Ähnliches Verhalten jedoch kein dimmen.

Ich seh den Fehler nicht. Hier der Code:
1
#include "io430.h"
2
#include "intrinsics.h"
3
4
5
typedef signed   int    int8;
6
typedef unsigned int    uint8;
7
typedef signed   short  int16;
8
typedef unsigned short  uint16;
9
typedef signed   long   int32;
10
typedef unsigned long   uint32;
11
12
13
#define PHASE_A   (P1IN & BIT4)         // P1.4 als Eingang Encoder
14
#define PHASE_B   (P1IN & BIT5)         // P1.5 als Eingang Encoder
15
16
volatile int8 enc_delta;                // -128 ... 127
17
static int8 last;
18
19
const uint16 pwm_table[64] = {
20
     0,    0,    2,    4,    8,   14,   21,   30,   41,   54, 
21
    69,   86,  106,  127,  151,  178,  206,  238,  271,  308, 
22
   347,  388,  433,  480,  530,  583,  638,  697,  758,  823, 
23
   890,  961, 1035, 1111, 1191, 1274, 1361, 1450, 1543, 1639, 
24
  1739, 1841, 1947, 2057, 2170, 2286, 2406, 2530, 2657, 2787, 
25
  2921, 3059, 3200, 3345, 3494, 3646, 3802, 3962, 4125, 4293, 
26
  4464, 4639, 4817, 5000
27
};
28
29
static uint8 pwm_index = 7;
30
31
32
void encode_init( void )
33
{
34
  int8 new;
35
 
36
  new = 0;
37
  if( PHASE_A )
38
    new = 3;
39
  if( PHASE_B )
40
    new ^= 1;                           // convert gray to binary
41
  last = new;                           // power on state
42
  enc_delta = 0;
43
}
44
45
int8 encode_read1( void )               // read single step encoders
46
{
47
  int8 val;
48
 
49
  __disable_interrupt();
50
  val = enc_delta;
51
  enc_delta = 0;
52
  __enable_interrupt();
53
  return val;                           // counts since last call
54
}
55
56
57
// Watchdog Timer interrupt service routine used for Encoder
58
#pragma vector=WDT_VECTOR
59
__interrupt void watchdog_timer(void)
60
{
61
  int8 new, diff;
62
 
63
  new = 0;
64
  if( PHASE_A )
65
    new = 3;
66
  if( PHASE_B )
67
    new ^= 1;                           // convert gray to binary
68
  diff = last - new;                    // difference last - new
69
  if( diff & 1 ){                       // bit 0 = value (1)
70
    last = new;                         // store new as next last
71
    enc_delta += (diff & 2) - 1;        // bit 1 = direction (+/-)
72
  }
73
}
74
75
76
void main( void )
77
{
78
  WDTCTL = WDT_MDLY_0_5;                // Set Watchdog Timer interval to ~0.5ms
79
  IE1 |= WDTIE;                         // Enable WDT interrupt
80
    
81
  BCSCTL1 = CALBC1_1MHZ;                // 1 MHz clock
82
  DCOCTL = CALDCO_1MHZ;
83
    
84
  P1SEL = 0x00;                         // Port 1 als GPIO nutzen
85
  P1REN |= (BIT4 + BIT5);               // P1.4 und P1.5 Resistor enabled
86
  P1OUT |= (BIT4 + BIT5);               // P1.4 und P1.5 Pullup enabled
87
  P1DIR |= BIT6;                        // P1.6 output (green LED)
88
  P1SEL |= BIT6;                        // P1.6 = TA0.1 (timer A's output)
89
  
90
  TACTL = TASSEL_2 + MC_1;              // Source Timer A from SMCLK (TASSEL_2), up mode (MC_1)
91
                                        // Up mode counts up to TACCR0
92
  TACCTL1 = OUTMOD_7;                   // OUTMOD_7 = CCR1 reset/set output when the timer counts to TACCR1
93
  TACCR0 = 5000;                        // PWM period = 1 MHz / 5000 = ~200 Hz
94
  TACCR1 = pwm_table[7];                // Initial CCR1 (= brightness)
95
    
96
  int8 val = 0;
97
 
98
  encode_init();
99
  __enable_interrupt();
100
 
101
  for(;;)
102
  {
103
    val += encode_read1();
104
    
105
    if(val > 0)                         // Encoder linksdrehung
106
    {                                   // grün dunkler (LED1)
107
      if (pwm_index > 1)
108
      {
109
        pwm_index--;
110
        TACCR1 = pwm_table[pwm_index];
111
      }
112
      else {TACCR1 = pwm_table[0];}
113
      val--;
114
    }                                 
115
        
116
    if(val < 0)                         // Encoder rechtsdrehung
117
    {                                   // grün heller (LED1)
118
      if (pwm_index < 62)
119
      {
120
        pwm_index++;
121
        TACCR1 = pwm_table[pwm_index];
122
      }
123
      else {TACCR1 = pwm_table[63];}
124
      val--;
125
    }                   
126
  }
127
}

von Mathias Z. (matziz198)


Lesenswert?

Kann es sein das dass TACCR1 nur in einem Interrupt veränderbar ist? 
Oder muss man den Timer während der Änderung anhalten? Wobei ich auch 
schon Beispiele gesehen habe die auf dem selben Prinzip, welches ich 
benutze, basieren.

von Peter D. (pdiener) Benutzerseite


Lesenswert?

1
    if(val < 0)                         // Encoder rechtsdrehung
2
    {                                   // grün heller (LED1)
3
      if (pwm_index < 62)
4
      {
5
        pwm_index++;
6
        TACCR1 = pwm_table[pwm_index];
7
      }
8
      else {TACCR1 = pwm_table[63];}
9
      val--;  <-------------------------------- Das sollte doch hochzählen
10
    }

Ich denke, der Fehler liegt darin, dass val noch weiter runter zählt, 
wenn es negativ ist. Siehe oben.

Grüße,

Peter

von Mathias Z. (matziz198)


Lesenswert?

Ja, das wars. Der Wald und die Bäume :)

Danke!!!

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.