⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 talktocardlg.cpp

📁 用VC++编的通过串口控制STC12C5410AD单片机的程序
💻 CPP
📖 第 1 页 / 共 2 页
字号:
// TalkToCarDlg.cpp : implementation file
//

#include "stdafx.h"
#include "TalkToCar.h"
#include "TalkToCarDlg.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

// 符号化常数定义:

// 小车通讯协议中的收、发方地址
const BYTE CAR_ADDR = 0x01;				// 暂定的小车地址
const BYTE PC_ADDR = 0xFE;				// PC机的地址,0xFF留作广播地址

// 小车通讯协议中的命令字
const BYTE READ_MEMORY = 1;				// 读内存命令字
const BYTE WRITE_MEMORY = 2;			// 写内存命令字
const BYTE MOTOR_PWM_CTRL = 3;		// 电机PWM控制
const BYTE RUN_STRAIGHT = 4;			// 走直线
const BYTE RUN_ON_LINE = 5;				// 走轨迹
const BYTE HOLD_GAP = 6;					// 保持距离

// PC程序中自己用的命令代号
const int READ_BYTE = 1;					// 读一个字节命令
const int WRITE_BYTE = 2;					// 写一个字节命令
const int MOTOR_PWM = 3;					// 电机PWM控制
const int RUN_STR = 4;						// 走直线测试
const int READ_SAMPLE = 5;				// 读取轨迹采样数据
const int READ_DIS = 6;						// 读取距离值

// 接收处理状态
const int NO_RCV = 0;
const int WAIT_FRAME_END = 1;

// 电机控制选项
const int FORWARD = 0;						// 对应下拉选项的定义
const int BACKWARD = 1;
const int FLOAT_C = 2;
const int BRAKE_C = 3;

// 特殊PWM 控制值定义
const BYTE FLOAT_PWM = 255;
const BYTE BRAKE_PWM =0;

// 读内存的内容说明 (因为需要用读内存命令处理多种需求)
const int GENERAL_DATA = 0;				// 无特殊意义的数据
const int SAMPLE_DATA = 1;				// 轨迹采样数据
const int DIS_DATA = 2;						// 距离数据
		 
/////////////////////////////////////////////////////////////////////////////
// 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()

/////////////////////////////////////////////////////////////////////////////
// CTalkToCarDlg dialog

