CRC hesaplama ve RX bufferına gelenle karşılaştırma

Başlatan Faruk53, 02 Şubat 2017, 20:51:12

Faruk53

Arkadaşlar merhaba. aklımın almadığı ve bir gün boyunca uğraştığım ama bir türlü çözüme varamadığım ve bana gerçekten mantıksız gelen bir sorunla karşı karşıyayım.
Öncelikle yapmak istediğim seri haberleşmede gelen bilginin ilk 12 hanesini alıp crc hesaplamak. Burası tamam problem yok. Daha sonra bana gelen bilgininde kendi üretmiş olduğu CRC'si var. Bunu da alıp bi değişkene atamam gerekiyor bu da tamam. Daha sonra bunları karşılaştırıp eşitlik durumlarına göre Uarttan belli başlı veriler göndermem gerekiyor. Programı aşağıda paylaşıp Dockligt görüntülerinide paylaşacağım.

main.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include "UART.h"
#include "config.h"

#define uart_cavap 100
char uart_karakterler;
char buffer[uart_cavap];
int16_t index_uart;
int16_t dongu;
bit string_alindi;
//unsigned int length; // crc hesaplamak içiin gelen bilginin uzunluğunu hesapladık.
unsigned int i;     //crc hesaplamak için uzunluk kadar i değişkeni saydırdık.
unsigned long int crc,crc_asil;
char gonderilecek_string[15]="";
int16_t crconyukleme;
int16_t hesaplanan_crc; // gonderilecek olan crc degeri.
int16_t gelen_crc; // gelen bilgideki crc değerinin saklandığı değişken.
char kelime_karsilatir[4]="";
int16_t gelen_crc1;
int16_t hesaplanan_crc1;

unsigned int sayac_degeri= 1234; 

//*****************************Haberleşme Kesmesi*****************************//
void interrupt high_priority UART1(void)
{
    if(PIE1bits.RC1IE && PIR1bits.RC1IF) //uart1 RX ucuna bilgi geldi mi?
    {
    uart_karakterler=usart1_oku(); // UART'dan gelen karakterleri okuyor.
    if(index_uart<uart_cavap)
    {
     buffer[index_uart]=uart_karakterler;
     index_uart++;
     }
    if(uart_karakterler==13)
    {
     index_uart=0;
     string_alindi=1;    
    }
    }
}
//****************************************************************************//

//****************************İşlemciyi Hazırla*******************************//
void mcu_init()
{
    ANSELC = 0x00;
    ANSELD = 0x00;
    ANSELB = 0x00;
    ANSELA = 0x00;         // A portundaki bütün adcler iptal edildi.
    ANSELE = 0x00;

    OSCCONbits.IRCF = 0b110; // OSSCON registerının IRCF bayrağı kullanılarak 8Mhz RC osilatör seçildi.
   
    while(!OSCCONbits.HFIOFS); //Frekans kararlı olana kadar bekle
     
}
//****************************************************************************//

//************************checksum hesaplanması okeylendi*********************//
void crc_hesapla()
{     
     for(i=0;i<12;i++)
      {
          crc=crc+buffer[i];       
          crc=crc%256;
          sprintf(hesaplanan_crc,"%d",crc);  
                   
      }            
     crc=0;
       
}
//****************************************************************************//
static void temizlik(void)
{
while(dongu<=uart_cavap)
{
buffer[dongu]=0;
dongu++;
}
}

void main()
{
    mcu_init();
    usart1_init();
    
    while(1)
    {          
    if (string_alindi==1)
    {   
     crc_hesapla();     
     UART1_SendString(hesaplanan_crc); 
     sprintf(gelen_crc,"%d",buffer[12]);     
     UART1_SendString(gelen_crc); 
     
   if(gelen_crc==hesaplanan_crc)
     {
         UART1_SendString("OKC"); 
     }
   else
   {
         UART1_SendString("OKE"); 
   }
     string_alindi=0;temizlik();
     }                     
    }
    }


Uart kütüphanleride aşağıdaki gibi.
Uart.h
#ifndef UART_H
#define	UART_H

