Advertisement
Guest User

Untitled

a guest
Aug 11th, 2015
205
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 21.20 KB | None | 0 0
  1. /*
  2. Modbus serial - RTU Slave Arduino Sketch
  3. Este exemplo é de domínio público
  4. Testado na IDE 1.0.1
  5. Baseado na biblioteca de Juan Pablo Zometa : jpmzometa@gmail.com
  6. http://sites.google.com/site/jpmzometa/
  7. and Samuel Marco: sammarcoarmengol@gmail.com
  8. and Andras Tucsni.
  9. As funções do protocolo MODBUS implementadas neste código:
  10. 3 - Read holding registers;
  11. 6 - Preset single register;
  12. 16 - Preset multiple registers.
  13. This program is free software; you can redistribute it and/or modify
  14. it under the terms of the GNU General Public License as published by
  15. the Free Software Foundation; either version 2 of the License, or
  16. (at your option) any later version.
  17. This program is distributed in the hope that it will be useful,
  18. but WITHOUT ANY WARRANTY; without even the implied warranty of
  19. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  20. GNU General Public License for more details.
  21. You should have received a copy of the GNU General Public License
  22. along with this program; if not, write to the Free Software
  23. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  24. The functions included here have been derived from the
  25. Modicon Modbus Protocol Reference Guide
  26. which can be obtained from Schneider at www.schneiderautomation.com.
  27. This code has its origins with
  28. paul@pmcrae.freeserve.co.uk (http://www.pmcrae.freeserve.co.uk)
  29. who wrote a small program to read 100 registers from a modbus slave.
  30. */
  31. /*
  32. * configure_mb_slave(baud, parity, tx_en_pin)
  33. *
  34. * configuração dos parametros da porta serial.
  35. *
  36. * baud: taxa de transmissão em bps (valores típicos entre 9600, 19200... 115200)
  37. * parity: seta o modo de paridade:
  38. * 'n' sem paridade (8N1); 'e' paridede impar (8E1), 'o' paridade par (8O1).
  39. * tx_en_pin: pino do arduino que controla a transmissão/recepção em uma linha RS485.
  40. * 0 or 1 desliga esta função (para rede RS232)
  41. * >2 para uma rede multiponto.
  42. */
  43. void configure_mb_slave(long baud, char parity, char txenpin);
  44. /*
  45. * update_mb_slave(slave_id, holding_regs_array, number_of_regs)
  46. *
  47. * verifica se há qualquer pedido válido do mestre modbus. Se houver,
  48. * executa a ação solicitada
  49. *
  50. * slave: endereço do escravo (arduino) (1 to 127)
  51.  
  52. * regs: uma matriz com os holding registers. Eles começam no endereço 1 (mestre ponto de
  53. vista)
  54. * Regs_size: número total de holding registers.
  55. * Retorna: 0 se não houver pedido do mestre,
  56. * NO_REPLY (-1) se nenhuma resposta é enviada para o mestre
  57. * Caso um código de exceção (1 a 4) em algumas exceções de modbus
  58. * O número de bytes enviados como resposta (> 4) se OK.
  59. */
  60. int update_mb_slave(unsigned char slave, int *regs,
  61. unsigned int regs_size);
  62. /* Aqui começa o código do exemplo */
  63. /* Parâmetros Modbus RTU de comunicação, o Mestre e os escravos devem usar os mesmos
  64. parâmetros */
  65. enum {
  66. COMM_BPS = 9600, /* baud rate */
  67. MB_SLAVE = 1, /* endereço do escravo modbus */
  68. /* cada escravo modbus deve ter um */
  69. /* endereço único na rede modbus */
  70. PARITY = 'n', /* paridade */
  71. TXEN = 6 /*Definir o pino usado para colocar o driver
  72. RS485 em modo de transmissão, utilizado
  73. somente em redes RS485 quando colocar em 0
  74. ou 1 para redes RS232 */
  75. };
  76. /* registros do escravo (holding registers)
  77. *
  78. * Aqui ficam ordenados todos os registros de leitura e escrita
  79. * da comunicação entre o mestre e o escravo (SCADA e arduino)
  80. *
  81. */
  82. #include "EmonLib.h" // Include Emon Library
  83. EnergyMonitor emon1; // Create an instance
  84. enum {
  85.  
  86. MB_A2, /* Leitura da entrada analógica 0 (0 a 1023) offset 0 (p/ data point no scadabr)*/
  87. MB_A3, /* Leitura da entrada analógica 1 (0 a 1023) offset 1 (p/ data point no scadabr)*/
  88. MB_A4, /* Leitura da entrada analógica 2 (0 a 1023) offset 2 (p/ data point no scadabr)*/
  89. MB_A5, /* Leitura da entrada analógica 3 (0 a 1023) offset 3 (p/ data point no scadabr)*/
  90. MB_A6, /* Leitura da entrada analógica 4 (0 a 1023) offset 4 (p/ data point no scadabr)*/
  91.  
  92. MB_REGS /* número total de registros do escravo */
  93. };
  94.  
  95. int regs[MB_REGS];
  96.  
  97.  
  98. unsigned long wdog = 0; /* watchdog */
  99. unsigned long tprev = 0; /* tempo anterior do último comando*/
  100. unsigned long tanalogprev = 0; /* tempo anterior da leitura dos pinos analógicos*/
  101. void setup()
  102. {
  103. /* configura cominicação modbus
  104. * 9600 bps, 8N1, RS485 network */
  105. configure_mb_slave(COMM_BPS, PARITY, TXEN);
  106. emon1.voltage(A0, 134.4, 1.7); // Voltage: input pin, calibration, phase_shift
  107. emon1.current(A1, 92); // Current: input pin, calibration.
  108. }
  109. void loop()
  110. {
  111. /* verifica se há solicitações do mestre */
  112. if (update_mb_slave(MB_SLAVE, regs, MB_REGS))
  113. wdog = millis();
  114. if ((millis() - tanalogprev) > 2000) { /* atualiza as entradas analogica a cada 1 segundo */
  115. regs[MB_A2] = emon1.realPower * 10; /* ler entrada analógica 0 e salva valor no registro modbus*/
  116. regs[MB_A3] = emon1.apparentPower * 10; /* ler entrada analógica 0 e salva valor no registro modbus*/
  117. regs[MB_A4] = emon1.powerFactor * 10; /* ler entrada analógica 0 e salva valor no registro modbus*/
  118. regs[MB_A5] = emon1.Vrms * 10; /* ler entrada analógica 0 e salva valor no registro modbus*/
  119. regs[MB_A6] = emon1.Irms * 10; /* ler entrada analógica 0 e salva valor no registro modbus*/
  120.  
  121. emon1.calcVI(20,2000); // Calculate all. No.of half wavelengths (crossings), time-out
  122.  
  123. tanalogprev = millis();
  124. }
  125.  
  126.  
  127. }
  128.  
  129. /****************************************************************************
  130. * INICIO DAS FUNÇÕES ESCRAVO Modbus RTU
  131. ****************************************************************************/
  132. /* variaveis globais */
  133. unsigned int Txenpin = TXEN; /*Definir o pino usado para colocar o driver
  134. RS485 em modo de transmissão, utilizado
  135. somente em redes RS485 quando colocar em 0
  136. ou 1 para redes RS232 */
  137. /* Lista de códigos de função modbus suportados. Se você implementar um novo, colocar o seu
  138. código de função aqui! */
  139. enum {
  140. FC_READ_REGS = 0x03, //Read contiguous block of holding register (Ler um bloco contíguo de registos)
  141. FC_WRITE_REG = 0x06, //Write single holding register (Escrever em um único registro)
  142. FC_WRITE_REGS = 0x10 //Write block of contiguous registers (Escrever em um bloco contíguo de registos)
  143. };
  144. /* Funções suportadas. Se você implementar um novo, colocar seu código em função nessa
  145. matriz! */
  146. const unsigned char fsupported[] = {
  147. FC_READ_REGS, FC_WRITE_REG, FC_WRITE_REGS
  148. };
  149. /* constantes */
  150. enum {
  151. MAX_READ_REGS = 0x7D,
  152. MAX_WRITE_REGS = 0x7B,
  153. MAX_MESSAGE_LENGTH = 256
  154. };
  155. enum {
  156. RESPONSE_SIZE = 6,
  157. EXCEPTION_SIZE = 3,
  158. CHECKSUM_SIZE = 2
  159. };
  160. /* código de exceções */
  161. enum {
  162. NO_REPLY = -1,
  163. EXC_FUNC_CODE = 1,
  164. EXC_ADDR_RANGE = 2,
  165. EXC_REGS_QUANT = 3,
  166. EXC_EXECUTE = 4
  167. };
  168. /* posições dentro da matriz de consulta / resposta */
  169. enum {
  170. SLAVE = 0,
  171. FUNC,
  172. START_H,
  173. START_L,
  174. REGS_H,
  175. REGS_L,
  176. BYTE_CNT
  177. };
  178. /*
  179. CRC
  180. INPUTS:
  181. buf -> Matriz contendo a mensagem a ser enviada para o controlador mestre.
  182. start -> Início do loop no crc do contador, normalmente 0.
  183. cnt -> Quantidade de bytes na mensagem a ser enviada para o controlador mestre
  184. OUTPUTS:
  185. temp -> Retorna byte crc para a mensagem.
  186. COMMENTÁRIOS:
  187. Esta rotina calcula o byte crc alto e baixo de uma mensagem.
  188. Note que este CRC é usado somente para Modbus, não em Modbus PLUS ou TCP.
  189. ****************************************************************************/
  190. unsigned int crc(unsigned char *buf, unsigned char start,
  191. unsigned char cnt)
  192. {
  193. unsigned char i, j;
  194. unsigned temp, temp2, flag;
  195. temp = 0xFFFF;
  196. for (i = start; i < cnt; i++) {
  197. temp = temp ^ buf[i];
  198. for (j = 1; j <= 8; j++) {
  199. flag = temp & 0x0001;
  200. temp = temp >> 1;
  201. if (flag)
  202. temp = temp ^ 0xA001;
  203. }
  204. }
  205. /* Inverter a ordem dos bytes. */
  206. temp2 = temp >> 8;
  207. temp = (temp << 8) | temp2;
  208. temp &= 0xFFFF;
  209. return (temp);
  210. }
  211. /***********************************************************************
  212. *
  213. * As seguintes funções constroem o frame de
  214. * um pacote de consulta modbus.
  215. *
  216. ***********************************************************************/
  217. /*
  218. * Início do pacote de uma resposta read_holding_register
  219. */
  220. void build_read_packet(unsigned char slave, unsigned char function,
  221. unsigned char count, unsigned char *packet)
  222. {
  223. packet[SLAVE] = slave;
  224. packet[FUNC] = function;
  225. packet[2] = count * 2;
  226. }
  227. /*
  228. * Início do pacote de uma resposta preset_multiple_register
  229. */
  230. void build_write_packet(unsigned char slave, unsigned char function,
  231. unsigned int start_addr,
  232. unsigned char count,
  233. unsigned char *packet)
  234. {
  235. packet[SLAVE] = slave;
  236. packet[FUNC] = function;
  237. packet[START_H] = start_addr >> 8;
  238. packet[START_L] = start_addr & 0x00ff;
  239. packet[REGS_H] = 0x00;
  240. packet[REGS_L] = count;
  241. }
  242. /*
  243. * Início do pacote de uma resposta write_single_register
  244. */
  245. void build_write_single_packet(unsigned char slave, unsigned char function,
  246. unsigned int write_addr, unsigned int reg_val, unsigned char* packet)
  247. {
  248. packet[SLAVE] = slave;
  249. packet[FUNC] = function;
  250. packet[START_H] = write_addr >> 8;
  251. packet[START_L] = write_addr & 0x00ff;
  252. packet[REGS_H] = reg_val >> 8;
  253. packet[REGS_L] = reg_val & 0x00ff;
  254. }
  255. /*
  256. * Início do pacote de uma resposta excepção
  257. */
  258. void build_error_packet(unsigned char slave, unsigned char function,
  259. unsigned char exception, unsigned char *packet)
  260. {
  261. packet[SLAVE] = slave;
  262. packet[FUNC] = function + 0x80;
  263. packet[2] = exception;
  264. }
  265. /*************************************************************************
  266. *
  267. * modbus_query( packet, length)
  268. *
  269. * Função para adicionar uma soma de verificação para o fim de um pacote.
  270. * Por favor, note que a matriz pacote deve ser de pelo menos 2 campos mais do que
  271. * String_length.
  272. **************************************************************************/
  273. void modbus_reply(unsigned char *packet, unsigned char string_length)
  274. {
  275. int temp_crc;
  276. temp_crc = crc(packet, 0, string_length);
  277. packet[string_length] = temp_crc >> 8;
  278. string_length++;
  279. packet[string_length] = temp_crc & 0x00FF;
  280. }
  281. /***********************************************************************
  282. *
  283. * send_reply( query_string, query_length )
  284. *
  285. * Função para enviar uma resposta a um mestre Modbus.
  286. * Retorna: o número total de caracteres enviados
  287. ************************************************************************/
  288. int send_reply(unsigned char *query, unsigned char string_length)
  289. {
  290. unsigned char i;
  291. if (Txenpin > 1) { // coloca o MAX485 no modo de transmissão
  292. UCSR0A = UCSR0A | (1 << TXC0);
  293. digitalWrite( Txenpin, HIGH);
  294. delayMicroseconds(3640); // aguarda silencio de 3.5 caracteres em 9600bps
  295. }
  296. modbus_reply(query, string_length);
  297. string_length += 2;
  298. for (i = 0; i < string_length; i++) {
  299. Serial.write(byte(query[i]));
  300. }
  301. if (Txenpin > 1) {// coloca o MAX485 no modo de recepção
  302. while (!(UCSR0A & (1 << TXC0)));
  303. digitalWrite( Txenpin, LOW);
  304. }
  305. return i; /* isso não significa que a gravação foi bem sucedida */
  306. }
  307. /***********************************************************************
  308. *
  309. * receive_request( array_for_data )
  310. *
  311. * Função para monitorar um pedido do mestre modbus.
  312. *
  313. * Retorna: Número total de caracteres recebidos se OK
  314. * 0 se não houver nenhum pedido
  315. * Um código de erro negativo em caso de falha
  316. ***********************************************************************/
  317. int receive_request(unsigned char *received_string)
  318. {
  319. int bytes_received = 0;
  320. /* FIXME: não Serial.available esperar 1.5T ou 3.5T antes de sair do loop? */
  321. while (Serial.available()) {
  322. received_string[bytes_received] = Serial.read();
  323. bytes_received++;
  324. if (bytes_received >= MAX_MESSAGE_LENGTH)
  325. return NO_REPLY; /* erro de porta */
  326. }
  327. return (bytes_received);
  328. }
  329. /*********************************************************************
  330. *
  331. * modbus_request(slave_id, request_data_array)
  332. *
  333. * Função que é retornada quando o pedido está correto
  334. * e a soma de verificação está correto.
  335. * Retorna: string_length se OK
  336. * 0 se não
  337. * Menos de 0 para erros de exceção
  338. *
  339. * Nota: Todas as funções usadas para enviar ou receber dados via
  340. * Modbus devolver esses valores de retorno.
  341. *
  342. **********************************************************************/
  343. int modbus_request(unsigned char slave, unsigned char *data)
  344. {
  345. int response_length;
  346. unsigned int crc_calc = 0;
  347. unsigned int crc_received = 0;
  348. unsigned char recv_crc_hi;
  349. unsigned char recv_crc_lo;
  350. response_length = receive_request(data);
  351. if (response_length > 0) {
  352. crc_calc = crc(data, 0, response_length - 2);
  353. recv_crc_hi = (unsigned) data[response_length - 2];
  354. recv_crc_lo = (unsigned) data[response_length - 1];
  355. crc_received = data[response_length - 2];
  356. crc_received = (unsigned) crc_received << 8;
  357. crc_received =
  358. crc_received | (unsigned) data[response_length - 1];
  359. /*********** verificar CRC da resposta ************/
  360. if (crc_calc != crc_received) {
  361. return NO_REPLY;
  362. }
  363. /* verificar a ID do escravo */
  364. if (slave != data[SLAVE]) {
  365. return NO_REPLY;
  366. }
  367. }
  368. return (response_length);
  369. }
  370. /*********************************************************************
  371. *
  372. * validate_request(request_data_array, request_length, available_regs)
  373. *
  374. * Função para verificar se o pedido pode ser processado pelo escravo.
  375. *
  376. * Retorna: 0 se OK
  377. * Um código de exceção negativa em caso de erro
  378. *
  379. **********************************************************************/
  380. int validate_request(unsigned char *data, unsigned char length,
  381. unsigned int regs_size)
  382. {
  383. int i, fcnt = 0;
  384. unsigned int regs_num = 0;
  385. unsigned int start_addr = 0;
  386. unsigned char max_regs_num;
  387. /* verificar o código de função */
  388. for (i = 0; i < sizeof(fsupported); i++) {
  389. if (fsupported[i] == data[FUNC]) {
  390. fcnt = 1;
  391. break;
  392. }
  393. }
  394. if (0 == fcnt)
  395. return EXC_FUNC_CODE;
  396. if (FC_WRITE_REG == data[FUNC]) {
  397. /* Para a função de escrever um reg único, este é o registro alvo.*/
  398. regs_num = ((int) data[START_H] << 8) + (int) data[START_L];
  399. if (regs_num >= regs_size)
  400. return EXC_ADDR_RANGE;
  401. return 0;
  402. }
  403. /* Para as funções de leitura / escrita de registros, este é o intervalo. */
  404. regs_num = ((int) data[REGS_H] << 8) + (int) data[REGS_L];
  405. /* verifica a quantidade de registros */
  406. if (FC_READ_REGS == data[FUNC])
  407. max_regs_num = MAX_READ_REGS;
  408. else if (FC_WRITE_REGS == data[FUNC])
  409. max_regs_num = MAX_WRITE_REGS;
  410. if ((regs_num < 1) || (regs_num > max_regs_num))
  411. return EXC_REGS_QUANT;
  412. /* verificará a quantidade de registros, endereço inicial é 0 */
  413. start_addr = ((int) data[START_H] << 8) + (int) data[START_L];
  414. if ((start_addr + regs_num) > regs_size)
  415. return EXC_ADDR_RANGE;
  416. return 0; /* OK, sem exceção */
  417. }
  418. /************************************************************************
  419. *
  420. * write_regs(first_register, data_array, registers_array)
  421. *
  422. * escreve nos registradores do escravo os dados em consulta,
  423. * A partir de start_addr.
  424. *
  425. * Retorna: o número de registros escritos
  426. ************************************************************************/
  427. int write_regs(unsigned int start_addr, unsigned char *query, int *regs)
  428. {
  429. int temp;
  430. unsigned int i;
  431. for (i = 0; i < query[REGS_L]; i++) {
  432. /* mudar reg hi_byte para temp */
  433. temp = (int) query[(BYTE_CNT + 1) + i * 2] << 8;
  434. /* OR com lo_byte */
  435. temp = temp | (int) query[(BYTE_CNT + 2) + i * 2];
  436. regs[start_addr + i] = temp;
  437. }
  438. return i;
  439. }
  440. /************************************************************************
  441. *
  442. * preset_multiple_registers(slave_id, first_register, number_of_registers,
  443. * data_array, registers_array)
  444. *
  445. * Escreva os dados na matriz dos registos do escravo.
  446. *
  447. *************************************************************************/
  448. int preset_multiple_registers(unsigned char slave,
  449. unsigned int start_addr,
  450. unsigned char count,
  451. unsigned char *query,
  452. int *regs)
  453. {
  454. unsigned char function = FC_WRITE_REGS; /* Escrever em múltiplos registros */
  455. int status = 0;
  456. unsigned char packet[RESPONSE_SIZE + CHECKSUM_SIZE];
  457. build_write_packet(slave, function, start_addr, count, packet);
  458. if (write_regs(start_addr, query, regs)) {
  459. status = send_reply(packet, RESPONSE_SIZE);
  460. }
  461. return (status);
  462. }
  463. /************************************************************************
  464. *
  465. * write_single_register(slave_id, write_addr, data_array, registers_array)
  466. *
  467. * Escrever um único valor inteiro em um único registo do escravo.
  468. *
  469. *************************************************************************/
  470. int write_single_register(unsigned char slave,
  471. unsigned int write_addr, unsigned char *query, int *regs)
  472. {
  473. unsigned char function = FC_WRITE_REG; /* Função: Write Single Register */
  474. int status = 0;
  475. unsigned int reg_val;
  476. unsigned char packet[RESPONSE_SIZE + CHECKSUM_SIZE];
  477. reg_val = query[REGS_H] << 8 | query[REGS_L];
  478. build_write_single_packet(slave, function, write_addr, reg_val, packet);
  479. regs[write_addr] = (int) reg_val;
  480. /*
  481. written.start_addr=write_addr;
  482. written.num_regs=1;
  483. */
  484. status = send_reply(packet, RESPONSE_SIZE);
  485. return (status);
  486. }
  487. /************************************************************************
  488. *
  489. * read_holding_registers(slave_id, first_register, number_of_registers,
  490. * registers_array)
  491. *
  492. * lê os registros do escravo e envia para o mestre Modbus
  493. *
  494. *************************************************************************/
  495. int read_holding_registers(unsigned char slave, unsigned int start_addr,
  496. unsigned char reg_count, int *regs)
  497. {
  498. unsigned char function = 0x03; /* Função 03: Read Holding Registers */
  499. int packet_size = 3;
  500. int status;
  501. unsigned int i;
  502. unsigned char packet[MAX_MESSAGE_LENGTH];
  503. build_read_packet(slave, function, reg_count, packet);
  504. for (i = start_addr; i < (start_addr + (unsigned int) reg_count);
  505. i++) {
  506. packet[packet_size] = regs[i] >> 8;
  507. packet_size++;
  508. packet[packet_size] = regs[i] & 0x00FF;
  509. packet_size++;
  510. }
  511. status = send_reply(packet, packet_size);
  512. return (status);
  513. }
  514. void configure_mb_slave(long baud, char parity, char txenpin)
  515. {
  516. Serial.begin(baud);
  517. switch (parity) {
  518. case 'e': // 8E1
  519. UCSR0C |= ((1 << UPM01) | (1 << UCSZ01) | (1 << UCSZ00));
  520. // UCSR0C &= ~((1<<UPM00) | (1<<UCSZ02) | (1<<USBS0));
  521. break;
  522. case 'o': // 8O1
  523. UCSR0C |= ((1 << UPM01) | (1 << UPM00) | (1 << UCSZ01) | (1 << UCSZ00));
  524. // UCSR0C &= ~((1<<UCSZ02) | (1<<USBS0));
  525. break;
  526. case 'n': // 8N1
  527. UCSR0C |= ((1 << UCSZ01) | (1 << UCSZ00));
  528. // UCSR0C &= ~((1<<UPM01) | (1<<UPM00) | (1<<UCSZ02) | (1<<USBS0));
  529. break;
  530. default:
  531. break;
  532. }
  533. if (txenpin > 1) { // pino 0 & pino 1 são reservados para RX/TX
  534. Txenpin = txenpin; /* definir variável global */
  535. pinMode(Txenpin, OUTPUT);
  536. digitalWrite(Txenpin, LOW);
  537. }
  538. return;
  539. }
  540. /*
  541. * update_mb_slave(slave_id, holding_regs_array, number_of_regs)
  542. *
  543. * verifica se há qualquer pedido válido do mestre modbus. Se houver,
  544. * executa a ação solicitada
  545. */
  546. unsigned long Nowdt = 0;
  547. unsigned int lastBytesReceived;
  548. const unsigned long T35 = 5;
  549. int update_mb_slave(unsigned char slave, int *regs,
  550. unsigned int regs_size)
  551. {
  552. unsigned char query[MAX_MESSAGE_LENGTH];
  553. unsigned char errpacket[EXCEPTION_SIZE + CHECKSUM_SIZE];
  554. unsigned int start_addr;
  555. int exception;
  556. int length = Serial.available();
  557. unsigned long now = millis();
  558. if (length == 0) {
  559. lastBytesReceived = 0;
  560. return 0;
  561. }
  562. if (lastBytesReceived != length) {
  563. lastBytesReceived = length;
  564. Nowdt = now + T35;
  565. return 0;
  566. }
  567. if (now < Nowdt)
  568. return 0;
  569. lastBytesReceived = 0;
  570. length = modbus_request(slave, query);
  571. if (length < 1)
  572. return length;
  573. exception = validate_request(query, length, regs_size);
  574. if (exception) {
  575. build_error_packet(slave, query[FUNC], exception,
  576. errpacket);
  577. send_reply(errpacket, EXCEPTION_SIZE);
  578. return (exception);
  579. }
  580. start_addr = ((int) query[START_H] << 8) +
  581. (int) query[START_L];
  582. switch (query[FUNC]) {
  583. case FC_READ_REGS:
  584. return read_holding_registers(slave,
  585. start_addr,
  586. query[REGS_L],
  587. regs);
  588. break;
  589. case FC_WRITE_REGS:
  590. return preset_multiple_registers(slave,
  591. start_addr,
  592. query[REGS_L],
  593. query,
  594. regs);
  595. break;
  596. case FC_WRITE_REG:
  597. write_single_register(slave,
  598. start_addr,
  599. query,
  600. regs);
  601. break;
  602. }
  603. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement