本帖最后由 cooldog123pp 于 2021-10-30 14:36 编辑
此程序通过USB转485连接计算机USB口与智能电度表的RS485接口来读取电度表数据,并存储在XLS表格中。程序用VC++6.0编写,经实际测试运行稳定。
硬件方面一台计算机,一个USB转RS485,电度表,接线简单,USB转RS485插入计算机的USB口,A-B分别接电度表的485端子。程序运行后设置好串
口参数,一般波特率设为2400,8个数据位,1个停止位,偶校验,具体参考电度表手册。点打开串口,如未出现错误提示就表示连接成功了。先点读电度表序号,再点自动读数据或点其他按扭就能读到数据。
我这里测试的电表是深圳某公司的,其他厂家的电表也是一样可用的。
部份源代码如下:
// 智能电表抄系统Dlg.cpp : implementation file
//
#include "stdafx.h"
#include "智能电表科陆抄表系统.h"
#include "智能电表科陆抄表系统Dlg.h"
#include "comdef.h"
#include <afxdb.h>
#include <odbcinst.h>
#include <Afxdlgs.h>
#include"comdef.h"
#include "ComSetDlg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CAboutDlg dialog used for App About
class CAboutDlg : public CDialog
{
public:
CAboutDlg();
// Dialog Data
//{{AFX_DATA(CAboutDlg)
enum { IDD = IDD_ABOUTBOX };
//}}AFX_DATA
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CAboutDlg)
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
//}}AFX_VIRTUAL
// Implementation
protected:
//{{AFX_MSG(CAboutDlg)
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
//{{AFX_DATA_INIT(CAboutDlg)
//}}AFX_DATA_INIT
}
void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CAboutDlg)
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
//{{AFX_MSG_MAP(CAboutDlg)
// No message handlers
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CMyDlg dialog
CMyDlg::CMyDlg(CWnd* pParent /*=NULL*/)
: CDialog(CMyDlg::IDD, pParent)
{
//{{AFX_DATA_INIT(CMyDlg)
m_command = _T("");
m_kwh = _T("");
m_sumkwh = _T("");
m_date = _T("");
m_datepick = 0;
m_operator = _T("");
m_nume = _T("");
m_time = COleDateTime::GetCurrentTime();
m_curtime = _T("");
m_curdate = _T("");
m_recdate = _T("");
m_rectime = _T("");
m_meternumb = _T("");
m_meterrecd = _T("");
m_readsumkwh = _T("");
m_voitage = _T("");
m_readcommand = _T("");
m_power = _T("");
m_stacommand = _T("");
m_epari = _T("");
m_eport = _T("");
m_estop = _T("");
m_recdkwh = _T("");
m_datard = _T("");
m_payment = _T("");
m_ebuad = 0;
m_edata = 0;
//}}AFX_DATA_INIT
// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void CMyDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CMyDlg)
DDX_Control(pDX, IDC_EDIT_TEMPER, m_temper);
DDX_Control(pDX, IDC_EDIT_BATTERY, m_battery);
DDX_Control(pDX, IDC_EDIT_SUMPOWER, m_sumpower);
DDX_Control(pDX, IDC_EDIT_DATAREAD, m_dataread);
DDX_Control(pDX, IDC_EDIT_HZ, m_hz);
DDX_Control(pDX, IDC_RECDVOITAGE, m_recdvoitage);
DDX_Control(pDX, IDC_RECDPOWER, m_recdpower);
DDX_Control(pDX, IDC_RECDCURRENT, m_recdcurrent);
DDX_Control(pDX, IDC_EDIT_METERNUMB, m_emeternumb);
DDX_Control(pDX, IDC_READCOMMAND, m_ereadcommand);
DDX_Control(pDX, IDC_POWER, m_epower);
DDX_Control(pDX, IDC_VOITAGE, m_evoitage);
DDX_Control(pDX, IDC_CURRENT, m_ecurrent);
DDX_Control(pDX, IDC_STATIC_TXD, m_stxd);
DDX_Control(pDX, IDC_STATIC_RXD, m_srxd);
DDX_Control(pDX, IDC_STATIC_COMMAND, m_scommand);
DDX_Control(pDX, IDC_SUMKWH, m_esumkwh);
DDX_Control(pDX, IDC_BUTTON_READDATA, m_readdata);
DDX_Control(pDX, IDC_EDIT_RETURNVAL, m_data);
DDX_Control(pDX, IDC_LIST1, m_list);
DDX_Control(pDX, IDC_BUTTON_OPENCOM, m_OpenCloseCtrl);
DDX_Control(pDX, IDC_COMMAND, m_commd);
DDX_Text(pDX, IDC_COMMAND, m_command);
DDX_Text(pDX, IDC_KWH, m_kwh);
DDX_Text(pDX, IDC_SUMKWH, m_sumkwh);
DDX_Text(pDX, IDC_EDIT_OPERATOR, m_operator);
DDX_Text(pDX, IDC_EDIT_NUME, m_nume);
DDX_Text(pDX, IDC_EDIT_CURTIME, m_curtime);
DDX_Text(pDX, IDC_EDIT_DATE, m_curdate);
DDX_Text(pDX, IDC_EDIT_RECDATE, m_recdate);
DDX_Text(pDX, IDC_EDIT_RECTIME, m_rectime);
DDX_Text(pDX, IDC_EDIT_METERNUMB, m_meternumb);
DDX_Text(pDX, IDC_EDIT_METERRECD, m_meterrecd);
DDX_Text(pDX, IDC_VOITAGE, m_voitage);
DDX_Text(pDX, IDC_READCOMMAND, m_readcommand);
DDX_Text(pDX, IDC_POWER, m_power);
DDX_Text(pDX, IDC_STATIC_COMMAND, m_stacommand);
DDX_Text(pDX, IDC_EDIT_PARI, m_epari);
DDX_Text(pDX, IDC_EDIT_PORT, m_eport);
DDX_Text(pDX, IDC_EDIT_STOP, m_estop);
DDX_Text(pDX, IDC_EDIT_RECDKWH, m_recdkwh);
DDX_Text(pDX, IDC_EDIT_DATAREAD, m_datard);
DDX_Text(pDX, IDC_PAYMENT, m_payment);
DDX_Text(pDX, IDC_EDIT_BUAD, m_ebuad);
DDX_Text(pDX, IDC_EDIT_DATA, m_edata);
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CMyDlg, CDialog)
//{{AFX_MSG_MAP(CMyDlg)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDC_BUTTON_OPENCOM, OnButtonOpencom)
ON_COMMAND(ID_MENU_COMSET, OnComset)
ON_BN_CLICKED(IDC_BUTTON_READADD, OnButtonReadadd)
ON_BN_CLICKED(IDC_BUTTON_READDATA, OnButtonReaddata)
ON_WM_TIMER()
ON_COMMAND(ID_MENU_HELP, OnMenuHelp)
ON_COMMAND(ID_MENU_CLOSE, OnMenuClose)
ON_COMMAND(ID_MENU_EXAMINE, OnMenuExamine)
ON_COMMAND(ID_MENU_OPEN, OnMenuOpen)
ON_COMMAND(ID_MENU_SAVE, OnMenuSave)
ON_COMMAND(ID_MENU_NEWS, OnMenuNews)
ON_BN_CLICKED(IDC_ADDRECORD, OnAddrecord)
ON_BN_CLICKED(IDC_BUTTON_DEL, OnButtonDel)
ON_BN_CLICKED(IDC_BUTTON_MODI, OnButtonModi)
ON_NOTIFY(NM_CLICK, IDC_LIST1, OnClickList1)
ON_WM_CTLCOLOR()
ON_BN_CLICKED(IDC_BUTTON_READVOIT, OnButtonReadvoit)
ON_BN_CLICKED(IDC_BUTTON_READCURR, OnButtonReadcurr)
ON_BN_CLICKED(IDC_BUTTON_READKWH, OnButtonReadkwh)
ON_BN_CLICKED(IDC_BUTTON_POWER, OnButtonPower)
ON_MESSAGE(WM_COMMNOTIFY, OnCommNotify)
ON_BN_CLICKED(IDC_BUTTON_DATAREAD, OnButtonDataread)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CMyDlg message handlers
BOOL CMyDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// Add "About..." menu item to system menu.
// IDM_ABOUTBOX must be in the system command range.
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
CString strAboutMenu;
strAboutMenu.LoadString(IDS_ABOUTBOX);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}
// Set the icon for this dialog. The framework does this automatically
// when the application's main window is not a dialog
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon
// TODO: Add extra initialization here
UpdateData(TRUE);//更新编辑框内容
//buf={0};
K=0;
CDC dc;
// CRect rect=IDR_MENU1;
CMenu *menu;
m_menu.LoadMenu(IDR_MENU1);
//m_menu.LoadToolbar(IDR_MENUIMAGES);
////m_menu.LoadToolbar(IDR_TOOLBAR);
// SetMenu(&m_menu);
//SetBackgroundColor(RGB(0,255,255)); //设置背景色为白色
m_Font.CreatePointFont(240,"宋体");//创建字体
//m_Font.CreatePointFont(120, "Arial", NULL);
dc.SelectObject(&m_Font);
// dc.FillSolidRect(rect,RGB(80,89,202));//菜单被选中
dc.SetTextColor(RGB(10,0,181));//设置文本颜色
//dc.DrawText(*pText,rect,DT_VCENTER|DT_LEFT|DT_SINGLELINE);
// dc.Detach();
m_menu.LoadMenu(IDR_MENU1);
SetMenu(&m_menu);
//修改菜单栏颜色
m_brushback.Detach();
m_brushback.CreateSolidBrush(RGB(215,255,255));//控件背景色
MENUINFO mi; //MENUINFO结构未定义
mi.cbSize=sizeof(MENUINFO);//在StdAfx.cpp文件里的最前面部分添加这个语句:#define WINVER 0x0501
mi.fMask=MIM_BACKGROUND;
mi.hbrBack=(HBRUSH)m_brushback;
int result=SetMenuInfo((HMENU)(m_menu.m_hMenu),&mi);
m_menu.Detach();//去掉这句可以让菜单栏变色,但是其他函数要GetMenu()所以。。
//m_menu.SetBackgroundColor(RGB(255,0,0));//210,220,235));
// DrawMenuBar();
//m_brushback.CreateSolidBrush(RGB(255,190,255));
//SetDialogBkColor(RGB(0,192,128),RGB(200,0,0));
// m_bmpback.LoadBitmap( IDB_BITMAP_BACK ); //加载背景图
// m_brushback.CreatePatternBrush( &m_bmpback );//用背景图填充主窗口背景
/* m_strPort="COM3"; //预设为COM2口
m_nBaud=2400;
m_nDataBits=8;
m_nParity=1;
m_nStopBits=0;
m_eport=m_strPort;
m_ebuad.Format("%d",m_nBaud);
m_edata.Format("%d",m_nDataBits);
m_epari.Format("%d",m_nParity);
m_estop.Format("%d",m_nStopBits); */
CFile file; //从ComSer.dat文件中调入串口参数
// if(!file.Open("./ComSer.dat",CFile::modeRead))
//{
// CreateUser();
//if(!file.Open("./ComSer.dat",CFile::modeRead))
// return FALSE;
// }
ComStat Cs;
file.Open("./ComSet.dat",CFile::modeRead);
while(file.Read(&Cs,sizeof(Cs)))
{
//file.Read(&Cs,sizeof(Cs));
m_eport=Cs.sPort;
m_strPort=Cs.sPort;
m_ebuad=Cs.nBaud;
m_nBaud=m_ebuad;
m_edata=Cs.nData;
m_nDataBits=Cs.nData;
m_nParity=Cs.nPari;
switch(m_nParity) // 校验设置
{
case 0:
m_epari="NOPARITY";
break;
case 1:
m_epari="EVENPARITY";
break;
case 2:
m_epari="ODDPARITY";
break;
default:;
}
m_nStopBits=Cs.nStop;
switch(m_nStopBits) // 停止位
{
case 0:
m_estop="ONESTOPBIT";
break;
case 1:
m_estop="ONE5STOPBITS";
break;
case 2:
m_estop="TWOSTOPBITS";
break;
default:;
}
}
hBitmap = LoadBitmap(AfxGetInstanceHandle(),
MAKEINTRESOURCE(IDB_BITMAP_OFF)); // IDB_BITMAP_TEST为资源图片ID
m_srxd.SetBitmap(hBitmap);
m_stxd.SetBitmap(hBitmap);
m_Font1.CreatePointFont(120, "Arial", NULL);//设置(控件型)变量的字体
m_esumkwh.SetFont(&m_Font1,true);
m_scommand.SetFont(&m_Font1,true);
m_commd.SetFont(&m_Font1,true);
m_ecurrent.SetFont(&m_Font1,true);
m_evoitage.SetFont(&m_Font1,true);
m_epower.SetFont(&m_Font1,true);
m_ereadcommand.SetFont(&m_Font1,true);
m_emeternumb.SetFont(&m_Font1,true);
m_data.SetFont(&m_Font1,true);
//m_list.SetFont(&m_Font1,true);
// m_color = RGB(0,0,128);
m_list.SetBkColor(RGB(0,0,255));
// m_color = RGB(0,128,128);
m_list.SetTextColor(RGB(0,128,128));//
m_list.SubclassDlgItem(IDC_LIST1,this);
m_list.InsertColumn(0,"序号",0,40);
m_list.InsertColumn(1,"电表表号",0,85);
m_list.InsertColumn(2,"抄表日期",0,100);
m_list.InsertColumn(3,"抄表时间",0,60);
m_list.InsertColumn(4,"电压",0,55);
m_list.InsertColumn(5,"电流",0,55);
m_list.InsertColumn(6,"功率",0,70);
m_list.InsertColumn(7,"操作员",0,50);
m_list.InsertColumn(8,"度数",0,85);
m_list.InsertColumn(9,"交费记录",0,60);
m_list.InsertColumn(10,"停电时间",0,70);
m_list.InsertColumn(11,"频率",0,60);
m_hWnd=this->GetSafeHwnd();
// 为WM_COMMNOTIFY消息创建事件对象,手工重置,初始化为有信号的
if((m_hPostMsgEvent=CreateEvent(NULL, TRUE, TRUE, NULL))==NULL)
return FALSE;
memset(&m_osRead, 0, sizeof(OVERLAPPED));
memset(&m_osWrite, 0, sizeof(OVERLAPPED));
// 为异步读创建事件对象,手工重置,初始化为无信号的
if((m_osRead.hEvent=CreateEvent(NULL, TRUE, FALSE, NULL))==NULL)
return FALSE;
m_stacommand="读电量命令";
m_readcommand="68 75 76 00 00 00 10 11 04 33 33 33 33";
m_bPortOpened=0;
m_command="68 AA AA AA AA AA AA 68 13 00";
Readfig=false;
SetTimer(1,1000,NULL);
UpdateData(false);//更新编辑框内容
return TRUE; // return TRUE unless you set the focus to a control
}
void CMyDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if ((nID & 0xFFF0) == IDM_ABOUTBOX)
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
else
{
CDialog::OnSysCommand(nID, lParam);
}
}
// If you add a minimize button to your dialog, you will need the code below
// to draw the icon. For MFC applications using the document/view model,
// this is automatically done for you by the framework.
void CMyDlg::OnPaint()
{
CPaintDC dc(this); // 填充背景色
CRect rect;
GetClientRect(&rect);
if (IsIconic())
{
CPaintDC dc(this); // device context for painting
SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);
// Center icon in client rectangle
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// Draw the icon
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialog::OnPaint();
}
//dc.FillRect( rect, &m_brushback ); //填充背景图
}
// The system calls this to obtain the cursor to display while the user drags
// the minimized window.
HCURSOR CMyDlg::OnQueryDragIcon()
{
return (HCURSOR) m_hIcon;
}
void CMyDlg::OnButtonOpencom() //打开关闭串口
{
// TODO: Add your control notification handler code here
CString temp;
m_OpenCloseCtrl.GetWindowText(temp); //
UpdateData(true);
m_bPortOpened=!m_bPortOpened;
if(m_bPortOpened) //如串口可连接
{
COMMTIMEOUTS TimeOuts;
// 异步方式打开串口
m_hCom=CreateFile(m_strPort, GENERIC_READ | GENERIC_WRITE, 0, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
if(m_hCom==INVALID_HANDLE_VALUE) ////如串口打开错误则返回
{
m_bPortOpened=!m_bPortOpened;
SetTimer(4,2000,NULL );
AfxMessageBox("串口不存在");
return ;
}
SetupComm(m_hCom,MAXBLOCK,MAXBLOCK);//设置输入、输出缓冲区的大小
SetCommMask(m_hCom,EV_RXCHAR);//设置事件驱动的类型
PurgeComm(m_hCom, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR| PURGE_RXCLEAR );
//清干净输入、输出缓冲区
// 把间隔超时设为最大,把总超时设为0将导致ReadFile立即返回并完成操作
TimeOuts.ReadIntervalTimeout=MAXDWORD;
TimeOuts.ReadTotalTimeoutMultiplier=50;
TimeOuts.ReadTotalTimeoutConstant=500;
/* 设置写超时以指定WriteComm成员函数中的GetOverlappedResult函数的等待时间*/
TimeOuts.WriteTotalTimeoutMultiplier=50;
TimeOuts.WriteTotalTimeoutConstant=500;
SetCommTimeouts(m_hCom, &TimeOuts);
DCB dcb;
//得到串口当前配置
if(!GetCommState(m_hCom, &dcb))
{ SetTimer(4,2000,NULL );
MessageBox("串口设置错误,请重新设置。");
return ;
}
dcb.fBinary=1;//允许二进制模式
dcb.BaudRate=m_nBaud;//波特率为9600
dcb.ByteSize=m_nDataBits;//数据位为8位
dcb.Parity=m_nParity ;//无校验位
dcb.StopBits=m_nStopBits;//停止位为1位
switch(m_nParity) // 校验设置
{
case 0:
dcb.Parity=NOPARITY;
break;
case 1:
dcb.Parity=EVENPARITY;
break;
case 2:
dcb.Parity=ODDPARITY;
break;
。。。。。。。。
|