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(); } }
2007版標准的下載地址:
http://wenku.baidu.com/view/b5e3e9d776a20029bd642d6d.html。