Forum: Mikrocontroller und Digitale Elektronik MSP430 F167 schläft ein


von Stefan S. (blacknighthawk)


Lesenswert?

Hallo MSP430 Spezialisten.

Heute Abend hatte ich ein seltsames Phänomen.
Ich betreibe eine selbst gebaute und programmierte Steuerung für meinen 
wassergeführten Holzofen (Temperaturen messen, Pumpe schalten, Mischer 
auf und zu fahren), diese lief seit dem letzten Winter bis jetzt ohne 
Probleme.

Heute wurden plötzlich die Ausgänge nicht mehr geschaltet und ich konnte 
auch über USART nichts mehr auslesen, also auch nicht sehen welche 
Temperaturen gemessen werden.
Die Tastenabfrage (über ISR) ging noch.
Nach einem Reset lief wieder alles wie gewohnt.

Ich benutze (meines Wissens) keine Art von LPM.
Allerdings kam es mir vor als würde alles außer was in der while(1) 
steht noch gehen.

Hier ist mal mein Code, für Verbesserungsvorschläge bin ich immer 
dankbar.
Und nebenbei erwähnt, ich erhebe nicht den Anspruch als Profi angesehen 
zu werden, ich stehe erst am Anfang.
1
/*
2
 * Ofensteuerung V2.00c
3
 * Mehrstufige Temperaturumrechnung
4
 * RS232 über USAT 1
5
 * Baud rate auf 19200
6
 * Taktfrequenz runter auf 8MHz wegen Problemen
7
 * Brennerabschaltung bei Pufferteperatur > 60°C
8
 */
9
10
#include <msp430f167.h>
11
#include <intrinsics.h>
12
#include <stdlib.h>
13
#include <string.h>
14
15
#define Offset 2588                //Offset von -50°C zu 0°C beim PT1000 1,79V (*100)
16
#define Steigung 1692             //Steigung 1/3 mV/°C (*10000)
17
#define Uref 28600                  //ADC Referenzspannung 2860,0mV (*10)
18
#define MaxDigit 4095             //Maximale Digits bei 12-Bit adc
19
volatile int cycles = 12500;      //Anzahl der Perioden Timer_A, 1sek. bei 100KHz DCO
20
21
#define A1_on (P4OUT |= BIT0)     //Relais 1 ein, Mischer auf
22
#define A1_off (P4OUT &= ~BIT0)   //Relais 1 aus
23
#define A2_on (P4OUT |= BIT1)     //Relais 2 ein, Mischer zu
24
#define A2_off (P4OUT &= ~BIT1)   //Relais 2 aus
25
#define A3_on (P4OUT |= BIT2)     //Relais 3 ein, Pumpe Rücklaufanhebung ein
26
#define A3_off (P4OUT &= ~BIT2)   //Relais 3 aus, Pumpe Rücklaufanhebung aus
27
#define A4_on (P4OUT |= BIT3)
28
#define A4_off (P4OUT &= ~BIT3)
29
#define A5_on (P4OUT |= BIT4)
30
#define A5_off (P4OUT &= ~BIT4)
31
#define A6_on (P4OUT |= BIT5)
32
#define A6_off (P4OUT &= ~BIT5)
33
#define A7_on (P4OUT |= BIT6)     //Relais 7 ein, Heizkessel
34
#define A7_off (P4OUT &= ~BIT6)   //Relais 7 aus, Heizkessel
35
#define A8_on (P4OUT |= BIT7)
36
#define A8_off (P4OUT &= ~BIT7)
37
38
39
void Timer_A(void);  //Timer A liest ADC und bildet  8 Mittelwerte
40
void Init_ADC(void); //ADC initialisierung
41
void Read_ADC(void); //Temp. T1 - T8 lesen
42
void Format(long l, char *s);
43
long int Temperatur (long int Digit);
44
void scrPos(char* x, char* y);
45
int uart_putc(char c);
46
void uart_puts (char* s);
47
void init_XT(void); //Ext. Quarz 8MHz
48
49
char buffer_1[6], buffer_2[6], buffer_3[6], buffer_4[6], buffer_5[6], buffer_6[6], buffer_7[6], buffer_8[6];
50
volatile long int Digit_1, Digit_2, Digit_3, Digit_4, Digit_5, Digit_6, Digit_7, Digit_8;
51
volatile long int Summe_1, Summe_2, Summe_3, Summe_4, Summe_5, Summe_6, Summe_7, Summe_8;
52
volatile long int Mittelwert_1, Mittelwert_2, Mittelwert_3, Mittelwert_4, Mittelwert_5, Mittelwert_6, Mittelwert_7, Mittelwert_8;
53
volatile long int Mittelwert_11, Mittelwert_12, Mittelwert_13, Mittelwert_14, Mittelwert_15, Mittelwert_16, Mittelwert_17, Mittelwert_18;
54
volatile int Temperatur_1, Temperatur_2, Temperatur_3, Temperatur_4, Temperatur_5, Temperatur_6, Temperatur_7, Temperatur_8;
55
volatile int i_scr = 0;
56
unsigned short int i_init;
57
short int delta_1;  //Differenz zur Mischersteuerung
58
short int delta_2;  //Differenz zur Pumpensteuerung
59
60
61
62
void main(void)
63
{
64
//Ext. Quarz 8MHz und Stop WDT
65
//DCO auf 100KHz
66
  init_XT();
67
68
  //Definition des Ports A für Schalter S1 bis S8
69
  P1SEL = 0x00;  //Port A I/O Funktion
70
  P1DIR = 0x00;  //Port A Input
71
  P1OUT = 0x00;  //Port A
72
  P1IE = 0xFF;   //Port A Interrupt freigegeben
73
  P1IES = 0xFF;  //Port A Interrupt H -> L
74
  P1IFG = 0x00;  //Port A Iterrupt Flag löschen
75
76
  //Definition des Ports B für 8 Bit Display
77
  P2SEL = 0x00;  //Port B I/O Funktion
78
  P2DIR = 0xFF;  //Port B Output
79
  P2OUT = 0x00;  //Port B Low
80
  P2IE = 0x00;   //Port B Interrupt nicht freigegeben
81
  P2IES = 0xFF;  //Port B Interrupt H -> L
82
  P2IFG = 0x00;  //Port B Iterrupt Flag löschen
83
84
85
  //Definition des Ports C für P3.0 und P3.2 (Stecker SV)
86
  P3SEL &= ~(BIT0 | BIT2);  //Port C P3.0 und P3.2 I/O Funktion
87
  P3DIR |= BIT0 + BIT2;  //Port C P3.0 und P3.2 Output
88
  P3OUT &= ~(BIT0 | BIT2);  //Port C P3.0 und P3.2 Low
89
90
  //Definition des Ports C für P3.1 und P3.3 für I2C
91
  //P3SEL |= BIT1 + BIT3;  //Port C P3.0 und P3.2 Aux Funktion
92
  //U0CTL |= I2C + SYNC;                      // Switch USART0 to I2C mode
93
  //U0CTL &= ~I2CEN;                          // Recommended I2C init procedure
94
  //I2CTCTL = I2CSSEL_2;                      // SMCLK
95
  //I2CSCLH = 0x03;                           // High period of SCL
96
  //I2CSCLL = 0x03;                           // Low period of SCL
97
  //I2CNDAT = 0x01;                           // Transmit one byte
98
  //I2CSA = 0x01;                             // Slave address
99
  //U0CTL |= I2CEN;                           // Enable I2C, 7 bit addr,
100
  //I2CIE = RXRDYIE;                          // I2C receive ready interrupt enable
101
102
  //Definition des Port C für P3.6 bis P3.7 (UART1) für RS232
103
  P3SEL |= BIT6 + BIT7;  //Port C P3.6 bis P3.7 Aux Funktion
104
105
  ME2 |= UTXE1 + URXE1;        //USART1 Rx + Tx einschalten
106
  UCTL1 |= CHAR;               //USART1 8N1
107
  UTCTL1 |= SSEL0;             //ACLK
108
    UBR01 = 0xA0;                       // 19200 baud bei 8 MHz erzeugen
109
    UBR11 = 0x01;                       // 19200 baud bei 8 MHz erzeugen
110
    UMCTL1 = 0x5B;                      // Korrektur der division noetig
111
    UCTL1 &= ~SWRST;                // USART1 freigeben
112
   // IE2 |= UTXIE1;                  // TX-interrupt anschalten
113
   // IFG2 &= ~UTXIFG1;            // initales interrupt-flag loeschen
114
115
116
117
118
  //Definition des Ports D für 8 Relais Ausgänge
119
  P4SEL = 0x00;  //Port D I/O Funktion
120
  P4DIR = 0xFF;  //Port D Output
121
  P4OUT = 0x00;  //Port D Low
122
123
// Interrupts freigeben
124
  __enable_interrupt();
125
126
127
//ADC initieren
128
//Timer A starten
129
  Init_ADC();
130
  Timer_A ();
131
132
//Zeit um genügend Mittelwerte zu bilden
133
  for (i_init = 0; i_init <= 1625; i_init++)
134
  {
135
    uart_puts ("System startet...\t\t");
136
  }
137
  uart_puts ("\x1b\[2J"); //Bildschirm löschen
138
139
while (1)
140
{
141
142
// Gemittelte Digits in Temperatur umrechen lassen
143
  Temperatur_1 = Temperatur (Mittelwert_11); // Temp. Puffer oben
144
  Temperatur_2 = Temperatur (Mittelwert_12); // Temp. Heizkreis-Rücklauf
145
  Temperatur_3 = Temperatur (Mittelwert_13); // Temp. Holzofen
146
  Temperatur_4 = Temperatur (Mittelwert_14); // Temp. Puffer- Rücklauf
147
  Temperatur_5 = Temperatur (Mittelwert_15);
148
  Temperatur_6 = Temperatur (Mittelwert_16);
149
  Temperatur_7 = Temperatur (Mittelwert_17);
150
  Temperatur_7 = Temperatur (Mittelwert_18);
151
152
// Differenzbildung aus Puffer-Temperatur oben
153
// und Heizkreis-Rücklauf
154
// Ansteuerung der Ausgänge A1 und A2 zur
155
// Mischersteuerung
156
delta_1 = Temperatur_1 - Temperatur_2;
157
158
        if (delta_1 >= 7)
159
        {
160
          A2_off;
161
          A1_on;
162
        }
163
164
165
        if (delta_1 <= 2)
166
        {
167
            A1_off;
168
             A2_on;
169
        }
170
171
//Rücklaufanhebung an A3 ein- und ausschalten
172
delta_2 = Temperatur_3 - Temperatur_1;
173
174
if (Temperatur_3 >= 90)
175
  A3_on;
176
else
177
   {
178
      if (delta_2 >= 2)
179
        {
180
          if (Temperatur_3 >= 65)
181
            A3_on;
182
183
          if (Temperatur_3 <= 60)
184
            A3_off;
185
        }
186
      else
187
     A3_off;
188
   }
189
190
//Brennerabschaltung bei Puffertemp. > 60°C
191
if (Temperatur_1 >= 60)
192
  A7_on;
193
194
if (Temperatur_1 <= 58)
195
  A7_off;
196
197
198
199
200
//Umwandlung INT -> ASCII, Zuweisung buffer_x
201
  Format (Temperatur_1, buffer_1);  //Temp. Puffer oben
202
  Format (Temperatur_2, buffer_2);  //Temp. Heizkreis Rücklauf
203
  Format (Temperatur_3, buffer_3);  //Temp. Holzofen
204
  Format (Temperatur_4, buffer_4);  //Temp. Puffer Rücklauf
205
  Format (delta_1, buffer_5);       //Differenz zw. Puffer oben und Heizkreis Rücklauf
206
  Format (Mittelwert_11, buffer_6); //Digits Puffer oben
207
208
209
210
// Positionen, Texte und Werte (Maske) setzen
211
  scrPos ("1", "25"); uart_puts ("\x1b\[1K"); uart_puts("Holzofensteuerung v2.00c");
212
  scrPos ("2", "25"); uart_puts ("\x1b\[1K"); uart_puts("von Stefan Sachs");
213
  scrPos ("4", "1"); uart_puts ("Temperatur Holzofen: ");
214
  scrPos ("5", "1"); uart_puts ("Temperatur Puffer oben: ");
215
  scrPos ("6", "1"); uart_puts ("Temperatur Heizkreis-Ruecklauf: ");
216
  scrPos ("7", "1"); uart_puts ("Temperatur Differenz: ");
217
  scrPos ("8", "1"); uart_puts ("Temperatur Puffer-Ruecklauf: ");
218
  scrPos ("4", "34"); uart_puts (buffer_3);
219
  scrPos ("5", "34"); uart_puts (buffer_1);
220
  scrPos ("5", "40"); uart_puts (buffer_6);
221
  scrPos ("6", "34"); uart_puts (buffer_2);
222
  scrPos ("7", "34"); uart_puts (buffer_5);
223
  scrPos ("8", "34"); uart_puts (buffer_4);
224
225
226
  }
227
}
228
229
//Ab hier Funktionen
230
231
// Hier werden die Positionen auf dem
232
// Bildschirm angefahren
233
void scrPos(char* x, char* y)
234
{
235
  uart_puts ("\x1b\[");  // x1b ESC- Zeichen
236
  uart_puts (x);         // Zeilenauswahl
237
  uart_putc (';');       // Gehört zur ESC- Sequenz
238
  uart_puts (y);         // Spaltenauswahl
239
  uart_putc ('H');       // Gehört zur ESC- Sequenz
240
  //uart_puts ("\x1b\[K");
241
242
}
243
244
245
//Hier wird der Timer A eigestellt
246
void Timer_A (void)
247
{
248
  TACTL = TASSEL_2 + TACLR;   //SMCLK (DCO) + Clear Timer A
249
  TACCTL0 = CCIE;             //Capture / compare interrupt en.
250
  TACCR0 = cycles;            //s. #define cycles
251
  TACTL |= MC_2 |ID_3;        //Continuous- Mode to TACCR0 + clock/8
252
}
253
254
255
// Hier wird der 8MHz Quarz aktiviert
256
// und der DCO auf 100KHz eigestellt
257
void init_XT(void)
258
{
259
  unsigned int i;
260
  WDTCTL = WDTPW + WDTHOLD;             // Stop WDT
261
  DCOCTL = DCO1 + DCO0;                 // SMCLK 100KHz
262
  BCSCTL1 &= ~RSEL2 |RSEL1 |RSEL0;      // SMCLK 100KHz
263
  BCSCTL1 |= XTS;                       // ACLK = LFXT1 = HF XTAL
264
  do
265
  {
266
    IFG1 &= ~OFIFG;                    // Clear OSCFault flag
267
    for (i = 0xFF; i > 0; i--);        // Time for flag to set
268
  }
269
  while ((IFG1 & OFIFG) == OFIFG);     // OSCFault flag still set?
270
  BCSCTL2 |= SELM1+SELM0;              // MCLK = LFXT1 (safe)
271
}
272
273
// Hier werden INT- Zahlen in ASCII umgewandelt (einfache Version)
274
void Format(long zahl, char* string) {
275
  int i;
276
277
  string[5]='\0';                  // String Terminator
278
  if( zahl < 0 ) {                  // ist die Zahl negativ?
279
    string[0] = '-';
280
    zahl = -zahl;
281
  }
282
  else string[0] = ' ';             // Zahl ist positiv
283
284
  for(i=4; i>=1; i--) {
285
    string[i]=(zahl % 10) +'0';     // Modulo rechnen, dann den ASCII-Code von '0' addieren
286
    zahl /= 10;
287
  }
288
}
289
290
291
292
// Umrechnung der Digits in Temperatur
293
long int Temperatur (long int Digit)
294
{
295
296
  if (Digit <= 2824)
297
      return (((Digit - Offset) * 1471) / 10000);
298
299
  if ((Digit >= 2825) && (Digit <= 2884))
300
    return (((Digit - Offset) * 1493) / 10000);
301
302
  if ((Digit >= 2885) && (Digit <= 2938))
303
      return (((Digit - Offset) * 1548) / 10000);
304
305
  if ((Digit >= 2939) && (Digit <= 2988))
306
      return (((Digit - Offset) * 1595) / 10000);
307
308
  if ((Digit >= 2989) && (Digit <= 3036))
309
      return (((Digit - Offset) * 1650) / 10000);
310
311
  if ((Digit >= 3037) && (Digit <= 3081))
312
      return (((Digit - Offset) * 1695) / 10000);
313
314
  if ((Digit >= 3082) && (Digit <= 3123))
315
      return (((Digit - Offset) * 1751) / 10000);
316
317
  if ((Digit >= 3124) && (Digit <= 3162))
318
      return (((Digit - Offset) * 1799) / 10000);
319
320
  if ((Digit >= 3163) && (Digit <= 3196))
321
      return (((Digit - Offset) * 1862) / 10000);
322
323
  if (Digit >= 3197)
324
      return (((Digit - Offset) * 1919) / 10000);
325
326
327
  //return (((Digit * ((Uref / MaxDigit) * Steigung)) / 10000) - Offset);
328
  //return (Digit - 2588);
329
}
330
331
332
333
// Senden eines Zeichens
334
int uart_putc(char c)
335
{
336
  while (!(IFG2 & UTXIFG1));  /* warten bis Senden moeglich */
337
338
    U1TXBUF = c;                      /* sende Zeichen */
339
    return 0;
340
}
341
342
343
// Senden eines Strings
344
void uart_puts (char *s)
345
{
346
    while (*s)
347
    {   /* so lange *s != '\0' also ungleich dem "String-Endezeichen(Terminator)" */
348
        uart_putc(*s);
349
        s++;
350
    }
351
}
352
353
354
//Hier wird der ADC eingestellt
355
void Init_ADC(void)
356
{
357
  P6SEL = 0xFF;  // Analogeingänge A0 - A7 (P6.0 - P6.7)
358
  ADC12CTL0 = ADC12ON + REFON + REF2_5V + MSC + SHT0_12 + SHT1_12;
359
  ADC12CTL1 = ADC12SSEL_1 + ADC12DIV_7 + SHP + CONSEQ_1;
360
  ADC12MCTL0 = SREF_7 + INCH_0; // Wert von A0 landet in ADC12MEM0
361
  ADC12MCTL1 = SREF_7 + INCH_1; // Wert von A1 landet in ADC12MEM1
362
  ADC12MCTL2 = SREF_7 + INCH_2; // Wert von A2 landet in ADC12MEM2
363
  ADC12MCTL3 = SREF_7 + INCH_3; // Wert von A3 landet in ADC12MEM3
364
  ADC12MCTL4 = SREF_7 + INCH_4; // Wert von A4 landet in ADC12MEM4
365
  ADC12MCTL5 = SREF_7 + INCH_5; // Wert von A5 landet in ADC12MEM5
366
  ADC12MCTL6 = SREF_7 + INCH_6; // Wert von A6 landet in ADC12MEM6
367
  ADC12MCTL7 = SREF_7 + INCH_7 + EOS; // Wert von A7 landet in ADC12MEM7
368
  ADC12IE = 0x80;  //ADC Interrupts freigeben
369
  ADC12CTL0 |= ENC;  // Konvertierung freigenben
370
}
371
372
373
374
//Hier wird der ADC gestartet
375
void Read_ADC(void)
376
{
377
  while (ADC12CTL1 & ADC12BUSY);  //ADC noch beschäftigt?
378
  ADC12CTL0 |= ADC12SC;   // Neue Konvertierung starten
379
}
380
381
382
383
384
385
386
//Ab hier ISR's
387
388
// Hier wird der ADC angestoßen
389
// und 8 Mittelwerte gebildet
390
#pragma vector=TIMERA0_VECTOR
391
__interrupt void TimerA0_VECTOR (void)
392
{
393
    Read_ADC();
394
395
//a=1/4
396
      Mittelwert_1 = ((Mittelwert_1 * 3) >> 2) + (Digit_1 >> 2);
397
      Mittelwert_2 = ((Mittelwert_2 * 3) >> 2) + (Digit_2 >> 2);
398
      Mittelwert_3 = ((Mittelwert_3 * 3) >> 2) + (Digit_3 >> 2);
399
      Mittelwert_4 = ((Mittelwert_4 * 3) >> 2) + (Digit_4 >> 2);
400
      Mittelwert_5 = ((Mittelwert_5 * 3) >> 2) + (Digit_5 >> 2);
401
      Mittelwert_6 = ((Mittelwert_6 * 3) >> 2) + (Digit_6 >> 2);
402
      Mittelwert_7 = ((Mittelwert_7 * 3) >> 2) + (Digit_7 >> 2);
403
      Mittelwert_8 = ((Mittelwert_8 * 3) >> 2) + (Digit_8 >> 2);
404
405
//a=1/2
406
      Mittelwert_11 = (Mittelwert_11 >> 1) + (Mittelwert_1 >> 1);
407
      Mittelwert_12 = (Mittelwert_12 >> 1) + (Mittelwert_2 >> 1);
408
      Mittelwert_13 = (Mittelwert_13 >> 1) + (Mittelwert_3 >> 1);
409
      Mittelwert_14 = (Mittelwert_14 >> 1) + (Mittelwert_4 >> 1);
410
      Mittelwert_15 = (Mittelwert_15 >> 1) + (Mittelwert_5 >> 1);
411
      Mittelwert_16 = (Mittelwert_16 >> 1) + (Mittelwert_6 >> 1);
412
      Mittelwert_17 = (Mittelwert_17 >> 1) + (Mittelwert_7 >> 1);
413
      Mittelwert_18 = (Mittelwert_18 >> 1) + (Mittelwert_8 >> 1);
414
415
  CCR0 += cycles;                        // Add Offset to CCR0
416
}
417
418
419
420
// Hier werden 8 ADC-Werte zugewiesen
421
#pragma vector=ADC12_VECTOR
422
__interrupt void ADC12ISR (void)
423
{
424
  Digit_1 = ADC12MEM0;
425
  Digit_2 = ADC12MEM1;
426
  Digit_3 = ADC12MEM2;
427
  Digit_4 = ADC12MEM3;
428
  Digit_5 = ADC12MEM4;
429
  Digit_6 = ADC12MEM5;
430
  Digit_7 = ADC12MEM6;
431
  Digit_8 = ADC12MEM7;
432
433
}
434
435
436
/*
437
// UART0 TX ISR
438
#pragma vector=USART0TX_VECTOR
439
__interrupt void usart0_tx (void)
440
{
441
  char i, j;
442
  for (j=0; j<2; j++)
443
  {
444
  for (i=0; i < sizeof Digit[j]; i++)
445
    TXBUF0 = Digit[j];
446
447
  }
448
}
449
*/
450
451
//Hier werden die Tasten abgefragt
452
#pragma vector = PORT1_VECTOR
453
__interrupt void PORT1_ISR (void)
454
{
455
//  __low_power_mode_off_on_exit();
456
457
  int i;
458
459
  //funktion = funktion + set;
460
      //  set = 0;
461
      //  if (funktion > 5) {funktion = 0;}
462
      //  if (funktion < 0) {funktion = 5;}
463
464
        if (!(P1IN & BIT0))
465
        {
466
          //P4OUT ^= BIT0;
467
          for (i=1; i <= 1200; i++){}
468
469
        //  set = 1;
470
        }
471
472
        P1IFG &= ~BIT0;  // Interrupt Flag löschen
473
474
475
        if (!(P1IN & BIT1))
476
        {
477
          //P4OUT ^= BIT1;
478
          for (i=1; i <= 1200; i++){}
479
480
        //  set = -1;
481
        }
482
        P1IFG &= ~BIT1;  // Interrupt Flag löschen
483
484
485
        if (!(P1IN & BIT2))
486
        {
487
          //P4OUT ^= BIT2;
488
          for (i=1; i <= 1200; i++){}
489
490
          //  set = -1;
491
        }
492
        P1IFG &= ~BIT2;  // Interrupt Flag löschen
493
494
495
        if (!(P1IN & BIT3))
496
        {
497
          P4OUT ^= BIT3;
498
          for (i=1; i <= 1200; i++){}
499
500
          //  set = -1;
501
        }
502
        P1IFG &= ~BIT3;  // Interrupt Flag löschen
503
504
505
        if (!(P1IN & BIT4))
506
        {
507
          P4OUT ^= BIT4;
508
          for (i=1; i <= 1200; i++){}
509
510
          //  set = -1;
511
        }
512
        P1IFG &= ~BIT4;  // Interrupt Flag löschen
513
514
515
        if (!(P1IN & BIT5))
516
        {
517
          P4OUT ^= BIT5;
518
          for (i=1; i <= 1200; i++){}
519
520
          //  set = -1;
521
        }
522
        P1IFG &= ~BIT5;  // Interrupt Flag löschen
523
524
525
        if (!(P1IN & BIT6))
526
        {
527
          P4OUT ^= BIT6;
528
          for (i=1; i <= 1200; i++){}
529
530
          //  set = -1;
531
        }
532
        P1IFG &= ~BIT6;  // Interrupt Flag löschen
533
534
535
        if (!(P1IN & BIT7))
536
        {
537
          P4OUT ^= BIT7;
538
          for (i=1; i <= 1200; i++){}
539
540
          //  set = -1;
541
        }
542
        P1IFG &= ~BIT7;  // Interrupt Flag löschen
543
544
545
546
}

Besten Dank

von Found (Gast)


Lesenswert?

Ein paar Dinge fallen mir auf:

  int           long int      long int
Temperatur_1 = Temperatur (Mittelwert_11)
Hier reichen durchgängig 16 Bit.

Format (Temperatur_1, buffer_1)
          int          char[6]
Hier reichen die 6 Byte nicht. 1 Byte Vorzeichen + 5 Zeichen für int + 1 
Byte '/'.

for (i=1; i <= 1200; i++){}
Das ist in einer ISR gar nicht gut. Such einmal nach Entprellung 
http://www.mikrocontroller.net/articles/Entprellung oder hier im Forum.

von Stefan S. (blacknighthawk)


Lesenswert?

Hallo Found,

besten Dank für deine Tips.
Bei den char[6] habe ich doch glatt vergessen das Schlusszeichen mit 
einzubeziehen.

Das mit der Entprellung werde ich mir mal genauer ansehen.

Dann mal noch eine allgemeine Frage an alle:

Wenn ich nicht explizit einen LPM aktiviere, dann kann der MSP doch 
unter keinen Umständen "schlafen" gehen, ist das richtig?

Oder soll ich zur Sicherheit alle Register die für LPM sind auf "0" 
setzten?

von MartinK (Gast)


Lesenswert?