#ifdef	__cplusplus
extern "C" {
#endif

void usart1_init(void); // UART1' i hazırla.
void UART1_SendData(char data); // Uart1 den tek bayt veri yolla.
void UART1_SendString(char* s); // uart1 den string yolla.
void usart2_init(void); // UART2' yi hazırla.
extern  void UART2_SendData(char data); // Uart2'den veri yollanıyor 1 byte
extern  void UART2_SendString (char* c); // Uart2 ' den string yollanıyor.
char usart1_oku(void); // uart1 RX bacaklarına gelen veriyi oku
char usart2_oku(void); // uart2 RX bacaklarınaa gelen veriyi oku


#ifdef	__cplusplus
}
#endif

#endif	/* UART_H */


Uart.c
#include <xc.h>
#include <stdio.h>
#include <stdlib.h>
#include "UART.h"

#define TX1 TRISCbits.TRISC6
#define RX1 TRISCbits.TRISC7

//*********************************Uart1 init*********************************//

void usart1_init(void) //1. USART HAZIRLANIYOR.

{
    BAUDCON1bits.BRG16 = 0;
    SPBRG1 = 12;
   
//***********************************//

    TX1STAbits.TXEN = 1; // Veri gönderimi etkinleştiriliyor.
    RC1STAbits.CREN = 1; // Haberleşme modu belirleniyor.
    RC1STAbits.SPEN = 1; // Seri port aktif etme biti etkinleştiriliyor.

    PIR1bits.TX1IF = 0;  // Veri gönderim yetkilentirme bayrağı. BBaşlangıçta boşaltılıyor.
    PIR1bits.RC1IF = 0;  // Veri alma yetkinlendirme bayrağı. Başlangıçta boşaltılıyor.
    PIE1bits.RC1IE = 1;  // RX kesmesinde izin verme biti.

    INTCONbits.PEIE = 1; // Bütün kesmelere izin verme biti.
    INTCONbits.GIE = 1;  //  İzin verilen bütün kesmeler aktif ediliyor.

    RX1 = 1; //RX giriş
    TX1 = 0; //TX çıkış
}

void UART1_SendData(char data) // uart1 den veri gönderiliyor.
{
// 1 byte gönder
while(!TXSTA1bits.TRMT); // Transfer tamponu boşalana kadar bekle
 TX1REG = data; // Tek byte gönderiliyor
}


void UART1_SendString(char* data) // uart1 string gönder
{
    while(*data)
    {
        UART1_SendData(*data);
        data++;
    }
}

char usart1_oku(void)
{
	while(!PIR1bits.RC1IF);	//veri gelene kadar bekle
	if(RCSTA1bits.OERR)	//hata varmı
	{
		RCSTA1bits.CREN=0; // ALIMI DURDUR
		RCSTA1bits.CREN=1; // Veri alımına devam et.
	}
	if(RCSTA1bits.FERR) // hata bayrağı.

		asm("MOVF _RCREG1,W"); // W registırındakileri RCREG1'e yükle
         
	return RCREG1; //RCREG1 registerının içeriğiyle dönüş yap.
}
//****************************************************************************//


//*******************************Uart2 İçin***********************************//

/*void usart2_init(void) //2. UART HAZIRLANIYOR.

{

    BAUDCON2bits.BRG16 = 0;
    SPBRG2 = 103;

    TX2STAbits.TXEN = 1;
    RC2STAbits.CREN = 1;
    RC2STAbits.SPEN = 1;

    PIR3bits.TX2IF = 0;
    PIR3bits.RC2IF = 0;
    PIE3bits.RC2IE = 1;

    INTCONbits.PEIE = 1;
    INTCONbits.GIE = 1;

    RX2 = 1; //RX giriş
    TX2 = 0; //TX çıkış
}

void UART2_SendData(char data) // uart2 den veri gönderiliyor.
{
   while (!TXSTA2bits.TRMT);
    TX2REG = data;
}

void UART2_SendString (unsigned char* veri) // uart1 string gönder
{
    while (*veri!=0)
    {
        UART2_SendData(*veri++);      
    }
}*/

/*char usart2_oku(void)
{
	while(!PIR3bits.RC2IF);	//veri gelene kadar bekle
	if(RCSTA2bits.OERR)	//hata varmı?
	{
		RCSTA2bits.CREN=0; // ALIMI DURDUR
		RCSTA2bits.CREN=1; // Veri alımına devam et.
	}
	if(RCSTA2bits.FERR) // hata bayrağı.

		asm("MOVF _RCREG2,W"); // W registırındakileri RCREG2'e yükle

	return RCREG2; //RCREG2 registerının içeriğiyle dönüş yap.
}*/
//****************************************************************************//


