Buscar

AUTOMAÇÃO DE SISTEMA INDUSTRIAL UTILIZANDO UM SUPERVISÓRIO

Prévia do material em texto

UNORP – CENTRO UNIVERSITÁRIO DO NORTE PAULISTA 
 
 
 
 
 
 
 
 
ALEX SANDRO GAREFA 
CARLOS OMERO DIAS SOARES 
JESSÉ AUGUSTO ALVES DOS SANTOS 
MAYKON DONIZETI GERVASONI 
RENAN ALEXANDRE ZIPPERT DA SILVA 
 
 
 
 
 
 
 
 
AUTOMAÇÃO DE SISTEMA INDUSTRIAL UTILIZANDO UM SUPERVISÓRIO 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
SÃO JOSÉ DO RIO PRETO - SP 
2016 
 
 
1 
 
ALEX SANDRO GAREFA 
CARLOS OMERO DIAS SOARES 
JESSÉ AUGUSTO ALVES DOS SANTOS 
MAYKON DONIZETI GERVASONI 
RENAN ALEXANDRE ZIPPERT DA SILVA 
 
 
 
 
 
 
AUTOMAÇÃO DE SISTEMA INDUSTRIAL UTILIZANDO UM SUPERVISÓRIO 
 
 
 
 
 
 
 
 
Trabalho apresentado para avaliação na 
disciplina de Eletrônica Básica do curso de 
Engenharia Elétrica do Centro Universitário do 
Norte Paulista. 
Orientador: Ms. Paulo César Fantinato. 
 
 
 
 
 
 
 
 
 
 
 
SÃO JOSÉ DO RIO PRETO - SP 
2016 
 
 
2 
 
RESUMO 
Este projeto comtempla etapas de projeto, simulação, confecção, testes e execução sobre 
a preparação de um microcontrolador Arduino para auxiliar no acionamento e monitoramento 
de três sistemas, um luminotécnico, um pneumático e um quadro de comandos para motores, 
utilizando uma central de controle e monitoramento, ou supervisório, programada pelo software 
ScadaBR. 
A preparação do Arduino envolveu duas partes principais, a programação deste para 
estabelecer comunicação com o supervisório, que estará instalado em um computador, e a 
elaboração de uma placa auxiliar, denominada shield, para estabelecer segurança dos sinais 
elétricos evitar que ocorra danificação do microcontrolador. 
Tal projeto foi de grande serventia para o currículo acadêmico dos alunos e se mostrou 
totalmente eficaz, pois explora os conhecimentos adquiridos ao decorrer do curso enquanto que 
os desafia a buscar soluções utilizando desses meios. 
 
 
3 
 
SUMÁRIO 
 
1 Introdução ............................................................................................................................. 06 
2 Objetivo ................................................................................................................................ 07 
3 Metodologia .......................................................................................................................... 08 
3.1 Materiais utilizados ......................................................................................................... 08 
3.2 Procedimentos ................................................................................................................. 09 
3.3 Detalhes da programação ................................................................................................ 10 
4 Circuito para recebimento do sinal de leitura ........................................................................ 11 
5 Circuito para envio do sinal de acionamento......................................................................... 13 
Resultados ................................................................................................................................ 16 
Referências bibliográficas ....................................................................................................... 17 
Anexo A – Código da programação do Arduino ...................................................................... 18 
 
 
 
 
4 
 
ÍNDICE DE IMAGENS 
 
Imagem 01 – Arduino UNO R3 ............................................................................................... 10 
Imagem 02 – Exemplo de circuito do ‘AmpOp’ para recepção da tensão de entrada do 
monitoramento .......................................................................................................................... 12 
Imagem 03 – Circuito do ‘AmpOp’ para recepção da tensão de entrada do monitoramento .. 13 
Imagem 04 – Exemplo de circuito de proteção e envio do sinal para atracar um relé. ............ 14 
 
 
 
 
5 
 
ÍNDICE DE TABELAS 
 
Tabela 01 – Componentes utilizados para confecção do circuito ............................................ 08 
Tabela 02 – Conexão entre o Circuito do ‘AmpOp’ e Arduino ............................................... 13 
Tabela 03 – Configuração das portas de saída do Arduino ...................................................... 15 
 
 
 
6 
 
1 INTRODUÇÃO 
O Arduino é uma plataforma eletrônica de código aberto que integra software e 
hardware no mesmo componente, é amplamente utilizado na automação de projetos. Sua placa 
é capaz de determinar um comando para uma saída, acionar um motor, ligar uma lâmpada, entre 
outros componentes eletrônicos, baseado em sinais de entrada simples, que pode ser um sensor 
de luminosidade ou temperatura ou o acionamento de um botão. Assim, possibilita que pessoas 
desenvolvam aplicações de objetos e ambientes interativos. (ALVES et al, 2012). 
Para que seja possível controlar um desses componentes eletrônicos, é necessário que o 
acionamento seja efetuado por um operador ou técnico que também realizará o monitoramento 
de tais componentes. A utilização de uma plataforma composta por um microcontrolador 
(Arduino) atuando como escravo de um supervisório (baseado no software ScadaBR) elimina 
a necessidade de monitoramento e acionamento manuais. (MUYNARSK; GARCIA, 2014). 
 
 
 
