Wall time is the most important information which Octoglow should provide, it is reasonable to have separate display for it. Having this in mind, the design principles shifted to more complicated contraption, having multiple boards and bigger enclosure. Octagonal steel chassis was devised at this time. The new board itself features the following:
- 4-digit numerical display for current wall time.
- 433.92 MHz ASK/OOK receiver to receive temperature and humidity data from remote weather sensor.
- Two relays to drive auxiliary loads. One of them is actually used, it drives telephone bell installed on the frame.
The PCB layout was designed in KiCad, all project files are located in pcb/clock-display/. The heart of the board is ATtiny461A microcontroller which acts as I2C slave on the system bus. It interprets the packets from 433.92 MHz receiver, controls the relays and sends the appropriate content to the VFD driver. There are following connectors on the board:
- 10-pin system bus
- 10-pin STK200 ISP header
- female Micro-MaTch for +35 V anode voltage and filament power
- four female Micro-MaTch’s for relays
Micro-MaTch are not popular but they were chosen because of the compactness and overall good look. It was important to me because the board’s front side was meant to be exposed, housing prominent filament resistors and relay connectors.
The VFD itself is salvaged from the pile of scrap electronics I found at the roadside when I was riding my bike. I took the weathered PCB home and examined the display. I was undamaged! I decided to give it a new life and purpose.
The display is quite unusual because it is not multiplexed. Every anode has it’s own pin and all grids are connected together - multiplexing is not possible in this setup. Overall, there are 30 pins to drive. I again used chip TD62C950RF which successfully works in main display. The grid is driven by TD62C950RF output, but in firmware it is effectively pulled high. The brightness is varied by driving CL ping by ATTiny’s
TIMER 1 PWM output. Filament voltage is ~3 V, I used the method described in my other article to find proper values for resistors R8 and R10.
The original 433.92 MHz receiver module was RFM83C-433S (as seen in the schematic), but the performance was rather low, I later replaced it with pin-incompatible RFM210LCF-433D-A. The antenna is made of copper wire as shown on Instructables. Receiver’s output drives the ATTiny’s interrupt line. The protocol and the decoding algorithm is described below.
Relay driving circuit is straightforward. One relay is unused, the other switches the telephone bell. The bell is powered directly from supply transformer’s 24 V AC. In the telephone line, 25 Hz usually is used, but 50 Hz still does its job (for your information, mains power in continental Europe is 230 V 50 Hz). The ringing sound is almost indistinguishable from classic telephone ring.
I found the bell when I was helping moving the local makerspace in Poznań to a new building. The old one was unsuitable for it and scavenged for any useful appliances. Previously there was some kind of paper processing facility in this building. The bell has been installed on the wall and used as crude communication tool.
Two-pin header on the front side was meant as 1-Wire interface, but eventually it was left unused. There is also unused pin with PWM output meant for driving analog gauge meter.
The code follows the same principle as for the main display; its root under firmware/clock-display/. It is quite simple, the only not-so-trivial routine is decoding data from receiver module. In its main loop, the software receives commands from I2C on address
0x10 and acts accordingly. It supports following requests:
Set display content
The display has four digits and separator dots.
'1'|digit 1|digit 2|digit 3|digit 4|dots
|digit 1||1||ASCII-encoded digit, leftmost.|
|dots||1||Bitwise OR for display dots: 0-th bit = lower dot, 1-st bit = upper dot.|
Set relay state
'2'|relay 1|relay 2
Set display brightness
Get weather sensor data
The only read request. To trigger read, send
4 to the device, then read response:
|humidity||1||Humidity in %.|
|flags||1||Weak battery =
Weather sensor protocol
The weather sensor I own is BIOWIN BIOTERM, shown in the photos. I reverse-engineered the protocol by connecting the receiver’s output to PC sound card and analysing the signal with Audacity. The process is described in detail in many articles on the web, for example here.
The protocol description
Weather sensor sends its OOK-modulated data at 433.92 MHz. A couple of packets are sent every minute, less often when battery is almost depleted. Each transmission starts with several impulses to set the Automatic Gain Control in the receiver. Then, following rules apply:
- start bit: ~9 ms of carrier
1data bit: ~4 ms
0data bit: ~2 ms
Each single packet consists of:
- start bit
- 36 data bits
- stop bit - valued
and has following structure:
|4-11||8||Random number generated at power-on.|
|14-15||2||Address selected by switch:
|16-27||12||Temperature in 0.1 deg C. Signed, two’s complement.|
|28-35||8||Humidity in %.|
The core of the algorithm is implemented in source file src/receiver433.cpp. Receiver is connected to hardware interrupt
INT0 and each rising edge triggers the interrupt service routine.
TIMER 0 is configured as counter, its purpose is to measure time between the subsequent interrupt calls. Interrupt service routine checks the time elapsed from its previous execution: if it is 4 ms +- 5%,
1 is saved to the packet buffer and the buffer is shifted left. Accordingly, when 2 ms +- 5%,
0 is saved. Other intervals are invalid and the buffer is cleared in this case.
As 36 bits are loaded, the content of the buffer is copied to spare buffer. The idea is to receive the identical packet once again. If their content match, the packet is assumed valid and appropriate fields in structure
WeatherSensorState are set among with the flag new measurement ready.
TIMER1, which is used by the display to generate PWM signal, has also interrupt configured to fire in order to implement timeouts. When the timeout fires, the buffer is reset. This is done to reset the state machine in case of partially received packet.