Advertisement
RaviBR

Código Arduino ScadaBR

Jun 12th, 2015
259
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 22.79 KB | None | 0 0
  1. /*
  2. * configure_mb_slave(baud, parity, tx_en_pin)
  3. *
  4. * configuração dos parametros da porta serial.
  5. *
  6. * baud: taxa de transmissão em bps (valores típicos entre 9600, 19200... 115200)
  7. * parity: seta o modo de paridade:
  8. * 'n' sem paridade (8N1); 'e' paridede impar (8E1), 'o' paridade par (8O1).
  9. * tx_en_pin: pino do arduino que controla a transmissão/recepção em uma linha RS485.
  10. * 0 or 1 desliga esta função (para rede RS232)
  11. * >2 para uma rede multiponto.
  12. */
  13. void configure_mb_slave(long baud, char parity, char txenpin);
  14.  
  15. /*
  16. * update_mb_slave(slave_id, holding_regs_array, number_of_regs)
  17. *
  18. * verifica se há qualquer pedido válido do mestre modbus. Se houver,
  19. * executa a ação solicitada
  20. *
  21. * slave: endereço do escravo (arduino) (1 to 127)
  22. * regs: uma matriz com os holding registers. Eles começam no endereço 1 (mestre ponto de vista)
  23. * Regs_size: número total de holding registers.
  24. * Retorna: 0 se não houver pedido do mestre,
  25. * NO_REPLY (-1) se nenhuma resposta é enviada para o mestre
  26. * Caso um código de exceção (1 a 4) em algumas exceções de modbus
  27. * O número de bytes enviados como resposta (> 4) se OK.
  28. */
  29.  
  30. int update_mb_slave(unsigned char slave, int *regs,
  31. unsigned int regs_size);
  32.  
  33. /* Aqui começa o código do exemplo */
  34.  
  35. /* Parâmetros Modbus RTU de comunicação, o Mestre e os escravos devem usar os mesmos parâmetros */
  36. enum {
  37. COMM_BPS = 9600, /* baud rate */
  38. MB_SLAVE = 1, /* endereço do escravo modbus */
  39. PARITY = 'n' /* paridade */
  40. };
  41.  
  42. /* registros do escravo (holding registers)
  43. *
  44. * Aqui ficam ordenados todos os registros de leitura e escrita
  45. * da comunicação entre o mestre e o escravo (SCADA e arduino)
  46. *
  47. */
  48.  
  49. enum {
  50.  
  51. MB_PINO_3, /* Controle do Led no pino 3 (desliga=0 liga=1) */
  52. MB_PINO_4, /* Controle do Led no pino 4 (desliga=0 liga=1) */
  53. MB_PINO_5, /* Controle do Led no pino 5 (desliga=0 liga=1) */
  54. MB_PINO_6, /* Controle do Led no pino 6 (desliga=0 liga=1) */
  55. MB_PINO_7, /* Controle do Led no pino 7 (desliga=0 liga=1) */
  56. MB_PINO_8, /* Controle do Led no pino 8 (desliga=0 liga=1) */
  57. MB_PINO_9, /* Controle do Led no pino 9 (desliga=0 liga=1) */
  58. MB_PINO_10, /* Controle do Led no pino 10 (desliga=0 liga=1) */
  59. MB_PINO_11, /* Controle do Led no pino 11 (desliga=0 liga=1) */
  60. MB_PINO_12, /* Controle do Led no pino 12 (desliga=0 liga=1) */
  61. MB_PINO_13, /* Controle do Led no pino 13 (desliga=0 liga=1) */
  62.  
  63. MB_A0, /* Leitura da entrada analógica 0 (0 a 1023) */
  64. MB_A1, /* Leitura da entrada analógica 1 (0 a 1023) */
  65. MB_A2, /* Leitura da entrada analógica 2 (0 a 1023) */
  66. MB_A3, /* Leitura da entrada analógica 3 (0 a 1023) */
  67. MB_A4, /* Leitura da entrada analógica 4 (0 a 1023) */
  68. MB_A5, /* Leitura da entrada analógica 5 (0 a 1023) */
  69.  
  70. MB_REGS /* número total de registros do escravo */
  71. };
  72.  
  73. int regs[MB_REGS];
  74. int ledPin3 = 3;
  75. int ledPin4 = 4;
  76. int ledPin5 = 5;
  77. int ledPin6 = 6;
  78. int ledPin7 = 7;
  79. int ledPin8 = 8;
  80. int ledPin9 = 9;
  81. int ledPin10 = 10;
  82. int ledPin11 = 11;
  83. int ledPin12 = 12;
  84. int ledPin13 = 13;
  85.  
  86. unsigned long wdog = 0; /* watchdog */
  87. unsigned long tprev = 0; /* tempo anterior do último comando*/
  88. unsigned long tanalogprev = 0; /* tempo anterior da leitura dos pinos analogicos*/
  89.  
  90. void setup()
  91. {
  92. Serial.begin(9600);
  93. /* configura cominicação modbus
  94. * 9600 bps, 8N1, RS485 network */
  95. configure_mb_slave(COMM_BPS, PARITY, 2);
  96.  
  97. pinMode(ledPin3, INPUT);
  98. pinMode(ledPin13, OUTPUT);
  99.  
  100. }
  101.  
  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.  
  109. if ((millis() - wdog) > 10000) { /* desliga as saidas se não recebe comando a mais de 10 segundos */
  110.  
  111. regs[MB_PINO_3] = 0; /* desliga led 3 */
  112. regs[MB_PINO_4] = 0; /* desliga led 4 */
  113. regs[MB_PINO_5] = 0; /* desliga led 5 */
  114. regs[MB_PINO_6] = 0; /* desliga led 6 */
  115. regs[MB_PINO_7] = 0; /* desliga led 7 */
  116. regs[MB_PINO_8] = 0; /* desliga led 8 */
  117. regs[MB_PINO_9] = 0; /* desliga led 9 */
  118. regs[MB_PINO_10] = 0; /* desliga led 10 */
  119. regs[MB_PINO_11] = 0; /* desliga led 11 */
  120. regs[MB_PINO_12] = 0; /* desliga led 12 */
  121. regs[MB_PINO_13] = 0; /* desliga led 13 */
  122. }
  123.  
  124. if ((millis() - tanalogprev) > 500) { /* atualiza as entradas analogica a cada 1 segundo */
  125.  
  126.  
  127. //Valor recebido pelo módulo ZigBee para mandar para a porta serial e para o ScadaBR
  128.  
  129. tanalogprev = millis();
  130.  
  131. regs[MB_A0] = Serial.read();
  132.  
  133. }
  134.  
  135. /* os valores dos registros são definidos pelo mestre modbus (SCADA) */
  136.  
  137. switch (regs[MB_PINO_3]) {
  138. case 1:
  139. digitalWrite(ledPin3, HIGH);
  140. break;
  141. default: /* apagado */
  142. digitalWrite(ledPin3, LOW);
  143. }
  144.  
  145. switch (regs[MB_PINO_4]) {
  146. case 1:
  147. digitalWrite(ledPin4, HIGH);
  148. break;
  149. default: /* apagado */
  150. digitalWrite(ledPin4, LOW);
  151. }
  152.  
  153. switch (regs[MB_PINO_5]) {
  154. case 1:
  155. digitalWrite(ledPin5, HIGH);
  156. break;
  157. default: /* apagado */
  158. digitalWrite(ledPin5, LOW);
  159. }
  160.  
  161. switch (regs[MB_PINO_6]) {
  162. case 1:
  163. digitalWrite(ledPin6, HIGH);
  164. break;
  165. default: /* apagado */
  166. digitalWrite(ledPin6, LOW);
  167. }
  168.  
  169. switch (regs[MB_PINO_7]) {
  170. case 1:
  171. digitalWrite(ledPin7, HIGH);
  172. break;
  173. default: /* apagado */
  174. digitalWrite(ledPin7, LOW);
  175. }
  176.  
  177. switch (regs[MB_PINO_8]) {
  178. case 1:
  179. digitalWrite(ledPin8, HIGH);
  180. break;
  181. default: /* apagado */
  182. digitalWrite(ledPin8, LOW);
  183. }
  184.  
  185. switch (regs[MB_PINO_9]) {
  186. case 1:
  187. digitalWrite(ledPin9, HIGH);
  188. break;
  189. default: /* apagado */
  190. digitalWrite(ledPin9, LOW);
  191. }
  192.  
  193. switch (regs[MB_PINO_10]) {
  194. case 1:
  195. digitalWrite(ledPin10, HIGH);
  196. break;
  197. default: /* apagado */
  198. digitalWrite(ledPin10, LOW);
  199. }
  200.  
  201. switch (regs[MB_PINO_11]) {
  202. case 1:
  203. digitalWrite(ledPin11, HIGH);
  204. break;
  205. default: /* apagado */
  206. digitalWrite(ledPin11, LOW);
  207. }
  208.  
  209. switch (regs[MB_PINO_12]) {
  210. case 1:
  211. digitalWrite(ledPin12, HIGH);
  212. break;
  213. default: /* apagado */
  214. digitalWrite(ledPin12, LOW);
  215. }
  216.  
  217. switch (regs[MB_PINO_13]) {
  218. case 1:
  219. digitalWrite(ledPin13, HIGH);
  220. break;
  221. default: /* apagado */
  222. digitalWrite(ledPin13, LOW);
  223. }
  224.  
  225.  
  226. }
  227.  
  228. /**************************************************************************
  229. * INICIO DAS FUNÇÕES ESCRAVO Modbus RTU
  230. **************************************************************************/
  231.  
  232. /* variaveis globais */
  233. unsigned int Txenpin = 2; /*Definir o pino usado para colocar o driver
  234. RS485 em modo de transmissão, utilizado
  235. somente em redes RS485 quando colocar em 0
  236. ou 1 para redes RS232 */
  237.  
  238.  
  239. /* Lista de códigos de função modbus suportados. Se você implementar um novo, colocar o seu código de função aqui! */
  240. enum {
  241. FC_READ_REGS = 0x03, //Read contiguous block of holding register (Ler um bloco contíguo de registos)
  242. FC_WRITE_REG = 0x06, //Write single holding register (Escrever em um único registro)
  243. FC_WRITE_REGS = 0x10 //Write block of contiguous registers (Escrever em um bloco contíguo de registos)
  244. };
  245.  
  246. /* Funções suportadas. Se você implementar um novo, colocar seu código em função nessa matriz! */
  247. const unsigned char fsupported[] = { FC_READ_REGS, FC_WRITE_REG, FC_WRITE_REGS };
  248.  
  249. /* constantes */
  250. enum {
  251. MAX_READ_REGS = 0x7D,
  252. MAX_WRITE_REGS = 0x7B,
  253. MAX_MESSAGE_LENGTH = 256
  254. };
  255.  
  256.  
  257. enum {
  258. RESPONSE_SIZE = 6,
  259. EXCEPTION_SIZE = 3,
  260. CHECKSUM_SIZE = 2
  261. };
  262.  
  263. /* código de exceções */
  264. enum {
  265. NO_REPLY = -1,
  266. EXC_FUNC_CODE = 1,
  267. EXC_ADDR_RANGE = 2,
  268. EXC_REGS_QUANT = 3,
  269. EXC_EXECUTE = 4
  270. };
  271.  
  272. /* posições dentro da matriz de consulta / resposta */
  273. enum {
  274. SLAVE = 0,
  275. FUNC,
  276. START_H,
  277. START_L,
  278. REGS_H,
  279. REGS_L,
  280. BYTE_CNT
  281. };
  282.  
  283.  
  284. /*
  285. CRC
  286.  
  287. INPUTS:
  288. buf -> Matriz contendo a mensagem a ser enviada para o controlador mestre.
  289. start -> Início do loop no crc do contador, normalmente 0.
  290. cnt -> Quantidade de bytes na mensagem a ser enviada para o controlador mestre
  291. OUTPUTS:
  292. temp -> Retorna byte crc para a mensagem.
  293. COMMENTÁRIOS:
  294. Esta rotina calcula o byte crc alto e baixo de uma mensagem.
  295. Note que este CRC é usado somente para Modbus, não em Modbus PLUS ou TCP.
  296. **************************************************************************/
  297.  
  298. unsigned int crc(unsigned char *buf, unsigned char start,
  299. unsigned char cnt)
  300. {
  301. unsigned char i, j;
  302. unsigned temp, temp2, flag;
  303.  
  304. temp = 0xFFFF;
  305.  
  306. for (i = start; i < cnt; i++) {
  307. temp = temp ^ buf[i];
  308.  
  309. for (j = 1; j <= 8; j++) {
  310. flag = temp & 0x0001;
  311. temp = temp >> 1;
  312. if (flag)
  313. temp = temp ^ 0xA001;
  314. }
  315. }
  316.  
  317. /* Inverter a ordem dos bytes. */
  318. temp2 = temp >> 8;
  319. temp = (temp << 8) | temp2;
  320. temp &= 0xFFFF;
  321.  
  322. return (temp);
  323. }
  324.  
  325.  
  326.  
  327.  
  328. /*********************************************************************
  329. *
  330. * As seguintes funções constroem o frame de
  331. * um pacote de consulta modbus.
  332. *
  333. *********************************************************************/
  334.  
  335. /*
  336. * Início do pacote de uma resposta read_holding_register
  337. */
  338. void build_read_packet(unsigned char slave, unsigned char function,
  339. unsigned char count, unsigned char *packet)
  340. {
  341. packet[SLAVE] = slave;
  342. packet[FUNC] = function;
  343. packet[2] = count * 2;
  344. }
  345.  
  346. /*
  347. * Início do pacote de uma resposta preset_multiple_register
  348. */
  349. void build_write_packet(unsigned char slave, unsigned char function,
  350. unsigned int start_addr,
  351. unsigned char count,
  352. unsigned char *packet)
  353. {
  354. packet[SLAVE] = slave;
  355. packet[FUNC] = function;
  356. packet[START_H] = start_addr >> 8;
  357. packet[START_L] = start_addr & 0x00ff;
  358. packet[REGS_H] = 0x00;
  359. packet[REGS_L] = count;
  360. }
  361.  
  362. /*
  363. * Início do pacote de uma resposta write_single_register
  364. */
  365. void build_write_single_packet(unsigned char slave, unsigned char function,
  366. unsigned int write_addr, unsigned int reg_val, unsigned char* packet)
  367. {
  368. packet[SLAVE] = slave;
  369. packet[FUNC] = function;
  370. packet[START_H] = write_addr >> 8;
  371. packet[START_L] = write_addr & 0x00ff;
  372. packet[REGS_H] = reg_val >> 8;
  373. packet[REGS_L] = reg_val & 0x00ff;
  374. }
  375.  
  376.  
  377. /*
  378. * Início do pacote de uma resposta excepção
  379. */
  380. void build_error_packet(unsigned char slave, unsigned char function,
  381. unsigned char exception, unsigned char *packet)
  382. {
  383. packet[SLAVE] = slave;
  384. packet[FUNC] = function + 0x80;
  385. packet[2] = exception;
  386. }
  387.  
  388.  
  389. /***********************************************************************
  390. *
  391. * modbus_query( packet, length)
  392. *
  393. * Função para adicionar uma soma de verificação para o fim de um pacote.
  394. * Por favor, note que a matriz pacote deve ser de pelo menos 2 campos mais do que
  395. * String_length.
  396. ************************************************************************/
  397.  
  398. void modbus_reply(unsigned char *packet, unsigned char string_length)
  399. {
  400. int temp_crc;
  401.  
  402. temp_crc = crc(packet, 0, string_length);
  403. packet[string_length] = temp_crc >> 8;
  404. string_length++;
  405. packet[string_length] = temp_crc & 0x00FF;
  406. }
  407.  
  408.  
  409.  
  410. /*********************************************************************
  411. *
  412. * send_reply( query_string, query_length )
  413. *
  414. * Função para enviar uma resposta a um mestre Modbus.
  415. * Retorna: o número total de caracteres enviados
  416. **********************************************************************/
  417.  
  418. int send_reply(unsigned char *query, unsigned char string_length)
  419. {
  420. unsigned char i;
  421.  
  422. if (Txenpin > 1) { // coloca o MAX485 no modo de transmissão
  423. UCSR0A = UCSR0A | (1 << TXC0);
  424. digitalWrite( Txenpin, HIGH);
  425. delayMicroseconds(3640); // aguarda silencio de 3.5 caracteres em 9600bps
  426. }
  427.  
  428. modbus_reply(query, string_length);
  429. string_length += 2;
  430.  
  431. for (i = 0; i < string_length; i++) {
  432. Serial.write(byte(query[i]));
  433. }
  434.  
  435. if (Txenpin > 1) {// coloca o MAX485 no modo de recepção
  436. while (!(UCSR0A & (1 << TXC0)));
  437. digitalWrite( Txenpin, LOW);
  438. }
  439.  
  440. return i; /* isso não significa que a gravação foi bem sucedida */
  441. }
  442.  
  443. /*********************************************************************
  444. *
  445. * receive_request( array_for_data )
  446. *
  447. * Função para monitorar um pedido do mestre modbus.
  448. *
  449. * Retorna: Número total de caracteres recebidos se OK
  450. * 0 se não houver nenhum pedido
  451. * Um código de erro negativo em caso de falha
  452. *********************************************************************/
  453.  
  454. int receive_request(unsigned char *received_string)
  455. {
  456. int bytes_received = 0;
  457.  
  458. /* FIXME: não Serial.available esperar 1.5T ou 3.5T antes de sair do loop? */
  459. while (Serial.available()) {
  460. received_string[bytes_received] = Serial.read();
  461. bytes_received++;
  462. if (bytes_received >= MAX_MESSAGE_LENGTH)
  463. return NO_REPLY; /* erro de porta */
  464. }
  465.  
  466. return (bytes_received);
  467. }
  468.  
  469.  
  470. /*******************************************************************
  471. *
  472. * modbus_request(slave_id, request_data_array)
  473. *
  474. * Função que é retornada quando o pedido está correto
  475. * e a soma de verificação está correto.
  476. * Retorna: string_length se OK
  477. * 0 se não
  478. * Menos de 0 para erros de exceção
  479. *
  480. * Nota: Todas as funções usadas para enviar ou receber dados via
  481. * Modbus devolver esses valores de retorno.
  482. *
  483. ********************************************************************/
  484.  
  485. int modbus_request(unsigned char slave, unsigned char *data)
  486. {
  487. int response_length;
  488. unsigned int crc_calc = 0;
  489. unsigned int crc_received = 0;
  490. unsigned char recv_crc_hi;
  491. unsigned char recv_crc_lo;
  492.  
  493. response_length = receive_request(data);
  494.  
  495. if (response_length > 0) {
  496. crc_calc = crc(data, 0, response_length - 2);
  497. recv_crc_hi = (unsigned) data[response_length - 2];
  498. recv_crc_lo = (unsigned) data[response_length - 1];
  499. crc_received = data[response_length - 2];
  500. crc_received = (unsigned) crc_received << 8;
  501. crc_received =
  502. crc_received | (unsigned) data[response_length - 1];
  503.  
  504. /********* verificar CRC da resposta **********/
  505. if (crc_calc != crc_received) {
  506. return NO_REPLY;
  507. }
  508.  
  509. /* verificar a ID do escravo */
  510. if (slave != data[SLAVE]) {
  511. return NO_REPLY;
  512. }
  513. }
  514. return (response_length);
  515. }
  516.  
  517. /*******************************************************************
  518. *
  519. * validate_request(request_data_array, request_length, available_regs)
  520. *
  521. * Função para verificar se o pedido pode ser processado pelo escravo.
  522. *
  523. * Retorna: 0 se OK
  524. * Um código de exceção negativa em caso de erro
  525. *
  526. ********************************************************************/
  527.  
  528. int validate_request(unsigned char *data, unsigned char length,
  529. unsigned int regs_size)
  530. {
  531. int i, fcnt = 0;
  532. unsigned int regs_num = 0;
  533. unsigned int start_addr = 0;
  534. unsigned char max_regs_num;
  535.  
  536. /* verificar o código de função */
  537. for (i = 0; i < sizeof(fsupported); i++) {
  538. if (fsupported[i] == data[FUNC]) {
  539. fcnt = 1;
  540. break;
  541. }
  542. }
  543. if (0 == fcnt)
  544. return EXC_FUNC_CODE;
  545.  
  546. if (FC_WRITE_REG == data[FUNC]) {
  547. /* Para a função de escrever um reg único, este é o registro alvo.*/
  548. regs_num = ((int) data[START_H] << 8) + (int) data[START_L];
  549. if (regs_num >= regs_size)
  550. return EXC_ADDR_RANGE;
  551. return 0;
  552. }
  553.  
  554. /* Para as funções de leitura / escrita de registros, este é o intervalo. */
  555. regs_num = ((int) data[REGS_H] << 8) + (int) data[REGS_L];
  556.  
  557. /* verifica a quantidade de registros */
  558. if (FC_READ_REGS == data[FUNC])
  559. max_regs_num = MAX_READ_REGS;
  560. else if (FC_WRITE_REGS == data[FUNC])
  561. max_regs_num = MAX_WRITE_REGS;
  562.  
  563. if ((regs_num < 1) || (regs_num > max_regs_num))
  564. return EXC_REGS_QUANT;
  565.  
  566. /* verificará a quantidade de registros, endereço inicial é 0 */
  567. start_addr = ((int) data[START_H] << 8) + (int) data[START_L];
  568. if ((start_addr + regs_num) > regs_size)
  569. return EXC_ADDR_RANGE;
  570.  
  571. return 0; /* OK, sem exceção */
  572. }
  573.  
  574.  
  575.  
  576. /**********************************************************************
  577. *
  578. * write_regs(first_register, data_array, registers_array)
  579. *
  580. * escreve nos registradores do escravo os dados em consulta,
  581. * A partir de start_addr.
  582. *
  583. * Retorna: o número de registros escritos
  584. **********************************************************************/
  585.  
  586. int write_regs(unsigned int start_addr, unsigned char *query, int *regs)
  587. {
  588. int temp;
  589. unsigned int i;
  590.  
  591. for (i = 0; i < query[REGS_L]; i++) {
  592. /* mudar reg hi_byte para temp */
  593. temp = (int) query[(BYTE_CNT + 1) + i * 2] << 8;
  594. /* OR com lo_byte */
  595. temp = temp | (int) query[(BYTE_CNT + 2) + i * 2];
  596.  
  597. regs[start_addr + i] = temp;
  598. }
  599. return i;
  600. }
  601.  
  602. /**********************************************************************
  603. *
  604. * preset_multiple_registers(slave_id, first_register, number_of_registers,
  605. * data_array, registers_array)
  606. *
  607. * Escreva os dados na matriz dos registos do escravo.
  608. *
  609. ***********************************************************************/
  610.  
  611. int preset_multiple_registers(unsigned char slave,
  612. unsigned int start_addr,
  613. unsigned char count,
  614. unsigned char *query,
  615. int *regs)
  616. {
  617. unsigned char function = FC_WRITE_REGS; /* Escrever em múltiplos registros */
  618. int status = 0;
  619. unsigned char packet[RESPONSE_SIZE + CHECKSUM_SIZE];
  620.  
  621. build_write_packet(slave, function, start_addr, count, packet);
  622.  
  623. if (write_regs(start_addr, query, regs)) {
  624. status = send_reply(packet, RESPONSE_SIZE);
  625. }
  626.  
  627. return (status);
  628. }
  629.  
  630.  
  631. /**********************************************************************
  632. *
  633. * write_single_register(slave_id, write_addr, data_array, registers_array)
  634. *
  635. * Escrever um único valor inteiro em um único registo do escravo.
  636. *
  637. ***********************************************************************/
  638.  
  639. int write_single_register(unsigned char slave,
  640. unsigned int write_addr, unsigned char *query, int *regs)
  641. {
  642. unsigned char function = FC_WRITE_REG; /* Função: Write Single Register */
  643. int status = 0;
  644. unsigned int reg_val;
  645. unsigned char packet[RESPONSE_SIZE + CHECKSUM_SIZE];
  646.  
  647. reg_val = query[REGS_H] << 8 | query[REGS_L];
  648. build_write_single_packet(slave, function, write_addr, reg_val, packet);
  649. regs[write_addr] = (int) reg_val;
  650. /*
  651. written.start_addr=write_addr;
  652. written.num_regs=1;
  653. */
  654. status = send_reply(packet, RESPONSE_SIZE);
  655.  
  656. return (status);
  657. }
  658.  
  659.  
  660. /**********************************************************************
  661. *
  662. * read_holding_registers(slave_id, first_register, number_of_registers,
  663. * registers_array)
  664. *
  665. * lê os registros do escravo e envia para o mestre Modbus
  666. *
  667. ***********************************************************************/
  668.  
  669. int read_holding_registers(unsigned char slave, unsigned int start_addr,
  670.  
  671. unsigned char reg_count, int *regs)
  672. {
  673. unsigned char function = 0x03; /* Função 03: Read Holding Registers */
  674. int packet_size = 3;
  675. int status;
  676. unsigned int i;
  677. unsigned char packet[MAX_MESSAGE_LENGTH];
  678.  
  679. build_read_packet(slave, function, reg_count, packet);
  680.  
  681. for (i = start_addr; i < (start_addr + (unsigned int) reg_count);
  682. i++) {
  683. packet[packet_size] = regs[i] >> 8;
  684. packet_size++;
  685. packet[packet_size] = regs[i] & 0x00FF;
  686. packet_size++;
  687. }
  688.  
  689. status = send_reply(packet, packet_size);
  690.  
  691. return (status);
  692. }
  693.  
  694.  
  695. void configure_mb_slave(long baud, char parity, char txenpin)
  696. {
  697. Serial.begin(baud);
  698.  
  699. switch (parity) {
  700. case 'e': // 8E1
  701. UCSR0C |= ((1 << UPM01) | (1 << UCSZ01) | (1 << UCSZ00));
  702. // UCSR0C &= ~((1<<UPM00) | (1<<UCSZ02) | (1<<USBS0));
  703. break;
  704. case 'o': // 8O1
  705. UCSR0C |= ((1 << UPM01) | (1 << UPM00) | (1 << UCSZ01) | (1 << UCSZ00));
  706. // UCSR0C &= ~((1<<UCSZ02) | (1<<USBS0));
  707. break;
  708. case 'n': // 8N1
  709. UCSR0C |= ((1 << UCSZ01) | (1 << UCSZ00));
  710. // UCSR0C &= ~((1<<UPM01) | (1<<UPM00) | (1<<UCSZ02) | (1<<USBS0));
  711. break;
  712. default:
  713. break;
  714. }
  715.  
  716. if (txenpin > 1) { // pino 0 & pino 1 são reservados para RX/TX
  717. Txenpin = txenpin; /* definir variável global */
  718. pinMode(Txenpin, OUTPUT);
  719. digitalWrite(Txenpin, LOW);
  720. }
  721.  
  722. return;
  723. }
  724.  
  725. /*
  726. * update_mb_slave(slave_id, holding_regs_array, number_of_regs)
  727. *
  728. * verifica se há qualquer pedido válido do mestre modbus. Se houver,
  729. * executa a ação solicitada
  730. */
  731.  
  732. unsigned long Nowdt = 0;
  733. unsigned int lastBytesReceived;
  734. const unsigned long T35 = 5;
  735.  
  736. int update_mb_slave(unsigned char slave, int *regs,
  737. unsigned int regs_size)
  738. {
  739. unsigned char query[MAX_MESSAGE_LENGTH];
  740. unsigned char errpacket[EXCEPTION_SIZE + CHECKSUM_SIZE];
  741. unsigned int start_addr;
  742. int exception;
  743. int length = Serial.available();
  744. unsigned long now = millis();
  745.  
  746. if (length == 0) {
  747. lastBytesReceived = 0;
  748. return 0;
  749. }
  750.  
  751. if (lastBytesReceived != length) {
  752. lastBytesReceived = length;
  753. Nowdt = now + T35;
  754. return 0;
  755. }
  756. if (now < Nowdt)
  757. return 0;
  758.  
  759. lastBytesReceived = 0;
  760.  
  761. length = modbus_request(slave, query);
  762. if (length < 1)
  763. return length;
  764.  
  765.  
  766. exception = validate_request(query, length, regs_size);
  767. if (exception) {
  768. build_error_packet(slave, query[FUNC], exception,
  769. errpacket);
  770. send_reply(errpacket, EXCEPTION_SIZE);
  771. return (exception);
  772. }
  773.  
  774.  
  775. start_addr = ((int) query[START_H] << 8) +
  776. (int) query[START_L];
  777. switch (query[FUNC]) {
  778. case FC_READ_REGS:
  779. return read_holding_registers(slave,
  780. start_addr,
  781. query[REGS_L],
  782. regs);
  783. break;
  784. case FC_WRITE_REGS:
  785. return preset_multiple_registers(slave,
  786. start_addr,
  787. query[REGS_L],
  788. query,
  789. regs);
  790. break;
  791. case FC_WRITE_REG:
  792. write_single_register(slave,
  793. start_addr,
  794. query,
  795. regs);
  796. break;
  797. }
  798. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement