Advertisement
RuiViana

New_ModBus_Slave

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