7 
 
2 OBJETIVO 
 O presente projeto tem por finalidade configurar um microcontrolador da plataforma 
Arduino para realizar o acionamento de três sistemas independentes, um pneumático, um 
luminotécnico e um quadro de comando e o monitoramento dos mesmos enquanto atua como 
escravo de um supervisório, que fora programado pelo software ScadaBR. 
 Tal configuração do microcontrolador envolve duas etapas, a parte física, que é a 
confecção de uma placa auxiliar para realizar o tratamento dos sinais de entrada e saída do 
microcontrolador e a parte lógica, que envolve a programação desse componente e sua 
comunicação com o supervisório. 
 
 
 
8 
 
3 METODOLOGIA 
O projeto consistiu em realizar o acionamento de três sistemas utilizando a plataforma 
Arduino integrada com um supervisório programado no software ScadaBR. Tal projeto foi 
realizado com a turma do terceiro ano de Engenharia Elétrica do ano de 2015 e foi proposto 
para que a turma atual, de 2016, fizesse o melhoramento do estudo viabilizando novos métodos 
e aperfeiçoamento do mesmo. 
O projeto foi dividido em cinco partes, onde cada parte foi designada a um grupo de 
alunos, sendo que esta parte do projeto visa o ponto intermediário do projeto, o 
microcontrolador, que realiza a comunicação entre o supervisório e os sistemas a serem 
acionados e monitorados. 
 
3.1 MATERIAIS UTILIZADOS 
Foi necessário confeccionar uma placa auxiliar para o Arduino, afim de fazer o 
tratamento dos sinais de entrada e de saída para não ocorrer danificação do mesmo por 
sobrecarga ou curto-circuito, os componentes utilizados para a confecção desta placa estão na 
tabela 01, esses, foram soldados em uma placa de fenolite com o auxílio de um ferro de solda 
de 40W. 
 
Descrição do material Quantidade Valor Total 
Amplificador Operacional LM324N 1 R$ 3,90 R$ 3,90 
Conector barra pino 1x20 vias, 11.2mm, 180° 1 R$ 0,70 R$ 0,70 
Conector Jack J4 fêmea 1 R$ 0,50 R$ 0,50 
Diodo retificador de silício 1N4007 1 R$ 0,10 R$ 0,10 
Estanho para solda, tubo 25gr, fio de 1mm 1 R$ 7,00 R$ 7,00 
Fonte 127/220VAC-12VDC, 1A, conector P4 1 R$ 8,00 R$ 8,00 
LED difuso vermelho 3mm 4 R$ 0,30R$ 1,20 
LED difuso verde 3mm 1 R$ 0,30 R$ 0,30 
Placa de fenolite perfurada 10x15cm 1 R$ 16,90 R$ 16,90 
Resistor cerâmico de 1kΩ - dissipação de 1/4W 2 R$ 0,10 R$ 0,90 
Resistor cerâmico de 10kΩ - dissipação de 1/4W 10 R$ 0,10 R$ 0,70 
Resistor cerâmico de 39kΩ - dissipação de 1/4W 1 R$ 0,10 R$ 0,10 
Soquete pata CI de 14 terminais 1 R$ 1,90 R$ 1,90 
Termoretrátil 2mm - 1 metro 1 R$ 4,00 R$ 4,00 
Transistor BC337 3 R$ 0,30 R$ 0,90 
Transistor BC558 3 R$ 0,50 R$ 1,50 
Total R$ 48,00 
Tabela 01 – Componentes utilizados para confecção do circuito. 
 
 
9 
 
 Na Tabela 01 também pode ser observado o valor investido para a confecção da placa 
auxiliar. Além dos componentes utilizados na confecção da placa, foram utilizados outros 
componentes e ferramentas, tais como: 
 Arduino UNO R3; 
 Cabo USB tipo B; 
 Caixa plástica 10x10cm; 
 Cola quente para acabamento; 
 Computador portátil (notebook) para testes da programação; 
 Conectores; 
 Ferro de Solda de 40W. 
 
3.2 PROCEDIMENTOS 
 O Arduino, ilustrado na Figura 01, é um microcontrolador que possui portas digitais, 
