本帖最后由 victor3l 于 2012-8-6 21:09 编辑
我的报文组织函数
xdata uchar datTab[16] = {0};//组织报文的
/*************************************************
函数名 :void DealDat(float num)
入口参数 :float
返回值 :无
全局变量 :uchar datTab[16]
功能 :组织报文
**************************************************/
void DealDat(float num)
{
uchar totalInt = 0; //总重的整数部分
uchar totalDec = 0; //总重的小数部分
uchar check = 0; //校验信息
uchar x1 = 0; //中间变量的处理
uchar x2 = 0;
uchar x3 = 0;
uchar x4 = 0;
uchar x5 = 0;
uchar x6 = 0;
datTab[0] = 0x24; //一下5位都是固定的
datTab[1] = 0x6a;
datTab[2] = 0x45;
datTab[3] = 0x30;
datTab[4] = 0x30; //上面两个30好像没有实际意义
datTab[5] = 0x30; //下面2位数据是固定的数据长度
datTab[6] = 0x33;
if(num > 0) //数据是正的,要用0x20表示
{
datTab[7] = 0x32;
datTab[8] = 0x30;
}
else //数据是负数要用0x2D表示。注意要用大写的字符
{
datTab[7] = 0x32;
datTab[8] = 0x44;
}
if(num > 0)
totalInt = (uint)(num); //我的总重整数部分由问题 2012年6月11日17:06:54
else
totalInt = (uint)(-num);
x1 = (totalInt >> 4); //把整数部分的高位(4位)他的范围是0----F
if( (x1 >= 0) && (x1 < 10) ) //0,1,2,3,4,5,6,7,8,9数据的ascii
datTab[9] = x1 + 0x30;
else if( (x1 > 9) && (x1 < 16)) //ABCDEF数据的ascii
datTab[9] = x1 + 0x37;
x2 = (totalInt & 0x0f); //取出整数部分的低位(4位)他的范围是0----F
if((x2 >= 0) && (x2 < 10))
datTab[10] = x1 + 0x30;
else if((x2 > 9) && (x2 < 16)) //ABCDEF数据的ascii
datTab[10] = x2 + 0x37;
/*********************小数部分******************************/
if(num > 0)
totalDec = ((uint)(num * 100)) % 100; //取出小数部分,这里也变成了整数了
else
totalDec = ((uint)((-num) * 100)) % 100; //取出小数部分,这里也变成了整数了
x3 = totalDec >> 4; //小数部分的高位 (4位)
if((x3 >= 0) && (x3 < 10))
datTab[11] = x3 + 0x30;
else if((x3 > 9) && (x3 < 16))
datTab[11] = x3 + 0x37;
x4 = (totalDec & 0x0f);
if((x4 >= 0) && (x4 < 10))
datTab[12] = x4 + 0x30;
else if((x4 > 9) && ( x4 < 16))
datTab[12] = x4 + 0x37;
if(num > 0)
check = 0^0x03^0x20^totalInt^totalDec;
else
check = 0^0x03^0x2D^totalInt^totalDec;
x5 = (check >> 4); //取出校验的高四位的
if((x5 >= 0) && (x5 < 10))
datTab[13] = x5 + 0x30;
else if((x5 > 9) && (x5 < 16))
datTab[13] = x5 + 0x37;
x6 = check & 0x0f ; //取出校验的低四位
if((x6 >= 0) && (x6 < 10))
datTab[14] = x6 + 0x30;
else if((x6 > 9) && (x6 < 16))
datTab[14] = x6 + 0x37;
datTab[15] = 0x0d; //数据的结束标志。
SendStr(datTab,16);
}
当上位机发送24 6a 45 0d这4个字节时,并且单片机收到后把标志位置位,在主循环中根据标志位把总重发送给串口,单片机在中断中接收串口发来的数据。
程序如下:
void Comser()interrupt 4
{
uchar count;
uchar i;
static uchar ComBuf[4] = {0};
ES = 0;
if(RI)
{
RI = 0;
ComBuf[0] = SBUF; //进了串口中断,就是接收数据的开始,而且此时第一个字节已经接收成功了.所以要及时将其保存.
for(i = 1;i < 4; i++)
{
while((!TI) && (++count < 250));
count = 0; //count可有可无,如果要那也是在限制时间到时,这时应该将接收缓存清空
RI = 0;
ComBuf = SBUF;
ComDelay(1); //延时时间不能长,否则前一数据会被后一数据覆盖,那数据就不齐了.
}
if((0x24 == ComBuf[0]) && (0x6a == ComBuf[1]) && (0x45 == ComBuf[2]) && (0x0d == ComBuf[3]))
flag = 1;
}
ES = 1;
}
我现在的问题是:串口发送的数据单片机已经接收到了,也返回数据了,但是为什么返回的数据,总是跟实际的总重想差一点点,并且假如发上来的数据就是总重但是他的校验位还是错的,但是前一段时间就是这个程序,发送返回的都是正确的,这个是什么原因,请大家帮看看,上面的代码有什么问题,谢谢,也请做过的朋友提供点思路,谢谢
1、通讯方式
标准RS232通讯;波特率:9600;通讯格式:8N1,8位数据,无奇偶校验位,有1位停止位。
2、基本格式
a、称重传感器回复重量数据给GPS监控主机格式。
名称
| 长度
| 值
| 说明
| 起始标志
| 1
| 0x24
| 与GPS接口共用
| 外设设备类型
| 1
| 0x6A
| 0x24 0x6A共同组成数据包头
| 命令字
| 1
| 0x45
| 指令类型
| 数据长度
| 2
| 0x00 0x03
| 固定的长度,3个十六进制数
| 符号
| 1
| 0x20/0x2D
| 0x20正 0x2D负
| 吨位小数点前两位
| 1
| 0x--
|
| 吨位小数点后两位
| 1
| 0x--
|
| 校验和
| 1
| 0x--
| 数据长度、符号、吨位共5个字节异或和
| 结束标志符
| 1
| 0x0D
| 回车符
|
发送时 黑色部分按十六进制发送,红色加下划线部分(数据长度,数据包,校验和)将一个十六进制数据拆分成两个十六进制数据发送,如0x3C,应该分别发送3和C的ASCII码0x33和0x43。数据中字母均用大写字母的ASCII码。
例:重量为29.72吨,传输数据为:
0x24 0x6A 0x45 0x30 0x33 0x32 0x30 0x31 0x44 0x34 0x38 0x37 0x36 0x0D
上面这个是通信协议,我发现我的数据分离上出错了,但是有找不出来,当整数部分小于10的时候按照我的这个程序竟然传回的都是0了,但是就出现而言,我有找不出错误,请大家帮帮忙,完成这个协议,怎么写代码较好。 |