智能电表数据读写心得

1、布线方面

    智能电表采用的是485通讯。如果单位的局域网布置得比较完整的话,建议使用串口转以太网模块,将数据接入以太网。这样做的好处是可以利用现有的网络布线,不用再重复布线。若是使用串口转以太网模块的话,那就需要在上位机上安装一个名为《虚拟VSPM虚拟串口服务器》的软件,它的功能是在将远端的TCP服务器虚拟成一个串口,这样一来,数据的读写跟使用485串口通讯是一样的。

    虚拟VSPM虚拟串口服务器的下载地地址:

     http://www.kinghwawin.com/DownloadShow.asp?ID=40

    串口转以太网络模块的地址:

     http://item.taobao.com/item.htm?spm=a1z09.2.9.66.LxUUjT&id=10248910782&_u=rlmt59h151e

 

2、程序方面

    智能电表的数据读写需要遵循相应的通讯协议,这些通讯协议已经被列入了国家标准。目前比较常用的有两个标准:一是2007版本的,全称是《中华人民共和国电力行业标准 DLT645-2007多功能电能表通信协议》,一个是1997版本的。本文使用的是2007版本的通讯协议。   

    下面的代码的GetPowerConsumption()函数演示了如何读取总电量。

using System;
using System.Collections.Generic;

using System.Text;
using System.IO.Ports;
using System.Windows.Forms;
using System.Diagnostics;


public class ElectricityMeter
{


    //****************************************************** 字 段 ************************************************************************** 
    SerialPort _serialPort = new SerialPort();
    Form _frm;

    private static readonly ElectricityMeter _instance = new ElectricityMeter();

    //*****************************************************  事 件 ***************************************************************************


    //****************************************************** 属 性 *************************************************************************** 


    //****************************************************** 构造函数  ******************************************************************* 

    /// <summary>
    /// 私有构造函数,防止类被实例化
    /// </summary>
    private ElectricityMeter()
    {

    }

    //****************************************************** 方 法  ******************************************************************* 



    /// <summary>
    /// 只能通过CreateInstance方法来创建类的实例。单例模式
    /// </summary>
    public static ElectricityMeter CreateInstance()
    {
        return _instance;
    }




    /// <summary>
    /// 打开设备
    /// </summary>
    /// <param name="portName">串口号</param>
    /// <param name="frm">调用这个类的窗体。</param>
    public void Open( string portName, Form frm )
    {
        try
        {
            // 初始化窗体对象
            _frm = frm;
            _frm.FormClosing += new FormClosingEventHandler( _frm_FormClosing );
            //初始化SerialPort对象
            _serialPort.PortName = portName;
            _serialPort.BaudRate = 2400; // 请将设备的波特率设置为此。
            _serialPort.DataBits = 8;
            _serialPort.StopBits = StopBits.One;
            _serialPort.Parity = Parity.Even;
            _serialPort.Open();
        }
        catch( Exception e )
        {
            MessageBox.Show( e.Message );
        }
    }





    /// <summary>
    /// 关闭设备。
    /// </summary>
    public void Close()
    {
        if( _serialPort.IsOpen == true )
        {
            _serialPort.Close();
            _serialPort.Dispose();
        }
    }


    /// <summary>
    /// 获取耗电量
    /// </summary>
    public Decimal GetPowerConsumption()
    {
        if( _serialPort.IsOpen == true )
        {
            // 十六进制的命令字符串
            string strCmd = "68 AA AA AA AA AA AA 68 11 04 33 33 33 33 AD 16";
            // 转换为十六进制的字节数组
            string[] strs = strCmd.Split( new char[] { ' ' } ); // 空格分组

            byte[] cmdBytes = new byte[ strs.Length ];

            //  转换为十进制的字节数组
            for( int i = 0; i < cmdBytes.Length; i++ )
            {
                cmdBytes[ i ] = Convert.ToByte( strs[ i ], 16 ); // 16进制转换为10进制
            }

            _serialPort.Write( cmdBytes, 0, cmdBytes.Length );

            System.Threading.Thread.Sleep( 500 );  // 500ms内应当有响应

            byte[] resultBytes = new byte[ 21 ]; // 容量为21的字节数组
            _serialPort.Read( resultBytes, 0, resultBytes.Length );

            string n1 = Convert.ToString( resultBytes[ 18 ] - 51, 16 ); // 将十进制转成16进制的字符串
            string n2 = Convert.ToString( resultBytes[ 17 ] - 51, 16 ); // 将十进制转成16进制的字符串
            string n3 = Convert.ToString( resultBytes[ 16 ] - 51, 16 ); // 将十进制转成16进制的字符串
            string n4 = Convert.ToString( resultBytes[ 15 ] - 51, 16 ); // 将十进制转成16进制的字符串
            string resultString = n1 + n2 + n3 + "." + n4;

            return Decimal.Parse( resultString );
        }
        else
        {
            throw new Exception( "串口没有打开" );
        }
    }



    /// <summary>
    /// 在窗体关闭的时候关闭串口连接。
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    void _frm_FormClosing( object sender, FormClosingEventArgs e )
    {
        this.Close();
    }



}
View Code

 

    2007版标准的下载地址:

    http://wenku.baidu.com/view/b5e3e9d776a20029bd642d6d.html

 

posted @ 2015-02-27 16:38  何德海  阅读(6109)  评论(1编辑  收藏  举报