que assumem apenas dois estados lógicos, e portas analógicas, que assumem valor em escala 
de 0 a 5VDC. Tais portas podem ser definidas como porta de entrada, que faz leitura, ou porta 
de saída, que envia certo sinal ou comando para outros meios. Portanto, de maneira simplória, 
pode-se dizer que o Arduino envia um sinal para a uma porta de saída quando a leitura dos 
sinais de entrada atender à certa condição pré-estabelecida, contudo, para que isso funcione 
realmente, é necessário que seja elaborada uma programação em C em um desktop, que após 
elaborada, é enviada ao microcontrolador Arduino por meio de um Cabo USB e fica salva na 
memora de seu microcontrolador, dessa forma, o Arduino executa e repete a programação toda 
vez que é energizado. 
Neste projeto, foram usadas somente portas digitais para entrada e saída de sinais. A 
programação inserida no Arduino foi para que ele trabalhasse como escravo do supervisório, 
através do protocolo de comunicação Modbus. O supervisório foi programado pelo software 
ScadaBR, que se trata de um programa para automação de processos e criação de centros de 
controle e operação. O protocolo de comunicação Modbus foi desenvolvido pela Modicon na 
década de 70 e consiste em uma estrutura de mensagem aberta, utilizada para comunicação 
entre dispositivos mestre-escravo ou cliente-servidor. 
 Também se fez necessária a construção de uma placa auxiliar para efetuar o tratamento 
dos sinais de entrada e de saída do Arduino, impedindo que a carga drene mais corrente do que 
é suportada por ele e também que os sinais recebidos por ele não causem sobre-corrente. Essa 
 
 
10 
 
placa foi adaptada de maneira que os pinos dela pudessem ser sobrepostos sobre o Arduino, 
dessa forma, encaixando um ao outro, ou seja, foi adaptada como um shield. 
 
Imagem 01 – Arduino UNO R3. 
 
3.3 DETALHES DA PROGRAMAÇÃO 
Toda a programação usada no Arduino está inclusa neste documento, ela pode ser 
visualizada no Anexo A. O que temos a seguir é uma breve explicação sobre as linhas de 
comando dessa. 
Existem inúmeros códigos ‘open-sources’ prontos para serem utilizados na área de 
automação industrial, programas para Arduino e até mesmo para trabalhar com o ScadaBR. 
Para o nosso projeto, fizemos o uso de uma versão indicada pelo Engenheiro Paulo Saes, que 
nos orientou durante o processo de programação. 
O Arduino foi programado para reconhecer a entrada de dados oriunda do supervisório 
ScadaBR pela porta USB a uma taxa de 9600bps utilizando o protocolo de comunicação 
Modbus. 
Todos os pinos utilizados do Arduino são pinos digitais, por ter apenas dois estados 
lógicos, simplifica a programação e execução dos projetos. As portas digitais 3, 4 e 5 são saídas 
de sinal e enviam um sinal conforme o comando recebido do supervisório através da porta USB, 
para ligar ou desligar os circuitos. Já as portas digitais 6, 7 e 8 são entradas de sinal e o recebem 
de cada um dos circuitos para enviar a informação até o supervisório. 
 
 
11 
 
Para garantir que o sistema mantenha-se funcionando, a leitura dos sinais de entrada 
(portas digitais 6, 7 e 8), foi programada para ser realizada a cada um segundo, dessa forma não 
tem um atraso de tempo tão relevante para o processo de monitoramento ao mesmo tempo que 
não sobrecarrega o processamento do supervisório. 
 
4 CIRCUITO PARA RECEBIMENTO DO SINAL DE LEITURA 
Para o recebimento do sinal de leitura na porta digital do Arduino houve um simples 
problema, o qual foi replicado entre es três grupos que devolveriam tal sinal, onde o sistema 
pneumático retornaria um sinal com tensão em torno de 5 a 7VDC, no sistema do quadro de 
comando dos motores e na iluminação um sinal com 12VDC. É sabido que o limite de tensão 
suportada pelas portas digitais do Arduino é de +5VDC com corrente máxima de 40mA, sendo 
assim, não seria possível receber o sinal de retorno na faixa de tensão que estava sendo enviado. 
Em primeira instância havia sido projetada a recepção de tal sinal com um relé, o qual 
acionaria a bobina e a mesma fecharia o +5VDC do próprio Arduino e devolveria para a entrada 
digital, contudo, haveria a necessidade de instalarmos um relé para cada entrada e com valores 
de tensão diferentes, o qual já ficou inviável economicamente e esteticamente, pois o mesmo 
ocuparia um espaço considerável na placa. 
Outro fator é que há a possibilidade de surgir problemas na recepção, pois não haveria 
garantia de que os grupos realmente enviariam a tensão declarada e se a mesma for superior, 
causaria avarias no relé. 
A solução foi oriunda de uma aula lecionada na instituição a respeito dos 
Amplificadores Operacionais (TAPPARO, 2016). Na apresentação do Amplificador 
Operacional (AmpOp) LM358N, o mesmo foi utilizado aplicando uma variação de resistência 
com o uso um potenciômetro conectado ao terminal 3 do ‘AmpOp’ LM358N e conectado em 
série a uma fonte de tensão. O terminal 8 do ‘AmpOp’ foi alimentado com o 5VDC do Arduino 
e o terminal 4 ligado ao GND (aterramento). A variação no terminal e não implicava na tensão 
de saída no terminal 1, pois esse é dependente da tensão aplicada no terminal 8. Foi projetado 
um potencial de 1VDC gerado a partir de um divisor de corrente e conectado ao terminal 2, de 
tal forma é possível gerar um comparador entre os terminais 2 e 3 do ‘AmpOp’. 
Com base nessa aula, podemos definir que a variação de entrada no terminal 3 seria o 
nosso problema com a recepção de três tensões diferentes. Em consulta ao discente TAPPARO, 
foi possível efetuar a solução da questão com uso de ‘AmpOp’ LM358N e obtivemos o circuito 
ilustrado a seguir. 
 
 
12 
 
 
Imagem 02 – Exemplo de circuito do ‘AmpOp’ para recepção da tensão de entrada do monitoramento. 
 