Docklight görüntüsüi:



Görüntüde siyahla çizilen bana gönderilen verinin CRC'si kırmızı olan benim hesapladığım CRC. seri porttan özellikle sayıların farklı olduğunu göstermek amacıyla gönderdim. Evet farklı ama else kısmına girmiyor. İnanın aklıma ne geldiyse yaptım.  Yok çok saçma çok garip.Tanımladığım değişkenlerin durumlarıyla oynadım. Karakter haline çevirip string olarak karşılaştırdım. bufferlar birbirini etkiliyo diye hesaplanan ile gelenin yapısını değiştirdim. yok olmadı. Muhakkak bi yeri sürekli olarak kaçırıyorum ama ney. Şimdiden Teşekkür ederim İyi çalışmalar herkese.

hwdesigner

Hocam merhabalar. Yazılım kodlarına bakamadım. Ancak şu siteyi faydalı buluyorum belki sorunun çözümünde rol oynar. Bir exel dosyasından Crc de hesaplamakta.
Umarım faydalı olur. Kolay gelsin.
http://www.simplymodbus.ca

Klein

Kodda bahsettiğiniz sorunun dışında başka sorunlar var.
Hesapladığınız long  crc değerini  sprintf ile  string hale dönüştürüp 16 bit değişkene atıyortsunuz. Ayrıc bunu döngü içerisinde 12 kez yapıyorsunuz.
Bunu neden yaptığınız başlı başına bir merak konusu iken , derleyicinin bu operasyona hata vermemiş olması da başka bir merak konusu.
Uart_SendString(...)  fonksiyonu  char tipinde işaretçi parametre alırken , 16 bit gerçek değeri geçmeye çalıştığında neden hata vermiyor?
kodda başından sonuna gariplikler var. Neyi neden yapmış olduğunuzu tam anlamadım açıkçası.
Öncelikle:
1- crc hesaplanan crc değişkeniniz long. Onu char tipi yaparsanız mod(255) almakla uğraşmazsınız.
2- hesapladığınız kontrol toplamı olduğu gibi kalsın. sprintf ile bir dönüşüm yapmayın.
3- Eğer gönderdiğiniz ve aldığınız veri binary ise gelen crc değerini de olduğu gibi alın. ASCII ise 3karakter olmalı. Bu 3 karakteri sayıya çevirin.
4- karşılaştırmayı sayılar üzerinden yapın. karakter dizisi üzerinde '==' karşılaştırma yapamazsınız.

Faruk53

@Klein Hocam bahsettiğiniz hataları farkettim ve kodu yeniden düzenledim.
Sorduğunuz sorulara cevap vermem gerekirse crc hesaplarken döngü içerisinde 12 kez dönüşüm yapmamım sebebi gelen her değerin benim için önemi var veriler sürekli değişkenler ve gelen paketin ilk 11 datası benim için önemli. ve hep ascii ile çalışmak zorundayım kodun bilgisayar tarafı yazıldı. yaklaşık 20 adet parametre kontrol etmek zorundayım.
Gelen veriler bir paket halinde geliyor ve her verinin değeri, anlamı farklı. ilk 3 tanesi hangi operasyonu yapıcağını belirliyor. sonraki 3'ü kimlik bilgileri vs. karşılaştırmaların hepsinide string fonksiyonlarıyla yaptım. Aynı şekilde aldığım sorgulara göre cevap verirkende gönderilecek paketin sadece belli bir kısmını pakete koyup CRC'yi ona göre hesaplamam gerekiyor.

Kod aşağıdaki gibi denendi şuana kadar yazılanlar sorunsuz çalışıyor. Yorumlarınızı bekliyorum hocam.Düzelt dediğiniz veya hata olarak gördüğünüz herhangi  bir yer olursa kesinlikle üstüne düşüceğimi bilmenizi isterm. Yorumunuz için teşekkür ederim hocam.


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include "UART.h"
#include "config.h"

#define uart_cavap 100
char uart_karakterler;
char buffer[uart_cavap];
int16_t index_uart;
int16_t dongu;
bit string_alindi;
unsigned int i;     //crc hesaplamak için uzunluk kadar i değişkeni saydırdık.
char gonderilecek_string[20]="";


