Bir önceki yazıda modbus rtu slave örneğini paylaşmıştık. Aslında bu örnek de ondan çok bir farkı bulunmamakta. Donanımsal altyapı olarak tamamen aynıdır. RS485 entegresinin çıkışındaki A ve B pini hat üzerindeki her slave cihazın A ve B pinlerine bağlıdır. Yani haberleşme iki tel üzerinden bütün cihazlara bağlıdır. RS232 gibi TX Rx'e, RX TX'e bağlı değildir. Yani Master'daki A pini Slave'deki A pinine, B pini de B pinine bağlıdır ve tek bir tel bütün cihazlara bağlıdır. 

Yukarıdaki resim RS485 altyapısı kullanıldığında geçerlidir. Eğer RS232 kullanılıyorsa Tx Rx'e, Rx Tx'e bağlanmalıdır.
Önceki yazımızda Slave örneği için bize sorgu gelmesini bekliyorduk. Şimdi ise Master olduğumuzdan mütevellit sorguyu bizim çekmemiz gerekiyor.
O halde kodu yazmaya başlayabiliriz.
KOD KISMI:
Başlnagıç olarak kütüphaneler eklenir.
#include "stm32f4xx.h"
#include "stm32f4xx_gpio.h" // GPIO kütüphanesi
#include "stm32f4xx_rcc.h" // RCC clock kütüphanesi
#include "stm32f4xx_usart.h" // Keil::Device:StdPeriph Drivers:USART
#include "stm32f4xx_it.h"
#include "stm32f4xx_tim.h"
Başlnagıç olarak kütüphaneler eklenir.
#include "stm32f4xx.h"
#include "stm32f4xx_gpio.h" // GPIO kütüphanesi
#include "stm32f4xx_rcc.h" // RCC clock kütüphanesi
#include "stm32f4xx_usart.h" // Keil::Device:StdPeriph Drivers:USART
#include "stm32f4xx_it.h"
#include "stm32f4xx_tim.h"
/********************************************************************************/
// Altta kullanılacak olan fonksiyonlar burada tanıtılır //
void GPIO_Init(void);
void USART_Init(void);
void TIM6_Init(void);
void USART1_IRQHandler(void);
void TIM6_DAC_IRQHandler(void);
void ReadHoldingRegister();
char CRC_check(char package[],unsigned int package_length);
void Get_CRC(unsigned char package[],unsigned int package_length);
/********************************************************************************/
/********************************************************************************/
/* Gerekli değişken tanımlamaları */
unsigned short Readed_Array[100];
unsigned char Modbus_Receive_Array[100];
unsigned char Modbus_Trans_Array[100];
unsigned short modbus_receive_counter = 0;
unsigned int modbus_data_counter = 0;
unsigned char modbus_slave_addr = 1; //Slave adresimiz 1 olsun
unsigned short Holding_Register_Adress_Value = 255;
unsigned char frame_length;
unsigned short Tx_count= 0;
unsigned short i=0;
unsigned short data_count = 0;
/********************************************************************************/
/* Gerekli değişken tanımlamaları */
unsigned short Readed_Array[100];
unsigned char Modbus_Receive_Array[100];
unsigned char Modbus_Trans_Array[100];
unsigned short modbus_receive_counter = 0;
unsigned int modbus_data_counter = 0;
unsigned char modbus_slave_addr = 1; //Slave adresimiz 1 olsun
unsigned short Holding_Register_Adress_Value = 255;
unsigned char frame_length;
unsigned short Tx_count= 0;
unsigned short i=0;
unsigned short data_count = 0;
/********************************************************************************/
/* Led için konfigürasyon ayarlamaları */
// ledler aslında kullanılmamıştır ancak haberleşmeyi kontrol amaçlı kullanılabilir //
void GPIO_Init(void)
{
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure; // Port yönlendirmesi
/* PD12, 13, 14 ve PD15 pinleri kullan1lacak */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; //Pinler cikis olarak belirlendi
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_Init(GPIOD, &GPIO_InitStructure);
/* PA0 pini buton için kullanılacak */
}
{
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure; // Port yönlendirmesi
/* PD12, 13, 14 ve PD15 pinleri kullan1lacak */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; //Pinler cikis olarak belirlendi
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_Init(GPIOD, &GPIO_InitStructure);
/* PA0 pini buton için kullanılacak */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN; //Pin giriş olarak belirlendi
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
/* USART1 ayarlamaları */
/* usart kesmesi de ayarlandı. sorgu yapıldıktan sonra gelen data direkt olarak kesme fonksiyonu ile alınacaktır */
void USART_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
// GPIO ALTERNATE FUNCTION olarak tanimlanan pinin konfigürasyonlari
// pin ile baglant1 kuracagi modül belirlenir.
GPIO_PinAFConfig(GPIOB, GPIO_PinSource6, GPIO_AF_USART1);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource7, GPIO_AF_USART1);
// USART1 Reset
USART_DeInit(USART1);
// USART konfigürasyonlari:
USART_InitStructure.USART_BaudRate = 9600;
USART_InitStructure.USART_HardwareFlowControl= USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_Init(USART1, &USART_InitStructure);
USART_ITConfig(USART1, USART_IT_RXNE,ENABLE);
// NVIC Init
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
USART_Cmd(USART1, ENABLE);
}
/* usart kesmesi de ayarlandı. sorgu yapıldıktan sonra gelen data direkt olarak kesme fonksiyonu ile alınacaktır */
void USART_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
// GPIO ALTERNATE FUNCTION olarak tanimlanan pinin konfigürasyonlari
// pin ile baglant1 kuracagi modül belirlenir.
GPIO_PinAFConfig(GPIOB, GPIO_PinSource6, GPIO_AF_USART1);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource7, GPIO_AF_USART1);
// USART1 Reset
USART_DeInit(USART1);
// USART konfigürasyonlari:
USART_InitStructure.USART_BaudRate = 9600;
USART_InitStructure.USART_HardwareFlowControl= USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_Init(USART1, &USART_InitStructure);
USART_ITConfig(USART1, USART_IT_RXNE,ENABLE);
// NVIC Init
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
USART_Cmd(USART1, ENABLE);
}
void TIM6_Init(void)
{
/*
1sn timeout zamanı için:
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE);
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; // Struct
NVIC_InitTypeDef NVIC_InitStructure;
TIM_DeInit(TIM6);
TIM_TimeBaseStructure.TIM_Period = 2000 -1;
TIM_TimeBaseStructure.TIM_Prescaler = 42000 -1; /
TIM_TimeBaseStructure.TIM_ClockDivision =0; // TIM_CKD_DIV1
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM6, &TIM_TimeBaseStructure);
TIM_ClearITPendingBit(TIM6,TIM_IT_Update); // Clear Update interrupt flag
TIM_ITConfig(TIM6, TIM_IT_Update, ENABLE); // Interrupt
NVIC_InitStructure.NVIC_IRQChannel = TIM6_DAC_IRQn; // NVIC Ayarlari
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
TIM6->CR1 &=~ 0x0001; // Counter Disable
// TIM6'yı daha aktif etmedik dikkat edin. !!
}
{
/*
1sn timeout zamanı için:
TIM6 APB1’e bağlı gözüküyor. APB1’in çalışma hızı 42 MHz. Ancak Datasheet’e bakıldığında önemli bir uyarı ile karşılaşıyoruz:
APB2’ye bağlı olan zamanlayıcılar için clock hattı 168Mhz’e kadar olabilir, APB1 içinse 84Mhz olabilir. Burada bir ikilem var gibi duruyor ancak datasheet’te bunu şöyle açıklıyor: APB ön bölücü değeri 1 ise timer clock hattı da aynı frekansta çalışır, ancak ön bölücü değeri 1 değilse veya 1’den farklı bir değerde ise timer clock hattı APB hattının 2 katı hızda çalışır.
Timer6’ye baktığımızda APB1 bus hattına bağlıdır. Bu hattın clock frekansı 42 Mhz. Daha önce CMSIS klasöründe oluşturduğumuz system_stm32f4xx.c dosyasında ön bölücü değeri 4 olarak kullanıldığı için bu hat 42*2 yani 84 Mhz clock frekansında çalışmaktadır. Daha detaylı bilgiye datasheet’ten bakılabilir.
Prescaler değeri ise: Timer hızı = Bus hızı / (prescaler + 1) formülünden bulunur.
Sorgu yapıldıktan sonra cevap beklenir burada timer ile bekleme süresini ayarlayabiliriz
Örneğin bekleme süremiz yani haberleşme timeout süremiz 1 saniye olsun:
1sn = 1/1 = 1Hz frekansa eşittir.
Öncelikle 2Khz (2000Hz) için: 2000 = 84Mhz(buz hızı) /(prescaler+1)
2000 = 84000000 / (PRSC + 1) = > PRSC = 41999
Periyodu da biz 2000’e kadar saydırırsak: 2000 Hz/ 2000 = 1Hz
1Hz = 1/1 = 1 sn demektir.
Prescaler değeri: 42000 - 1
Periyod: 2000 -1 = 1999 (sayıma 0’dan başladığı için 1 eksiği olur)
1 sn için değerlerimizi yukarıdaki gibi hesaplarız.
*/RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE);
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; // Struct
NVIC_InitTypeDef NVIC_InitStructure;
TIM_DeInit(TIM6);
TIM_TimeBaseStructure.TIM_Period = 2000 -1;
TIM_TimeBaseStructure.TIM_Prescaler = 42000 -1; /
TIM_TimeBaseStructure.TIM_ClockDivision =0; // TIM_CKD_DIV1
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM6, &TIM_TimeBaseStructure);
TIM_ClearITPendingBit(TIM6,TIM_IT_Update); // Clear Update interrupt flag
TIM_ITConfig(TIM6, TIM_IT_Update, ENABLE); // Interrupt
NVIC_InitStructure.NVIC_IRQChannel = TIM6_DAC_IRQn; // NVIC Ayarlari
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
TIM6->CR1 &=~ 0x0001; // Counter Disable
// TIM6'yı daha aktif etmedik dikkat edin. !!
}
/********************************************************************************/
int main(void)
{
unsigned short adres_baslangic = 0; //ahngi adresten veri istenilecek
GPIO_Init();
USART_Init();
/* modbus sorgusunu çektikten sonra gelen paketi değerlendirmek için 1sn timeout zamanı olsun dedik. bu süreyi siz istediğiniz gibi değiştirebilirsiniz.
Bu zamanı timer6 birimi ile yapmak istiyoruz. o yüzden timer6 yı yaklaşık olarak 1sn timeout süresine ayarlamamız gerekli.
yukarıdaki hesabımıza göre bize yaklaşık olarak 9600 baudrate hızında,
1sn için hesaplamaları alttaki fonksiyon içerisinde yapalım
*/
TIM6_Init();
/* Bütün ayarlamaları yaptık. Artık iş sorguyu çekmek ve gelen veriyi analiz etmede. Cevap için usart kesmesinden gelen veri takip edilecek. verinin bittiği timer ile anlaşılacak.
*/
/* Burada öncelikle sorgu yapacağımız paketi oluşturalım */
Modbus_Trans_Array[0] = 1; // sorgu çekilecek slave adresi, biz 1.slave sorgu yapacağız Modbus_Trans_Array[1] = 03; // fonksiyon kodu, 03 Read Holding Register Modbus_Trans_Array[2] = adres_baslangic>>8; // hangi adresten bilgi isteyeceğiz Modbus_Trans_Array[3] = adres_baslangic; // hangi adresten bilgi isteyeceğiz Modbus_Trans_Array[4] = 2>>8; // yukarıdaki adresten kaç adet bilgi isteyeceğiz, 2 adet dedik Modbus_Trans_Array[5] = 2; // yukarıdaki adresten kaç adet bilgi isteyeceğiz, 2 adet dedik Get_CRC(Modbus_Trans_Array,8); // Gidecek paketin son 2 byte'ına CRC kodunu ekledik
while(1)
{
/* butona her basıldığında sorgu çekilsin.
öncelikle gidecek paketi hazırlayalım{
unsigned short adres_baslangic = 0; //ahngi adresten veri istenilecek
GPIO_Init();
USART_Init();
/* modbus sorgusunu çektikten sonra gelen paketi değerlendirmek için 1sn timeout zamanı olsun dedik. bu süreyi siz istediğiniz gibi değiştirebilirsiniz.
Bu zamanı timer6 birimi ile yapmak istiyoruz. o yüzden timer6 yı yaklaşık olarak 1sn timeout süresine ayarlamamız gerekli.
yukarıdaki hesabımıza göre bize yaklaşık olarak 9600 baudrate hızında,
1sn için hesaplamaları alttaki fonksiyon içerisinde yapalım
*/
TIM6_Init();
/* Bütün ayarlamaları yaptık. Artık iş sorguyu çekmek ve gelen veriyi analiz etmede. Cevap için usart kesmesinden gelen veri takip edilecek. verinin bittiği timer ile anlaşılacak.
*/
/* Burada öncelikle sorgu yapacağımız paketi oluşturalım */
Modbus_Trans_Array[0] = 1; // sorgu çekilecek slave adresi, biz 1.slave sorgu yapacağız Modbus_Trans_Array[1] = 03; // fonksiyon kodu, 03 Read Holding Register Modbus_Trans_Array[2] = adres_baslangic>>8; // hangi adresten bilgi isteyeceğiz Modbus_Trans_Array[3] = adres_baslangic; // hangi adresten bilgi isteyeceğiz Modbus_Trans_Array[4] = 2>>8; // yukarıdaki adresten kaç adet bilgi isteyeceğiz, 2 adet dedik Modbus_Trans_Array[5] = 2; // yukarıdaki adresten kaç adet bilgi isteyeceğiz, 2 adet dedik Get_CRC(Modbus_Trans_Array,8); // Gidecek paketin son 2 byte'ına CRC kodunu ekledik
while(1)
{
/* butona her basıldığında sorgu çekilsin.
*/
// RTU istegi Yapilacak
if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0))
{
while(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)); // tuşa basılıp çekildikten sonra
for(Tx_count=0;Tx_count<8;Tx_count++)
{
while(!(USART_GetFlagStatus(USART1, USART_FLAG_TXE)));
USART_SendData(USART1, Modbus_Trans_Array[Tx_count]);
// Clear & Start Timer
TIM6->CNT = 0; // TIM6 Clear
TIM_Cmd(TIM6, ENABLE); // Enable TIM6
{
while(!(USART_GetFlagStatus(USART1, USART_FLAG_TXE)));
USART_SendData(USART1, Modbus_Trans_Array[Tx_count]);
// Clear & Start Timer
TIM6->CNT = 0; // TIM6 Clear
TIM_Cmd(TIM6, ENABLE); // Enable TIM6
// timeri çalıştırdık ve artık timeout sonunda veriyi inceleyeceğiz
// veriyi gönderdik ve cevabı bekliyoruz
// cevap usart kesmesine gelecek
}
} // veriyi gönderdik ve cevabı bekliyoruz
// cevap usart kesmesine gelecek
}
}
}
/********************************************************************************/
/* USART1 KESME FONKSİYONU */
void USART1_IRQHandler(void)
{
if( USART_GetITStatus(USART1, USART_IT_RXNE) )
{
USART_ClearITPendingBit(USART1, USART_IT_RXNE);//kesme bayrağı temizlenir
/* Burada slave örneğinde olduğu gibi bir timeri veya farklı bir gecikme fonksiyonu uygulayarak gelen paket takibi yapılabilirdi. ancak buraya yazılması uzun olacağı için gerek duyulmadı. Bu şekilde olan haberleşme de gayet sağlıklı bir şekilde çalışmaktadır. Program timer6 kesmesine girdiğinde eğer veri gelmiş ise gelen veri değerlendirilir, eğer veri yoksa timeout'a düşmüştür yani ya slave cihazından veri gelmemiştir ya da slave cihazı bizim belirlediğimiz timeout süresi içerisinde bize cevap göndermemiştir*/
// Gelen veriyi oku ve diziye atamasını yap
Modbus_Receive_Array[modbus_receive_counter ] = USART_ReceiveData(USART1);
// Gelen paketteki veri sayacini arttir
modbus_receive_counter ++;
}
else if( USART_GetITStatus(USART1, USART_IT_TXE) )
{
USART_ClearITPendingBit(USART1, USART_IT_TXE);
}
}
/********************************************************************************/
/* TIMER6 KESME FONKSİYONU */
void TIM6_DAC_IRQHandler(void)
{
/* Yukarıda da anlatıldığı üzere, eğer program bu kesme fonksiyonuna girmiş ise sorgu gönderilmiş ve Slave cihazdan cevap gelmiş demektir ( eğer haberleşmede bir yanlışlık yok ise). Gelen veri paketini usart kesmesinde almıştık. şimdi paketi inceleyelim
*//
TIM_ClearITPendingBit(TIM6,TIM_IT_Update); // Clear Update interrupt flag
// Counter Disable
TIM6->CR1 &=~ 0x0001;
TIM_Cmd(TIM6, DISABLE); // Disable TIM6
//eğer veri gelmiş ise, sorgu yaptığımız slave adresi 1
if (Modbus_Receive_Array[0] == 1)
{
//CRC dogru ise, yani paketimiz güvenli bir şekilde bize ulaştı mı
if(CRC_check((char*)Modbus_Receive_Array,modbus_receive_counter )==1)
{
// Modbus haberleşmesinde 3 numaralı fonksiyon Read Holding Register fonksiyonu
if ( (Modbus_Receive_Array[1] == 3) ) // fonksiyon kodu 3 ise
{
data_count=0;
for(i=0;i<Modbus_Receive_Array[2]/2;i++)
{ Readed_Array[i] = panelcontrol.RxBuf[data_count+3]*256 + panelcontrol.RxBuf[data_count+4]; data_count = data_count+2; }
/* Readed_Array dizimize gelen verileri yükledik.
burada artık gelen veri ile ne yapmak istiyorsak yapabiliriz
Led kontrolu
slave'den alınan sensör bilgileri
istenildi ise parametre değerleri
.... bu liste uzatılabilir artık ne yapılmak isteniliyorsa..
*/
}
}
}
modbus_receive_counter = 0;
}
char CRC_check(char package[],unsigned int package_length)
{
volatile unsigned int crc[2];
volatile unsigned int CRCFull = 0xFFFF;
volatile unsigned int CRCHigh = 0xFF, CRCLow = 0xFF;
volatile unsigned int CRCLSB;
volatile unsigned int i=0;
volatile unsigned int j=0;
char CRC_OK=0;
for (i = 0; i < package_length-2; i++)
{
CRCFull = (unsigned int)(CRCFull ^ package[i]);
for (j = 0; j < 8; j++)
{
CRCLSB = (unsigned int)( CRCFull & 0x0001);
CRCFull = (unsigned int)((CRCFull >> 1) & 0x7FFF);
if (CRCLSB == 1)
CRCFull = (unsigned int)(CRCFull ^ 0xA001);
}
}
crc[1] = CRCHigh = (unsigned int)((CRCFull >> 8) & 0xFF);
crc[0] = CRCLow = (unsigned int)( CRCFull & 0xFF);
if((crc[0] == package[package_length-2]) && (crc[1] == package[package_length-1]))
CRC_OK = 1;
else
CRC_OK = 0;
return CRC_OK;
}
void Get_CRC(unsigned char package[],unsigned int package_length)
{
volatile unsigned int crc[2];
volatile unsigned int CRCFull = 0xFFFF;
volatile unsigned int CRCHigh = 0xFF, CRCLow = 0xFF;
volatile unsigned int CRCLSB;
volatile unsigned int i=0;
volatile unsigned int j=0;
volatile char CRC_OK=0;
for (i = 0; i < package_length-2; i++)
{
CRCFull = (unsigned int)(CRCFull ^ package[i]);
for (j = 0; j < 8; j++)
{
CRCLSB = (unsigned int)(CRCFull & 0x0001);
CRCFull = (unsigned int)((CRCFull >> 1) & 0x7FFF);
if (CRCLSB == 1)
CRCFull = (unsigned int)(CRCFull ^ 0xA001);
}
}
crc[1] = CRCHigh = (unsigned int)((CRCFull >> 8) & 0xFF);
crc[0] = CRCLow = (unsigned int)( CRCFull & 0xFF);
package[package_length-2] = crc[0];
package[package_length-1] = crc[1];
}
/*
Anlamadığınız yerleri sorabilirsiniz.İyi Çalışmalar
*/
master örnegini görünce şok oldum .
YanıtlaSileline bilgine saglık .