Von alleine geht der MSP nicht in den Schlafzustand.
Hast du mal den Stromverbrauch gemessen?

von Stefan S. (blacknighthawk)


Lesenswert?

MartinK schrieb:
> Von alleine geht der MSP nicht in den Schlafzustand.

Diese Aussage alleine reicht mir schon.

> Hast du mal den Stromverbrauch gemessen?

Da komme ich in der fertigen Schaltung nicht mehr so gut dran, dafür 
müsste ich Leiterbahnen auftrennen.
Und bis jetzt läuft die Anlage wieder ohne Zwischenfälle, ich weiß also 
nicht wann der nächste Crash passiert.

von EMV (Gast)


Lesenswert?

Wie steht es um EMV. Hast du deine Schaltung gut entkoppelt und 
geschützt? Sonst kannst du die Wertebereiche vor der Verarbeitung 
überprüfen. Wie verhält sich dein Code bei unerwarteten Werten?

Stefan S. schrieb:
> if (Digit <= 2824)
>       return (((Digit - Offset) * 1471) / 10000);
>
>   if ((Digit >= 2825) && (Digit <= 2884))
>     return (((Digit - Offset) * 1493) / 10000);
>
>   if ((Digit >= 2885) && (Digit <= 2938))
>       return (((Digit - Offset) * 1548) / 10000);
Das lässt sich optimieren:
1
if (Digit <= 2824)
2
      return (((Digit - Offset) * 1471) / 10000);