Onde: 
VOUT ARDUINO = Alimentação do Arduino através do terminal Power 5VDC; 
VIN X = Tensão do sinal de retorno do sistema para monitoramento (até 32VDC); 
VIN ARDUINO = Tensão de entrada no terminal digital do Arduino; 
U1:A = Amplificador Operacional (AmpOp) LM358N; 
R1 e R2 = Resistores utilizados para referenciar o ‘AmpOp’; 
R3 = Resistor instalado para evitar flutuação de corrente de fuga no terminal; 
R4 = Resistor para limitação de corrente de saída para proteção da porta digital do Arduino. 
 
Visto que há a necessidade de três ‘AmpOps’ no circuito, utilizaremos o LM324N, pois 
o mesmo se trata de um circuito integrado que possui quatro ‘AmpOps’ internos, enquanto o 
LM358N possui apenas dois, contudo, ambos componentes atuamda mesma forma. A 
identificação dos terminais é diferente entre os ‘AmpOps’ LM358N e LM234N, então tomar a 
figura anterior apenas como exemplo do projeto. 
O divisor de tensão projetado com um resistor de 39kΩ e um de 10kΩ consegue gerar 
em VR2 uma tensão de 1,02VDC, a qual utilizaremos como referencial para que o ‘AmpOp’ 
compare tensões entre VR2 e VMÁX do LM324N. Em consulta ao datasheet do componente, 
indicado nas Referências Bibliográficas, na seção 6, tabela da alínea 6.1, a tensão de entrada 
pode chegar até 32Vdc, ou seja, a tensão de entrada do sinal de recepção para leitura pode variar 
entre 1,02VDC e 32VDC. 
Quanto aos resistores, poderão ser utilizados componentes com dissipação para 1/16W, 
pois a potência nos mesmos é de 104µW para o de 10kΩ e de 406µW para o de 39kΩ. 
 
 
13 
 
Fundamentado no explícito anteriormente, foi possível projetar o circuito para a 
primeira etapa da confecção da shield, para que o Arduino recebesse um sinal com tensão 
suficiente, que é de 3,6VDC devido à queda de tensão gerada pelo ‘AmpOp’, onde o terminal 
analógico interpretará como ligado. 
 
 
Imagem 03 – Circuito do ‘AmpOp’ para recepção da tensão de entrada do monitoramento. 
 
Para a comunicação desse sistema de proteção de tensão para o monitoramento do 
estado (ligado - 1 ou desligado - 0), o Output do ‘AmpOp’ deverá ser conectado aos terminais 
analógicos no Arduino como segue a seguir: 
 
Terminal Tipo Estado Nome Conexão ao AmpOp Identificação 
6 Digital Entrada sensorPin6 Output 1 E1 
7 Digital Entrada sensorPin7 Output 2 E2 
8 Digital Entrada sensorPin8 Output 3 E3 
Tabela 02 – Conexão entre o Circuito do ‘AmpOp’ e Arduino 
 
5 CIRCUITO PARA ENVIO DO SINAL DE ACIONAMENTO 
Para o acionamento dos sistemas deverá ser emitido um pulso através da saída digital 
do Arduino. Tendo em vista que os três grupos que receberão o sinal digital do Arduino para 
acionamento da bonina dos relés no circuito particular de cada sistema. A partir disso há a 
necessidade de elaborar um circuito para a proteção das portas do Arduino, pois mesmo que 
haja proteção em cada sistema, não há garantia de que essa irá realmente atuar como deve e 
 
 
14 
 
