s555ht.c


1
// Beispielcode zur Auswertung der S555HT Temperatur/Feuchtesensoren (Conrad)
2
// und EM1000 Energiemonitore
3
// http://www.dc3yc.privat.t-online.de/protocol.htm
4
// http://www.mikrocontroller.net/topic/193435
5
// http://www.jansipke.nl/tag/s555th
6
7
#include <string.h>
8
#include <avr/io.h>
9
#include <util/delay.h>
10
#include <util/parity.h>
11
#include <avr/interrupt.h> 
12
#include <stdlib.h>
13
#include <stdio.h>
14
 
15
#include "uart.h"
16
17
#define DEBUG
18
19
#ifdef DEBUG
20
FILE usart_out = FDEV_SETUP_STREAM(uart_putc, NULL, _FDEV_SETUP_WRITE);
21
#endif
22
23
struct WS300_t
24
{
25
  uint8_t sync;
26
  uint8_t nstart;
27
  uint8_t bitcnt;
28
  uint8_t bytecnt;
29
  uint8_t nibble[16];
30
};
31
32
struct          WS300_t  aWs;
33
volatile struct WS300_t  aWs2;
34
volatile        uint8_t ws2_ready;
35
36
struct em1000_t
37
{
38
  uint8_t sync;
39
  uint8_t nstart;
40
  uint8_t bitcnt;
41
  uint8_t bytecnt;
42
  uint8_t bytes[12];
43
};
44
45
struct em1000_t          aEm;
46
volatile struct em1000_t aEm2;
47
volatile        uint8_t  em2_ready;
48
49
uint8_t in;  
50
uint8_t il;
51
uint8_t c1;
52
uint8_t c0;
53
54
#define WS300_HIGHMIN 15
55
#define WS300_HIGHMAX 40
56
#define WS300_LOWMIN   4
57
#define WS300_LOWMAX  15
58
59
60
#define EM100_LONGMIN  19
61
#define EM100_LONGMAX  26
62
#define EM100_SHORTMIN  8
63
#define EM100_SHORTMAX 14
64
65
66
ISR(TIMER2_OVF_vect)    
67
{ 
68
  // Port setzen um Interruptzeit mit DSO zu messen   
69
  PORTB |= _BV(PB0);
70
71
  // aktuellen Zustand in merken und vorher nach links verschieben
72
  // damit stehen die letzten Zustände in "in"
73
  in<<=1;
74
  if (PIND & _BV(PD2))
75
    in|=1;
76
77
  // 3 mal 1 im Register bedeutet High
78
  if ((in & 0x7) == 0x7) 
79
    {
80
    // Heigh-Ticks zählen
81
    c1++;
82
    
83
    // immer an der 01 Flanke testen?
84
    if (il==0)
85
      {
86
      
87
      //-------------------- WS300 --------------------
88
      if (   c1>WS300_HIGHMIN && c1<WS300_HIGHMAX
89
          && c0>WS300_LOWMIN  && c0<WS300_LOWMAX)
90
        {
91
        // gültiges Low-Bit erkannt
92
        
93
        // Nullen am Anfang zaehlen
94
        if (!aWs.sync)
95
          aWs.nstart++;
96
        else
97
          {
98
          // das Bit ins Array einsortieren
99
          aWs.nibble[aWs.bytecnt]>>=1;  
100
          aWs.bitcnt++;
101
          if (aWs.bitcnt==5)
102
            {
103
            aWs.bitcnt=0;
104
            aWs.bytecnt++;
105
            // ueberlauf verhindern
106
            if (aWs.bytecnt>15)
107
              aWs.bytecnt=15;
108
            }             
109
          }
110
        }          
111
      else if (   c0>WS300_HIGHMIN && c0<WS300_HIGHMAX
112
               && c1>WS300_LOWMIN  && c1<WS300_LOWMAX)
113
        {
114
        // gültiges Heigh-Bit erkannt
115
        if (!aWs.sync)
116
          {
117
          // jedes Telegramm beginnt mit wenigstens 6 mal 0
118
          if (aWs.nstart>6)
119
            {   
120
            aWs.sync=1;
121
            aWs.bitcnt=0;
122
            aWs.bytecnt=0;
123
            }
124
          else
125
            {
126
            // Anzahl Low-Bits am Telegrammanfang zu klein
127
            aWs.nstart=0;
128
            }
129
          }
130
        else
131
          {
132
          // das Bit ins Array einsortieren
133
          // jedes nibble von links nach rechts reinschieben
134
          // das Trennbit (1) ist das letzte und wird auch 
135
          // reingeschoben
136
          aWs.nibble[aWs.bytecnt]>>=1;  
137
          aWs.nibble[aWs.bytecnt]|=0x10;  
138
          aWs.bitcnt++;
139
          if (aWs.bitcnt==5)
140
            {
141
            aWs.bitcnt=0;
142
            aWs.bytecnt++;
143
            // ueberlauf verhindern
144
            if (aWs.bytecnt>15)
145
              aWs.bytecnt=15;
146
            }             
147
          }
148
        }
149
      else  
150
        {
151
        // die Auswertung erfolgt mit den ersten ungültigen Bit
152
        if (aWs.sync)
153
          {
154
          // Umkopieren wenn die Hauptschleife
155
          // nicht gerade darauf zugreift
156
          if (!ws2_ready)
157
            {
158
            aWs2=aWs; 
159
            ws2_ready=1;
160
            }
161
          }
162
        aWs.sync=0;
163
        aWs.nstart=0;     
164
        } 
165
      
166
      // ------------- EM100 ------------------------------
167
      if (   c1>EM100_SHORTMIN && c1<EM100_SHORTMAX
168
          && c0>EM100_SHORTMIN && c0<EM100_SHORTMAX)
169
        {
170
        // gültiges Low-Bit erkannt
171
        
172
        // Nullen am Anfang zaehlen
173
        if (!aEm.sync)
174
          aEm.nstart++;
175
        else
176
          {
177
          // das Bit ins Array einsortieren
178
          if (aEm.bitcnt==8)
179
            {
180
            // 
181
            aEm.bitcnt=0;
182
            aEm.bytecnt++;
183
            if (aEm.bytecnt<=9)
184
              {
185
              // fehlerhaftes stopp bit
186
              aEm.sync=0;
187
              aEm.nstart=0;     
188
              }
189
            // ueberlauf verhindern
190
            if (aEm.bytecnt>11)
191
              aEm.bytecnt=11;
192
            }          
193
          else
194
            {   
195
            aEm.bytes[aEm.bytecnt]>>=1;  
196
            aEm.bitcnt++;
197
            }
198
          }
199
        }          
200
      else if (   c1>EM100_SHORTMIN && c1<EM100_SHORTMAX
201
               && c0>EM100_LONGMIN  && c0<EM100_LONGMAX)
202
        {
203
        // gültiges Heigh-Bit erkannt
204
        if (!aEm.sync)
205
          {
206
          // jedes Telegramm beginnt mit wenigstens 10 mal 0
207
          if (aEm.nstart>10)
208
            {   
209
            aEm.sync=1;
210
            aEm.bitcnt=0;
211
            aEm.bytecnt=0;
212
            }
213
          else
214
            {
215
            aEm.nstart=0;
216
            }
217
          }
218
        else
219
          {
220
          if (aEm.bitcnt==8)
221
            {
222
            // Stop-Bit   
223
            aEm.bitcnt=0;
224
            aEm.bytecnt++;
225
            if (aEm.bytecnt>11)
226
              aEm.bytecnt=11;
227
            }          
228
          else
229
            {   
230
            // das Bit ins Array einsortieren 
231
            aEm.bytes[aEm.bytecnt]>>=1;  
232
            aEm.bytes[aEm.bytecnt]|=0x80;  
233
            aEm.bitcnt++;
234
            }
235
          }
236
        }
237
      else  
238
        {
239
        // die Auswertung erfolgt mit den ersten ungültigen Bit
240
        if (aEm.sync)
241
          {
242
          // Umkopieren nur wenn der Hauptprozess nicht gerade 
243
          // darauf zugreift
244
          if (!em2_ready)
245
            {
246
            aEm2=aEm; 
247
            em2_ready=1;
248
            }
249
          }
250
        aEm.sync=0;
251
        aEm.nstart=0;     
252
        } 
253
      
254
      // bei jeder 01 Flanke geht die Messung neu los
255
      c0=0; 
256
      c1=0;
257
      }
258
    il=1; 
259
    }
260
  
261
  if ((in & 0x7) == 0)
262
    {
263
    c0++;
264
    il=0;
265
    }
266
  
267
  // Pin für DSO wieder ausschalten
268
  PORTB &= ~_BV(PB0);
269
}
270
271
272
uint8_t ParseWS300() 
273
{
274
  if (aWs2.nibble[0]!=0x11 || aWs2.bytecnt<9)
275
    { 
276
    printf("type err\r\n");
277
    return 0;
278
    }
279
280
  uint8_t xor=0;
281
  uint8_t sum=0;
282
  for (uint8_t n=0; n<9; n++)
283
    {
284
    // Markerbits testen
285
    if ((aWs2.nibble[n] & 0x10) != 0x10)
286
      return 0;
287
    
288
    uint8_t nib=aWs2.nibble[n]&0x0f;
289
    xor^=nib;
290
    sum+=nib;
291
    aWs2.nibble[n] &= 0x0F;
292
    }    
293
  
294
  // wenn das letzte Bit im Protokoll nicht erkannt wurde
295
  // ist das nibble 1bit zu weit links
296
  uint8_t sumhas=aWs2.nibble[9];
297
  if (aWs2.bytecnt<10)
298
    sumhas>>=1;
299
  else
300
    sumhas&=0x0f;
301
302
  if (xor!=0)
303
    { 
304
    printf("xor err\r\n");
305
    return 0;
306
    }
307
308
  sum=(sum+5) & 0x0f; 
309
310
  if (sum != sumhas)
311
    { 
312
    printf("sum err %x %x\r\n", sum, (aWs2.nibble[9] & 0x0F) );
313
    return 0;
314
    }
315
  
316
  int16_t temp=aWs2.nibble[2]+aWs2.nibble[3]*10+aWs2.nibble[4]*100;
317
  int16_t hum=aWs2.nibble[5]+aWs2.nibble[6]*10+aWs2.nibble[7]*100;
318
  uint8_t Adr=aWs2.nibble[1] & 0x07;
319
  if ((aWs2.nibble[1] & 0x08) != 0)
320
    temp*=-1;
321
322
  printf("adr %i temp %i hum %i\r\n", Adr+1, temp, hum);
323
324
  return 1;
325
}
326
327
328
void ParseEm100()
329
{
330
  uint8_t u;
331
  uint8_t xor=0;
332
  if (aEm2.bytecnt<9)
333
    {
334
    printf("bytecnt err %i\r\n", aEm2.bytecnt);
335
    return;
336
    }
337
338
  for (u=0; u<10; u++)
339
    {
340
    // printf(" %x", aEm2.bytes[u]);
341
    xor^=aEm2.bytes[u];
342
    }
343
344
  // printf("\r\n");   
345
  if (xor!=0)
346
    {
347
    printf("xor err\r\n");
348
    return;
349
    }
350
351
  uint16_t umw=aEm2.bytes[4];
352
  umw<<=8;
353
  umw|=aEm2.bytes[3];
354
  printf("EM100 adr %i = %i\r\n", (int)aEm2.bytes[1], umw);
355
}
356
357
int main()
358
{
359
#ifdef DEBUG  
360
  uart_init();
361
  stdout=&usart_out;
362
#endif
363
  sei();
364
365
#ifdef DEBUG  
366
  printf_P(PSTR( "Hallo Welt\n\r"));
367
#endif
368
369
  // Timer 2 initialisieren 
370
  TCNT2  = 0;
371
  TCCR2A = 0;
372
  TCCR2B = _BV(CS20);  // kein Vorteiler
373
  TIMSK2 = _BV(TOIE2); // Interrupt an
374
  DDRB  |= _BV(PB0);   // Testpin als Ausgang setzten  
375
376
377
  while (1)
378
    {
379
    if (ws2_ready)
380
      {
381
      ParseWS300();
382
      ws2_ready=0;
383
      }
384
385
    if (em2_ready)
386
      {
387
      ParseEm100();
388
      em2_ready=0;
389
      }
390
391
    }  
392
  return 0;
393
}