Guia CNC Brasil - Tudo sobre CNC, Router, Laser, Torno e 3D Print
ELETRÔNICA / ELÉTRICA => Eletrônica Básica => Microcontroladores => Tópico iniciado por: EduardoGrieger em 19 de Outubro de 2017, 08:44
-
Olá pessoal, preciso de uma ajuda para desenvolver uma lógica de comunicação Modbus RTU entre um microcontrolador PIC e um supervisório.
Minha arquitetura é a seguinte:
Tenho um microcontrolador 16F877A e o mesmo terá que comunicar via modbus RTU com um sistema de supervisório indusoft. A comunicação precisa ser Modbus por conta da distância que o microcontrolador ficará do PC. Entre o PC e o microcontrolador tenho um conversor TTL/RS485.
Estou usando o compilador MikroC Pro para desenvolver a lógica do microcontrolador.
Desde já agradeço a atenção de todos.
-
Você quer desenvolver um Slave ou Master Modbus?
Quais funções Modbus pretende usar?
-
Olá Minilathe,
Eu quero desenvolver um Slave Modbus RTU, onde o SCADA deverá trocar dados com ele.
As funções que preciso é:
Ler dados do microcontrolador, boolenas e inteiras;
Escrever dados no microcontrolador, booleanas e inteiras;
-
Há vários anos criei um Master para um pic similar a este seu (com menos pinos). O Slave é um pouquinho mais complicado, seria conveniente usar interrupção, para a correta detecção da mensagem de requisição.
-
No compilador MikroC tem um exemplo de comunicação mestre e escrava via RS485 mas não sei se é modbus, ou seja, não sei identificar se é modbus ou não. Segue abaixo o exemplo:
PIC Master Code:
char dat[10]; // buffer for receving/sending messages
char i,j;
sbit rs485_rxtx_pin at RC2_bit; // set transcieve pin
sbit rs485_rxtx_pin_dire ction at TRISC2_bit; // set transcieve pin direction
// Interrupt routine
void interrupt() {
RS485Master_Receive(dat);
}
void main(){
long cnt = 0;
ANSEL = 0; // Configure AN pins as digital I/O
ANSELH = 0;
PORTB = 0;
PORTD = 0;
TRISB = 0;
TRISD = 0;
UART1_Init(9600); // initialize UART1 module
Delay_ms(100);
RS485Master_Init(); // initialize MCU as Master
dat[0] = 0xAA;
dat[1] = 0xF0;
dat[2] = 0x0F;
dat[4] = 0; // ensure that message received flag is 0
dat[5] = 0; // ensure that error flag is 0
dat[6] = 0;
RS485Master_Send(dat,1,160);
PIE1.RCIE = 1; // enable interrupt on UART1 receive
PIE2.TXIE = 0; // disable interrupt on UART1 transmit
INTCON.PEIE = 1; // enable peripheral interrupts
INTCON.GIE = 1; // enable all interrupts
while (1){
// upon completed valid message receiving
// data[4] is set to 255
cnt++;
if (dat[5]) { // if an error detected, signal it
PORTD = 0xAA; // by setting portd to 0xAA
}
if (dat[4]) { // if message received successfully
cnt = 0;
dat[4] = 0; // clear message received flag
j = dat[3];
for (i = 1; i <= dat[3]; i++) { // show data on PORTB
PORTB = dat[i-1];
} // increment received dat[0]
dat[0] = dat[0]+1; // send back to master
Delay_ms(1);
RS485Master_Send(dat,1,160);
}
if (cnt > 100000) {
PORTD ++;
cnt = 0;
RS485Master_Send(dat,1,160);
if (PORTD > 10) // if sending failed 10 times
RS485Master_Send(dat,1,50); // send message on broadcast address
}
}
// function to be properly linked.
}
PIC Slave Code:
char dat[9]; // buffer for receving/sending messages
char i,j;
sbit rs485_rxtx_pin at RC2_bit; // set transcieve pin
sbit rs485_rxtx_pin_dire ction at TRISC2_bit; // set transcieve pin direction
// Interrupt routine
void interrupt() {
RS485Slave_Receive(dat);
}
void main() {
long cnt = 0;
//ANSEL = 0; // Configure AN pins as digital I/O
//ANSELH = 0;
PORTB = 0;
PORTD = 0;
TRISB = 0;
TRISD = 0;
UART1_Init(9600); // initialize UART1 module
Delay_ms(100);
RS485Slave_Init(160); // Intialize MCU as slave, address 160
dat[4] = 0; // ensure that message received flag is 0
dat[5] = 0; // ensure that message received flag is 0
dat[6] = 0; // ensure that error flag is 0
PIE1.RCIE = 1; // enable interrupt on UART1 receive
PIE2.TXIE = 0; // disable interrupt on UART1 transmit
INTCON.PEIE = 1; // enable peripheral interrupts
INTCON.GIE = 1; // enable all interrupts
while (1) {
if (dat[5]) { // if an error detected, signal it by
PORTD = 0xAA; // setting portd to 0xAA
dat[5] = 0;
}
if (dat[4]) { // upon completed valid message receive
cnt++;
dat[4] = 0; // data[4] is set to 0xFF
j = dat[3];
for (i = 1; i <= dat[3];i++){
PORTB = dat[i-1];
}
if (cnt>=100){ // besteira, conta de 1 até 7 a cada 100 ciclos
dat[0] = dat[0]+1; // increment received dat[0]
cnt=0;
if(dat[0] > 7) {
dat[0] = 0;
}
}
Delay_ms(1);
RS485Slave_Send(dat,1); // and send it back to master
}
}
}
Nesses códigos comunica PIC com PIC, não sei se dá pra aproveitar alguma coisa porque não sei se está usando protocolo Modbus RTU.
-
Faltaram as funções RS485Slave_Receive, RS485Slave_Send e RS485Slave_Init.
-
Olá Minilathe,
Acho que não entendi sua resposta. As funções que você comentou eu coloquei em negrito no código abaixo:
PIC Slave Code:[/size]char dat[9]; // buffer for receving/sending messageschar i,j;sbit rs485_rxtx_pin at RC2_bit; // set transcieve pinsbit rs485_rxtx_pin_dire ction at TRISC2_bit; // set transcieve pin direction// Interrupt routinevoid interrupt() { RS485Slave_Receive(dat);}void main() { long cnt = 0; //ANSEL = 0; // Configure AN pins as digital I/O //ANSELH = 0; PORTB = 0; PORTD = 0; TRISB = 0; TRISD = 0; UART1_Init(9600); // initialize UART1 module Delay_ms(100); RS485Slave_Init(160); // Intialize MCU as slave, address 160 dat[4] = 0; // ensure that message received flag is 0 dat[5] = 0; // ensure that message received flag is 0 dat[6] = 0; // ensure that error flag is 0 PIE1.RCIE = 1; // enable interrupt on UART1 receive PIE2.TXIE = 0; // disable interrupt on UART1 transmit INTCON.PEIE = 1; // enable peripheral interrupts INTCON.GIE = 1; // enable all interrupts while (1) { if (dat[5]) { // if an error detected, signal it by PORTD = 0xAA; // setting portd to 0xAA dat[5] = 0; } if (dat[4]) { // upon completed valid message receive cnt++; dat[4] = 0; // data[4] is set to 0xFF j = dat[3]; for (i = 1; i <= dat[3];i++){ PORTB = dat[i-1]; } if (cnt>=100){ // besteira, conta de 1 até 7 a cada 100 ciclos dat[0] = dat[0]+1; // increment received dat[0] cnt=0; if(dat[0] > 7) { dat[0] = 0; } } Delay_ms(1); RS485Slave_Send(dat,1); // and send it back to master } }}
-
Olá Minilathe,
Acho que não entendi sua resposta. As funções que você comentou eu coloquei em negrito no código abaixo:
char dat[9]; // buffer for receving/sending messages
char i,j;
sbit rs485_rxtx_pin at RC2_bit; // set transcieve pin
sbit rs485_rxtx_pin_dire ction at TRISC2_bit; // set transcieve pin direction
// Interrupt routine
void interrupt() {
RS485Slave_Receive(dat);
}
void main() {
long cnt = 0;
//ANSEL = 0; // Configure AN pins as digital I/O
//ANSELH = 0;
PORTB = 0;
PORTD = 0;
TRISB = 0;
TRISD = 0;
UART1_Init(9600); // initialize UART1 module
Delay_ms(100);
RS485Slave_Init(160); // Intialize MCU as slave, address 160
dat[4] = 0; // ensure that message received flag is 0
dat[5] = 0; // ensure that message received flag is 0
dat[6] = 0; // ensure that error flag is 0
PIE1.RCIE = 1; // enable interrupt on UART1 receive
PIE2.TXIE = 0; // disable interrupt on UART1 transmit
INTCON.PEIE = 1; // enable peripheral interrupts
INTCON.GIE = 1; // enable all interrupts
while (1) {
if (dat[5]) { // if an error detected, signal it by
PORTD = 0xAA; // setting portd to 0xAA
dat[5] = 0;
}
if (dat[4]) { // upon completed valid message receive
cnt++;
dat[4] = 0; // data[4] is set to 0xFF
j = dat[3];
for (i = 1; i <= dat[3];i++){
PORTB = dat[i-1];
}
if (cnt>=100){ // besteira, conta de 1 até 7 a cada 100 ciclos
dat[0] = dat[0]+1; // increment received dat[0]
cnt=0;
if(dat[0] > 7) {
dat[0] = 0;
}
}
Delay_ms(1);
RS485Slave_Send(dat,1); // and send it back to master
}
}
}
-
Não... seu programa apenas chama essas rotinas. As menções feitas são chamadas e não declarações. Ok?
Por exemplo, a linha
RS485Slave_Send(dat,1); // and send it back to master
Aparece apenas uma vez (na chamada). Onde está a respectiva declaração?
O mesmo se aplica às outras funções.
-
Essas rotinas são da biblioteca do MikroC. Eu não sei o que essa rotina faz por é fechado pra visualização, abaixo segue o link da biblioteca:
https://download.mikroe.com/documents/compilers/mikroc/pic/help/rs-485_library.htm
-
Essas rotinas são da biblioteca do MikroC. Eu não sei o que essa rotina faz por é fechado pra visualização, abaixo segue o link da biblioteca:
https://download.mikroe.com/documents/compilers/mikroc/pic/help/rs-485_library.htm
Você pode usar o exemplo que você postou juntamente com as rotinas de sua biblioteca. Pode tentar obter o código fonte dessas rotinas, se precisar consertar alguma coisa.
-
Em uma pesquisa na internet achei um trabalho de conclusão de curso onde um cara desenvolveu uma lógica usando protocolo modbus. Peguei esse código abri no meu compilador que foi o mesmo onde o criador desenvolveu, simulei no protheus mas não deu certo. Não sei se foi por conta do protheus, porque tive que virtualizar a porta COM e usar o COMPIN do protheus. Vou tentar simular na real com PIC e depois posto aqui o resultado.
-
Já usei a porta serial no Proteus com PIC sem problemas. Considere que, se você está implementando um Master Modbus, deveria estar recebendo as mensagens de requisição num monitor de serial, dentro do Proteus. Como não há um Slave ativo, a comunicação não possuirá respostas. E dependendo do programa, pode tentar comunicar algumas vezes e parar.