Demo Code
This page provides the complete Waveshare demo code for both CAN bus and RS-485, in Python and C. These examples are the canonical starting point for verifying your hardware setup.
Download
Section titled “Download”wget https://files.waveshare.com/upload/4/4e/RS485_CAN_HAT_Code.zipunzip RS485_CAN_HAT_Code.zipDirectory Structure
Section titled “Directory Structure”RS485_CAN_HAT_Code/├── CAN/│ ├── python/│ │ ├── send.py│ │ └── receive.py│ └── wiringPi/│ ├── send/│ │ ├── can_send.c│ │ └── Makefile│ └── receive/│ ├── can_receive.c│ └── Makefile└── 485/ ├── python/ │ ├── send.py │ └── receive.py └── WiringPi/ ├── send/ │ ├── 485_send.c │ └── Makefile └── receive/ ├── 485_receive.c └── MakefileCAN Bus Examples
Section titled “CAN Bus Examples”The CAN examples use SocketCAN, the Linux kernel’s native CAN framework. The Python version wraps it with the python-can library; the C version uses raw CAN sockets directly.
CAN Send
Section titled “CAN Send”import osimport can
os.system('sudo ip link set can0 type can bitrate 100000')os.system('sudo ifconfig can0 up')
can0 = can.interface.Bus(channel='can0', bustype='socketcan')msg = can.Message(arbitration_id=0x123, data=[0, 1, 2, 3, 4, 5, 6, 7], is_extended_id=False)can0.send(msg)
os.system('sudo ifconfig can0 down')#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <net/if.h>#include <sys/ioctl.h>#include <sys/socket.h>#include <linux/can.h>#include <linux/can/raw.h>
int main(){ int ret; int s, nbytes; struct sockaddr_can addr; struct ifreq ifr; struct can_frame frame; memset(&frame, 0, sizeof(struct can_frame));
system("sudo ip link set can0 type can bitrate 100000"); system("sudo ifconfig can0 up"); printf("this is a can send demo\r\n");
s = socket(PF_CAN, SOCK_RAW, CAN_RAW); if (s < 0) { perror("socket PF_CAN failed"); return 1; }
strcpy(ifr.ifr_name, "can0"); ret = ioctl(s, SIOCGIFINDEX, &ifr); if (ret < 0) { perror("ioctl failed"); return 1; }
addr.can_family = AF_CAN; addr.can_ifindex = ifr.ifr_ifindex; ret = bind(s, (struct sockaddr *)&addr, sizeof(addr)); if (ret < 0) { perror("bind failed"); return 1; }
setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, NULL, 0);
frame.can_id = 0x123; frame.can_dlc = 8; frame.data[0] = 1; frame.data[1] = 2; frame.data[2] = 3; frame.data[3] = 4; frame.data[4] = 5; frame.data[5] = 6; frame.data[6] = 7; frame.data[7] = 8;
printf("can_id = 0x%X\r\n", frame.can_id); printf("can_dlc = %d\r\n", frame.can_dlc); int i = 0; for(i = 0; i < 8; i++) printf("data[%d] = %d\r\n", i, frame.data[i]);
nbytes = write(s, &frame, sizeof(frame)); if(nbytes != sizeof(frame)) { printf("Send Error frame[0]!\r\n"); system("sudo ifconfig can0 down"); }
close(s); system("sudo ifconfig can0 down"); return 0;}The C send example opens a raw CAN socket, binds it to the can0 interface, populates an 8-byte frame with ID 0x123, and writes it to the bus. The setsockopt call with a NULL filter disables reception filtering since this program only transmits. After sending, the interface is brought back down.
CAN Receive
Section titled “CAN Receive”import osimport can
os.system('sudo ip link set can0 type can bitrate 100000')os.system('sudo ifconfig can0 up')
can0 = can.interface.Bus(channel='can0', bustype='socketcan')msg = can0.recv(10.0)print(msg)if msg is None: print('Timeout occurred, no message.')
os.system('sudo ifconfig can0 down')#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <net/if.h>#include <sys/ioctl.h>#include <sys/socket.h>#include <linux/can.h>#include <linux/can/raw.h>
int main(){ int ret; int s, nbytes; struct sockaddr_can addr; struct ifreq ifr; struct can_frame frame;
memset(&frame, 0, sizeof(struct can_frame));
system("sudo ip link set can0 type can bitrate 100000"); system("sudo ifconfig can0 up"); printf("this is a can receive demo\r\n");
s = socket(PF_CAN, SOCK_RAW, CAN_RAW); if (s < 0) { perror("socket PF_CAN failed"); return 1; }
strcpy(ifr.ifr_name, "can0"); ret = ioctl(s, SIOCGIFINDEX, &ifr); if (ret < 0) { perror("ioctl failed"); return 1; }
addr.can_family = PF_CAN; addr.can_ifindex = ifr.ifr_ifindex; ret = bind(s, (struct sockaddr *)&addr, sizeof(addr)); if (ret < 0) { perror("bind failed"); return 1; }
struct can_filter rfilter[1]; rfilter[0].can_id = 0x123; rfilter[0].can_mask = CAN_SFF_MASK; setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, &rfilter, sizeof(rfilter));
while(1) { nbytes = read(s, &frame, sizeof(frame)); if(nbytes > 0) { printf("can_id = 0x%X\r\ncan_dlc = %d \r\n", frame.can_id, frame.can_dlc); int i = 0; for(i = 0; i < 8; i++) printf("data[%d] = %d\r\n", i, frame.data[i]); break; } }
close(s); system("sudo ifconfig can0 down");
return 0;}The C receive example sets a hardware-level CAN filter using CAN_SFF_MASK to accept only standard frames with ID 0x123. It then blocks in a read() loop until a matching frame arrives, prints the payload, and exits. The filter is applied via setsockopt on the raw CAN socket before entering the receive loop.
RS-485 Examples
Section titled “RS-485 Examples”The RS-485 examples use the Pi’s UART (/dev/ttyS0) with GPIO 4 controlling the transceiver direction. The Python version uses pyserial and RPi.GPIO; the C version uses the wiringPi library.
RS-485 Send
Section titled “RS-485 Send”import RPi.GPIO as GPIOimport serial
EN_485 = 4GPIO.setmode(GPIO.BCM)GPIO.setup(EN_485, GPIO.OUT)GPIO.output(EN_485, GPIO.HIGH)
t = serial.Serial("/dev/ttyS0", 115200)print(t.portstr)strInput = input('enter some words:')n = t.write(strInput.encode())print(n)str = t.read(n)print(str)#include <wiringSerial.h>#include <wiringPi.h>#include <stdio.h>#include <strings.h>#include <unistd.h>
#define EN_485 4
int main(void){ if(wiringPiSetupGpio() < 0) { printf("set wiringPi lib failed\t!!! \r\n"); return 1; } else { printf("set wiringPi lib success !!! \r\n"); } pinMode(EN_485, OUTPUT); digitalWrite(EN_485, HIGH);
int fd; if((fd = serialOpen("/dev/ttyS0", 9600)) < 0) { printf("serial err\n"); return -1; }
serialFlush(fd); serialPrintf(fd, "\r");
serialPuts(fd, "12345\n"); serialPuts(fd, "56789\n");
serialClose(fd); return 0;}The C send example initializes wiringPi with BCM pin numbering, sets GPIO 4 HIGH to put the SP3485 transceiver into transmit mode, opens the serial port at 9600 baud, flushes the buffer, and sends two test strings. Note the baud rate difference from the Python example (9600 vs 115200) — match both ends accordingly.
RS-485 Receive
Section titled “RS-485 Receive”import RPi.GPIO as GPIOimport serial
EN_485 = 4GPIO.setmode(GPIO.BCM)GPIO.setup(EN_485, GPIO.OUT)GPIO.output(EN_485, GPIO.LOW)
ser = serial.Serial("/dev/ttyS0", 115200, timeout=1)while True: str = ser.readall() if str: print(str)#include <wiringSerial.h>#include <wiringPi.h>#include <stdio.h>#include <unistd.h>#include <string.h>#include <strings.h>#include <sys/time.h>
#define EN_485 4
int main(void){ int nbytes;
if(wiringPiSetupGpio() < 0) { printf("set wiringPi lib failed\t!!! \r\n"); return 1; } else { printf("set wiringPi lib success !!! \r\n"); } pinMode(EN_485, OUTPUT); digitalWrite(EN_485, LOW);
int fd; int data; if((fd = serialOpen("/dev/ttyS0", 9600)) < 0) { printf("serial err\n"); return -1; }
serialFlush(fd); while(1) { nbytes = serialDataAvail(fd); if(nbytes == -1) { printf("receive data error\r\n"); break; } else if(nbytes > 0) { printf("%c\r\n", serialGetchar(fd)); } }
serialClose(fd); return 0;}The C receive example sets GPIO 4 LOW to put the SP3485 into receive mode, then polls serialDataAvail() in a tight loop. Each byte is printed individually as it arrives. The loop exits only on error (serialDataAvail returns -1).
Building the C Examples
Section titled “Building the C Examples”Each C example includes a Makefile. To compile:
cd RS485_CAN_HAT_Code/CAN/wiringPi/sendmakesudo ./can_sendThe CAN C examples link against standard system libraries. The RS-485 C examples require wiringPi to be installed:
sudo apt-get install wiringpiFor the Python examples, install the required packages:
pip install python-can RPi.GPIO pyserial