Página 1 de 2

CRC

MensagemEnviado: 03 Mai 2010 08:28
por verd
Estou tentando montar um crc modbus mas não estou conseguindo, estou seguindo este padrão, a função gera um crc mas meus programas de teste e o clp não aceita este crc!
alguem tem alguma idéia do que está faltando? estou usando o MikroC.


Código: Selecionar todos
unsigned short CRC16 ( puchMsg, usDataLen ) /* The function returns the CRC as a unsigned short type */
unsigned char *puchMsg ; /* message to calculate CRC upon */
unsigned short usDataLen ; /* quantity of bytes in message */
{
unsigned char uchCRCHi = 0xFF ; /* high byte of CRC initialized */
unsigned char uchCRCLo = 0xFF ; /* low byte of CRC initialized */
unsigned uIndex ; /* will index into CRC lookup table */
while (usDataLen--) /* pass through message buffer */
{
uIndex = uchCRCLo ^ *puchMsgg++ ; /* calculate the CRC */
uchCRCLo = uchCRCHi ^ auchCRCHi[uIndex} ;
uchCRCHi = auchCRCLo[uIndex] ;
}
return (uchCRCHi << 8 | uchCRCLo) ;
}


o crc precisa atender este padrão mas sou fraco em C não entendo-o completamente!

A procedure for generating a CRC is:
1, Load a 16–bit register with FFFF hex (all 1’s). Call this the CRC register.
2. Exclusive OR the first 8–bit byte of the message with the low–order byte
of the 16–bit CRC register, putting the result in the CRC register.
3. Shift the CRC register one bit to the right (toward the LSB), zero–filling the
MSB. Extract and examine the LSB.
4. (If the LSB was 0): Repeat Step 3 (another shift).
(If the LSB was 1): Exclusive OR the CRC register with the polynomial
value A001 hex (1010 0000 0000 0001).
5. Repeat Steps 3 and 4 until 8 shifts have been performed. When this is
done, a complete 8–bit byte will have been processed.
6. Repeat Steps 2 through 5 for the next 8–bit byte of the message.
Continue doing this until all bytes have been processed.
7. The final contents of the CRC register is the CRC value.
8. When the CRC is placed into the message, its upper and lower bytes
must be swapped as described below.

MensagemEnviado: 03 Mai 2010 08:46
por tcpipchip
http://www.control.com/thread/1026149685

Eu nao usei este CRC para modbus, mas em um protocolo que usei para falar com os modulos da ZWORLD e funcionou.

MensagemEnviado: 03 Mai 2010 08:57
por verd
Valeu TCP vou tentar inplementar, ja montei uns 4 tipos de modbus difetente hehehe!! obrigado!

MensagemEnviado: 03 Mai 2010 21:49
por RobL
O cálculo do CRC acima usa tabela. É necessário ter certeza que esta tabela foi gerada com o polinômio 0xA001.
No link do tcpipchip o calculo é feito em runtime.

O CLP pode não responder, não apenas por erro de CRC. Tem vários outros que podem estar acontecendo, por exemplo, faixa de registros não existentes, funções que não estão habilitadas e principalmente se seu frame está exatamente dentro do padrão de tempo, desde o tempo do startup e os tempo entre bytes. Veja esses tempos no protocolo. Eles dependem da velocidade de transmissão.
Cabe lembrar, não custa nada, que a velocidade de TX / RX tem que ser a mesma.

Há uns programas de teste para o protocolo na net, tente usá-los antes. Isto ajuda.

MensagemEnviado: 04 Mai 2010 07:53
por verd
Então Robl eu peguei estes programas e eles detectam erro de crc! sim eu utilizo tabelas com estas funções acima!

Código: Selecionar todos
const char modbus_auchCRCHi[] = {
   0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
   0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
   0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01,
   0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
   0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81,
   0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
   0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01,
   0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
   0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
   0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
   0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01,
   0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
   0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
   0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
   0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01,
   0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
   0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
   0x40
};

