Słomkowski's technical musings

Playing with software, hardware and touching the sky with paraglider.

Octoglow VFD - Clock display board


Second module of Octoglow, which contains numerical VFD to display wall time and 433 MHz weather sensor receiver.

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:

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:

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.

Electrical wiring schematic.
Electrical wiring schematic.

↑ click to enlarge ↑

Firmware

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
Value Size Description
1 1 Magic byte
digit 1 1 ASCII-encoded digit, leftmost.
digit 2 1
digit 3 1
digit 4 1
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
Value Size Description
2 1 Magic byte
relay 1 1 1 - switched on, 0 - switched off.
relay 2 1

Set display brightness

'3'|brightness
Value Size Description
3 1 Magic byte
brightness 1 From 0 (display shutdown) to 5 (max).

Get weather sensor data

The only read request. To trigger read, send 4 to the device, then read response:

temperature|humidity|flags.

Value Size Description
temperature 2 int16_t, temperature in 0.1 deg C.
humidity 1 Humidity in %.
flags 1 Weak battery = 0x1, valid measurement = 0x2, already read = 0x4.

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:

Each single packet consists of:

and has following structure:

Bit Length Function
0-3 4 Always value 9.
4-11 8 Random number generated at power-on.
12 1 0 - battery OK, 1 - weak battery.
13 1 1 - transmission forced by TEST button, 0 - automatic transmission.
14-15 2 Address selected by switch: 00 - 1, 01 - 2, 10 - 3.
16-27 12 Temperature in 0.1 deg C. Signed, two’s complement.
28-35 8 Humidity in %.

Decoding

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.