char sayac_degeri_okuma[]="T01A"; //
char hedef_degeri_okuma[]="T01B"; // 
char para_degeri_okuma[]= "T01C"; // 
char parb_degeri_okuma[]= "T01D"; //
char parc_degeri_okuma[]= "T01E"; // 
char pard_degeri_okuma[]= "T01F"; // 
char pare_degeri_okuma[]= "T01G"; //

char sayac_degeri_yaz[]= "T01I"; // 
char hedef_degeri_yaz[]= "T01J"; //
char  para_degeri_yaz[]= "T01K"; // 
char  parb_degeri_yaz[]= "T01L"; // 
char  parc_degeri_yaz[]= "T01M"; //
char  pard_degeri_yaz[]= "T01N"; // 
char  pare_degeri_yaz[]= "T01O"; // 

char crc; // geçiçi olarak hafızada tutulan crc değeri.
char gelen_veri_crc[]={" "}; //  süslü parantez olmadığında sonuç düzgün işlenmiyor.
char gelen_crc[]={" "}; // süslü parantez olmadığında sonuç düzgün işlenmiyor.
char islem_kodu[]={" "}; // bufferdan gelen işlemin saklandığı yer.  


char cihaz_kimlik[4]="";//bufferdan gelen cihazın kimliği.

char gonderilecek_crc; // geçiçi olarak hafızada tutulan crc değeri.
char gonderilecek_veri_crc[]={" "}; // Tam anlamıya string ifadeye dönüştürüldü. süslü parantez olmadığında sonuç düzgün işlenmiyor.

uint8_t sayac_degeri= 123; 

//*****************************Haberleşme Kesmesi*****************************//
void interrupt high_priority UART1(void)
{
    if(PIE1bits.RC1IE && PIR1bits.RC1IF) //uart1 RX ucuna bilgi geldi mi?
    {
    uart_karakterler=usart1_oku(); // UART'dan gelen karakterleri okuyor.
    if(index_uart<uart_cavap)
    {
     buffer[index_uart]=uart_karakterler;
     index_uart++;
     }
    if(uart_karakterler==13)
    {
     index_uart=0;
     string_alindi=1;    
    }
    }
}
//****************************************************************************//

//****************************İşlemciyi Hazırla*******************************//
void mcu_init()
{
    ANSELC = 0x00;
    ANSELD = 0x00;
    ANSELB = 0x00;
    ANSELA = 0x00;         // A portundaki bütün adcler iptal edildi.
    ANSELE = 0x00;

    OSCCONbits.IRCF = 0b110; // OSSCON registerının IRCF bayrağı kullanılarak 8Mhz RC osilatör seçildi.
   
    while(!OSCCONbits.HFIOFS); //Frekans kararlı olana kadar bekle
    
}
//****************************************************************************//

//************************checksum hesaplanması okeylendi*********************//
void gelen_veri_crc_hesapla()
{                  
       for(i=0;i<12;i++)
      {       
          crc=crc+buffer[i];       
          crc=crc%256; 
          sprintf(gelen_veri_crc,"%c",crc);          
      }            
     crc=0;   
}
//****************************************************************************//

//**********************Gonderilecek Veriye Eklenecek CRC*********************//
void gonderilene_eklenecek_crc()
{
    for(i=3;i<13;i++)
      {       
          gonderilecek_crc=gonderilecek_crc+buffer[i];       
          gonderilecek_crc=gonderilecek_crc%256; 
          sprintf(gonderilecek_veri_crc,"%c",crc);   
          
      }            
     gonderilecek_crc=0;  
}
//****************************************************************************//

//**************************RX temizlenmesi***********************************//
static void temizlik(void)
{
while(dongu<=uart_cavap)
{
buffer[dongu]=0;
dongu++;
}
}
//****************************************************************************//