/* Table of CRC values for low–order byte */
const char modbus_auchCRCLo[] = {
   0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7, 0x05, 0xC5, 0xC4,
   0x04, 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09,
   0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A, 0x1E, 0xDE, 0xDF, 0x1F, 0xDD,
   0x1D, 0x1C, 0xDC, 0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,
   0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32, 0x36, 0xF6, 0xF7,
   0x37, 0xF5, 0x35, 0x34, 0xF4, 0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A,
   0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA, 0xEE,
   0x2E, 0x2F, 0xEF, 0x2D, 0xED, 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,
   0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 0x61, 0xA1, 0x63, 0xA3, 0xA2,
   0x62, 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F,
   0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68, 0x78, 0xB8, 0xB9, 0x79, 0xBB,
   0x7B, 0x7A, 0xBA, 0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,
   0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0, 0x50, 0x90, 0x91,
   0x51, 0x93, 0x53, 0x52, 0x92, 0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C,
   0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98, 0x88,
   0x48, 0x49, 0x89, 0x4B, 0x8B, 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,
   0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 0x43, 0x83, 0x41, 0x81, 0x80,
   0x40
};

union
{
   int b[2];
   int d;
} modbus_serial_crc;


void modbus_calc_crc(char data)
{
int uIndex ; // will index into CRC lookup table

uIndex = modbus_serial_crc.b[1] ^ data; // calculate the CRC
modbus_serial_crc.b[1] = modbus_serial_crc.b[0] ^ modbus_auchCRCHi[uIndex];
modbus_serial_crc.b[0] = modbus_auchCRCLo[uIndex];
}

faço a função com os endereços corretos e mando imprimir o crc!!
Uart1_write(modbus_serial_crc.b[0]);

Uart1_write(modbus_serial_crc.b[1]);

ela forma o crc mas o programa não aceita!

MensagemEnviado: 04 Mai 2010 08:54
por verd
sou fraco em C estou tentando implementar a função como no descritivo do primeiro post!

Código: Selecionar todos
unsigned getcrc( unsigned crc, char c)
{
crc = 0xff;
c = 0xff;
int i;
crc ^= (c & 0xff);
 for (i = 0; i < 8; ++i) {
    if (crc & 1) crc = (crc >> 1) ^ 0xA001;
    else crc = (crc >> 1);
  }
  return crc;
}


no caso teria que colocar um array pro "crc"

MensagemEnviado: 04 Mai 2010 09:04
por RobL
Se o erro é de CRC mesmo, verifique se no frame os dois bytes do CRC estão na ordem correta, quando transmitido, ou seja ao entrar para a UART.

Já experimentou trocar os bytes do CRC (low pelo hi) e transmitir para ver o que dá?
O seu programa faz isso corretamente mas tente ai, pois, se está dando erro de CRC é por que:

0- O CRC está sendo calculado por uma sequencia e outra, com ordenação diferente está sendo transmitida (o frame como um todo, qualquer byte).
1- Está sendo calculado errado (pouco provável e fácil de verificar por simulação no PC).
2- Está sendo recebido o frame na ordem errada
3- A ordem dos bytes CRC está sendo transmitida errada.
4- Alguma coisa na transmissão está ocorrendo, ruído, nível inadequado, baud rate, etc.

MensagemEnviado: 04 Mai 2010 09:08
por KrafT
Esse manual da Alfa foi a referencia inicial para muita gente, eu incluso:

http://www.alfainstrumentos.com.br/manu ... manual.pdf

Na pagina 17 tem exemplo em C. Lendo esse manual com carinho voce resolve rapidinho teus probelmas.

MensagemEnviado: 04 Mai 2010 10:14
por verd
valeu Kraft!!

MensagemEnviado: 04 Mai 2010 11:57
por verd
então eu tinha montado o crc parecido com esse, meu programa gera o crc, mas acho q o problema está no tempo, estava testando o protocolo e não implementei interrupção da serial, fiz assim quando recebesse qq coisa da serial ele retorna o pacote, será q iso pode estar dando erro?

ta assim! começei a aprender c eses dias, to apanhando ainda!


