tiistai 23. helmikuuta 2021

433 MHz transmitter

 Continuing from previous part.

Later addition: you can find sources here.

After I got receiver working - that is, successfully decoding received data - and played a bit with it, it was time to start thinking about transmitter part. I mentioned that I had neglected to order one, so I went looking for one from same large web store. This is where I hit a wall though.

My system is running at about 3.2v. As it turns out, most of the transmitter and receiver modules available are designed or at least sold to be used with Arduino. Therefore most had operating voltage specified to be 5v, with lower limit at 3.5v. Just a few transmitter modules listed 3.0v as lower operating voltage, but these had somewhat worrying review history and I chose not to risk it. (received I had ordered however was specced to work at 3v and had mostly good reviews so no issue there). All in all, no luck.

Then I realized I had transmitter already. Hand-held module works with 3v battery, and circuit was relatively simple (very close to this SAW-based one from this site). Main difference is that transmitter I had was passing supply voltage of RF through LED (so when LED is on, RF is on). Easy enough to hack, I thought.

So to testing. Left pin is enable (connected to LED series resistor input), other wires are modulation input from my PCB (and other for scope probing). At lower part of board were 3v supply and ground (battery inputs). I think I could have cut the lower part of board completely off but decided against that.

Getting waveform shape roughly right didn't take long (this I did without transmitter being connected, just looking at generated modulation data from scope), but final tweaks to get it just right for receiver to accept it took a bit longer, mostly getting start and end conditions to match original signal closely enough. That code is fairly trivial, just I/O pin switching and delays of various lengths in between, done with interrupts disabled so that they don't mess with timings. Nothing fancy required here, unlike receiver where a bit of timer trickery was needed to be able to receive data buried in noise as background operation (without interfering with other operations of system)


tiistai 9. helmikuuta 2021

433MHz receiver

Later addition: you can find sources here.

I've been thinking about rudimentary home automation stuff, specifically remotely controlled heating to our cabin. Since it has munincipal water it must remain above freezing temperature, but I'd rather not keep temperature too high (i.e. near comfortable) when we're not there to save electricity, so it's often around +10 degrees C when we go there, and it takes almost a full day for it to warm to more comfortable +20 C. Not great situation.

I already have temperature monitoring in place, with remote reporting (to send an alarm if it gets too cold and needs attention, and also for curiosity monitoring the temperature from home), but controlling heaters - that is, mains voltages - is something I'd rather not fiddle with directly. Although I have no double could make it safe, there's still the issue of pesky insurance claim denials in case something were to happen.

For this purpose I bought a set of remote controlled sockets with sufficient power rating. These are controlled with 433MHz radio signal, so I would have to duplicate signals sent by remote somehow.

I did some web searching and there is actually some articles about this, but they all work on higher level than I'd like. "take Arduino and use this library" is not my thing, really. But those anyway gave me enough pointers to start moving to right direction.

I bought some cheap receivers from certain large internet dealer, but somehow managed forgot to buy transmitters! Damn it. But at least I could start with signal decode part.

This turned out to be slightly more difficult than I though, as either my surroundings is full of 433MHz signals, or these receivers are horribly noisy even when there is no signal around, as presented by this scope capture of actual signal amongst noise. Yellow is output signal of receiver, and small green dots indicate locations where there is end of actual transmitted signal as parsed by (my eventual) system.

Here the original transmitter probing came in handy. I knew that sequence started with short high, followed by fixed length low, followed by actual PWM signal. Getting scope trigger to that reliably wasn't happening, but managed to get it trigger on specific-length "low" often enough to verify that my initial assumptions are correct.

Here's a bit closed look at actual transmitted signal. Start of signal is marked with cursor X1, and end (as I think it is) by X2. At start there's short, 2000us zero pulse, followed by 24-bit PWM coded signal, then possibly "stop bit" of some kind. PWM signals are 380us for "0" and 1200us for "1" (or other way around, I don't really care - I just want to be able to replicate it.)  Next pulse starts always 1500us after previous one, regardless of width of pulse.

I already had thought of the receiver software that could parse this (and other similar signals) with MCU I had ready to go - STM32 series chip (and system) I've used often recently. The idea is this:

Connect receiver output to STM32 I/O pin that can handle external interrupts. I set this line to handle both rising and falling edge interrupts, to stop on both edges. 

I already use the RTC part of STM32 with 32768 Hz clock crystal on it. It has sub-second counter (SSR) which I set to to count to 8192 on every second - 122us per tick. Not great resolution but sufficient here (there is also small power cost involved with higher rates when using battery backup, although it is not important here as I do not need to optimize for that), as "0" and "1" signals have significant time difference. Any hardware timer that allows its internal counter to be read reliably should be fine for this though.

As there is a lot of noise, and thus lots of interrupts here, I designed the interrupt handler to be as short as possible for common case - no recognizable signal, or start of false signal - to reduce time spent there.

When idle, system looks for low period of 1800us or more to start decoding signal. (trigger SSR read on lowering edge, then check elapsed time on rising edge, calculate elapsed time in ticks - obsiously taking care of wraparounds in calculation if there are some). 

After this, on lowering edge SSR is read and time compated; I accept fairly wide range of values; around 200us to 500us as "0" and 900us to 1500us as "1". If timing is out of these bounds, signal is treated as noise and system returns to idle (this large scale is in case I want to use modules with slight timing differences, such as radio-based temperature sensor I haven't tested yet. Also there is the issue of SSR having 122us resolution, so I could expect half of that as average timing error, and also other interrupts that might have blocked this handler temporarily)

Next rising edge is also checked; it must have happened from 1300us to 1700us after before. Again, falling outside this range is noise and system returns to idle, waiting next signal. If timing was correct, system waits for lowering edge, i.e. next bit. After 24 bits data treated as successfully received.

This turned out to be more reliable than I expected, as system received all four identical sequences sent by remote extremely reliably, without any false positives so far. For further proof system might check with majority vote the actual received value, but that has to wait for now.

Next, playing with receivers some more.