3
else if (Digit <= 2884)
4
     return (((Digit - Offset) * 1493) / 10000);
5
else if (Digit <= 2938)
6
     return (((Digit - Offset) * 1548) / 10000);
Und da du mit return den restlichen Teil der Funktion überspringst, geht 
es hier auch ohne die else.

von Stefan S. (blacknighthawk)


Lesenswert?

EMV schrieb:
> Wie steht es um EMV. Hast du deine Schaltung gut entkoppelt und
> geschützt? Sonst kannst du die Wertebereiche vor der Verarbeitung
> überprüfen.

EMV hin oder her, ich habe 6 Jahre in einem EMV- Labor gearbeitet und so 
manchen seltsamen Effekt gesehen.
Natürlich kann der Ausfall von neulich auch auf eine seltene Störung von 
außen zurückzuführen sein.
Die AVCC ist über 15uH von der DVCC entkoppelt, allerdings liegen AVSS 
und DVSS auf der selben Masse.

Die Roh- Digits vom ADC sind sehr unruhig, da dachte ich zuerst auch ein 
Problem in meiner Schaltung. Aber Arbeitskollegen haben mir von 
ähnlichen Erfahrungen berichtet, was die Stabilität der ADC- Werte 
angeht.

> Wie verhält sich dein Code bei unerwarteten Werten?

