BCD編碼

單個遙測顯示命令6位(21)

 D7  09  21  地址 04  XX  XX  XX  XX  CS

     

       D7 D6 D5 D4    D3 D2 D1 D0    D7 D6 D5 D4  D3 D2 D1 D0

       A,B表示符號  小數點位置         0~9表示顯示0~9

   A:+   B:—  C:“L”

地址爲遙測表的地址,每個遙測表最多可顯示6位數據。數據位向高位靠,不足補0。

CS表示異或校驗

例如:

1):D7 09 21 01 04 00 12 34 50 8C    (顯示數據123450.)

2):D7 09 21 01 04 01 12 34 50 8D    (顯示數據12345.0)

3):D7 09 21 01 04 02 12 34 50 8E     (顯示數據1234.50)

4):D7 09 21 01 04 0312 34 50 8F     (顯示數據123.450)

5):D7 09 21 01 04 04 12 34 50 88    (顯示數據12.3450)

6):D7 09 21 01 04 05 12 34 50 89    (顯示數據1.23450)

7):D7 09 21 01 04 06 12 34 50 8A    (顯示數據0.12345)

以下是數據解析:

findDecimal()函數找到小數點在第幾位,比如例子中紅色標記了小數點的位置。找到的位置就是int decimal,要用到BCD編碼函數裏。

int FindDecimal(char *str,int nlen)
{	
	int len = 0, i;	
    for(i = 0; i < nlen; i ++)
	{		
		if(str[i] != '.')
		{
			len ++;
		}
		else
		{
			break;
		}		
	}
    return nlen - len;		
}

 

 以下是BCD編碼

/*-------------------------------------------------------------------------------------------
 	 函數名 : FloattoBCD	
 	函數功能 : BCD編碼
 	返回類型 : void
 	函數參數 : int width : 目標寬度, int decimal: 目標小數位數(從0開始)
 	 創建者 :  	創建日期 : 2012.3.6
 	   修改 : 
-------------------------------------------------------------------------------------------*/
void CMAND2000::FloattoBCD(float value, int width, int &decimal)
{
	memset(m_tempbuf,0,sizeof(m_tempbuf));
	int i = 0;
	int j = 0;
	int k = 0;
	int m = 0;
	int n = 0;
	int p = 0;
	int q = 0;
	int r = 0;
	int s = 0;
	//判斷傳參數是否有誤
	if ((float)value >= pow(10.0, width-decimal))
	{
		memset(m_tempbuf, 0, width);
		return;
	}

	//折半處理
	for (i=0; i<(width-decimal)/2; i++)
	{
		p = (int)(value/pow(10.0, width-decimal-i*2-1));
		q = (int)(value/pow(10.0, width-decimal-i*2-1)+0.5);
		r = (int)(value/pow(10.0, width-decimal-i*2-2)+0.5);
		s = (int)(value/pow(10.0, width-decimal-i*2-2));
		//如果等於最後一個字節時,需要四捨五入處理,否則不處理
		if (i == (width/2-1))
		{
			//當等於最後一個字節,並且有向大於1位目標小數位數進位時
			if (q*10 == r)
			{
				//當向最高位進位時,反之是向次高位進位時,
				if (r == 1000000)
				{
					m_tempbuf[i-2] = 0x10;
					m_tempbuf[i-1] = 0;
					m_tempbuf[i] = 0;
					decimal--;
				}
				else
				{
					m_tempbuf[i-2] = q/10000%10*16 + r/10000%10;
					m_tempbuf[i-1] = q/100%10*16 + r/100%10;
					m_tempbuf[i] = q%10*16 + r%10;
				}				
			}
			else
			{
				m_tempbuf[i] = p%10*16 + r%10;
			}
		}
		else
		{
			
			m_tempbuf[i] = p%10*16 + s%10;
		}		
	}
	
	for (i=(width-decimal)/2; i<width/2; i++)
	{		
		j = (int)(value*pow(10, i*2+decimal-width+1));
		k = (int)(value*pow(10, i*2+decimal-width+1)+0.5);
		m = (int)(value*pow(10, i*2+decimal-width+2)+0.5);
		n = (int)(value*pow(10, i*2+decimal-width+2));
		//如果等於最後一個字節時,需要四捨五入處理,否則不處理
		if (i == (width/2-1))
		{
			//當等於最後一個字節,並且有向大於1位目標小數位數進位時
			if (k*10 == m)
			{
				//當向最高位進位時,反之是向次高位進位時,
				if (m == 1000000)
				{
					m_tempbuf[i-2] = 0x10;
					m_tempbuf[i-1] = 0;
					m_tempbuf[i] = 0;
					decimal--;
				}
				else
				{
					m_tempbuf[i-2] = k/10000%10*16 + m/10000%10;
					m_tempbuf[i-1] = k/100%10*16 + m/100%10;
					m_tempbuf[i] = k%10*16 + m%10;
				}				
			}
			else
			{
				m_tempbuf[i] = j%10*16 + m%10;
			}
		}
		else
		{
			
			m_tempbuf[i] = j%10*16 + n%10;
		}		
	}
}


 

 