//**********************Gelen-Giden Veriler Ayıklanıyor***********************//
void verileri_ayikla()
{
    sprintf(cihaz_kimlik,"%c%c%c%c",buffer[4],buffer[5],buffer[6],buffer[7]);
    sprintf(gelen_crc,"%c",buffer[12]); // bufferdan gönderilenin CRC'si ayıklanıyor.
    sprintf(islem_kodu,"%c%c%c%c",buffer[0],buffer[1],buffer[2],buffer[3]);//gelen bilgi hangi operasyonu yapıyor o belirleniyor. 
    gelen_veri_crc_hesapla();//bufferdan gelen bilginin CRC hesabı yapılan algoritmaya dallanıyor.
   
}
//****************************************************************************//
void main()
{
    mcu_init();
    usart1_init();
    
    while(1)
    {          
       
    if (string_alindi==1)
    {   
         verileri_ayikla();
                  
        if (strstr(islem_kodu,sayac_degeri_okuma)!=NULL)//eğer gelen bilgi sorgusu Sayaç değerini okumaysa 1 döndürür ve ifin içine girer.             
        {                          
            sprintf(cihaz_kimlik,"%c%c%c%c%d",buffer[4],buffer[5],buffer[6],buffer[7],sayac_degeri);//bufferdan gelen cihaz kimliği değişkene sayaç değeriyle birlikte ekleniyor.
                                              
          if (strstr(gelen_veri_crc,gelen_crc)!=NULL)// eğer hesaplanan CRC ile gelen CRC aynıysa 1 döndürür ve ifin içine girer.
            {               
              sprintf(gonderilecek_string,"OKC01A");            
              strcat(gonderilecek_string,cihaz_kimlik); // cihazın kimliği OKC01A'nın sonuna kopyalandı.                                             
              UART1_SendString(gonderilecek_string);
            }
          else
            {
              sprintf(gonderilecek_string,"OKE01A%c%c%c%cXXXX",buffer[4],buffer[5],buffer[6],buffer[7]);
              UART1_SendString(gonderilecek_string);
            }            
        }
          if (strstr(islem_kodu,hedef_degeri_okuma)!=NULL) 
          {
              UART1_SendString("deneme");
          }
       string_alindi=0;temizlik();     
    } 
    }
}

Klein

Merak konusu neden 12 kez yaptığın değildi. neden sprintf dönüşümünü 12 kez yaptığındı. ama önemi yok orada hata var zaten.

//************************checksum hesapla *********************//
unsigned char Checksum(char * Buf, char Len)
{
unsigned char cs = 0;
       while(Len--)
       {           
          cs += *Buf++;
       }     
       return(cs);
}
//**********************   Gelen verinin kontrol toplamı hesaplanıyor******************************************************//

Hesaplanan_cs = Checksum(Buffer, 12);

/********************************************************/

Devamı hakkında konuşmak için şunu bilmem gerek.  Kontrol toplamı verinin sonunda tek karakter mi 3 karakter mi?
Yani kontrol toplamın 100 ise  verinin sonuna  ascii olarak '1' , '0' , '0' şeklinde 3 karakterlik dizi mi ekliyorsun? Yoksa doğrudan 100 değeri mi?

Verinin tam formatını gönderirsen daha iyi olur.







Faruk53

Hocam Allah razı olsun valla orası tamamen gözümden kaçmış. Uykusuzluktan heralde  :D pazartesi okulum açılıyo ve en azından o güne kadar bu kısmı bitirmek istiyorum.  Verilerde tam olarak bu şekilde geliyor ve bu şekilde göndermem gerekiyor hocam. daha gönderdiğim verinin sonuna CRC eklemedim hocam. Ama gelen veriyle aynı formatta gidicek.




Klein

OKC01A00011 234
Buradaki 234 mü? kontrol toplamı?

Sonuna checksum eklemedim demişsiniz. şimdi farkettim. ama benim görmek istediğim asıl o.
diyelim ki kontrol toplamınız  119
veri şöyle mi görünecek
OKC01A00011234119

yoksa
OKC01A00011234w  ( 119 sayısının ASCII karşılığı w)



Faruk53

Hocam veriyi size açarak şöyle özetliyim
OKC: Gelen bilginin Cevabı doğru şekilde verildi.
01A: Yapılacak olan operasyonun bilgisi
0001: Veriyi alan cihazın kimlik bilgisi
1234: İstenilen operasyonun cihazdaki o andaki durumu.
OKC hariç hepsi değişken hocam. Gelen bilgide eğer eksik veya cihazı ilgilendirmeyen bir şey olduğunda OKE döndürücek

Faruk53

 OKC01A00011234w şeklinde cevap verilicek hocam.

Klein

Tamam şimdi oldu.
O zaman sprintf(...) ile uğraşmayacaksın.
gelen verinin kontrol toplamını söylediğim gibi hesaplayacaksın.

if(Checksum(Buffer, 12) == RxBuf[12])
...
...


gönderirken de 
TxBuf[x] = Checksum(TxBuf, x);
gönder(TxBuf);


Faruk53

Teşekkür ederim dediğiniz güncellemeleri yapıcam. Hakkınızı helal edin hocam  :)