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 | }
|