Código: Selecionar todos
static unsigned char CRC_HiByte[]={0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,0x01,0xC0,0x80,
0x41,0x00,0xC1,0x81,0x40,
0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,
0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,
0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,
0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,
0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,
0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,
0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,
0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,
0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,
0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,
0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,
0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,
0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,
0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,
0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40};

static char CRC_LoByte[]= {
0x00,0xC0,0xC1,0x01,0xC3,0x03,0x02,0xC2,0xC6,0x06,0x07,0xC7,0x05,0xC5,0xC4,0x04,
0xCC,0x0C,0x0D,0xCD,0x0F,0xCF,0xCE,0x0E,0x0A,0xCA,0xCB,0x0B,0xC9,0x09,0x08,0xC8,
0xD8,0x18,0x19,0xD9,0x1B,0xDB,0xDA,0x1A,0x1E,0xDE,0xDF,0x1F,0xDD,0x1D,0x1C,0xDC,
0x14,0xD4,0xD5,0x15,0xD7,0x17,0x16,0xD6,0xD2,0x12,0x13,0xD3,0x11,0xD1,0xD0,0x10,
0xF0,0x30,0x31,0xF1,0x33,0xF3,0xF2,0x32,0x36,0xF6,0xF7,0x37,0xF5,0x35,0x34,0xF4,
0x3C,0xFC,0xFD,0x3D,0xFF,0x3F,0x3E,0xFE,0xFA,0x3A,0x3B,0xFB,0x39,0xF9,0xF8,0x38,
0x28,0xE8,0xE9,0x29,0xEB,0x2B,0x2A,0xEA,0xEE,0x2E,0x2F,0xEF,0x2D,0xED,0xEC,0x2C,
0xE4,0x24,0x25,0xE5,0x27,0xE7,0xE6,0x26,0x22,0xE2,0xE3,0x23,0xE1,0x21,0x20,0xE0,
0xA0,0x60,0x61,0xA1,0x63,0xA3,0xA2,0x62,0x66,0xA6,0xA7,0x67,0xA5,0x65,0x64,0xA4,
0x6C,0xAC,0xAD,0x6D,0xAF,0x6F,0x6E,0xAE,0xAA,0x6A,0x6B,0xAB,0x69,0xA9,0xA8,0x68,
0x78,0xB8,0xB9,0x79,0xBB,0x7B,0x7A,0xBA,0xBE,0x7E,0x7F,0xBF,0x7D,0xBD,0xBC,0x7C,
0xB4,0x74,0x75,0xB5,0x77,0xB7,0xB6,0x76,0x72,0xB2,0xB3,0x73,0xB1,0x71,0x70,0xB0,
0x50,0x90,0x91,0x51,0x93,0x53,0x52,0x92,0x96,0x56,0x57,0x97,0x55,0x95,0x94,0x54,
0x9C,0x5C,0x5D,0x9D,0x5F,0x9F,0x9E,0x5E,0x5A,0x9A,0x9B,0x5B,0x99,0x59,0x58,0x98,
0x88,0x48,0x49,0x89,0x4B,0x8B,0x8A,0x4A,0x4E,0x8E,0x8F,0x4F,0x8D,0x4D,0x4C,0x8C,
0x44,0x84,0x85,0x45,0x87,0x47,0x46,0x86,0x82,0x42,0x43,0x83,0x41,0x81,0x80,0x40};

union
{
   unsigned short b[2];
   unsigned int d;
} modbus_serial_crc;

void CRC_RTU_serial()
{
unsigned char n_caracters;
unsigned char *pointer;
unsigned char cont_carac,carac=0;
unsigned char CRC_Hi= 0xFF;
unsigned char CRC_Lo = 0xFF;
cont_carac=0;
modbus_serial_crc.d=0xFFFF;
do
{

carac=modbus_serial_crc.b[1]^*pointer++;
modbus_serial_crc.b[1]=modbus_serial_crc.b[0]^CRC_HiByte[carac];
modbus_serial_crc.b[0]=CRC_LoByte[carac];
cont_carac++;
} while(cont_carac<n_caracters);
*pointer++=CRC_Lo;
*pointer++=CRC_Hi;
}

    if ( UART1_Data_Ready()==1){
              unsigned char i;
            delay_ms(100);

                  UART1_Read_text(A,"A",10);
                  CRC_RTU_serial();
                  //modbus_serial_crc.d=0xFFFF;
                   UART1_Write(0x01);
                  UART1_Write(0x03);
                  UART1_Write(0x02);
                  UART1_Write(0x00);
                  UART1_Write(0x07);
                  UART1_Write(modbus_serial_crc.b[1]);
                  UART1_Write(modbus_serial_crc.b[0]);
                      delay_ms(100);

                     UART1_Data_Ready() == 0 ;


                                 }


