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;
}


网上找的代码其实有很多小问题的,



 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值