proteger o circuito da shield, então foram iniciados estudos para verificar tal situação e envio 
do sinal aos sistemas. 
No primeiro momento havia sido projetado a emissão de tal sinal com relés, o qual seria 
atracado com tal sinal dado a partir da porta digital do Arduino e o mesmo fecharia a bobina do 
relé com a tensão de 12VDC gerada a partir de uma fonte externa. Contudo, encontrar um relé 
com bobina que se acione com 5VDC não é uma tarefa tão fácil se comparado à utilização de 
componentes mais modestos e que cumpririam a mesma função e, já que nesse momento não 
haveria grande carga a acionar, foi considerada a utilização de transistores. Portanto, o uso de 
relés foi abortado, devido à dificuldade citada e pela região ocupada pelo relé numa placa. 
Tendo em vista que realizar o envio do sinal para acionamento das cargas através de 
transistores seria mais viável analisando o ponto de vista técnico e econômico, logo foi 
analisado e adotada uma ligação entre os transistores BC337 (NPN) e BC558 (PNP), pois seria 
suficiente para enviar o sinal para os três sistemas, esses que por possuir uma carga elevada 
devem projetar em cada sistema um relé para recepção do sinal enviado. Tal informação foi 
divulgada entre os três grupos a fim de evitar erro de projeto por parte deles. 
 
Imagem 04 – Exemplo de circuito de proteção e envio do sinal para atracar um relé. 
 
Onde: 
VDC = Alimentação da placa através do terminal digital do Arduino; 
VOUT = Alimentação do relé individual de cada sistema; 
Q1 e Q2 = Transistores; 
E = Fonte de alimentação externa; 
R1 = Resistor para limitar a corrente do LED; 
R2 e R3 = Resistores utilizados para limitar a corrente na base dos transistores; 
 
 
15 
 
D1 = LED de indicação de que o sinal está sendo enviado; 
D2 = Diodo de silício para proteção contra polarização contrária. 
 
A comunicação oriunda do esquema elétrico acima garante o estado (ligado - 1 ou 
desligado - 0), para acionamento dos relés solicitados aos outros grupos, como orientado abaixo. 
 
Terminal Tipo Estado Nome Identificação 
3 Digital Saída bobPin3 S1 
4 Digital Saída bobPin4 S2 
5 Digital Saída bobPin5 S3 
Tabela 03 – Configuração das portas de saída do Arduino 
 
 
 
16 
 
RESULTADOS 
O planejamento e estudo dos componentes antes de tomar qualquer decisão, somado ao 
fato da interação entre os grupos e ao conhecimento adquirido no decorrer do ano possibilitou 
que esse sistema de comunicação através de supervisório fosse aplicado com eficiência. 
Em comparação ao projeto anterior, onde houve o projeto e execução de uma fonte 
estabilizada, nesse projeto conseguimos evitar vários erros e consequentemente houve tempo 
suficiente para planejar executar acertos no projeto inicial de forma muito eficiente e eficaz. 
Além do tempo, também houve economia financeira, pois, o prévio planejamento possibilitou 
que não executássemos o projeto com base em componentes erroneamente atribuídos de alguma 
forma, como o caso do relé que foi substituído por transistores logo na etapa inicial. 
Na etapa de testes, a qual ocorreu no dia 28 de novembro de 2016 no laboratório de 
eletrotécnica, não houve erro de transmissão ou de recepção dos sinais e logo concluímos que 
o projeto atente rigorosamente aos atributos solicitados. 
Tendo em vista que se tratava de um melhoramento do projeto elaborado pela turma do 
terceiro ano de engenharia elétrica de 2015, denotamos que houve realmente várias melhoras 
de projeto e de comunicação entre os sistemas que seriam controlados e entre o software 
ScadaBR, tendo em vista que o tempo de leitura e resposta era altamente baixo e com extrema 
precisão. 
 
 
 
17 
 
REFERENCIAS BIBLIOGRÁFICAS 
 
CIPELLI, Antônio M. V.; MARKUS, Otávio; SANDRINI, Waldir. Teoria e desenvolvimento 
de projetos de circuitos eletrônicos. Ed. 23. São Paulo: Editora Érica Ltda, 2009. 
 
Datasheet LMx24-N, LM2902-N Low-Power, Quad-Operational Amplifiers. Disponível em: 
<http://www.ti.com/lit/ds/symlink/lm124-n.pdf>. Acesso em: 18 nov 2016. 
 
Primeira instalação e tutorial de configuração do Software ScadaBR - Automação Open Source. 
Disponível em: <http://www.scadabr.com.br/?q=downloads>. Acesso em: 16 nov 2016. 
 
