Je suis en train de lire un registre à partir d'un adaptateur RS485 en utilisant une connexion UART sur une carte ARM sans succèsARM: la lecture des données modbus par UART échoue
Machines
- board ARM: CM -T335 - TI AM335x Computer-on-Module http://www.compulab.co.il/products/computer-on-modules/cm-t335/
- PC: machine x86 exécutant Ubuntu
- dispositif esclave: Elnet Pico (énergie du wattmètre) - fonctionne comme un esclave modbus et envoie des statuts d'énergie à måste r la demande en utilisant le protocole modbus http://elnet.feniks-pro.com/documents/User_manual/Elnet%20Pico%20-%20User%20Manual.pdf
Connecteurs
- RX/TX câble
- SENA adaptateur RS485: http://www.senanetworks.com/download/datasheet/ds_ltc100.pdf
- Homme - Adaptateur mâle COM: http://i.ebayimg.com/images/i/300758549547-0-1/s-l1000.jpg
- mini ultra série au câble DB9: https://cdn3.yawarra.com.au/wp-content/uploads/Ultra-mini-serial-DB9-adapter_600x600.jpg
dispositif esclave connecté au bord ARM
puissance Compteur d'énergie < --rx/tx câble -> SENA Adaptateur RS485 < --serial mâle/adaptateur mâle + série de mini-câble série -> ARM carte mini-port série
voir les images de la configuration:
- https://ibin.co/3CCvTVPPIUWQ.jpg
- https://ibin.co/3CCvhrr3CQjr.jpg
- https://ibin.co/3CCw5uNqTW8B.jpg
- https://ibin.co/3CCvuys1tUgt.jpg
arbre de l'appareil utilisé: am335x-sbc-t335.dts
ressources forestières de l'appareil:http://get-album.com/dts/
dispositif esclave connecté au PC
puissance Compteur d'énergie < --2 fil rx/tx -> SENA Adaptateur RS485 < -> PC
Note: Le port mini-série sur la carte est le même port qui est utilisé pour la communication série-console (sur baud 115200) - et cela fonctionne sans problème
ci-dessous est un code alternatif qui lit le premier registre du dispositif esclave connecté à l'utilisation de la bibliothèque de libmodbus
libmodbus_test.c - la lecture et l'impression de la première reigster du dispositif:
#include <sys/types.h>
#include <string.h>
#include <modbus.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#define MODBUS_DEVICE "/dev/ttyS2"
#define MODBUS_STOP_BIT 1
#define MODBUS_DATA_BIT 8
#define MODBUS_START_BIT 1
#define MODBUS_PARITY 'N'
int main(int argc, char *argv[]) {
const char *dev_path = MODBUS_DEVICE;
uint16_t result[2];
int slave_nr = 31, baud = 9600;
modbus_t *mb;
if (argc == 2) {
dev_path=argv[1];
}
mb = modbus_new_rtu(dev_path, baud, MODBUS_PARITY, MODBUS_DATA_BIT, MODBUS_STOP_BIT);
if (mb == NULL) {
printf("error creating libmodbus rtu\n");
return -1;
}
printf("created new rtu...\n");
modbus_set_debug(mb, 1);
if (modbus_connect(mb) < 0){
printf("modbus error: %s\n", modbus_strerror(errno));
modbus_close(mb);
modbus_free(mb);
return -1;
}
modbus_set_slave(mb, slave_nr);
printf("ModBus connected !\n");
if (modbus_read_registers(mb, 0x1, 2, result) < 0) {
printf("error reading bits: %s\n", modbus_strerror(errno));
modbus_close(mb);
modbus_free(mb);
return -1;
}
printf("successfully red integer: %d: %X (hex)\n", result[0], result[0]);
modbus_free(mb);
return 0;
}
[sortie de l'exécution libmodbus_test sur PC]
[email protected]:~/new# modbus gcc -I /usr/local/include/modbus libmodbus_test.c -o libmodbus_test -lmodbus
[email protected]:~/new# ./libmodbus_test /dev/ttyS2
created new rtu...
Opening /dev/ttyS2 at 9600 bauds (N, 8, 1)
ModBus connected !
[1F][03][00][01][00][02][96][75]
Waiting for a confirmation...
<1F><03><04><00><DD><00><DD><54><51>
successfully red integer: 221: DD (hex)
[sortie de l'exécution libmodbus_test sur la carte ARM]
[email protected]:~/new# gcc -I /usr/include/modbus/ libmodbus_test.c -o libmodbus_test -lmodbus
[email protected]:~/new# ./libmodbus_test /dev/ttyO0
created new rtu...
Opening /dev/ttyO0 at 9600 bauds (N, 8, 1)
ModBus connected !
[1F][03][00][01][00][02][96][75]
Waiting for a confirmation...
ERROR Connection timed out: select
lors de l'exécution de libmodbus_test à partir de la carte ARM, select() renvoie toujours 0 lors de l'exécution du même programme sur PC, cela fonctionne très bien => l'appareil esclave renvoie des données.
Une tentative en utilisant termios a également échoué avec des résultats similaires
de termios_test.c
#include <sys/select.h>
#include <termios.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/types.h>
#include <string.h>
#include <stdint.h>
#include <linux/serial.h>
#include <sys/ioctl.h>
static const uint8_t table_crc_hi[] = {
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40
};
/* Table of CRC values for low-order byte */
static const uint8_t table_crc_lo[] = {
0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06,
0x07, 0xC7, 0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD,
0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09,
0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A,
0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC, 0x14, 0xD4,
0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,
0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3,
0xF2, 0x32, 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4,
0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A,
0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29,
0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF, 0x2D, 0xED,
0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,
0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60,
0x61, 0xA1, 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67,
0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F,
0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68,
0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA, 0xBE, 0x7E,
0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,
0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71,
0x70, 0xB0, 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92,
0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C,
0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B,
0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89, 0x4B, 0x8B,
0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,
0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42,
0x43, 0x83, 0x41, 0x81, 0x80, 0x40
};
void calc_crc(uint8_t *buffer, ssize_t length, uint8_t *crc_hi_arg, uint8_t *crc_lo_arg) {
uint8_t crc_hi = 0xff;
uint8_t crc_lo = 0xff;
unsigned int i;
while (length--) {
i = crc_hi^*buffer++;
crc_hi = crc_lo^table_crc_hi[i];
crc_lo = table_crc_lo[i];
}
*crc_hi_arg = crc_hi;
*crc_lo_arg = crc_lo;
}
int main(int argc, char **argv){
char *dev_path = "/dev/ttyS2";
if (argc == 2) {
dev_path = argv[1];
}
uint8_t write_data[8];
int fd,write_len,select_ret, bytes_avail, status;
struct termios config;
char c;
uint8_t crc_hi, crc_lo;
fd_set activefs, tmpfs;;
struct timeval timeout;
timeout.tv_sec = 0;
timeout.tv_usec= 500000;
fd = open(dev_path, O_RDWR | O_NOCTTY | O_NDELAY | O_EXCL);
if (fd == -1){
perror("open");
return 1;
}
FD_ZERO(&tmpfs);
FD_SET(fd, &tmpfs);
printf("opened device\n");
if (tcgetattr(fd, &config) < 0) { close(fd); return -1 }
if (cfsetispeed(&config, B9600) < 0 || cfsetospeed(&config, B9600) < 0) {
printf("cant setting speed!\n");
close(fd);
return 1;
}
config.c_cflag |= (CREAD | CLOCAL);
config.c_cflag &=~ CSIZE;
config.c_cflag &=~ CSTOPB;
config.c_cflag &=~ PARENB;
config.c_cflag |= CS8;
config.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
config.c_iflag &= ~INPCK;
config.c_iflag &= ~(IXON | IXOFF| IXANY);
config.c_oflag &= ~OPOST;
config.c_cc[VMIN] = 0;
config.c_cc[VTIME] = 0;
if (tcsetattr(fd, TCSANOW, &config) < 0) {
printf("cant apply config!\n");
close(fd);
return 1;
}
write_data[0] = 0x1f; // slave addr
write_data[1] = 0x03; // function
write_data[2] = 0x00; // data address of first coil (8b)
write_data[3] = 0x01; // data address of first coil (8b)
write_data[4] = 0x00; // num of coils requested
write_data[5] = 0x01; // num of coils requested
calc_crc(write_data, 6, &crc_hi, &crc_lo);
write_data[6] = crc_hi;
write_data[7] = crc_lo;
printf("data: [0x%x][0x%x][0x%x][0x%x][0x%x][0x%x][0x%x][0x%x]", write_data[0], write_data[1], write_data[2], write_data[3], write_data[4], write_data[5], write_data[6], write_data[7]);
while (1) {
sleep(1);
write_len= write(fd, write_data, 8);
activefs = tmpfs;
select_ret = select(1, &activefs, NULL, NULL, &timeout);
if (select_ret < 0) {
perror("select");
return 1;
}
if (select_ret > 0) {
printf("select returned %d\n", select_ret);
if (read(fd, &c, 1) < 0) {
perror("read");
} else {
printf("received: %d\n", c);
}
}
}
}
[de sortie de termios.c sur la carte ARM]
[email protected]:~/new# ./termios /dev/ttyO0
opened device
... select continue de revenir 0
[Sortie termios.c sur PC]
$ gcc -o termios_test termios_test.c
$ ./termios_test /dev/ttyS2
opened device
data: [0x1f][0x3][0x0][0x1][0x0][0x1][0xd6][0x74]select returned 1
received: 31
select returned 1
Peu importe les valeurs, il y a un échange de données et c'est ce que je veux réaliser en utilisant la carte
J'ai essayé attributs passer RS485 via pcntl, mais le mêmes résultats se sont passées termios_rs485_test.c: http://pastebin.com/RWtHtjLF
la connexion entre la carte et le PC se fait par l'ultra mini-série au câble DB9 et je peux lire avec succès les données/écriture depuis et vers le conseil d'administration. Comment se fait-il que la lecture des données de l'adaptateur RS485 ne réussisse jamais? Où devrais-je chercher afin de me rapprocher d'une solution?
Voici quelques informations au sujet du conseil/drivers/etc
[email protected]:~/modbus# uname -a
Linux cm-debian 4.4.0-cm-t335-5.1 #98 SMP Thu Sep 1 15:12:31 IDT 2016 armv7l GNU/Linux
[email protected]:~/new# dmesg | grep -i --color '\(serial\|tty\|uart\)'
[ 0.000000] Kernel command line: console=ttyO0,115200n8 root=ubi0:rootfs rw rootfstype=ubifs ubi.mtd=rootfs
[ 0.771007] Serial: 8250/16550 driver, 4 ports, IRQ sharing enabled
[ 0.780286] omap_uart 44e09000.serial: no wakeirq for uart0
[ 0.780329] of_get_named_gpiod_flags: can't parse 'rts-gpio' property of node '/ocp/[email protected][0]'
[ 0.780960] 44e09000.serial: ttyO0 at MMIO 0x44e09000 (irq = 155, base_baud = 3000000) is a OMAP UART0
[ 1.543031] console [ttyO0] enabled
[ 1.550036] omap_uart 48022000.serial: no wakeirq for uart1
[ 1.556099] of_get_named_gpiod_flags: can't parse 'rts-gpio' property of node '/ocp/[email protected][0]'
[ 1.556764] 48022000.serial: ttyO1 at MMIO 0x48022000 (irq = 156, base_baud = 3000000) is a OMAP UART1
[ 2.953486] usb usb1: New USB device strings: Mfr=3, Product=2, SerialNumber=1
[ 2.973176] usb usb1: SerialNumber: musb-hdrc.0.auto
[ 3.572722] usb 1-1: New USB device strings: Mfr=0, Product=0, SerialNumber=0
[ 6.689030] systemd[1]: Expecting device dev-ttyO0.device...
[ 7.210727] systemd[1]: Starting system-getty.slice.
[ 7.235407] systemd[1]: Created slice system-getty.slice.
[ 7.241302] systemd[1]: Starting system-serial\x2dgetty.slice.
[ 7.265277] systemd[1]: Created slice system-serial\x2dgetty.slice.
[ 7.925632] systemd[1]: Starting LSB: controls configuration of serial ports...
[ 8.485680] systemd[1]: Started LSB: controls configuration of serial ports.
[ 14.840532] pinctrl-single 44e10800.pinmux: pin 44e10978.0 already requested by 48022000.serial; cannot claim for 481cc000.can
[ 14.895866] pinctrl-single 44e10800.pinmux: pin 44e10980.0 already requested by 48022000.serial; cannot claim for 481d0000.can
[email protected]:~/modbus# setserial -a /dev/ttyO0
/dev/ttyO0, Line 0, UART: undefined, Port: 0x0000, IRQ: 155
Baud_base: 3000000, close_delay: 50, divisor: 0
closing_wait: 3000
Flags: spd_normal
[email protected]:~/new# setserial -a /dev/ttyS2
/dev/ttyS2, Line 2, UART: unknown, Port: 0x0000, IRQ: 0
Baud_base: 0, close_delay: 50, divisor: 0
closing_wait: 3000
Flags: spd_normal
[email protected]:~/new# setserial -a /dev/ttyS1
/dev/ttyS1, Line 1, UART: unknown, Port: 0x0000, IRQ: 0
Baud_base: 0, close_delay: 50, divisor: 0
closing_wait: 3000
Flags: spd_normal
[email protected]:~/new# setserial -a /dev/ttyS0
/dev/ttyS0, Line 0, UART: unknown, Port: 0x0000, IRQ: 0
Baud_base: 0, close_delay: 50, divisor: 0
closing_wait: 3000
Flags: spd_normal
[email protected]:~/modbus# lsmod
Module Size Used by
sha256_generic 9731 1
hmac 2866 1
drbg 13731 1
ctr 3673 2
ccm 7928 2
arc4 2000 2
wl12xx 57190 0
wlcore 180594 1 wl12xx
mac80211 605465 2 wl12xx,wlcore
cfg80211 492985 2 mac80211,wlcore
snd_soc_davinci_mcasp 15953 2
snd_soc_tlv320aic23_i2c 2092 1
snd_soc_simple_card 7474 0
snd_soc_tlv320aic23 10191 1 snd_soc_tlv320aic23_i2c
snd_soc_edma 1309 1 snd_soc_davinci_mcasp
snd_soc_core 158330 5 snd_soc_davinci_mcasp,snd_soc_edma,snd_soc_tlv320aic23_i2c,snd_soc_tlv320aic23,snd_soc_simple_card
snd_pcm_dmaengine 5548 1 snd_soc_core
snd_pcm 92743 4 snd_soc_davinci_mcasp,snd_soc_core,snd_soc_tlv320aic23,snd_pcm_dmaengine
c_can_platform 6650 0
c_can 9638 1 c_can_platform
wlcore_spi 5086 0
can_dev 12315 1 c_can
ti_am335x_adc 5635 0
snd_timer 21413 1 snd_pcm
kfifo_buf 3452 1 ti_am335x_adc
snd 55936 3 snd_soc_core,snd_timer,snd_pcm
industrialio 40286 2 ti_am335x_adc,kfifo_buf
evdev 13187 0
omap_wdt 5293 0
soundcore 1339 1 snd
[email protected]:~/new# cat /proc/cpuinfo
processor : 0
model name : ARMv7 Processor rev 2 (v7l)
BogoMIPS : 597.60
Features : half thumb fastmult vfp edsp thumbee neon vfpv3 tls vfpd32
CPU implementer : 0x41
CPU architecture: 7
CPU variant : 0x3
CPU part : 0xc08
CPU revision : 2
Hardware : Generic AM33XX (Flattened Device Tree)
Revision : 0000
Serial : 0000000000000000
[email protected]:~/new# cat /proc/consoles
ttyO0 -W- (EC p ) 250:0
[email protected]:/etc# cat debian_version
8.2
Toute aide est très appréciée Merci
MISE À JOUR
Alors que le ultra mini-série au câble DB9 est connecté au tableau, j'ai couru termios_test.c et en courant, j'ai inséré un morceau de métal dans la broche du milieu du câble (le TX) et je pouvais voir les données de déchets affichées sur l'écran (parfois !). J'ai branché l'adaptateur mâle-mâle sur le câble et j'ai de nouveau touché la broche du milieu, et j'ai pu voir à nouveau les données d'ordures.
Une autre chose que j'ai fait est de connecter l'appareil esclave à l'adaptateur SENA RS485, et utiliser la pièce métallique sur les broches, la broche du milieu de l'adaptateur, lorsque le métal touche, allume la led TX. aucune broche n'allume la led RX. Lors de la connexion de cet adaptateur RS485 au port COM du PC, l'envoi de données à ce port ferait clignoter le voyant RX. Je commence à soupçonner que la carte n'écrit pas correctement sur l'adaptateur RS485 ou que les broches ne sont pas correctement mappées. Où devrais-je aller d'ici? cela pourrait-il vraiment être un problème logiciel?
Il semble que systemd lance également getty sur/dev/ttyO0. Et il y a des paramètres du noyau qui utilisent ttyO0 comme console du noyau. Essayez de vous débarrasser de cette configuration – nos
Supprimé/dev/ttyO0 de bootargs mais cela n'a pas fonctionné non plus, mêmes résultats – Smokie
Pouvez-vous pointer vers un fichier d'arborescence de périphérique en cours d'utilisation? Il semble que vous ayez «CAN» en cours d'exécution sur la carte ARM (je suppose pas sur le PC) et ces différents protocoles peuvent prétendre à l'UART. Un test de base est de connecter un câble de bouclage (ou de se connecter directement à un PC avec cross over) et d'exécuter mini-com, etc juste pour voir que vous pouvez utiliser ce port. Avez-vous fait cela? Ceci élimine tout problème avec votre code, les tensions avec les périphériques, la configuration linux/init, etc. Diviser et conquérir est toujours bon. Il y a beaucoup de couches où les choses peuvent mal tourner, alors les gens ne peuvent que deviner. –