|
马上注册,结交更多好友,享用更多功能^_^
您需要 登录 才可以下载或查看,没有账号?立即注册
x
小白一枚,最近用MFC写了一个串口通信,但是存在一个bug,当我发送一个正常的完整的数据时,程序不会有问题。但是当我先发送一个不完整的数据,再发送完整的数据,他就无法接收到数据了,估摸着是缓存变量没有清空的原因,但是不知道怎么处理这个问题。清0操作不起左右,有大神帮我一下吗
发送的数据格式是这样的>+123456+223456+323456+423456+523456+623456+723456+823456
附件上传失败,把代码贴出来
// SerialConnectionDlg.cpp : 实现文件
//
#include "stdafx.h"
#include "SerialConnection.h"
#include "SerialConnectionDlg.h"
#include "afxdialogex.h"
#include <string.h>
using namespace std;
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
INPKG pkg;
CTRLPKG ctrlpkg;
/* CRC高位字节值表*/
/* CRC高位字节值表*/
UCHAR CrcHi[] = {
};
/* CRC低位字节值表*/
UCHAR CrcLo[] = {
};
CSerialPort m_SerialPort;
BOOL m_bPortOpen;
// 用于应用程序“关于”菜单项的 CAboutDlg 对话框
class CAboutDlg : public CDialogEx
{
public:
CAboutDlg();
// 对话框数据
enum { IDD = IDD_ABOUTBOX };
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
// 实现
protected:
DECLARE_MESSAGE_MAP()
};
CAboutDlg::CAboutDlg() : CDialogEx(CAboutDlg::IDD)
{
}
void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()
// CSerialConnectionDlg 对话框
CSerialConnectionDlg::CSerialConnectionDlg(CWnd* pParent /*=NULL*/)
: CDialogEx(CSerialConnectionDlg::IDD, pParent)
, m_Edit_Receive(_T(""))
, m_Edit_Send(_T(""))
, m_ncombo1(_T(""))
, m_ncombo2(_T(""))
, m_ncombo3(_T(""))
, m_1(_T(""))
, m_2(_T(""))
, m_3(_T(""))
, m_4(_T(""))
, m_5(_T(""))
, m_6(_T(""))
, m_7(_T(""))
, m_8(_T(""))
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void CSerialConnectionDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
DDX_Text(pDX, IDC_EDIT_Rev, m_Edit_Receive);
DDX_Text(pDX, IDC_EDIT_Rep, m_Edit_Send);
DDX_Control(pDX, IDC_COMBO1, m_combo1);
DDX_Control(pDX, IDC_COMBO2, m_combo2);
DDX_CBString(pDX, IDC_COMBO1, m_ncombo1);
DDX_CBString(pDX, IDC_COMBO2, m_ncombo2);
DDX_Control(pDX, IDC_COMBO3, m_combo3);
DDX_Control(pDX, IDC_COMBO4, m_combo4);
DDX_Control(pDX, IDC_COMBO5, m_combo5);
DDX_CBString(pDX, IDC_COMBO3, m_ncombo3);
DDX_Text(pDX, IDC_EDIT_show1, m_1);
DDX_Text(pDX, IDC_EDIT_show2, m_2);
DDX_Text(pDX, IDC_EDIT_show3, m_3);
DDX_Text(pDX, IDC_EDIT_show4, m_4);
DDX_Text(pDX, IDC_EDIT_show5, m_5);
DDX_Text(pDX, IDC_EDIT_show6, m_6);
DDX_Text(pDX, IDC_EDIT_show7, m_7);
DDX_Text(pDX, IDC_EDIT_show8, m_8);
}
BEGIN_MESSAGE_MAP(CSerialConnectionDlg, CDialogEx)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_MESSAGE(WM_COMM_RXCHAR,OnComm)
//ON_BN_CLICKED(IDC_BUTTON_OPEN,&CSerialConnectionDlg)
ON_BN_CLICKED(IDC_BUTTON_OPEN, &CSerialConnectionDlg::OnBnClickedButtonOpen)
ON_BN_CLICKED(IDC_BUTTON_CLOSE, &CSerialConnectionDlg::OnBnClickedButtonClose)
ON_BN_CLICKED(IDC_BUTTON_SEND, &CSerialConnectionDlg::OnBnClickedButtonSend)
ON_BN_CLICKED(IDC_BUTTON_CLEAN, &CSerialConnectionDlg::OnBnClickedButtonClean)
// ON_EN_CHANGE(IDC_EDIT_Rev, &CSerialConnectionDlg::OnEnChangeEditRev)
//ON_EN_CHANGE(IDC_EDIT_Rev, &CSerialConnectionDlg::OnEnChangeEditRev)
ON_WM_TIMER()
ON_BN_CLICKED(IDC_BUTTON1, &CSerialConnectionDlg::OnBnClickedButton1)
ON_EN_CHANGE(IDC_EDIT_Rev, &CSerialConnectionDlg::OnEnChangeEditRev)
ON_EN_CHANGE(IDC_EDIT_show3, &CSerialConnectionDlg::OnEnChangeEditshow3)
END_MESSAGE_MAP()
// CSerialConnectionDlg 消息处理程序
BOOL CSerialConnectionDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
// 将“关于...”菜单项添加到系统菜单中。
// IDM_ABOUTBOX 必须在系统命令范围内。
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
BOOL bNameValid;
CString strAboutMenu;
bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
ASSERT(bNameValid);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}
// 设置此对话框的图标。 当应用程序主窗口不是对话框时,框架将自动
// 执行此操作
SetIcon(m_hIcon, TRUE); // 设置大图标
SetIcon(m_hIcon, FALSE); // 设置小图标
// TODO: 在此添加额外的初始化代码
//初始化端口
m_combo1.AddString(_T("COM1"));
m_combo1.AddString(_T("COM2"));
m_combo1.AddString(_T("COM3"));
m_combo1.AddString(_T("COM4"));
m_combo1.AddString(_T("COM5"));
m_combo1.AddString(_T("COM6"));
m_combo1.AddString(_T("COM7"));
m_combo1.AddString(_T("COM8"));
m_combo1.AddString(_T("COM9"));
m_combo1.AddString(_T("COM10"));
m_combo1.SetCurSel(1);
//初始化波特率
m_combo2.AddString(_T("1200"));
m_combo2.AddString(_T("2400"));
m_combo2.AddString(_T("4800"));
m_combo2.AddString(_T("9600"));
m_combo2.AddString(_T("19200"));
m_combo2.AddString(_T("38400"));
m_combo2.AddString(_T("57600"));
m_combo2.SetCurSel(3);
//初始化校验位
m_combo3.AddString(_T("NONE"));
m_combo3.AddString(_T("EVEN"));
m_combo3.AddString(_T("ODD"));
m_combo3.SetCurSel(0);
//初始化数据位
m_combo4.AddString(_T("7"));
m_combo4.AddString(_T("8"));
m_combo4.SetCurSel(1);
//初始化停止位
m_combo5.AddString(_T("1"));
m_combo5.AddString(_T("2"));
m_combo5.SetCurSel(0);
GetDlgItem(IDC_BUTTON_OPEN)->EnableWindow(TRUE);//把窗口中的 打开串口 设置为可操作状态
GetDlgItem(IDC_BUTTON_CLOSE)->EnableWindow(FALSE);//把窗口中的 退出 设置为不可操作状态
SetTimer(1, 1000, NULL);
return TRUE; // 除非将焦点设置到控件,否则返回 TRUE
}
//添加的 在对话框cpp文件中加入函数OnComm()的实现
LRESULT CSerialConnectionDlg::OnComm(WPARAM ch, LPARAM port){
CStringArray road;
recvBuf[recvIndex++] = ch;
s.Format("%s", recvBuf);
a += s[recvIndex - 1];
s = "";
CString aa;
char fbuff[256] = { 0 };
memcpy(fbuff, a, 58);
if (fbuff[0] == '>'&&fbuff[57] == '\r'&&recvIndex == 58){ //开始符号一直+结束符一致+长度一致
fbuff[57] = 0x00;
for (int i = 1; i < recvIndex-1; i++){//跳过> 减去'\r'
if (fbuff[i] == '+'){
aa += " ";
}
else{
aa += fbuff[i];
}
}
if (recvIndex == 58){//
recvIndex = 0;
a = "";
}
m_Edit_Receive = aa;
CString temp = aa;
int s0 = temp.ReverseFind(' ');
road.Add(temp.Mid(s0 + 1));
while (s0 > 0)
{
temp = temp.Mid(0, s0);
s0 = temp.ReverseFind(' ');
road.Add(temp.Mid(s0 + 1));
}
m_8 = road.GetAt(0);
m_7 = road.GetAt(1);
m_6 = road.GetAt(2);
m_5 = road.GetAt(3);
m_4 = road.GetAt(4);
m_3 = road.GetAt(5);
m_2 = road.GetAt(6);
m_1 = road.GetAt(7);
}
UpdateData(FALSE);
return 0;
}
void CSerialConnectionDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if ((nID & 0xFFF0) == IDM_ABOUTBOX)
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
else
{
CDialogEx::OnSysCommand(nID, lParam);
}
}
// 如果向对话框添加最小化按钮,则需要下面的代码
// 来绘制该图标。 对于使用文档/视图模型的 MFC 应用程序,
// 这将由框架自动完成。
void CSerialConnectionDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // 用于绘制的设备上下文
SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
// 使图标在工作区矩形中居中
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;
// 绘制图标
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialogEx::OnPaint();
}
}
//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CSerialConnectionDlg::OnQueryDragIcon()
{
return static_cast<HCURSOR>(m_hIcon);
}
//打开串口操作
void CSerialConnectionDlg::OnBnClickedButtonOpen()
{
// TODO: 在此添加控件通知处理程序代码
int SelPort, SelBaudRate, SelDataBits, SelStopBits;
char SelParity;
SelPort = m_combo1.GetCurSel() + 1;
SelStopBits = m_combo5.GetCurSel() + 1;
SelDataBits = m_combo4.GetCurSel() + 7;
UpdateData(TRUE);
SelBaudRate = _ttoi(m_ncombo2);//字符型转整型atoi和_ttoi
SelParity = m_ncombo3.GetAt(0);//获得数据位:GetAt返回的是字符串的第一个字符值
if (m_SerialPort.InitPort(this,SelPort,SelBaudRate,SelParity,SelDataBits,SelStopBits)){
m_SerialPort.StartMonitoring();//启动串口通信检测函数
m_bPortOpen = TRUE;//指示串口已经打开
UpdateData(FALSE);
AfxMessageBox(_T("端口已打开"));
//SetTimer(1, 1000, NULL);
}
else
{
AfxMessageBox(_T("端口被占用"));
//GetDlgItem(IDC_BUTTON_OPEN)->EnableWindow(TRUE);
}
GetDlgItem(IDC_BUTTON_OPEN)->EnableWindow(FALSE);
GetDlgItem(IDC_BUTTON_CLOSE)->EnableWindow(TRUE);
}
void CSerialConnectionDlg::OnBnClickedButtonClose()
{
// TODO: 在此添加控件通知处理程序代码
m_bPortOpen = FALSE;
GetDlgItem(IDC_BUTTON_OPEN)->EnableWindow(!m_bPortOpen);//使能打开串口按钮
//CSerialConnectionDlg::OnClose();
m_SerialPort.ClosePort();
AfxMessageBox(_T("端口已关闭"));
//KillTimer(1);
}
void CSerialConnectionDlg::OnBnClickedButtonSend()
{
// TODO: 在此添加控件通知处理程序代码
if (!m_bPortOpen){//检测串口是否打开
AfxMessageBox("串口未打开");
return ;
}
else//打开执行以下
{
UpdateData(TRUE);// 读入编辑框的数据(把编辑框中字符写入变量)
/* unsigned char a[8] = { 0x01, 0x03, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00 };
USHORT crc = crc16(a, 6);
a[6] = crc >> 8;
a[7] = crc & 0xff;*/
unsigned char a[4] = {0x23,0x30,0x37,0x0d};
m_SerialPort.WriteBin2Port(a, 4);
//m_SerialPort.WriteToPort(m_Edit_Send.GetBuffer(0));//调用函数发送数据*********************************************************************************
//SetTimer(1, 1000, NULL);
//m_SerialPort.WriteToPort();
}
}
void CSerialConnectionDlg::OnBnClickedButtonClean()
{
// TODO: 在此添加控件通知处理程序代码
SetDlgItemText(IDC_EDIT_Rev, NULL);//清空接收框消息
SetDlgItemText(IDC_EDIT_show1, NULL);
SetDlgItemText(IDC_EDIT_show2, NULL);
SetDlgItemText(IDC_EDIT_show3, NULL);
SetDlgItemText(IDC_EDIT_show4, NULL);
SetDlgItemText(IDC_EDIT_show5, NULL);
SetDlgItemText(IDC_EDIT_show6, NULL);
SetDlgItemText(IDC_EDIT_show7, NULL);
SetDlgItemText(IDC_EDIT_show8, NULL);
UpdateData(TRUE);
}
//CRC校验
USHORT CSerialConnectionDlg::crc16(UCHAR *updata, UINT len)
{
UCHAR uchCRCHi = 0xff;
UCHAR uchCRCLo = 0xff;
UINT uindex;
while (len--)
{
uindex = uchCRCHi^*updata++;
uchCRCHi = uchCRCLo^CrcHi[uindex];
uchCRCLo = CrcLo[uindex];
}
return (uchCRCHi << 8 | uchCRCLo);
}
void CSerialConnectionDlg::OnTimer(UINT_PTR nIDEvent)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
switch (nIDEvent)
{
case 1:
{
if (send == 1)
{
send = 0;
recvIndex = 0;//清空数据长度
unsigned char a[4] = { 0x23, 0x30, 0x37, 0x0d };
m_SerialPort.WriteBin2Port(a, 4);
/******************MODBUS发送**************************/
/*unsigned char a[8] = { 0x01, 0x03, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00 };
USHORT crc = crc16(a, 6);
a[6] = crc >> 8;
a[7] = crc & 0xff;
m_SerialPort.WriteBin2Port(a, 8);*/
SetTimer(2, 5000, NULL);
}
break;
}
case 2:
send = 1;
KillTimer(2);
}
CDialogEx::OnTimer(nIDEvent);
}
void CSerialConnectionDlg::OnBnClickedButton1()
{
// TODO: 在此添加控件通知处理程序代码
OnOK();
}
void CSerialConnectionDlg::OnEnChangeEditRev()
{
// TODO: 如果该控件是 RICHEDIT 控件,它将不
// 发送此通知,除非重写 CDialogEx::OnInitDialog()
// 函数并调用 CRichEditCtrl().SetEventMask(),
// 同时将 ENM_CHANGE 标志“或”运算到掩码中。
// TODO: 在此添加控件通知处理程序代码
}
void CSerialConnectionDlg::OnEnChangeEditshow3()
{
// TODO: 如果该控件是 RICHEDIT 控件,它将不
// 发送此通知,除非重写 CDialogEx::OnInitDialog()
// 函数并调用 CRichEditCtrl().SetEventMask(),
// 同时将 ENM_CHANGE 标志“或”运算到掩码中。
// TODO: 在此添加控件通知处理程序代码
}
|
|