BCD編碼是網上找的,但是在使用過程中發現有點小問題,已經進行了修改,增加了小數四捨五入得判定,

對應代碼用紅色表示,int i=int(float+0.5)表達式

 

小工程以外的提外問題:

BCD解碼

long int BCDToInt(char *buf, int len)
{
	unsigned char reg = 0, reg2 = 0, ucTemp = 0;
	long int tem = 0, i = 0,lValue =0;
	for(i=0; i<len; i++)
	{
		reg = buf[i];
		reg2 = reg>>4;
		ucTemp = reg&0x0F;
		lValue =reg2*10 +ucTemp;
		tem = tem*100 + lValue ;
	}	
	return tem;
}


 

以下是一段調試代碼

#include <STDIO.H>
#include <MATH.H>
#include <STRING.H>
//以下是我用過的函數,希望對你有些幫助
/*----------------------------------------------------------------------
* BCD編碼與解碼
* char* buff : 目標緩衝區
* float value : 值
* int width : 目標寬度
* int decimal: 目標小數位數
*--------------------------------------------------------------------*/
void PackBCD(char* buff, float value, int width, int decimal)
{
	int i;
	
	if ((float)value >= pow(10.0, width-decimal))
	{
		memset(buff, 0, width);
		return;
	}
	
	for (i=0; i<(width-decimal)/2; i++)
	{
		buff[i] = (int)(value/pow(10.0, width-decimal-i*2-1)) % 10*16
			+ (int)(value/pow(10.0, width-decimal-i*2-2)) % 10;
	}
	
	for (i=(width-decimal)/2; i<width/2; i++)
	{
		buff[i] = (int)(value*pow(10, i*2+decimal-width+1)) % 10 *16
			+ (int)(value*pow(10, i*2+decimal-width+2)) % 10;
	}
}


float UnPackBCD(char* buff, int width, int decimal)
{
	float value = 0;
	int i;
	
	for (i=0; i<(width-decimal)/2; i++)
	{
		value+=(buff[i]/16 * pow(10, width-decimal-i*2-1)
			+ buff[i]%16 * pow(10, width-decimal-i*2-2));
	}
	
	for (i=(width-decimal)/2; i<width/2; i++)
	{
		value+=(buff[i]/16 / pow(10, i*2+decimal-width+1)
			+ buff[i]%16 / pow(10, i*2+decimal-width+2));
	}
	
	return value;
}

int FindDecimal(char *str)
{	
	int len = 0, i;	
    for(i = 0; i < strlen(str); i ++)
	{
		if(str[i]!='.')
		{
			len ++;
		}
        else
		{
			break;
		}
	}
    return strlen(str) - len - 1;		
}

int main()
{
	unsigned tempbuf[1000];
	char str[10];
	float fValue=123.45;
	memset(tempbuf,0,sizeof(tempbuf));
	memset(str,0,sizeof(str));
	sprintf(str,"%06f",fValue);
	int num=FindDecimal(str);
	PackBCD((char *)tempbuf,0.5,6,2);
	return 0;
}


網上找的代碼其實有很多小問題的,



 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章