MensagemEnviado: 04 Mai 2010 12:02
por fabim
verd, deixa perguntar.
Você esta usando em modo serial , P2P com o equipo, ou tem uma RS485 ai no meio ?
Eu a um tempo fui remexer com essa anarquia em 485, e tava dando erro de CRC. Fazendo alguns testes.

Descobri que quando da o TX enable, tu tem que esperar alguns uSegundos, antes de começar a mandar os dados. Se você baixar o TX e ja sair mandando bala, ele da erro de CRC..

MensagemEnviado: 04 Mai 2010 13:38
por verd
fabim to montando minha estação meteorológica como escravo modbus, to usando o proteus via serial para simular, ai coloco um conversor 232 para 485 e ligo no clp! eu to achando que tem algo a vem com tempo pq quando utilizo os programas de teste modbus fazendo um laço nas com´s virtuais com o proteus, eles dão time out!! vou por um tempo antes de transmitir para fazer um teste!! valeu!!

MensagemEnviado: 04 Mai 2010 14:07
por verd
percebi uma coisa utilizo um simulado para ser escravo e consigo escrever na clp com ele blz, no conversor rs232 para 485 tem 2 led´s primeiro pisca o RX e depois o TX em sequência, quando coloco meu proteus para comunicar com o clp, primeiro pisca o TX e depois o RX!

MensagemEnviado: 04 Mai 2010 17:57
por Beto_s
Olá Verd

To mexendo justamente com isso por esses dias.
Como disse o Fabim, tem que dar um tempo quando habilita Tx no 485 . aqui to usando 1ms exagerando para testar .
Outra coisa que me ajudou bastante foi fazer um conversor 485 x 232 e ligar o Compim no Proteus e ficar ouvindo um PIC conversando com outro ou com o dispositivo modbus.
Enviar um pacote simples como escrever em um registrador somente , já que a resposta é o eco dos dados enviados , tambem facilita para testar o sistema.

Estou convertendo um programa para MikroC que já funcionava parcialmente em ASM.
Outro ponto que deu problema foi na recepção , pois sempre que terminava de TX e comutava para RX os dois primeiros Bytes que vinham eram o CRC do pacote anterior .
Motivo : o buffer Rx estava cheio .
Desliguei a habilitação de recepçao após cada RX , para resolver.

* Outro método que utilizei foi montar uma mensagem com o CAS Modbus RTU Parser para saber o CRC sem calcular EX:

# This file was created by CAS Modbus RTU Parser version 1.00fA on Tue May 04 17:51:54 2010
# Please visit http://www.chipkin.com

Frame Analysis (01 06 00 01 00 01 19 ca)
--------------

The frame has no errors.

The direction of the message is ambiguous. In isolation it cannot be determined if it is a poll or response. If information of about the previous or next message was known a best guess could have been made.


Poll Analysis
-------------
Device Address =1 =0x01
Function =6 =0x06 =Preset Single Register
Point Address =40002
Required value =1 =0x01

Response Analysis
-----------------
Device Address =1 =0x01
Function =6 =0x06 =Preset Single Register
Point Address =40002
Required value =1 =0x01


Finis.
-----------------------------------------------------


Voce pode mandar o escravo responder sem calcular o CRC desde que o mestre mande tambem esse comando e entao testa só os tempos e a transmissao.

Beto.

MensagemEnviado: 05 Mai 2010 07:57
por verd
Olá Beto! cara descobri o que estava cagando o meu crc! eu pensava que o crc era calculado em cima do pacote inteiro, descobri que tem que calcular o crc de cada bit do pacote que estou enviando!