Sotware para programação do Arduino Genuino. Disponível em: 
<https://www.arduino.cc/download_handler.php>. Acesso em: 16 nov 2016. 
 
 
 
18 
 
 
ANEXO A – CÓDIGO DA PROGRAMAÇÃO DO ARDUINO 
void configure_mb_slave(long baud, char parity, char txenpin); 
int update_mb_slave(unsigned char slave, int *regs, 
unsigned int regs_size); 
enum { 
COMM_BPS = 9600, 
MB_SLAVE = 1, 
PARITY = 'n' 
}; 
enum { 
MB_PINO_3, 
MB_PINO_4, 
MB_PINO_5, 
MB_PINO_6, 
MB_PINO_7, 
MB_PINO_8, 
MB_A0, 
MB_A1, 
MB_A2, 
MB_REGS 
}; 
int regs[MB_REGS]; 
int bobPin3 = 3; 
int bobPin4 = 4; 
int bobPin5 = 5; 
int sensorPin6 = 6; 
int sensorPin7 = 7; 
int sensorPin8 = 8; 
unsigned long wdog = 0; 
unsigned long tprev = 0; 
unsigned long tdigitalprev = 0; 
unsigned long tanalogprev = 0; 
 
 
19 
 
void setup() 
{ 
configure_mb_slave(COMM_BPS, PARITY, 0);//ATENÇÃO nesta linha de comando. 
pinMode(bobPin3, OUTPUT); 
pinMode(bobPin4, OUTPUT);pinMode(bobPin5, OUTPUT); 
pinMode(sensorPin6, INPUT); 
pinMode(sensorPin7, INPUT); 
pinMode(sensorPin8, INPUT); 
} 
void loop() 
{ 
if(update_mb_slave(MB_SLAVE, regs, MB_REGS)) 
wdog = millis(); 
if ((millis() - wdog) > 10000) { 
regs[MB_PINO_3] = 0; 
regs[MB_PINO_4] = 0; 
regs[MB_PINO_5] = 0; 
} 
if ((millis() - tdigitalprev) > 1000) { 
regs[MB_PINO_6] = digitalRead(6); 
regs[MB_PINO_7] = digitalRead(7); 
regs[MB_PINO_8] = digitalRead(8); 
tdigitalprev = millis(); 
} 
if ((millis() - tanalogprev) > 1000) { 
regs[MB_A0] = analogRead(0); 
regs[MB_A1] = analogRead(1); 
regs[MB_A2] = analogRead(2); 
tanalogprev = millis(); 
} 
switch(regs[MB_PINO_3]) { 
case 1: 
 
 
20 
 
digitalWrite(bobPin3, HIGH); 
break; 
default: 
digitalWrite(bobPin3, LOW); 
} 
switch(regs[MB_PINO_4]) { 
case 1: 
digitalWrite(bobPin4, HIGH); 
break; 
default: 
digitalWrite(bobPin4, LOW); 
} 
switch(regs[MB_PINO_5]) { 
case 1: 
digitalWrite(bobPin5, HIGH); 
break; 
default: 
digitalWrite(bobPin5, LOW); 
} 
} 
unsigned int Txenpin = 2; 
enum { 
FC_READ_REGS = 0x03, 
FC_WRITE_REG = 0x06, 
FC_WRITE_REGS = 0x10 
}; 
const unsigned char fsupported[] = { FC_READ_REGS, FC_WRITE_REG, 
FC_WRITE_REGS }; 
enum { 
MAX_READ_REGS = 0x7D, 
MAX_WRITE_REGS = 0x7B, 
MAX_MESSAGE_LENGTH = 256 
}; 
 
 
21 
 