CTalkToCarDlg::CTalkToCarDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CTalkToCarDlg::IDD, pParent)
{
	//{{AFX_DATA_INIT(CTalkToCarDlg)
	m_ucWriteData = 0;
	m_ucMotorL_PWM = 0;
	m_ucMotorR_PWM = 0;
	m_ucBase_PWM = 0;
	m_uiLeftRunNum = 0;
	m_iReadData = 0;
	m_szDataAddr = _T("");
	m_ucSampleVal1 = 0;
	m_ucSampleVal2 = 0;
	m_ucSampleVal3 = 0;
	m_ucSampleVal4 = 0;
	m_ucSensorStat = 0;
	m_szSampleAddr = _T("");
	m_szCommandBack = _T("");
	m_szDisValAddr = _T("");
	m_uiGap2Object = 0;
	m_ucDisMeanVal = 0;
	m_ucDisVal1 = 0;
	m_ucDisVal2 = 0;
	m_ucDisVal3 = 0;
	m_ucDisVal4 = 0;
	m_ucDisVal5 = 0;
	m_ucDisVal6 = 0;
	m_ucDisVal7 = 0;
	m_ucDisVal8 = 0;
	//}}AFX_DATA_INIT
	// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CTalkToCarDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CTalkToCarDlg)
	DDX_Control(pDX, IDC_RUN_MODE, m_ctrlRunMode);
	DDX_Control(pDX, IDC_DATA_TYPE, m_ctrlDataType);
	DDX_Control(pDX, IDC_RUN_DIR, m_ctrlRunDir);
	DDX_Control(pDX, IDC_MOTORR_CTRL, m_ctrlMotor_R);
	DDX_Control(pDX, IDC_MOTORL_CTRL, m_ctrlMotor_L);
	DDX_Control(pDX, IDC_SEL_COMMPORT, m_ctrlSelCommPort);
	DDX_Control(pDX, IDC_MSCOMM1, m_ctrlCommToCar);
	DDX_Text(pDX, IDC_WRITE_DATA, m_ucWriteData);
	DDX_Text(pDX, IDC_MOTORL_PWM, m_ucMotorL_PWM);
	DDV_MinMaxByte(pDX, m_ucMotorL_PWM, 0, 250);
	DDX_Text(pDX, IDC_MOTORR_PWM, m_ucMotorR_PWM);
	DDV_MinMaxByte(pDX, m_ucMotorR_PWM, 0, 250);
	DDX_Text(pDX, IDC_BASE_PWM, m_ucBase_PWM);
	DDX_Text(pDX, IDC_LEFT_RUN_NUM, m_uiLeftRunNum);
	DDV_MinMaxUInt(pDX, m_uiLeftRunNum, 0, 65535);
	DDX_Text(pDX, IDC_READ_DATA, m_iReadData);
	DDX_Text(pDX, IDC_DATA_ADDR, m_szDataAddr);
	DDX_Text(pDX, IDC_SAMPLE_VAL1, m_ucSampleVal1);
	DDX_Text(pDX, IDC_SAMPLE_VAL2, m_ucSampleVal2);
	DDX_Text(pDX, IDC_SAMPLE_VAL3, m_ucSampleVal3);
	DDX_Text(pDX, IDC_SAMPLE_VAL4, m_ucSampleVal4);
	DDX_Text(pDX, IDC_SENSOR_STAT, m_ucSensorStat);
	DDX_Text(pDX, IDC_SAMPLE_ADDR, m_szSampleAddr);
	DDX_Text(pDX, IDC_COMMAND_BACK, m_szCommandBack);
	DDX_Text(pDX, IDC_DISVAL_ADDR, m_szDisValAddr);
	DDX_Text(pDX, IDC_GAP2OBJECT, m_uiGap2Object);
	DDX_Text(pDX, IDC_DIS_MEAN_VAL, m_ucDisMeanVal);
	DDX_Text(pDX, IDC_DIS_VAL1, m_ucDisVal1);
	DDX_Text(pDX, IDC_DIS_VAL2, m_ucDisVal2);
	DDX_Text(pDX, IDC_DIS_VAL3, m_ucDisVal3);
	DDX_Text(pDX, IDC_DIS_VAL4, m_ucDisVal4);
	DDX_Text(pDX, IDC_DIS_VAL5, m_ucDisVal5);
	DDX_Text(pDX, IDC_DIS_VAL6, m_ucDisVal6);
	DDX_Text(pDX, IDC_DIS_VAL7, m_ucDisVal7);
	DDX_Text(pDX, IDC_DIS_VAL8, m_ucDisVal8);
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CTalkToCarDlg, CDialog)
	//{{AFX_MSG_MAP(CTalkToCarDlg)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_CBN_SELCHANGE(IDC_SEL_COMMPORT, OnSelCommPort)
	ON_BN_CLICKED(IDC_READ, OnRead)
	ON_BN_CLICKED(IDC_WRITE, OnWrite)
	ON_BN_CLICKED(IDC_PWM_OUT, OnPWM_Out)
	ON_BN_CLICKED(IDC_BRAKE, OnBrake)
	ON_BN_CLICKED(IDC_FLOAT, OnFloat)
	ON_BN_CLICKED(IDC_RUN_STRAIGHT, OnRunStraight)
	ON_BN_CLICKED(IDC_READ_SAMPLE, OnReadSample)
	ON_BN_CLICKED(IDC_READ_DIS, OnReadDis)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CTalkToCarDlg message handlers

BOOL CTalkToCarDlg::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
	GetDlgItem(IDC_READ) -> EnableWindow(false);				// 初始化时将两个按钮禁止,等串口有效后再允许。
	GetDlgItem(IDC_WRITE) -> EnableWindow(false);
	GetDlgItem(IDC_FLOAT) -> EnableWindow(false);
	GetDlgItem(IDC_BRAKE) -> EnableWindow(false);
	GetDlgItem(IDC_PWM_OUT) -> EnableWindow(false);
	GetDlgItem(IDC_RUN_STRAIGHT) -> EnableWindow(false);
	GetDlgItem(IDC_READ_SAMPLE) -> EnableWindow(false);
	GetDlgItem(IDC_READ_DIS) -> EnableWindow(false);
	

	m_ucGetBack = 0;
	m_ucSaveBack = 0;																		// 初始化存取数指针,等效于缓冲区为空

	return TRUE;  // return TRUE  unless you set the focus to a control
}

void CTalkToCarDlg::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 CTalkToCarDlg::OnPaint() 
{
	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();
	}
}

// The system calls this to obtain the cursor to display while the user drags
//  the minimized window.
HCURSOR CTalkToCarDlg::OnQueryDragIcon()
{
	return (HCURSOR) m_hIcon;
}

// 选择串口处理,测试所选择的串口是否存在、可用,使用时再打开。

void CTalkToCarDlg::OnSelCommPort() 
{
	// TODO: Add your control notification handler code here
	int PortNo;

	if(m_ctrlCommToCar.GetPortOpen())							//如果串口开着
	{
		m_ctrlCommToCar.SetPortOpen(false);
	}

	PortNo = m_ctrlSelCommPort.GetCurSel() + 1;

	m_ctrlCommToCar.SetCommPort(PortNo);					//打开串口

	if(!m_ctrlCommToCar.GetPortOpen())						//判断打开是否成功,不成功的话系统会自动弹出错误信息
	{
		m_ctrlCommToCar.SetPortOpen(true);
	}


	GetDlgItem(IDC_READ) -> EnableWindow(true);
	GetDlgItem(IDC_WRITE) -> EnableWindow(true);
	GetDlgItem(IDC_FLOAT) -> EnableWindow(true);
	GetDlgItem(IDC_BRAKE) -> EnableWindow(true);
	GetDlgItem(IDC_PWM_OUT) -> EnableWindow(true);
	GetDlgItem(IDC_RUN_STRAIGHT) -> EnableWindow(true);
	GetDlgItem(IDC_READ_SAMPLE) -> EnableWindow(true);
	GetDlgItem(IDC_READ_DIS) -> EnableWindow(true);


	m_ctrlCommToCar.SetPortOpen(false);						// 此处只是确认一下口是否可用,到实际用时再打开!	
}

BEGIN_EVENTSINK_MAP(CTalkToCarDlg, CDialog)
    //{{AFX_EVENTSINK_MAP(CTalkToCarDlg)
	ON_EVENT(CTalkToCarDlg, IDC_MSCOMM1, 1 /* OnComm */, OnData_T_R, VTS_NONE)
	//}}AFX_EVENTSINK_MAP
END_EVENTSINK_MAP()

// 串口收到数据处理
void CTalkToCarDlg::OnData_T_R() 
{
	// TODO: Add your control notification handler code here
	VARIANT rcv_temp;
	COleSafeArray rcv_temp1;
	long len,k;

	union
	{
		UINT all;
		BYTE b[4];
	}uitemp;

	int	iCommand;

	if(m_ctrlCommToCar.GetCommEvent() == 2)
	{
		// 收到数据
		rcv_temp = m_ctrlCommToCar.GetInput();
		rcv_temp1 = rcv_temp;										// 转换类型
		len = rcv_temp1.GetOneDimSize();				// 得到接收的字节数

		for(k=0;k<len;k++)											// 将数据复制到接收缓冲区
		{
			rcv_temp1.GetElement(&k,&m_ucBackBuf[m_ucSaveBack]);
			m_ucSaveBack++;
		}

		
		iCommand = DataFrame_OK();							// 检测是否为有效帧,

		if(iCommand != -1)
		{
			m_szCommandBack = "成功";							// 增加此显示以便判断小车是否有返回帧
		
			switch(iCommand)												// 因为现在命令较少,故直接在此处理
			{
				case READ_MEMORY:
				{
					uitemp.all = 0;
					uitemp.b[0] = m_ucBackBuf[m_ucStartPtr+1];
					uitemp.b[1] = m_ucBackBuf[m_ucStartPtr+2];

					switch(m_iReadMemContent)
					{
						case GENERAL_DATA:
						{
							gatGeneralData();	
							break;
						}

						case SAMPLE_DATA:
						{
							getSampleData();
							break;
						}

						case DIS_DATA:
						{
							getDisData();
							break;
						}

						default: break;
					}

					break;
				}

				case WRITE_MEMORY:
				{
					uitemp.all = 0;
					uitemp.b[0] = m_ucBackBuf[m_ucStartPtr+1];
					uitemp.b[1] = m_ucBackBuf[m_ucStartPtr+2];
					if(m_ucBackBuf[m_ucStartPtr+3] == 0)
					{
						m_ucWriteData = 0xFF;											// 如果写失败,则将写数据显示为 255
					}
					break;
				}

				default: break;
			}

			this->UpdateData(false);										// s刷新显示
		}
	}
}


// 检测接收缓冲区中是否收到有效帧,如果是,则返回帧中的命令字;
// 没有收到合法帧, 则返回“0”;
// 收到检验和错误帧则返回 “-1”。

// 帧格式:
// 帧头(2字节) 接收方地址(1字节) 发送方地址(1字节) 帧长(1字节) 
// 命令(1字节) 数据域(N字节) 校验和(1字节)
// 校验和 -- 数据帧中从命令开始到数据域结束所有字节的算术和,取最低字节的反码。

