代码改变世界

(SerialPort)串口编程知识整理:(二)串口编程中经常用到的进制转换和其他公共方法

2010-03-31 14:05  doggies  阅读(5702)  评论(22编辑  收藏  举报

     在进行串口编程时,经常会涉及到进制转换、计算协议校验码以及数据格式化的操作,本文整理了在实际项目中可能会用到的公共方法,分享给需要的朋友。

一、以下包含了三部分的内容: 

1、进制转换:

主要包括了串口通讯中比较常用的16进制、byte、压缩BCD码、long、ASCII、Float等之间的转换方法。

ConvertHelper.cs 进制转换
/*----------------------------------------------------------------
           // Copyright (C) 北京****科技有限公司
           // 版权所有。 
           //
           // 文件名:ConvertHelper
           // 文件功能描述:进制转换
           //
           // 
           // 创建标识:** 2008-05-04
           //
           // 修改标识:
           // 修改描述:
           //
           // 修改标识:
           // 修改描述:
//----------------------------------------------------------------
*/
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;

namespace LY
{
    
/// <summary>
    
/// 进制转换
    
/// </summary>
    public static class ConvertHelper
    {
        
#region 进制转换
        
/// <summary>
        
/// 整形转化成字节
        
/// </summary>
        
/// <param name="i"></param>
        
/// <returns></returns>
        public static byte IntToByte(int i)
        {
            
return Convert.ToByte(i % 0x100);
        }

        
/// <summary>
        
/// 16进制转化成BCD
        
/// </summary>
        
/// <param name="b">byte</param>
        
/// <returns>返回BCD码</returns>
        public static byte HexToBCD(byte b)
        {
            
int r1 = b % 0x10;     // b = 0x12 -> r1 = 0x02
            int r2 = b / 0x10;     // b = 0x12 -> r2 = 0x01
            if (r1 > 9)             //r1 = 0x0A -> r1 = 0x00
                r1 = 0;
            
if (r2 > 9)             //r2 = 0x0A -> r2 = 0x00
                r2 = 0;
            
return Convert.ToByte(r1 + 10 * r2);    //0x12 -> 12
        }

        
/// <summary>
        
/// 16进制转化成BCD
        
/// </summary>
        
/// <param name="i">int</param>
        
/// <returns>返回BCD码</returns>
        public static byte HexToBCD(int i)
        {
            
return HexToBCD(IntToByte(i));
        }

        
/// <summary>
        
/// Double转换为压缩BCD
        
/// </summary>
        
/// <param name="d">0-100内的双精度浮点数字</param>
        
/// <returns>返回压缩BCD码</returns>
        public static string DoubleToBCD(double d)
        {
            
string[] strs = d.ToString("F2").Split('.');
            
string temp1 = int.Parse(strs[0]).ToString("D2");
            
string temp2 = int.Parse(strs[1]).ToString("D2");
            
return string.Format("{0} {1}", temp1, temp2);
        }

        
/// <summary>
        
/// long转换为BCD
        
/// </summary>
        
/// <param name="val"></param>
        
/// <returns></returns>
        public static long ToBCD(long val)
        {
            
long res = 0;
            
int bit = 0;
            
while (val >= 10)
            {
                res 
|= (val % 10 << bit);
                val 
/= 10;
                bit 
+= 4;
            }
            res 
|= val << bit;
            
return res;
        }

        
/// <summary>
        
/// BCD转换为long
        
/// </summary>
        
/// <param name="vals"></param>
        
/// <returns></returns>
        public static long FromBCD(long vals)
        {
            
long c = 1;
            
long b = 0;
            
while (vals > 0)
            {
                b 
+= ((vals & 0xf* c);
                c 
*= 10;
                vals 
>>= 4;
            }
            
return b;
        }

        
/// <summary>
        
/// BCD转化成16进制
        
/// </summary>
        
/// <param name="b"></param>
        
/// <returns></returns>
        public static byte BCDToHex(byte b)
        {
            
int r2 = b % 100;      // b = 12 -> r2 = 12        //123 -> r2 = 23
            int r1 = r2 % 10;      //r2 = 12 -> r1 = 2     
            r2 = r2 / 10;           //r2 = 12 -> r2 =1
            return Convert.ToByte(r1 + 0x10 * r2);
        }

        
/// <summary>
        
/// BCD转化成16进制
        
/// </summary>
        
/// <param name="i"></param>
        
/// <returns></returns>
        public static byte BCDToHex(int i)
        {
            
return BCDToHex(IntToByte(i));
        }

        
/// <summary>
        
/// btye转化成16进制字符
        
/// </summary>
        
/// <param name="b">byte</param>
        
/// <returns></returns>
        public static string ToHexString(byte b)
        {
            
return Convert.ToString(b, 16);
        }

        
/// <summary>
        
/// int转化成16进制字符
        
/// </summary>
        
/// <param name="num">int</param>
        
/// <returns></returns>
        public static string ToHexString(int num)
        {
            
return Convert.ToString(num, 16);
        }

        
/// <summary>
        
/// 16进制字符串转换成字节数组
        
/// </summary>
        
/// <param name="s"></param>
        
/// <returns></returns>
        public static byte[] HexStringToByteArray(string s)
        {
            s 
= s.Replace(" """);
            
byte[] buffer = new byte[s.Length / 2];
            
for (int i = 0; i < s.Length; i += 2)
            {
                buffer[i 
/ 2= (byte)Convert.ToByte(s.Substring(i, 2), 16);
            }
            
return buffer;
        }

        
/// <summary> 
        
/// 字节数组转换成16进制字符串
        
/// </summary>
        
/// <param name="data"></param>
        
/// <returns></returns>
        public static string ByteArrayToHexString(byte[] data)
        {
            StringBuilder sb 
= new StringBuilder(data.Length * 3);
            
foreach (byte b in data)
            {
                sb.Append(Convert.ToString(b, 
16).PadLeft(2'0').PadRight(3' '));
            }
            
return sb.ToString().Trim().ToUpper();
        }

        
/// <summary>
        
/// ASCII转16进制
        
/// </summary>
        
/// <param name="ascii">ASCII</param>
        
/// <returns></returns>
        public static string ASCIIToHex(string ascii)
        {
            
char[] cs = ascii.ToCharArray();
            StringBuilder sb 
= new StringBuilder();
            
for (int i = 0; i < cs.Length; i++)
            {
                
string hex = ((int)cs[i]).ToString("X");
                sb.AppendFormat(
"{0} ", hex);
            }
            
return sb.ToString().TrimEnd(' ');
        }

        
/// <summary>
        
/// HEX to ASCII
        
/// </summary>
        
/// <param name="hex"></param>
        
/// <returns></returns>
        public static string HexToASCII(string hex)
        {
            
if (hex.Length % 2 == 0)
            {
                
int iValue;
                
byte[] bs;
                
string sValue = string.Empty;
                
string result = string.Empty;
                
int length = hex.Length / 2;

                
for (int i = 0; i < length; i++)
                {
                    iValue 
= Convert.ToInt32(hex.Substring(i * 22), 16); // 16进制->10进制
                    bs = System.BitConverter.GetBytes(iValue); //int->byte[]
                    sValue = System.Text.Encoding.ASCII.GetString(bs, 01);  //byte[]-> ASCII
                    result += char.Parse(sValue).ToString();
                }
                
return result.PadLeft(length, '0');
            }
            
return string.Empty;
        }

        
/// <summary>
        
/// ASCII To Float
        
/// </summary>
        
/// <param name="ascii"></param>
        
/// <returns></returns>
        public static float ASCIIToFloat(string ascii)
        {
            
if (ascii.Length == 8)
            {
                
byte[] arr = new byte[4];
                
for (int i = 0; i < 4; i++)
                {

                    arr[i] 
= Convert.ToByte(ascii.Substring((3 - i) * 22), 16);
                }
                
float f = BitConverter.ToSingle(arr, 0);
                
return f;
            }
            
return 0f;
        }

        
/// <summary>
        
/// Hex to Float
        
/// </summary>
        
/// <param name="hex"></param>
        
/// <returns></returns>
        public static float HexToFloat(string hex)
        {
            
string ascii = HexToASCII(hex);
            
float f = ASCIIToFloat(ascii);
            
return f;
        }
        
#endregion
    }
}

2、校验码计算: 

包括了16进制异或和、16进制累加、16进制ASCII累加三种类型的校验码计算方法。

CheckHelper.cs 代码校验码计算
/*----------------------------------------------------------------
           // Copyright (C) 北京****科技有限公司
           // 版权所有。 
           //
           // 文件名:CheckHelper
           // 文件功能描述:校验码计算
           //
           // 
           // 创建标识:** 2008-05-04
           //
           // 修改标识:
           // 修改描述:
           //
           // 修改标识:
           // 修改描述:
//----------------------------------------------------------------
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace LY
{
    
/// <summary>
    
/// 校验码计算
    
/// </summary>
    public static class CheckHelper
    {   
        
#region 校验码计算的方法
        
/// <summary>
        
/// 返回协议验证码,默认命令字的开始位置为第二位
        
/// </summary>
        
/// <param name="hex">协议串/param>
        
/// <returns>16进制字符串表示的异或计算结果</returns>
        private static string HexXorToString(string hex)
        {
            
string[] hexTemp = hex.Split(' ');
            
int k = 0;
            
for (int i = 0; i < hexTemp.Length; i++)
            {
                
int j = Convert.ToInt32(hexTemp[i], 16);

                
if (i == 1)
                {
                    k 
= j;
                }
                
else if (i > 1)
                {
                    k 
= k ^ j;
                }

            }
            
string hexResult = string.Format("{0:X}", k % 256);//保证得到一个字节长度的值
            if (hexResult.Length == 1)
            {
                hexResult 
= string.Format("0{0}", hexResult);
            }
            
return hexResult;
        }

        
/// <summary>
        
/// 返回协议验证码
        
/// </summary>
        
/// <param name="hex">协议串</param>
        
/// <param name="cmdIndex">命令字的开始位置</param>
        
/// <returns>验证码</returns>
        private static string HexXorToString(string hex, int cmdIndex)
        {
            
string[] hexTemp = hex.Split(' ');
            
int k = 0;
            
for (int i = cmdIndex; i < hexTemp.Length; i++)
            {
                
int j = Convert.ToInt32(hexTemp[i], 16);

                
if (i == cmdIndex)
                {
                    k 
= j;
                }
                
else if (i > cmdIndex)
                {
                    k 
= k ^ j;
                }

            }
            
string hexResult = string.Format("{0:X}", k % 256);//保证得到一个字节长度的值
            if (hexResult.Length == 1)
            {
                hexResult 
= string.Format("0{0}", hexResult);
            }
            
return hexResult;
        }

        
/// <summary>
        
/// 16进制相加的值
        
/// </summary>
        
/// <param name="hex1"></param>
        
/// <param name="hex2"></param>
        
/// <returns></returns>
        private static string HexAddToString(string hex1, string hex2)
        {
            
int h1 = Convert.ToInt32(hex1, 16);
            
int h2 = Convert.ToInt32(hex2, 16);
            
int sum = (h1 + h2) % 256;//保证得到一个字节长度的值
            string hexResult = string.Format("{0:X}", sum);

            
if (hexResult.Length == 1)
            {
                hexResult 
= string.Format("0{0}", hexResult);
            }

            
return hexResult;
        }

        
/// <summary>
        
/// 返回带验证码的协议命令
        
/// </summary>
        
/// <param name="hex">协议串</param>
        
/// <returns>带验证码的协议命</returns>
        public static string GetSendProtocol(string hex)
        {
            
string hexTemp = string.Empty;
            hexTemp 
= HexXorToString(hex);

            
string hexResult = string.Empty;
            
string hexTemp1 = HexAddToString(hexTemp, "37");
            
string hexTemp2 = HexAddToString(hexTemp, "D5");
            
string hexTemp3 = HexAddToString(hexTemp, "9E");
            hexResult 
= string.Format("{0} {1} {2} {3}", hex, hexTemp1, hexTemp2, hexTemp3);

            
return hexResult;
        }

        
/// <summary>
        
/// 返回带验证码的协议命令
        
/// </summary>
        
/// <param name="hex">协议串</param>
        
/// <param name="cmdIndex">命令字的开始位置</param>
        
/// <returns>带验证码的协议命</returns>
        public static string GetSendProtocol(string hex, int cmdIndex)
        {
            
string hexTemp = string.Empty;
            hexTemp 
= HexXorToString(hex, cmdIndex);

            
string hexResult = string.Empty;
            
string hexTemp1 = HexAddToString(hexTemp, "37");
            
string hexTemp2 = HexAddToString(hexTemp, "D5");
            
string hexTemp3 = HexAddToString(hexTemp, "9E");
            hexResult 
= string.Format("{0} {1} {2} {3}", hex, hexTemp1, hexTemp2, hexTemp3);

            
return hexResult;
        }

        
/// <summary>
        
/// 得到校验码
        
/// </summary>
        
/// <param name="message">16进制ASCII</param>
        
/// <returns></returns>
        private static string GetChecksum(string message)
        {
            
char[] chars = message.ToCharArray();
            
ushort c;
            
ushort total = 0;

            
for (int i = 0; i < chars.Length; i++)
            {
                total 
+= (ushort)chars[i];
            }

            c 
= (ushort)(0 - total);
            
string hex = Convert.ToString(c, 16);
            
return hex.ToUpper();
        }
        
/// <summary>
        
/// 检查校验码是否相等
        
/// </summary>
        
/// <param name="message">16进制ASCII</param>
        
/// <param name="checksum">16进制校验码</param>
        
/// <returns>是否相等</returns>
        private static bool CalculateChecksum(string message, string checksum)
        {
            
char[] chars = message.ToCharArray();
            
ushort c = Convert.ToUInt16(checksum, 16);
            
ushort total = 0;

            
for (int i = 0; i < chars.Length; i++)
            {
                total 
+= (ushort)chars[i];
            }

            
if ((ushort)(c + total) == 0return true;
            
return false;
        }
        
#endregion
    }
}

3、字符串格式化:

主要是针对协议中涉及到的金额、数量、时间等字符串的处理。 

FormatHelper.cs 字符串格式化
/*----------------------------------------------------------------
           // Copyright (C) 北京****科技有限公司
           // 版权所有。 
           //
           // 文件名:FormatHelper
           // 文件功能描述:字符串格式化
           //
           // 
           // 创建标识:** 2008-05-04
           //
           // 修改标识:
           // 修改描述:
           //
           // 修改标识:
           // 修改描述:
//----------------------------------------------------------------
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Test
{
    
/// <summary>
    
/// 字符串格式化
    
/// </summary>
    public static class FormatHelper
    {    
        
#region 格式化字符串
        
/// <summary>
        
/// 将字符数组装换成字符串
        
/// </summary>
        
/// <param name="array">数组</param>
        
/// <param name="startIndex">开始位置</param>
        
/// <param name="count">长度</param>
        
/// <returns>拼接字符串</returns>
        public static string GetStringByArray(string[] array, int startIndex, int count)
        {
            
int index = array.Length;

            
if (startIndex < 0 || startIndex > index)
            {
                
return string.Empty;
            }

            
int endIndex = startIndex + count;
            
if (endIndex < 0 || endIndex > index)
            {
                
return string.Empty;
            }

            
if (startIndex > endIndex)
            {
                
return string.Empty;
            }

            
string result = string.Empty;
            result 
= string.Join(" ", array, startIndex, count);
            
return result;
        }

        
/// <summary>
        
/// 将BCDto日期
        
/// </summary>
        
/// <param name="now"></param>
        
/// <returns></returns>
        public static DateTime GetDateTimeByBCD(string now)
        {
            
string[] tempNow = now.TrimEnd(' ').Split(' ');

            
string dt = string.Format("{6}{0}-{1}-{2} {3}:{4}:{5}", tempNow[0], tempNow[1], tempNow[2], tempNow[3], tempNow[4], tempNow[5], DateTime.Now.Year.ToString().Substring(02));

            DateTime result;

            
bool done = DateTime.TryParse(dt, out result);
            
if (done)
            {
                
return result;
            }
            
return DateTime.Now;
        }

        
/// <summary>
        
/// 返回格式化的日期时间字符串
        
/// </summary>
        
/// <param name="current"></param>
        
/// <returns></returns>
        public static string GetBCDDateTime(DateTime current)
        {
            
string result = current.ToString("yy MM dd HH mm ss");
            
return result;
        }

        
/// <summary>
        
/// 将字符串转换成对应的数值/100
        
/// </summary>
        
/// <param name="value"></param>
        
/// <returns></returns>
        public static decimal GetValueByString(string value)
        {
            
string tempValue = value.Replace(" """);
            
return decimal.Divide(decimal.Parse(tempValue), 100);
        }

        
/// <summary>
        
/// 返回对应的整型字符串
        
/// </summary>
        
/// <param name="i"></param>
        
/// <returns></returns>
        public static string BinaryToIntString(int i)
        {
            
string result = string.Empty;
            
if (i < 0 || i > 999999)
            {
                
return "00 00 00";
            }
            
else if (i < 100)
            {
                
return string.Format("00 00 {0}", i.ToString("D2"));
            }
            
else if (i >= 100 && i < 1000)
            {
                
return string.Format("00 0{0} {1}", i.ToString().Substring(01), i.ToString().Substring(12));
            }
            
else if (i >= 1000 && i < 10000)
            {
                
return string.Format("00 {0} {1}", i.ToString().Substring(02), i.ToString().Substring(22));
            }
            
else if (i >= 10000 && i < 100000)
            {
                
return string.Format("0{0} {1} {2}", i.ToString().Substring(01), i.ToString().Substring(12), i.ToString().Substring(32));
            }
            
else if (i >= 100000 && i < 1000000)
            {
                
return string.Format("{0} {1} {2}", i.ToString().Substring(02), i.ToString().Substring(22), i.ToString().Substring(42));
            }
            
return "00 00";
        }

        
/// <summary>
        
/// 整形格式化为两位小数
        
/// </summary>
        
/// <param name="value"></param>
        
/// <returns></returns>
        public static string IntFormatString(int value)
        {
            
return value.ToString("D2");
        }
        
#endregion
    }
}

二、声明

     本文的内容大部分方法经过了项目测试,少量没有用到的方法不保证其正确性,希望各位朋友在使用之前测试一下。

如果发现问题,请及时反馈给本人,谢谢!

    本系列文章:

(1)(SerialPort)串口编程知识整理:(一)基本概念和项目实践概述

(2)(SerialPort)串口编程知识整理:(二)串口编程中经常用到的进制转换和其他公共方法

 (3)(SerialPort)串口编程知识整理:(三)串口编程的系统设计实用经验总结

(4)(SerialPort)串口编程知识整理:(四)多串口系统的分布式架构设计