TLDR: BeagleBone Black에서 직렬 통신(RS485)이 작동하지 않습니다. 이 문제를 어떻게 해결하나요?
——
나 이후질문해결책을 찾지 못했습니다. 지금은 통신의 Linux 측면을 탐색 중입니다.
상황을 요약하자면: BeagleBone black이 장착된 RS485 9600 보드, 8N1 통신 문제를 해결하고 있습니다.케이프커뮤니케이션즈 2. uart는 /dev/ttyS4에 연결됩니다. 내 소프트웨어는 nodejs로 개발되었으며 RS485 통신 문제 해결을 위한 간단한 버전이 있습니다(코드는 질문 끝에 있습니다).
내가 가지고 있는 데비안 버전:
$ uname -a
Linux pepsr-drix 4.14.108-ti-r131 #1stretch SMP PREEMPT Tue Mar 24 19:18:37 UTC 2020 armv7l GNU/Linux
UART 구성은 다음과 같습니다.
$ cat /boot/uEnv.txt
#Docs: http://elinux.org/Beagleboard:U-boot_partitioning_layout_2.0
uname_r=4.14.108-ti-r131
#uuid=
#dtb=
###U-Boot Overlays###
###Documentation: http://elinux.org/Beagleboard:BeagleBoneBlack_Debian#U-Boot_Overlays
###Master Enable
enable_uboot_overlays=1
###
###Overide capes with eeprom
uboot_overlay_addr0=/lib/firmware/BB-UART1-00A0.dtbo
uboot_overlay_addr1=/lib/firmware/BB-UART2-00A0.dtbo
uboot_overlay_addr2=/lib/firmware/BB-UART4-00A0.dtbo
uboot_overlay_addr3=/lib/firmware/BB-UART5-00A0.dtbo
###
###Additional custom capes
#uboot_overlay_addr4=/lib/firmware/<file4>.dtbo
#uboot_overlay_addr5=/lib/firmware/<file5>.dtbo
#uboot_overlay_addr6=/lib/firmware/<file6>.dtbo
#uboot_overlay_addr7=/lib/firmware/<file7>.dtbo
###
###Custom Cape
#dtb_overlay=/lib/firmware/<file8>.dtbo
###
###Disable auto loading of virtual capes (emmc/video/wireless/adc)
#disable_uboot_overlay_emmc=1
#disable_uboot_overlay_video=1
#disable_uboot_overlay_audio=1
#disable_uboot_overlay_wireless=1
#disable_uboot_overlay_adc=1
###
###PRUSS OPTIONS
###pru_rproc (4.14.x-ti kernel)
uboot_overlay_pru=/lib/firmware/AM335X-PRU-RPROC-4-14-TI-00A0.dtbo
###pru_rproc (4.19.x-ti kernel)
#uboot_overlay_pru=/lib/firmware/AM335X-PRU-RPROC-4-19-TI-00A0.dtbo
###pru_uio (4.14.x-ti, 4.19.x-ti & mainline/bone kernel)
#uboot_overlay_pru=/lib/firmware/AM335X-PRU-UIO-00A0.dtbo
###
###Cape Universal Enable
enable_uboot_cape_universal=1
###
###Debug: disable uboot autoload of Cape
#disable_uboot_overlay_addr0=1
#disable_uboot_overlay_addr1=1
#disable_uboot_overlay_addr2=1
#disable_uboot_overlay_addr3=1
###
###U-Boot fdt tweaks... (60000 = 384KB)
#uboot_fdt_buffer=0x60000
###U-Boot Overlays###
cmdline=coherent_pool=1M net.ifnames=0 lpj=1990656 rng_core.default_quality=100 quiet
#In the event of edid real failures, uncomment this next line:
#cmdline=coherent_pool=1M net.ifnames=0 lpj=1990656 rng_core.default_quality=100 quiet video=HDMI-A-1:1024x768@60e
##enable Generic eMMC Flasher:
##make sure, these tools are installed: dosfstools rsync
#cmdline=init=/opt/scripts/tools/eMMC/init-eMMC-flasher-v3.sh
직렬 포트를 보면 a) 모두가 준비되어 있습니다(RTS|CTS|DTR|DSR). b) 전송 데이터 크기가 증가합니다. c) 수신 데이터 크기가 1로 고정되어 있습니다.
$ sudo cat /proc/tty/driver/serial
[sudo] password for debian:
serinfo:1.0 driver revision:
4: uart:8250 mmio:0x481A8000 irq:34 tx:1917 rx:1 brk:1 RTS|CTS|DTR|DSR
4: uart:8250 mmio:0x481A8000 irq:34 tx:2008 rx:1 brk:1 RTS|CTS|DTR|DSR
4: uart:8250 mmio:0x481A8000 irq:34 tx:2060 rx:1 brk:1 RTS|CTS|DTR|DSR
...
4: uart:8250 mmio:0x481A8000 irq:34 tx:4400 rx:1 brk:1 RTS|CTS|DTR|DSR
최소 세션을 테스트하기 위해 bash 스크립트를 작성했지만 최소 세션에서는 아무 것도 나타나지 않습니다.
$ cat ./testRs485.sh
#!/bin/bash
echo 'RS485 test script by Sdl on October 2021 @ Will’s Kissimmee, FL, USA (/dev/ttyS4 serial 9600 bauds 8N1)'
echo 'Asking for Daly BMS information'
DEVICE=/dev/ttyS4
stty -F $DEVICE speed 9600 cs8 -cstopb -echo
#echo -en "\xD2\x03\x00\x0C\x01\x57\xAA" > $DEVICE
echo 'Query voltage and current'
echo -en "\xa5\x40\x90\x08\x00\x00\x00\x00\x00\x00\x00\x00\x7d" > $DEVICE
# Expected response: 69 40 86 00 83 00 00 75 30 01 e8 4f
sleep 10
echo 'Query nominal capacity and cell voltage'
echo -en "\xa5\x40\x50\x08\x00\x00\x00\x00\x00\x00\x00\x00\x3d" > $DEVICE
# Expected response : 69 40 85 00 00 c3 50 00 00 00 00 11
sleep 10
내 설정에 어떤 문제가 있나요?
부록:
Nodejs testRs485.js 코드:
$ cat testRs485.js
/**
* @abstract RS 485 test file
* @file src/testRs485.js
* @module pepsr
*
* @summary RS485 tester
*
* @Copyright © 2019-2021 - All rights reserved
* @author SDL
* @created RS485 testing code by Sdl on Saturday December 18th 2021 8:41pm @ Will’s Hoadland av. in Kissimmee, FL, USA.
*/
const devices = {
bmsMaster: 0x01,
bluetoothApp: 0x20,
gprs: 0x40,
hostComputer: 0x80,
}
const messages = {
socVoltageCurrent: 0x90,
}
const dalyHeader = 0xa5
const device = devices.gprs
const message = messages.socVoltageCurrent
const payloadLength = 8
function pack(address, action, parameter, data) {
var length = String('00' + data.length.toString()).slice(-2);
var bufferAsString = address + action + parameter + length + data;
var check = 0;
for (var i = 0; i < bufferAsString.length; ++i) {
check += bufferAsString.charCodeAt(i)
}
var checkSum = String('000' + String(check % 256)).slice(-3);
var buffer = Buffer.from(bufferAsString + checkSum),
carriageReturn = Buffer.from('\r');
return Buffer.concat([buffer, carriageReturn]);
}
/**
* Computes the check sum
* @param {[uint8]} data The data buffer
* @param {Number} length The number of bytes
* @returns The ine-byte checksum
*/
function checksum(buffer, length) {
let checksum = 0
for (let i=0; i<length; i++) {
checksum += buffer[i]
}
return checksum & 0xff
}
setInterval(function() {
console.log("timer that keeps nodejs processing running");
}, 1000 * 60);
var SerialPort = require('serialport')
const portDevice = '/dev/ttyS4'
var port = new SerialPort(portDevice, {
autoOpen: false,
baudRate: 9600,
dataBits: 8,
stopBits: 1,
parity: 'none',
// COntrol flow: none
/*xon: false,
xoff: false,
rtscts: false*/
}, false)
function open () {
if (port.isOpen) return;
console.log('Opening serial port', portDevice, '…')
port.open(err => {
if (!err) {
console.log('Serial port is open')
return
}
console.err('Port is not open:', err)
// next attempt to open after 10s
setTimeout(open, 10000)
});
}
// == On open…
port.on('open', () => {
console.log('Successfully open')
console.log("In port.open():", port.isOpen)
console.log('Preparing message to be sent')
const messagetoSend = new Buffer.from([
dalyHeader,
device,
message,
payloadLength,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x7d // checksum to be computed
])
//pack('001', '00', '740', '=?')
const ccs = checksum(messagetoSend, messagetoSend.length-1)
const cs = messagetoSend[messagetoSend.length-1]
console.log('Computed checksum is', ccs, ', stored checksum is', cs, 'on the',messagetoSend.length, '-byte packet', messagetoSend)
messagetoSend[messagetoSend.length-1] = ccs
let counter = 1
setInterval(function() {
console.log(`About to send message #${counter++}:`, messagetoSend)
const sent = port.write(messagetoSend, err => {
if (err) {
return console.error('Send error:',err)
}
console.log('Sent message successfuly')
if (false) {
console.log('Draining serial')
port.drain(() => console.log('Drain done'))
}
})
console.log('Send returned', sent)
}, 15000)
})
port.on('data', data => {
console.log('Received data: ' + data);
})
port.on('close', () => {
console.log('Serial port closed')
console.log('Reopening')
open()
})
port.on('error', err => {
console.error('Error:', err);
})
open()