Ich hätte ja mal behauptet, alles was kleiner / gleich 2824 Digits ist 
(entspricht glaube ich 0°C) wird mit
1
return (((Digit - Offset) * 1471) / 10000);

behandelt.
Und alles was größer / gleich 3197 Digits ist (entspricht glaube ich 120 
°C) wird mit
1
return (((Digit - Offset) * 1919) / 10000);

behandelt.
Klar dass alles was unter 0°C und über 120°C ungenau wird, aber in der 
Anlage herrschen Temperaturen von min. 20°C und max. 90°C.
Aber wenn hier ein Denkfehler vorliegt, bitte sagen.


> Das lässt sich optimieren:
>
1
> if (Digit <= 2824)
2
>       return (((Digit - Offset) * 1471) / 10000);
3
> else if (Digit <= 2884)
4
>      return (((Digit - Offset) * 1493) / 10000);
5
> else if (Digit <= 2938)
6
>      return (((Digit - Offset) * 1548) / 10000);
7
>
> Und da du mit return den restlichen Teil der Funktion überspringst, geht
> es hier auch ohne die else.

Da hast du allerdings Recht, die ganzen else's hätte ich mir sparen 
können.

Was ich allerdings mal noch gerne implementieren würde ist, die Digit- 
Werte in einer Tabelle abzulegen und zu interpolieren. Da weiß ich aber 
noch nicht wie es geht.


Was mir noch eingefallen ist, macht es überhaupt Sinn oder ist es sogar 
schlecht die RS232 bei diesem MSP mit 19200 Baud zu befeuern?

Und ist es schlecht an XT2 einen 32KHz Quarz anzuschließen, diesen aber 
nicht zu benutzen?

von EMV (Gast)


Lesenswert?

Stefan S. schrieb:
>> if (Digit <= 2824)
>>       return (((Digit - Offset) * 1471) / 10000);
>> else if (Digit <= 2884)
>>      return (((Digit - Offset) * 1493) / 10000);
>> else if (Digit <= 2938)
>>      return (((Digit - Offset) * 1548) / 10000);
>> > Und da du mit return den restlichen Teil der Funktion überspringst, geht
>> es hier auch ohne die else.
>
> Da hast du allerdings Recht, die ganzen else's hätte ich mir sparen
> können.

Mir ging es dabei um etwas anderes. In deinem Post fragst du Intervalle 
ab. Da kann durch eine kleine Unachtsamkeit schnell ein Wert durch 
rutschen. Wenn du nur eine Schwelle auswertest, kann das nicht 
passieren.

Stefan S. schrieb:
> Die Roh- Digits vom ADC sind sehr unruhig, da dachte ich zuerst auch ein
> Problem in meiner Schaltung.

Welche Auflösung nutzt du und wieviel Bits wackeln?

Stefan S. schrieb:
> Und ist es schlecht an XT2 einen 32KHz Quarz anzuschließen, diesen aber
> nicht zu benutzen?

Wenn du den externen Takt nicht konfiguriest, ist das kein Problem. Der 
schwingt dann auch nicht.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Stefan S. schrieb:
> Was mir noch eingefallen ist, macht es überhaupt Sinn oder ist es sogar
> schlecht die RS232 bei diesem MSP mit 19200 Baud zu befeuern?

Die UART auch dieses steinalten MSP430-Exemplars hat einen recht 
flexiblen Baudratengenerator, so daß --eine stabile Takterzeugung 
vorausgesetzt-- diese Baudrate kein Problem ist. Sogenannte 
"Baudratenquarze" sind i.d.R. nicht erforderlich.

Um auf Nummer Sicher zu gehen, solltest Du Dir im "Family User's Guide" 
(SLAU149) den Abschnitt über die Baudratenerzeugung zu Gemüte führen, da 
wird beschrieben, wie der Baudratenfehler für verschiedene 
Taktfrequenzen zu berechnen ist.

Auf http://processors.wiki.ti.com/index.php/USART_Baud_Rate_Calculator 
ist eine Tabelle 
(http://processors.wiki.ti.com/images/8/81/MSP430_USART_Baud_Rate.pdf) 
verlinkt, bei der die Baudratenberechnung für übliche Baudraten und 
übliche Taktfrequenzen durchgeführt wurde.

Einen Online-Berechner, der das alles ausspuckt, gibt es auch noch:
http://mspgcc.sourceforge.net/baudrate.html

Allerdings ist eine stabile Takterzeugung nötig, und zwar unabhängig von 
der Baudrate. Der DCO ist nicht stabil genug, und auch die 
Stabilisierung mit einem Uhrenquarz, wie in einer TI-Appnote 
beschrieben, ist wegen des ständig schwankenden Takts auch ungeeignet.

von stef (Gast)


Lesenswert?

Hallo,

ich arbeite auch viel mit MSP430, von alleine in den LPM habe ich noch 
nicht erlebt, dafür alles andere drumherum :)
Ich glaube auch das kein System von sich aus 100% stabil ist, alles nur 
eine Frage der Zeit.


Deine Entprellung sieht merkwürdig und sinnlos aus, Ich würde das in 
einem Timer Interrupt abfragen:
__interrupt void TimerA0_1ms(void)
{
  if ( (Taster_OK_I&Taster_OK) )Taste_OK_debounce++;
  else Taste_OK_debounce = 0;
  if (Taste_OK_debounce == DEBOUNCE ){
    Taste_OK = 1;
  }

so mach ich das, funktioniert prima, also nur soalnge Taste gedrückt ist 
wird sie gezählt und das über ein paar ms weg.

Das Rauschen auf der ADC Messung kann ich so bestätigen, ich messe mit 
12 bit bei internen oder externen Vref von 2,5 V habe ich auch bis zu 
50mV Rauschen drauf, keine Ahnung ob das an meinem PCB Layout liegt oder 
intern im MSP430 oder doch an der externen Quelle, wobei ich der schon 
vertraue. Da kommt man wohl nicht drumherum ohne sehr gute Kenntnisse 
und Layouts.

Viele Grüße,

von Max G. (l0wside) Benutzerseite


Lesenswert?

Rufus Τ. Firefly schrieb:
> Allerdings ist eine stabile Takterzeugung nötig, und zwar unabhängig von
> der Baudrate. Der DCO ist nicht stabil genug, und auch die
> Stabilisierung mit einem Uhrenquarz, wie in einer TI-Appnote
> beschrieben, ist wegen des ständig schwankenden Takts auch ungeeignet.

Gilt diese Aussage nur für den F167, oder für alle Derivate? Ich setze 
den MSP430F5310 ein, allerdings stets ohne Quarz. War auf der UART nie 
ein Problem. SPI und I2C sind sowieso unkritisch.

Max

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Max G. schrieb:
> Gilt diese Aussage nur für den F167, oder für alle Derivate?

Der DCO im 'F5310 ist nicht mit dem der steinalten 'F1xx-Reihe 
vergleichbar, da er über die FLL mit dem REFO stabilisiert werden kann. 
Das ist um Größenordnungen genauer.

Mir ist sowieso unklar, warum jetzt noch Leute mit 'F1xx arbeiten. Die 
Dinger sind deutlich teurer, langsamer und können weniger als alles, was 
TI danach herausgebracht hat.

Als so eine Art "Wasserscheide" kann man das Vorhandensein von SBW 
ansehen.

> SPI und I2C sind sowieso unkritisch.

Das ist logisch, da bei synchronen seriellen Schnittstellen ein 
Taktsignal mitgeliefert wird.

von stef (Gast)


Lesenswert?

manche MSP430 haben eine kalibrierte DCO, das ist dann im Datenblatt zu 
lesen und man kann da mit gewissen kleinen Abweichungen, die natürlich 
auch angegegeben sind, davon ausgehen, dass der Takt zB 1 MHz sehr genau 
gehalten wird.

Andere DCOs schwanken da schon stärker was sich durchaus auf BAudrate 
auswirkne kann.
Ich habe bisher immer einen externen Quarz drauf gehabt, vor allem um 
eben die hohen Freuqenzen zu haben und weil ich doch verschiedene Timer 
benutze die zB eine PWM ansteuern, und da will ich eben genau wissen was 
meine Zeiten sind.

von Max G. (l0wside) Benutzerseite


Lesenswert?

Rufus Τ. Firefly schrieb:
>> SPI und I2C sind sowieso unkritisch.
>
> Das ist logisch, da bei synchronen seriellen Schnittstellen ein
> Taktsignal mitgeliefert wird.

You got my point :-)


stef schrieb:
> Ich habe bisher immer einen externen Quarz drauf gehabt, vor allem um
> eben die hohen Freuqenzen zu haben und weil ich doch verschiedene Timer
> benutze die zB eine PWM ansteuern, und da will ich eben genau wissen was
> meine Zeiten sind.

Hohe Frequenzen? Ist das auch ein F1xxx-Thema? Meine F53xx laufen mit 25 
MHz ohne Quarz und ohne Probleme. Toleranz ist so 1%-2%, das tut mir 
nicht weh.