enum { 
RESPONSE_SIZE = 6, 
EXCEPTION_SIZE = 3, 
CHECKSUM_SIZE = 2 
}; 
enum { 
NO_REPLY = -1, 
EXC_FUNC_CODE = 1, 
EXC_ADDR_RANGE = 2, 
EXC_REGS_QUANT = 3, 
EXC_EXECUTE = 4 
}; 
enum { 
SLAVE = 0, 
FUNC, 
START_H, 
START_L, 
REGS_H, 
REGS_L, 
BYTE_CNT 
}; 
unsigned int crc(unsigned char *buf, unsigned char start, 
unsigned char cnt) 
{ 
unsigned char i, j; 
unsigned temp, temp2, flag; 
temp = 0xFFFF; 
for (i = start; i < cnt; i++) { 
temp = temp ^ buf[i]; 
for (j = 1; j <= 8; j++) { 
flag = temp & 0x0001; 
temp = temp >> 1; 
if (flag) 
 
 
22 
 
temp = temp ^ 0xA001; 
} 
} 
temp2 = temp >> 8; 
temp = (temp << 8) | temp2; 
temp &= 0xFFFF; 
return (temp); 
} 
void build_read_packet(unsigned char slave, unsigned char function, 
unsigned char count, unsigned char *packet) 
{ 
packet[SLAVE] = slave; 
packet[FUNC] = function; 
packet[2] = count * 2; 
} 
void build_write_packet(unsigned char slave, unsigned char function, 
unsigned int start_addr, 
unsigned char count, 
unsigned char *packet) 
{ 
packet[SLAVE] = slave; 
packet[FUNC] = function; 
packet[START_H] = start_addr >> 8; 
packet[START_L] = start_addr & 0x00ff; 
packet[REGS_H] = 0x00; 
packet[REGS_L] = count; 
} 
void build_write_single_packet(unsigned char slave, unsigned char function, 
unsigned int write_addr, unsigned int reg_val, unsigned char* packet) 
{ 
packet[SLAVE] = slave; 
packet[FUNC] = function; 
packet[START_H] = write_addr >> 8; 
 
 
23 
 
packet[START_L] = write_addr & 0x00ff; 
packet[REGS_H] = reg_val >> 8; 
packet[REGS_L] = reg_val & 0x00ff; 
} 
void build_error_packet(unsigned char slave, unsigned char function, 
unsigned char exception, unsigned char *packet) 
{ 
packet[SLAVE] = slave; 
packet[FUNC] = function + 0x80; 
packet[2] = exception; 
} 
void modbus_reply(unsigned char *packet, unsigned char string_length) 
{ 
int temp_crc; 
temp_crc = crc(packet, 0, string_length); 
packet[string_length] = temp_crc >> 8; 
string_length++; 
packet[string_length] = temp_crc & 0x00FF; 
} 
int send_reply(unsigned char *query, unsigned char string_length) 
{ 
unsigned char i; 
if (Txenpin > 1) { 
UCSR0A=UCSR0A |(1 << TXC0); 
digitalWrite( Txenpin, HIGH); 
delayMicroseconds(3640); 
} 
modbus_reply(query, string_length); 
string_length += 2; 
for (i = 0; i < string_length; i++) { 
Serial.write(byte(query[i])); 
} 
if (Txenpin > 1) { 
 
 
24 
 
while (!(UCSR0A & (1 << TXC0))); 
digitalWrite( Txenpin, LOW); 
} 
return i; 
int receive_request(unsigned char *received_string) 
{ 
int bytes_received = 0; 
while (Serial.available()) { 
received_string[bytes_received] = Serial.read(); 
bytes_received++; 
if (bytes_received >= MAX_MESSAGE_LENGTH) 
return NO_REPLY; 
} 
return (bytes_received); 
} 
int modbus_request(unsigned char slave, unsigned char *data) 
{ 
int response_length; 
unsigned int crc_calc = 0; 
unsigned int crc_received = 0; 
unsigned char recv_crc_hi; 
unsigned char recv_crc_lo; 
response_length = receive_request(data); 
if (response_length > 0) { 
crc_calc = crc(data, 0, response_length - 2); 
recv_crc_hi = (unsigned) data[response_length - 2]; 
recv_crc_lo = (unsigned) data[response_length - 1]; 
crc_received = data[response_length - 2]; 
crc_received = (unsigned) crc_received << 8; 
crc_received = 
crc_received | (unsigned) data[response_length - 1]; 
if (crc_calc != crc_received) { 
return NO_REPLY; 
 
 
25 
 
} 
if (slave != data[SLAVE]) { 
return NO_REPLY; 
} 
} 
return (response_length); 
} 
int validate_request(unsigned char *data, unsigned char length, 
unsigned int regs_size) 
{ 
int i, fcnt = 0; 
unsigned int regs_num = 0; 
unsigned int start_addr = 0; 
unsigned char max_regs_num; 
for (i = 0; i < sizeof(fsupported); i++) { 
if (fsupported[i] == data[FUNC]) { 
fcnt = 1; 
break; 
} 
} 
if (0 == fcnt) 
return EXC_FUNC_CODE; 
if (FC_WRITE_REG == data[FUNC]) { 
regs_num = ((int) data[START_H] << 8) + (int) data[START_L]; 
if (regs_num >= regs_size) 
return EXC_ADDR_RANGE; 
return 0; 
} 
regs_num = ((int) data[REGS_H] << 8) + (int) data[REGS_L]; 
if (FC_READ_REGS == data[FUNC]) 
max_regs_num = MAX_READ_REGS; 
else if (FC_WRITE_REGS == data[FUNC]) 
max_regs_num = MAX_WRITE_REGS; 
 
 
26 
 
if ((regs_num < 1) || (regs_num > max_regs_num)) 
return EXC_REGS_QUANT; 
start_addr = ((int) data[START_H] << 8) + (int) data[START_L]; 
if ((start_addr + regs_num) > regs_size) 
return EXC_ADDR_RANGE; 
return 0; 
} 
int write_regs(unsigned int start_addr, unsigned char *query, int *regs) 
{ 
int temp; 
unsigned int i; 
for (i = 0; i < query[REGS_L]; i++) { 
 
temp = (int) query[(BYTE_CNT + 1) + i * 2] << 8; 
temp = temp | (int) query[(BYTE_CNT + 2) + i * 2]; 
regs[start_addr + i] = temp; 
} 
return i; 
} 
int preset_multiple_registers(unsigned char slave, 
unsigned int start_addr, 
unsigned char count, 
unsigned char *query, 
int *regs) 
{ 
unsigned char function = FC_WRITE_REGS; 
int status = 0; 
unsigned char packet[RESPONSE_SIZE + CHECKSUM_SIZE]; 
build_write_packet(slave, function, start_addr, count, packet); 
if (write_regs(start_addr, query, regs)) { 
status = send_reply(packet, RESPONSE_SIZE); 
} 
return (status); 
 
 
27 
 
} 
int write_single_register(unsigned char slave, 
unsigned int write_addr, unsigned char *query, int *regs) 
{ 
unsigned char function = FC_WRITE_REG; 
int status = 0; 
unsigned int reg_val; 
unsigned char packet[RESPONSE_SIZE + CHECKSUM_SIZE]; 
reg_val = query[REGS_H] << 8 | query[REGS_L]; 
build_write_single_packet(slave, function, write_addr, reg_val, packet); 
regs[write_addr] = (int) reg_val; 
status = send_reply(packet, RESPONSE_SIZE); 
return (status); 
} 
int read_holding_registers(unsigned char slave, unsigned int start_addr, 
unsigned char reg_count, int *regs) 
{ 
unsigned char function = 0x03; 
int packet_size = 3; 
int status; 
unsigned int i; 
unsigned char packet[MAX_MESSAGE_LENGTH];build_read_packet(slave, function, reg_count, packet); 
for (i = start_addr; i < (start_addr + (unsigned int) reg_count); 
i++) { 
packet[packet_size] = regs[i] >> 8; 
packet_size++; 
packet[packet_size] = regs[i] & 0x00FF; 
packet_size++; 
} 
status = send_reply(packet, packet_size); 
return (status); 
} 
 
 
28 
 
void configure_mb_slave(long baud, char parity, char txenpin) 
{ 
Serial.begin(baud); 
switch (parity) { 
case 'e': 
UCSR0C |= ((1<<UPM01) | (1<<UCSZ01) | (1<<UCSZ00)); 
break; 
case 'o': 
UCSR0C |= ((1<<UPM01) | (1<<UPM00) | (1<<UCSZ01) | (1<<UCSZ00)); 
break; 
case 'n': 
UCSR0C |= ((1<<UCSZ01) | (1<<UCSZ00)); 
break; 
default: 
break; 
} 
if (txenpin > 1) { 
Txenpin = txenpin; 
pinMode(Txenpin, OUTPUT); 
digitalWrite(Txenpin, LOW); 
} 
return; 
} 
unsigned long Nowdt = 0; 
unsigned int lastBytesReceived; 
const unsigned long T35 = 5; 
int update_mb_slave(unsigned char slave, int *regs, 
unsigned int regs_size) 
{ 
unsigned char query[MAX_MESSAGE_LENGTH]; 
unsigned char errpacket[EXCEPTION_SIZE + CHECKSUM_SIZE]; 
unsigned int start_addr; 
int exception; 
 
 
29 
 
int length = Serial.available(); 
unsigned long now = millis(); 
if (length == 0) { 
lastBytesReceived = 0; 
return 0; 
} 
if (lastBytesReceived != length) { 
lastBytesReceived = length; 
Nowdt = now + T35; 
return 0; 
} 
if (now < Nowdt) 
return 0; 
lastBytesReceived = 0; 
length = modbus_request(slave, query); 
if (length < 1) 
return length; 
exception = validate_request(query, length, regs_size); 
if (exception) { 
build_error_packet(slave, query[FUNC], exception, 
errpacket); 
send_reply(errpacket, EXCEPTION_SIZE); 
return (exception); 
} 
start_addr = ((int) query[START_H] << 8) + 
(int) query[START_L]; 
switch (query[FUNC]) { 
case FC_READ_REGS: 
return read_holding_registers(slave, 
start_addr, 
query[REGS_L], 
regs); 
break; 
 
 
30 
 
case FC_WRITE_REGS: 
return preset_multiple_registers(slave, 
start_addr, 
query[REGS_L], 
query, 
regs); 
break; 
case FC_WRITE_REG: 
write_single_register(slave, 
start_addr, 
query, 
regs); 
break; 
} 
}

Continue navegando