int CTalkToCarDlg::DataFrame_OK()
{
	int returnval = 0;
	int rcv_chk,i;
	BYTE sum,j;
	
	while(m_ucGetBack != m_ucSaveBack)
	{
		switch (m_iRcvStat)
		{
			case NO_RCV:
			{		
				// 检测帧头
				rcv_chk = 0;
				if(m_ucBackBuf[m_ucGetBack-5] == 0x55)
				{
					rcv_chk++;
				}
			
				if(m_ucBackBuf[m_ucGetBack-4] == 0xAA)
				{
					rcv_chk++;
				}

				if(m_ucBackBuf[m_ucGetBack-3] == PC_ADDR)
				{
					rcv_chk++;
				}

				if(rcv_chk == 3)
				{
					m_ucStartPtr = m_ucGetBack;
					m_ucEndPtr = m_ucGetBack + m_ucBackBuf[m_ucGetBack-1];
					m_iRcvStat = WAIT_FRAME_END;	
				}
				break;
			}

			case WAIT_FRAME_END:
			{
				if(m_ucEndPtr == m_ucGetBack)
				{
					m_iRcvStat = NO_RCV;											// 恢复初始状态

					sum =0;																		// 检查校验和
					j=m_ucStartPtr;
					for(i=0;i<m_ucBackBuf[m_ucStartPtr-1];i++)
					{
						sum +=m_ucBackBuf[j];
						j++;
					}
					sum = ~sum;
					if(sum == m_ucBackBuf[j])
					{
						returnval = m_ucBackBuf[m_ucStartPtr];		// 返回命令字
					}
					else
					{
						returnval = -1;
					}

					m_ctrlCommToCar.SetPortOpen(false);				// 收完数据帧后关闭串口,释放设备。
				}
				break;
			}

			default:	break;
		}

		m_ucGetBack++;
	}

	return(returnval);
}


// 读按钮操作,打开串口,构建命令帧,启动发送

void CTalkToCarDlg::OnRead() 
{
	// TODO: Add your control notification handler code here

	this->UpdateData(true);				// 将对话框中的地址等数据取回

	if(open_CommPort())
	{
		m_iReadMemContent = GENERAL_DATA;
		makeSendFrame(READ_BYTE, &m_baSendFrame);									// 构建发送帧

		m_iRcvStat = NO_RCV;																			// 初始化接收状态
		m_ctrlCommToCar.SetOutput((COleVariant)m_baSendFrame);		// 启动发送
		m_baSendFrame.RemoveAll();
	}
	else
	{
		m_ctrlCommToCar.SetPortOpen(false);
	}	
}

// 写按钮操作,打开串口,构建命令帧,启动发送

void CTalkToCarDlg::OnWrite() 
{
	// TODO: Add your control notification handler code here
	this->UpdateData(true);				// 将对话框中的地址等数据取回

	if(open_CommPort())
	{
		makeSendFrame(WRITE_BYTE, &m_baSendFrame);							// 构建发送帧

		m_iRcvStat = NO_RCV;																		// 初始化接收状态
		m_ctrlCommToCar.SetOutput((COleVariant)m_baSendFrame);	// 启动发送
		m_baSendFrame.RemoveAll();
	}
	else
	{
		m_ctrlCommToCar.SetPortOpen(false);
	}		
}


// 这是一个自己添加的函数,用鼠标选中类“CTalkToCarDlg”,
// 右键中选择“Add Member Function..."即可

// 函数功能:打开 m_ctrlSelCommPort 中所选的串口,成功返回真。

bool CTalkToCarDlg::open_CommPort()
{
	CString CommConfig;

	int PortNo;

	this->UpdateData(true);	

	
	if(m_ctrlCommToCar.GetPortOpen())							//如果串口开着
	{
		m_ctrlCommToCar.SetPortOpen(false);
	}

	PortNo = m_ctrlSelCommPort.GetCurSel() + 1;

	m_ctrlCommToCar.SetCommPort(PortNo);			//打开串口

	if(!m_ctrlCommToCar.GetPortOpen())				//判断打开是否成功,不成功的话系统会自动弹出错误信息
	{
		m_ctrlCommToCar.SetPortOpen(true);
	}

	CommConfig = _T("19200,N,8,1");						//传输率,无校验,8个数据位,1个停止位
	m_ctrlCommToCar.SetSettings(CommConfig);				//设置串口
	
	//参数1表示接收缓冲中有1个或多于1个字符时,引发一个接收数据的OnComm事件
	m_ctrlCommToCar.SetRThreshold(1);
	
	m_ctrlCommToCar.SetRTSEnable(true);				// 设置RTS为可以发送
	m_ctrlCommToCar.SetInputMode(1);					// 0 表示以文本格式接收,1表示以二进制方式接收

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -