Quantcast
Channel: 懒得折腾
Viewing all articles
Browse latest Browse all 764

MegaStat – Second Gen Smart Thermostat – 3. 433Mhz Receiver

$
0
0

http://csb.idilks.com/2014/03/megastat-second-gen-smart-thermostat-3.html

MegaStat – Second Gen Smart Thermostat – 3. 433Mhz Receiver

433 Mhz Communication with Spark Core

We have successful communication from the PIC temperature monitors to the Spark Core using the Linx 433 Mhz module.  The first step is to solder the Linx module to some wires since this module is a 16-SMD package and will be hard to bread board.  With some solder wizardry I managed to get all the wires on the module and attach an antenna.

Linx 433 Mhz Receiver

On the transmitter modules (OOK Modulated) you will notice that in the code I have inverted the output going from the UART to the transmitter.  This is done because the normal marking state of a UART is logic 1 or high.  This marking state causes constant transmission.  This would not be good when we are trying to have many monitoring modules transmitting to the thermostat.  Therefore on the receiving end I also have to invert the output from the receiver going to the spark core.  This can be achieved with a transistor or there are some chips you can buy to do the inverting.

Inverter circuit hooked up to the receiver
So with the power (24VAC to 5VDC), Spark Core, and 433 Mhz receiver all together looks like the following photo.
I have updated the schematic but here is a snapshot pic of the schematic before adding more components.
The code for receiving the messages on the spark core is located here.  The code verifies the message a byte at a time.  This is done by XORing the previous byte.  It is a very simple but effective encoding method.  With this method I can verify the message as it is being received and I do not have to wait for the entire message and then check a checksum.  This message is composed in the following method.  Byte, XORed Byte, Byte, XORed Byte till the message is complete.  Our message is composed like so “!”, XOR, “T” (for temperature), XOR, device ID (0 – 255), XOR, Sign (“+” or “-” for the temperature reading), XOR, Degrees whole number, XOR, Degrees Decimal, XOR.  Here is a snapshot of the code that just verifies the message.
License is located here.

 byte RxMsg[11]; // Message from the sensors
 byte RxIdx = 0; // Index in message buffer
 void setup() {
   Serial.begin(9600);
   Serial1.begin(1200); // Init UART at 1200 baud
 }
 void loop() {
   // Loop while bytes are available
   while (Serial1.available()) {
     RxMsg[RxIdx] = Serial1.read(); // Read in first byte
     if (RxMsg[0] == 33) { // All messages start with "!"
       if ((RxIdx == 1 && RxMsg[1] != 222) || (RxIdx == 2 && RxMsg[2] != 84) || (RxIdx == 3 && RxMsg[3] != 171)) { // Verify First Part of Message is correct
         RxIdx = 0; // Message invalid start over
       } else if (RxIdx == 11) {
         bool goodMsg = true; // Made it this far, optimistic outcome
         RxIdx = 0; // Start message index over for next temp broadcast
         for (byte i=4; i <= 10 && goodMsg; i+=2) { // Validate the remaining bytes in the message
           if ((RxMsg[i] ^ 255) != RxMsg[(i + 1)]) {
             goodMsg = false;
             break;
           }
         }
         if (goodMsg) {
           // Create MonitorTmp, DeviceId, Sign, DegreesF, DecimalF
           //MonitorTemp Msg = MonitorTemp(RxMsg[4], RxMsg[6], RxMsg[8], RxMsg[10]);
           Serial.println("Code here to set processing temp");
         }
       } else {
         RxIdx++;
       }
     }
   }
 }
The above code was just to prove out we can send and receive a message via the USART and over the 433 Mhz module.
The temperature monitors are written in PICBasic Pro 2.5 using an 8 dip  PIC12F683 and the DS18B20 to measure the temperature.  Code for the temperature module can be found here.  Points to note in the temperature monitor code is that we use the software serial out with an inverted 1200 baud as our selection for transmitting the message.  The inversion takes in to account the UART normal marking state of logic 1 causing constant transmission.  On the code page you will also see a great example of one wire communiction with the temperature sensor and how to convert the temperature.  The temperature conversion calculation also considers if the result is in negative Celsius.  Many of the examples for converting temperature states that their calculation doesn’t work for negative results.  The code provided does not have this limitation.  Below is a snapshot of the temperature monitor code.  The code and design will change in the near future.  There are plans for adding a PIR sensor to detect if a room is occupied or not.  Occupied rooms ultimately will have more weight compared to other rooms.
License is located here. 
'**************************************************************** '* Name : Monitor.pbp * '* Author : Brian Dilks * '* Date : 10/11/2008 * '* Version : 1.0 * '* Notes : PIC12F683 * '* : * '**************************************************************** '_FCMEN_ON EQU H'3FFF' Fail Safe Clock Monitor '_FCMEN_OFF EQU H'37FF' '_IESO_ON EQU H'3FFF' Internal External Switchover bit '_IESO_OFF EQU H'3BFF' '_BOD_ON EQU H'3FFF' Brown Out '_BOD_NSLEEP EQU H'3EFF' Brown Out on, but not in sleep '_BOD_SBODEN EQU H'3DFF' Brown Out controlled by register '_BOD_OFF EQU H'3CFF' Brown Out off '_CPD_ON EQU H'3F7F' Data Code Protection '_CPD_OFF EQU H'3FFF' '_CP_ON EQU H'3FBF' Program Code Protection '_CP_OFF EQU H'3FFF' '_MCLRE_ON EQU H'3FFF' Reset Pin On '_MCLRE_OFF EQU H'3FDF' Reset Pin Off, Digital Input '_PWRTE_OFF EQU H'3FFF' '_PWRTE_ON EQU H'3FEF' Power Up Timer Enabled '_WDT_ON EQU H'3FFF' Watchdog Timer Enabled '_WDT_OFF EQU H'3FF7' '_LP_OSC EQU H'3FF8' '_XT_OSC EQU H'3FF9' XT OSC, OSC1 & OSC2 pins used '_HS_OSC EQU H'3FFA' '_EC_OSC EQU H'3FFB' '_INTRC_OSC_NOCLKOUT EQU H'3FFC' '_INTOSCIO EQU H'3FFC' '_INTRC_OSC_CLKOUT EQU H'3FFD' '_INTOSC EQU H'3FFD' '_EXTRC_OSC_NOCLKOUT EQU H'3FFE' '_EXTRCIO EQU H'3FFE' '_EXTRC_OSC_CLKOUT EQU H'3FFF' '_EXTRC EQU H'3FFF' @ __CONFIG _FCMEN_OFF & _IESO_OFF & _BOD_OFF & _CPD_OFF & _CP_OFF & _MCLRE_OFF & _PWRTE_ON & _WDT_ON & _XT_OSC DEFINE OSC 4 DEFINE CHAR_PACING 1000 ' WPU Disabled, Interrupt on rising edege, Internal Instruction Cycle Clock, inc low to high T0CK1, Prescaler on TMR0 ' TMR0 1:4, WDT 1:2 OPTION_REG = %11000001 INTCON = 0 ' All interrupts off ADCON0 = 0 ' A/D Converter disabled ANSEL = 0 WPU = 0' Weak pull ups disabled ' 76543210 CMCON0 = 000111 ' All digital i/o GPIO = 000000 TRISIO = 111100 ' MCLR pin - input, GPIO2 Input, <5:4> 1 for OSC1 & 2, GPIO<1:0> Output T1CON.0 = %0 ' Timer1 Off T2CON.2 = %0 ' Timer2 Off DeviceID CON 1 'OSC1 VAR GPIO.5 'OSC2 VAR GPIO.4 'MCLR VAR GPIO.3 pTempSensorIO VAR GPIO.2 pTxData VAR GPIO.1 pTxSTBY VAR GPIO.0 RandomVal VAR WORD ' Random value to drift some transmitters don't broadcast on top of each other. LastRandomVal VAR WORD ' Last value SleepSec VAR BYTE ' Amount of time to sleep TxMsg VAR BYTE[11] '-------------- Temp Sensor Variables ------------- Busy VAR BIT ' Busy Status-Bit LocalTempRaw VAR WORD ' RAW Temperature readings LocalTemp VAR WORD ' Temp in deg F LocalTempSign VAR LocalTempRaw.Bit11' Sign-Bit for +/- Temp. 1 = Below 0 deg C LocalTempCalc VAR BYTE ' Dummy for Div32 LocalTempDeg VAR BYTE ' Degrees LocalTempDec1 VAR BYTE ' Tenths of temp LocalFullTemp VAR WORD ' Final Temperature in full, tenths is ones position IsNegC VAR BIT ' Raw reading was negative '-------------- End Temp Sensor Variables ------------- '-------------- Pre-Loop Code --------------- LocalFullTemp = 0 RandomVal = 0 LastRandomVal = 0 TxMsg[0] = "!" TxMsg[1] = (TxMsg[0] ^ 255) TxMsg[2] = "T" TxMsg[3] = (TxMsg[2] ^ 255) TxMsg[4] = DeviceID TxMsg[5] = (TxMsg[4] ^ 255) SLEEP 10 MainLoop: OWOUT pTempSensorIO, 1, [$CC, $44]' Skip ROM search & do temp conversion Nag: OWIN pTempSensorIO, 4, [Busy] ' Read busy bit IF Busy = 0 THEN Nag ' busy keep looping OWOUT pTempSensorIO, 1, [$CC, $BE]' Skip ROM search & read scratchpad memory OWIN pTempSensorIO, 2, [LocalTempRaw.Lowbyte, LocalTempRaw.Highbyte]' Read two bytes IsNegC = LocalTempSign IF IsNegC = 1 THEN LocalTempRaw = (LocalTempRaw ^ 65535) + 1 LocalTempCalc = LocalTempRaw * 1125 LocalTemp = DIV32 100 TxMsg[6] = "+" IF IsNegC = 1 THEN IF LocalTemp > 3200 THEN TxMsg[6] = "-" LocalTemp = 3200 - LocalTemp ELSE LocalTemp = LocalTemp + 3200 ENDIF ' encode next char based off of last one TxMsg[7] = (TxMsg[6] ^ 255) LocalTempDeg = LocalTemp / 100 ' whole degrees LocalTempDec1 = LocalTemp DIG 1 ' Tenths IF LocalTemp DIG 0 >= 5 THEN ' Hundreths, round it LocalTempDec1 = LocalTempDec1 + 1 if LocalTempDec1 > 9 THEN ' Rounded up a degree LocalTempDeg = LocalTempDeg + 1 LocalTempDec1 = 0 ENDIF ENDIF TxMsg[8] = LocaltempDeg TxMsg[9] = (TxMsg[8] ^ 255) TxMsg[10] = LocalTempDec1 TxMsg[11] = (TxMsg[10] ^ 255) pTxSTBY = 1 'Tx Not in standby SLEEP 1 ' Give 1 second to wait for temp sensor and transmitter to settle SEROUT pTxData, 5, [$55, $55, $55, $55, $55, TxMsg[0], TxMsg[1], TxMsg[2], TxMsg[3], TxMsg[4], TxMsg[5], TxMsg[6], TxMsg[7], TxMsg[8], TxMsg[9], TxMsg[10], TxMsg[11]] pTxSTBY = 0 'Tx in standby WHILE ABS (RandomVal - LastRandomVal) < 546 RANDOM RandomVal ' Get a random value 1 - 65535 WEND LastRandomVal = RandomVal SleepSec = 30 + (RandomVal / 546) ' Add to the 30 seconds a random amount of seconds up to 90 SLEEP SleepSec ' Preform sleep GOTO MainLoop END 
There are so many design decisions left to figure out…  Will the monitors be battery powered or wall wart powered?  How will the thermostat look?  All these decisions coming up.


Viewing all articles
Browse latest Browse all 764

Trending Articles