Clunet
CLUNET library - simple single-wire peer-to-peer network driver for AVR microcontrollers, perfect way to interconnect microcontrollers in your house
Install / Use
/learn @ClusterM/ClunetREADME
CLUNET
The CLUNET library - is a simple single-wire peer-to-peer network driver for AVR microcontrollers, perfect way to interconnect microcontrollers in your house.
Features:
- Requires only a few cheap additional components;
- Using only a single wire;
- Using only two pins;
- There is no master device, all devices are equal;
- You can use a very long cable, more than 100 meters;
- You don't need to care about collisions;
- Automatic CRC calculation and CRC check;
- Pseudo multitasking using interrupts;
- Up to 255 devices on one bus.
How to use
Hardware part

You need a pin with an external interrupt to read data and any other pin to send data. Transistor method is recommended.
Software part
You will need one free 8-bit timer with output compare match interrupt.
Configuration####
Edit clunet_config.h and change some values:
- CLUNET_DEVICE_ID - address of the device (0-254);
- CLUNET_DEVICE_NAME - name of the device (optional);
- CLUNET_SEND_BUFFER_SIZE - send buffer size and maximum output packet size (memory usage);
- CLUNET_READ_BUFFER_SIZE - read buffer size and maximum input packet size (memory usage);
- CLUNET_WRITE_PORT and CLUNET_WRITE_PIN - port and pin to send data;
- CLUNET_READ_PORT and CLUNET_READ_PIN - port and pin to read data, should be connected directly to the line;
- CLUNET_WRITE_TRANSISTOR - define if you are using a transistor on output pin (see schematics);
- CLUNET_TIMER_PRESCALER - prescaler for timer, define it to autocalculate
CLUNET_Tvalue as64us, it must match timer initialization code,(F_CPU / CLUNET_TIMER_PRESCALER) / 15625must be >= 8 and <= 24, thus 64 is the optimal value for 8MHz; - CLUNET_T - T value, it's a time period between signals in timer ticks, length of logical 0 is T, and logical 1 is 3*T, lower T is faster while higher T is more stable, it's autocalculated as 64us based on CLUNET_TIMER_PRESCALER if not defined;
- CLUNET_TIMER_INIT - code to init timer (normal mode);
- CLUNET_TIMER_REG - timer/counter register;
- CLUNET_TIMER_REG_OCR - timer/counter
output compareregister; - CLUNET_ENABLE_TIMER_COMP and CLUNET_DISABLE_TIMER_COMP - code to enable/disable timer
output compare matchinterrupt; - CLUNET_ENABLE_TIMER_OVF and CLUNET_DISABLE_TIMER_OVF - code to enable/disable timer
overflowinterrupt; - CLUNET_INIT_INT - code to init external interrupt (read pin);
- CLUNET_TIMER_COMP_VECTOR - timer
output compare matchinterrupt vector; - CLUNET_TIMER_OVF_VECTOR - timer
overflowinterrupt vector`; - CLUNET_INT_VECTOR -
external interruptvector.
Default configuration file is optimised for ATMEGA8 / 8MHz.
Code
Include "clunet.h" and create callback function to receive data:
#include "clunet.h"
void data_received(unsigned char src_address, unsigned char dst_address, unsigned char command, char* data, unsigned char size)
{
/* your code here */
}
Add initialization code and enable interrupts:
int main (void)
{
clunet_init();
clunet_set_on_data_received(data_received);
sei();
Also you can use clunet_set_on_data_received_sniff() to set callback function which will receive all packets, not only for this device.
Function to send data:
void clunet_send(unsigned char address, unsigned char prio, unsigned char command, char* data, unsigned char size);
- address - address of destination device or
CLUNET_BROADCAST_ADDRESSfor multicast - prio - packet priority:
CLUNET_PRIORITY_NOTICE,CLUNET_PRIORITY_INFO,CLUNET_PRIORITY_MESSAGE,CLUNET_PRIORITY_COMMAND;
- command - command ID (0-255), note that some IDs are occupied by predefined commands (see clunet.h) and some are reserved (see below);
- data - pointer to data if any;
- size - data size.
Sample code:
char buffer[1];
buffer[0] = 1;
clunet_send(CLUNET_BROADCAST_ADDRESS, CLUNET_PRIORITY_MESSAGE, CLUNET_COMMAND_DEVICE_POWER_INFO, buffer, sizeof(buffer));
while (clunet_ready_to_send()); // wait while sending, otherwise next call will replace output buffer
// clunet_ready_to_send() returns current task priority
// or 0 if output buffer is not busy
char *hello = "Hello world!";
clunet_send(1, CLUNET_PRIORITY_INFO, 100, hello, strlen(hello));
Reserved commands
There are some reserved commands:
- CLUNET_COMMAND_DISCOVERY (0x00) - send this command as broadcast packet to find all devices in your network, devices will answer with command CLUNET_COMMAND_DISCOVERY_RESPONSE (0x01) and CLUNET_DEVICE_NAME in data section;
- CLUNET_COMMAND_REBOOT (0x02) - send this command to reboot a device;
- CLUNET_COMMAND_BOOT_CONTROL - (0x03) reserved for bootloader and firmware update;
- CLUNET_COMMAND_BOOT_COMPLETED (0x04) - sent by device on start (call of
clunet_init()), data is value of MCUCSR register, so your can determine reset source; - CLUNET_COMMAND_PING (0xFE) - ping, you can test line using this command, device(s) will answer with CLUNET_COMMAND_PING_REPLY (0xFF) and same data.
Tested on
- ATMEGA8;
- ATMEGA16;
- ATMEGA64.
Known bugs/problems
- Any data on bus will slow down every connected device a little.
- No delivery check, you can make it in your application code if necessary.
Author/contacts
Alexey 'Cluster' Avdyukhin
clusterrr@clusterrr.com
Related Skills
node-connect
344.1kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
96.8kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
344.1kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
qqbot-media
344.1kQQBot 富媒体收发能力。使用 <qqmedia> 标签,系统根据文件扩展名自动识别类型(图片/语音/视频/文件)。
