最近手上有個(gè)威綸通MT6056I的HMI,需要與公司的一款板卡通訊,板卡遵循的是自由協(xié)議,但是采用的校驗方式CRC-16/XMODEM.
這種校驗方式是CRC16校驗方式的一種,但是與MODBUS協(xié)議的CRC16的生成方式不同。威綸通的腳本語(yǔ)言庫中有CRC校驗函數,但是這個(gè)校驗
函數是CRC-16/MODBUS版本的,不能為我所用,所以我計劃自己設計一個(gè)CRC16/XMODEM的函數,然后將這個(gè)函數保存到函數庫里,以備他用
。由于第一次使用這個(gè)屏幕,經(jīng)驗不做,遇到一些困難,但也努力解決了。
首先不得不吐槽下,威綸通的宏指令說(shuō)明書(shū)寫(xiě)的太簡(jiǎn)單了,在遇到問(wèn)題的時(shí)候,可能無(wú)法從指令的說(shuō)明手冊上找到答案,更多的是自己摸索。比如
自己寫(xiě)子函數時(shí)就遇到狗血的問(wèn)題
1:數組不能作為函數參數
比如
sub short function(char dat[],char len)
其中 char dat[] 參數將出錯。
解決方法,后面有表述
2: 在調用子函數的時(shí)候,在函數的參數中不能出現常量,只能是變量的方式
例如我定義了子函數 function( short a,short b)
調用方式 function( 1000,1000) 編譯器將會(huì )告訴你參數類(lèi)型錯誤
當我改成如下掉用方式就可以了
short i=1000
short j=1000
function(i,j)
好進(jìn)入正題吧,如何寫(xiě)個(gè)CRC校驗函數,其實(shí)根本問(wèn)題,是如何將一串數據傳給子函數,子函數將傳過(guò)來(lái)的數據根據特定算法,運算出計算結果,關(guān)于CRC算法,本文不做論述,只提供代碼。
我首先想到的是這樣的思路:定義 這樣一個(gè)函數 short CRC16(short dat[],short len),用來(lái)計算CRC。
但是卻遇到了上面1中的問(wèn)題,數組參數無(wú)法作為函數的形參,官方也找不到解決方法。
最后想到的解決方法是在LW存儲區開(kāi)辟一塊暫存區域,將要進(jìn)行CRC計算的數據搬運到這塊暫存區域上。再CRC校驗函數中根據LW的地址將數據取出,進(jìn)行CRC計算。
如此可解決無(wú)法傳遞數組參數的問(wèn)題。操作如下。
定義 sub short CRC_16(short dataddr, short len)
參數說(shuō)明 short dataddr,dataddr是位于LW暫存區的起始地址,short len len 數據長(cháng)度。
下面紅色區域為重點(diǎn)區域,注意理解。
sub short CRC_16(short dataddr, short len)
short i, j
unsigned short crc_reg = 0x0000
unsigned short current
unsigned char dattmp[128] //申請一定長(cháng)度的數組來(lái)保存要進(jìn)行校驗的數據。
GetData(dattmp[0], "Local HMI", LW, dataddr, len)//將暫存區的數據復制到dattmp中 len=len-1
for i = 0 to len
current = dattmp
current=current<<8
crc_reg=crc_reg^current
for j = 1 to 8
if (crc_reg & 0x8000) <> 0 then
crc_reg = (crc_reg << 1) ^ 0x1021
else
crc_reg=crc_reg << 1
end if
next
next
return crc_reg;
end sub
上面綠色部分是進(jìn)行CRC計算的,這里不做研究。下面來(lái)講講紅色部分。紅色部分就是申請數組空間,然后,將LW,暫存空間的數據,轉移到所申請的數組中,交給下面計算。
這里的疑惑是為何要申請數組,然后在拷貝數據,這么麻煩,而不是用下面的方式進(jìn)行,下面的算法是每次循環(huán)開(kāi)始先讀取暫存空間數據,先不說(shuō)犧牲時(shí)間什么的,最起碼這
中不用申請上面那128大的數組。理論可行,但是實(shí)際上確實(shí)錯誤的。其主要GetData和SetData 函數實(shí)現原理,以及數據在LW中存儲方式不清楚造成的。
sub short CRC_16_2(short dataddr, short len)
short i, j
unsigned short crc_reg = 0x0000
unsigned short current
unsigned char dattmp
short addr
addr=dataddr
len=len-1
for i = 0 to len
GetData(dattmp, "Local HMI", LW, addr, 1) addr=addr+1
current = dattmp
current=current<<8
crc_reg=crc_reg^current
for j = 1 to 8
if (crc_reg & 0x8000) <> 0 then
crc_reg = (crc_reg << 1) ^ 0x1021
else
crc_reg=crc_reg << 1
end if
next
next
return crc_reg;
end sub
GetData和SetData 函數實(shí)現原理,以及數據在LW中存儲方式
先來(lái)說(shuō)說(shuō)LW中的數據存儲 (吐槽:為何網(wǎng)上關(guān)于這方面的資料很少,幾乎沒(méi)有LW存儲空間的詳細說(shuō)明)
目前 筆者使用 軟件 EB8000 V4.65
LW 可理解為計算機的RAM ,掉電數據不保存,但是存取速度快。每個(gè)存儲單元是16bit。分為高字節 (bit15-bit8)和低字節(bit7 -bit 0)
bit15 bit0
例如 0x1234 存儲方式為高字節 0x12 ,低字節0x34.
SetData 當用SetData 來(lái)寫(xiě)LW中的數據的時(shí)候,會(huì )根據第一個(gè)參數的類(lèi)型來(lái)指導操作
如下程序,這是正常的操作程序。a的類(lèi)型是short
unsigned short a=0x1234
unsigned char b[2]
unsigned char c
SetData(a, "Local HMI", LW, 0, 1)
GetData(c, "Local HMI", LW, 0, 1)
GetData(b[0], "Local HMI", LW, 0, 2)
TRACE("C = %d", c) //c=0x34
TRACE("b[0] = %d", b[0]) //b[0]=0x34
TRACE("b[1] = %d", b[1]) //b[1]=0x12
但是SetData的第一個(gè)參數是第一個(gè)char類(lèi)型的數組如下
unsigned short a
unsigned char b[2]
b[1]=0x12
b[0]=0x34
SetData(b[0], "Local HMI", LW, 0, 2)
GetData(a, "Local HMI", LW, 0, 1)
TRACE("a = %d", a) //a=0x1234
可以看出,在保存char 型數據的時(shí)候,為了節省空間進(jìn)行了特別處理
理論上b[0]應該保存在LW0000,b[1]保存在LW0001.但是實(shí)際上確實(shí)b[0]保存在 LW0000的低字節,b[1]保存在LW0000的高字節。
同樣的道理GetData 也遵循相同的操作。
現在能回答為何不能采用第二種子函數寫(xiě)法.主要原因是 每次循環(huán)都是讀取一個(gè)字的底字節。高字節數據被丟棄了。
假如寫(xiě)入內存的是b[0]到b[10],則通過(guò)下面循環(huán)讀取的是b[0],b[2],b[4].....,請好好體會(huì )。
for i = 0 to len
GetData(dattmp, "Local HMI", LW, addr, 1)
addr=addr+1
current = dattmp
next
再需要調用CRC函數的時(shí)候,可用如下的方法操作
char sendbus[26]
short lwadd=7000 //lw 暫存區開(kāi)始地址
short len=26
SetData(sendbuf[1], "Local HMI", LW, lwadd, len) //將得計算的數阻搬到LW7000開(kāi)始的空間,具體在什么地址,可自己安排,只要注意LW 范 //0-9000
tmp = CRC_16(lwadd, len) //CRC計算
版權申明:本文章由逸創(chuàng )論壇(
www.yeecon.com)原創(chuàng ),轉載請標明出處:
http://www.yeecon.com/forum.php?mod=viewthread&tid=74&fromuid=1(出處: 逸控BBS)
由于本人知識有限,文中如有錯誤,請告知。
作者:semonpic
E-Mail:
semonping@163.com企鵝號 442999791
[ 此帖被peteryi在2014-10-28 20:45重新編輯 ]