Max

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


Lesenswert?

Max G. schrieb:
> Hohe Frequenzen? Ist das auch ein F1xxx-Thema?

'F1xx können mit maximal 8 MHz betrieben werden.

Und ja, die Dinger sind im Vergleich zu allen neueren MSP430-Varianten 
ziemlich primitiv.

von Stefan S. (blacknighthawk)


Lesenswert?

stef schrieb:
> Deine Entprellung sieht merkwürdig und sinnlos aus, Ich würde das in
> einem Timer Interrupt abfragen:
> __interrupt void TimerA0_1ms(void)
> {
>   if ( (Taster_OK_I&Taster_OK) )Taste_OK_debounce++;
>   else Taste_OK_debounce = 0;
>   if (Taste_OK_debounce == DEBOUNCE ){
>     Taste_OK = 1;
>   }

Das dachte ich mir schon als ich es geschrieben habe, aber der Winter 
stand vor der Tür und das System sollte laufen.
Ich werde deinen Vorschlag mal versuchen in die Tat umzusetzen.

Rufus Τ. Firefly schrieb:
> Mir ist sowieso unklar, warum jetzt noch Leute mit 'F1xx arbeiten. Die
> Dinger sind deutlich teurer, langsamer und können weniger als alles, was
> TI danach herausgebracht hat.

Ich weiß, aber von den Teilen lagen noch ca. 30 Stück ungenutzt auf der 
Arbeit herum. Dieser MSP ist sozusagen mein Einstiegsprozessor.

Rufus Τ. Firefly schrieb:
> 'F1xx können mit maximal 8 MHz betrieben werden.

Das habe ich auch schon gemerkt, ich habe es mal mit einem 16MHz Quarz 
versucht... Das ging 3 Tage gut, dann löste plötzlich die thermische 
Sicherung am Ofen aus weil die Steuerung komplett hängen blieb. Das war 
ein Spass und das (zum Glück) auf den Sonntag.


Ich werde mal versuchen dem Watchdog in Betrieb zu setzten, vielleicht 
rettet der mich aus den kritischen Situationen.
Oder spricht etwas dagegen?

von Stefan S. (blacknighthawk)


Lesenswert?

Ich wünsche allen einen geruhsamen Sonntag.

Ich bin gerade meinen Code nochmals durchgegangen weil meine Anlage 
gerade eben wieder in einem undefinierten Zustand war. Ich glaube also 
nicht mehr dass sich etwas aufhängt, sondern grundlegende Probleme im 
Code sind.

Z.B. hier:
1
  Temperatur_1 = Temperatur (Mittelwert_11); // Temp. Puffer oben
2
  Temperatur_2 = Temperatur (Mittelwert_12); // Temp. Heizkreis-Rücklauf
3
  Temperatur_3 = Temperatur (Mittelwert_13); // Temp. Holzofen
4
5
6
delta_1 = Temperatur_1 - Temperatur_2;
7
8
        if (delta_1 >= 7)
9
        {
10
          A2_off;
11
          A1_on;
12
        }
13
14
15
        if (delta_1 <= 2)
16
        {
17
            A1_off;
18
             A2_on;
19
        }

Wenn delta_1 etwas zwischen 2 und 7 ist, passiert nach einem Reset 
nichts und auch sonst ist der Zustand undefiniert.

und dann:
1
delta_2 = Temperatur_3 - Temperatur_1;
2
3
if (Temperatur_3 >= 80)
4
  A3_on;
5
else
6
   {
7
      if (delta_2 >= 2)
8
        {
9
          if (Temperatur_3 >= 65)
10
            A3_on;
11
12
          if (Temperatur_3 <= 60)
13
            A3_off;
14
        }
15
      else
16
     A3_off;
17
   }

Wenn Temperatur_3 einen Wert zwischen 60 und 65 annimmt, ist auch ein 
toter Bereich.
Aber da muss noch ein Denkfehler drin sein.

von EMV (Gast)


Lesenswert?

Stefan S. schrieb:
> weil meine Anlage
> gerade eben wieder in einem undefinierten Zustand war

Das heißt?

Stefan S. schrieb:
> Wenn delta_1 etwas zwischen 2 und 7 ist, passiert nach einem Reset
> nichts und auch sonst ist der Zustand undefiniert.

Nö, den Zustand nach Reset kannst du aus dem Datenblatt lesen. Und wenn 
keine Bedingung trifft, bleibt der Zustand wir er ist.

Stefan S. schrieb:
> Wenn Temperatur_3 einen Wert zwischen 60 und 65 annimmt, ist auch ein
> toter Bereich.

Aber nur wenn delta_2 ... Sonst bleibt es wie es ist.

Das Ganze ist aber ein wenig konfus. In der Timer ISR wird er AD-Wandler 
gestartet. Parallel wird mit den gleichen Werten gerechnet, die in der 
AD ISR gerade beschrieben werden?
Wie erfolgt die Auswahl der Datentypen? Groß und klein sind bunt 
gemischt. Der Wertebereich sollte der Grund sein. Und ich glaube es geht 
mit weniger Variablen übersichtlicher.

Das Programm ist nicht besonders groß. Da ist ein neuer Ansatz durchaus 
erlaubt.

von Stefan S. (blacknighthawk)


Lesenswert?

EMV schrieb:
> Das Programm ist nicht besonders groß. Da ist ein neuer Ansatz durchaus
> erlaubt.

Das stimmt allerdings.
Ich werde das Programm mal grundlegend überarbeiten müssen.
Einiges kann noch einfacher und besser gemacht werden.

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.