如何用VC++实现串口通信

合集下载

用VC实现PC机与单片机串口通讯

用VC实现PC机与单片机串口通讯

用VC实现PC机与单片机串口通讯梁伯福PC机与单片机串口通讯可以通过多种方式来实现,在这里只介绍使用MSCOMM控件进行通讯。

PC机与单片机进行串口通讯的电路如下:因为单片机输入输出的是TTL电平,而PC机串口输入输出的是RS232电平,其与TTL 电平不兼容,所以要通过RS232接口进行电平转换,这可通过集成电路MAX232来实现。

在这里,我们的通讯采用主从方式,即PC机做主机,单片机作从机,PC机控制单片机发送或者接收数据,单片机没有主动发起通讯的权力。

PC机程序。

我们首先在VC中通过appWizard生成一个基于对话框的程序,接着在对话框中添加MSCOMM控件。

方法是:右击对话框-> insert activeX control -> MSCOMM32.OCX。

添加MSCOMM控件后,我们需要在头文件中定义一个类型为CMScomm的变量。

CMSComm m_msComm;// CMSComm是添加控件后VC自动生成的类接着我们使用此变量对串口进行初始化操作(可在对话框初始化时或通讯前调用此函数)。

void InitComm(){m_msComm.SetCommPort(1); // 设置通讯的串口,可为1,2,….,N//(如你的PC机有N个串口的话)m_msComm.SetInputMode(1); //设置接收模式,0为文本,1为二进制,要想能接收//值为0的数据,一定要设置为二进制模式m_msComm.SetInputLen(0); // 设置读取方式,0为读取接收缓冲区的全部数据m_msComm.SetSettings("4800, n, 8, 1"); //设置串口的波特率为4800,//无校验位,8数据位, 1位停止位m_msComm.SetPortOpen(true); // 打开串口,准备通讯}为了方便,我们这里假定PC机一次只接收或发送一个数据。

VC++串口通信编程详解

VC++串口通信编程详解

VC++串口通信编程详解在工业控制中,工控机(一般都基于Windows平台)经常需要与智能仪表通过串口进行通信。

串口通信方便易行,应用广泛。

一般情况下,工控机和各智能仪表通过RS485总线进行通信。

RS485的通信方式是半双工的,只能由作为主节点的工控PC机依次轮询网络上的各智能控制单元子节点。

每次通信都是由PC机通过串口向智能控制单元发布命令,智能控制单元在接收到正确的命令后作出应答。

在Win32下,可以使用两种编程方式实现串口通信,其一是使用ActiveX控件,这种方法程序简单,但欠灵活。

其二是调用Windows 的API函数,这种方法可以清楚地掌握串口通信的机制,并且自由灵活。

本文我们只介绍API串口通信部分。

串口的操作可以有两种操作方式:同步操作方式和重叠操作方式(又称为异步操作方式)。

同步操作时,API函数会阻塞直到操作完成以后才能返回(在多线程方式中,虽然不会阻塞主线程,但是仍然会阻塞监听线程);而重叠操作方式,API函数会立即返回,操作在后台进行,避免线程的阻塞。

无论那种操作方式,一般都通过四个步骤来完成:(1)打开串口(2)配置串口(3)读写串口(4)关闭串口1、打开串口Win32系统把文件的概念进行了扩展。

无论是文件、通信设备、命名管道、邮件槽、磁盘、还是控制台,都是用API函数CreateFile来打开或创建的。

该函数的原型为:C++代码1. HANDLE CreateFile( LPCTSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDistribution, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile);lpFileName:将要打开的串口逻辑名,如“COM1”;dwDesiredAccess:指定串口访问的类型,可以是读取、写入或二者并列;dwShareMode:指定共享属性,由于串口不能共享,该参数必须置为0;lpSecurityAttributes:引用安全性属性结构,缺省值为NULL;dwCreationDistribution:创建标志,对串口操作该参数必须置为OPEN_EXISTING;dwFlagsAndAttributes:属性描述,用于指定该串口是否进行异步操作,该值为FILE_FLAG_OVERLAPPED,表示使用异步的I/O;该值为0,表示同步I/O操作;hTemplateFile:对串口而言该参数必须置为NULL。

VC++串口通信编程

VC++串口通信编程

在工业控制中,工控机(一般都基于Windows平台)经常需要与智能仪表通过串口进行通信。

串口通信方便易行,应用广泛。

一般情况下,工控机和各智能仪表通过RS485总线进行通信。

RS485的通信方式是半双工的,只能由作为主节点的工控PC机依次轮询网络上的各智能控制单元子节点。

每次通信都是由PC机通过串口向智能控制单元发布命令,智能控制单元在接收到正确的命令后作出应答。

在Win32下,可以使用两种编程方式实现串口通信,其一是使用ActiveX控件,这种方法程序简单,但欠灵活。

其二是调用Windows的API函数,这种方法可以清楚地掌握串口通信的机制,并且自由灵活。

本文我们只介绍API串口通信部分。

串口的操作可以有两种操作方式:同步操作方式和重叠操作方式(又称为异步操作方式)。

同步操作时,API函数会阻塞直到操作完成以后才能返回(在多线程方式中,虽然不会阻塞主线程,但是仍然会阻塞监听线程);而重叠操作方式,API函数会立即返回,操作在后台进行,避免线程的阻塞。

无论那种操作方式,一般都通过四个步骤来完成:(1)打开串口(2)配置串口(3)读写串口(4)关闭串口(1)打开串口Win32系统把文件的概念进行了扩展。

无论是文件、通信设备、命名管道、邮件槽、磁盘、还是控制台,都是用API函数CreateFile来打开或创建的。

该函数的原型为:HANDLE CreateFile( LPCTSTR lpFileName,DWORD dwDesiredAccess,DWORD dwShareMode,LPSECURITY_ATTRIBUTES lpSecurityAttributes,DWORD dwCreationDistribution,DWORD dwFlagsAndAttributes,HANDLE hTemplateFile);•lpFileName:将要打开的串口逻辑名,如“COM1”;•dwDesiredAccess:指定串口访问的类型,可以是读取、写入或二者并列;•dwShareMode:指定共享属性,由于串口不能共享,该参数必须置为0;•lpSecurityAttributes:引用安全性属性结构,缺省值为NULL;•dwCreationDistribution:创建标志,对串口操作该参数必须置为OPEN_EXISTING;•dwFlagsAndAttributes:属性描述,用于指定该串口是否进行异步操作,该值为FILE_FLAG_OVERLAPPED,表示使用异步的I/O;该值为0,表示同步I/O操作;•hTemplateFile:对串口而言该参数必须置为NULL;同步I/O方式打开串口的示例代码:HANDLE hCom; //全局变量,串口句柄hCom=CreateFile("COM1",//COM1口GENERIC_READ|GENERIC_WRITE, //允许读和写0, //独占方式NULL,OPEN_EXISTING, //打开而不是创建0, //同步方式NULL);if(hCom==(HANDLE)-1){AfxMessageBox("打开COM失败!");return FALSE;}return TRUE;重叠I/O打开串口的示例代码:HANDLE hCom; //全局变量,串口句柄hCom =CreateFile("COM1", //COM1口GENERIC_READ|GENERIC_WRITE, //允许读和写0, //独占方式NULL,OPEN_EXISTING, //打开而不是创建FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED, //重叠方式NULL);if(hCom ==INVALID_HANDLE_VALUE){AfxMessageBox("打开COM失败!");return FALSE;}return TRUE;(2)、配置串口在打开通讯设备句柄后,常常需要对串口进行一些初始化配置工作。

VC++6.0实现串口

VC++6.0实现串口
if(WriteFile(hCom,m_strSend,m_strSend.GetLength(),&factdata,&wOverLaped))//开始发送数据
{
IsStop = True;
}
else
{
res = WaitForSingleObject(wOverLaped.hEvent,5000); //延时5秒,等待数据发送
3
窗体模块程序如下:
(1)在pc_pc_apiDlg.cpp文件的开始处,增加全局变量、消息和线程函数,代码如下:
const CM_RECEIVE = WM_USER+100;//自定义一个消息
OVERLAPPED tOverLaped= {0};//线程函数使用的OVERLAPPED结构
OVERLAPPED wOverLaped = {0};//写操作使用的OVERLAPPED结构
(2)删除对话框中原来的Static文本,用面板为对话框添加如表6-2所示的控件,并按照图6-2所示放置。
表6-2对话框的控件类型、ID及相关属性
控件类型
ID号
标题
属性
功能
静态文本
默认
显示接收字符区
默认
标签
静态文本
默认
输入发送字符区
默认
标签
编辑框
IDC_receive
——
Horizontal scroll(√)
ON_WM_QUERYDRAGICON()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
(3)设置初始化函数OnInitDialog(),添加代码实现对话框串口通信的初始化工作,如下:
BOOLCPc_pcDlg::OnInitDialog()

vc++mfc串口通信

vc++mfc串口通信

Vc++串口通信(加密解密以及反馈协议)一.主要功能:实现两台计算机通过串口进行数据通信。

二.软件特色:与本软件传输协议不同的串口信息接收到之后不做显示,发送过程中经过数据包加首部尾部来确定数据是否为同一个协议,之后再经过加密发送,接受时先解密,然后经过除去首部跟尾部来得到本来的数据。

三.加密原理:发送时先加首部跟尾部,然后再将所有字符串转换成字符数组,进而对数组中的每个字符进行处理,具体方法是首先获得本次发送的数据总长度,单个字符减去本次字符串总长度的数字,再将数组转换成字符串发送出去,解码时先将受到的字符串转换成字符数组,再将每个字符加上本次接收到的字符串总长度,然后除去首部跟尾部,得到实际有用的数据。

四.协议原理:在每次收到数据之后进行判断,是否为预先设定的反馈数据,如果是,则不做处理,如果不是,则进行发送反馈数据操作。

每次发送完数据对话框有提示“数据已发送“,当收到反馈数据时,提示”数据已成功接收“。

五.主要问题:单次发送的数据不能大于33个字符,否则会接收不正常。

波特率已加到程序里面固定为“115200“,如果太小了可能会出现接收不到信息或者接收速度慢等情况。

六.界面图示:1.发送完数据,但是对方未收到。

2.发送完数据,对方已经成功接收。

七.部分代码界面设计类向导中的函数设计“serilDlg.cpp”文件内部代码#include "stdafx.h"#include "seril.h"#include "serilDlg.h"#ifdef _DEBUG#define new DEBUG_NEW#undef THIS_FILEstatic char THIS_FILE[] = __FILE__;#endifint comseril;///////////////////////////////////////////////////////////////////////////// // CAboutDlg dialog used for App Aboutclass 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// Implementationprotected://{{AFX_MSG(CAboutDlg)//}}AFX_MSGDECLARE_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_MAPEND_MESSAGE_MAP()/////////////////////////////////////////////////////////////////////////////// CSerilDlg dialogCSerilDlg::CSerilDlg(CWnd* pParent /*=NULL*/): CDialog(CSerilDlg::IDD, pParent){//{{AFX_DATA_INIT(CSerilDlg)m_strRXData = _T("");m_strTXData = _T("");m_TestFlag = _T("");//}}AFX_DATA_INIT// Note that LoadIcon does not require a subsequent DestroyIcon in Win32 m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);}void CSerilDlg::DoDataExchange(CDataExchange* pDX){CDialog::DoDataExchange(pDX);//{{AFX_DATA_MAP(CSerilDlg)DDX_Control(pDX, IDC_OPENSERIL, m_Opensril);DDX_Control(pDX, IDC_COM, m_serilcom);DDX_Text(pDX, IDC_EDIT_RXDATA, m_strRXData);DDX_Text(pDX, IDC_EDIT_TXDATA, m_strTXData);DDX_Control(pDX, IDC_MSCOMM1, m_ctrlComm);DDX_Text(pDX, IDC_TESTFLAG, m_TestFlag);//}}AFX_DATA_MAP}BEGIN_MESSAGE_MAP(CSerilDlg, CDialog)//{{AFX_MSG_MAP(CSerilDlg)ON_WM_SYSCOMMAND()ON_WM_PAINT()ON_WM_QUERYDRAGICON()ON_BN_CLICKED(IDC_CLEAR, OnClear)ON_BN_CLICKED(IDC_CLEARSEND, OnClearsend)ON_CBN_CLOSEUP(IDC_COM, OnCloseupCom)ON_BN_CLICKED(IDC_FASONG, OnFasong)ON_BN_CLICKED(IDC_OPENSERIL, OnOpenseril)//}}AFX_MSG_MAPEND_MESSAGE_MAP()/////////////////////////////////////////////////////////////////////////////// CSerilDlg message handlersBOOL CSerilDlg::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 dialogSetIcon(m_hIcon, TRUE); // Set big iconSetIcon(m_hIcon, FALSE); // Set small icon// TODO: Add extra initialization herereturn TRUE; // return TRUE unless you set the focus to a control}void CSerilDlg::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 CSerilDlg::OnPaint(){if (IsIconic()){CPaintDC dc(this); // device context for paintingSendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);// Center icon in client rectangleint 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 icondc.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 CSerilDlg::OnQueryDragIcon(){return (HCURSOR) m_hIcon;}BEGIN_EVENTSINK_MAP(CSerilDlg, CDialog)//{{AFX_EVENTSINK_MAP(CSerilDlg)ON_EVENT(CSerilDlg, IDC_MSCOMM1, 1 /* OnComm */, OnComm, VTS_NONE)//}}AFX_EVENTSINK_MAPEND_EVENTSINK_MAP()void CSerilDlg::OnComm(){// TODO: Add your control notification handler code hereVARIANT variant_inp;COleSafeArray safearray_inp;LONG len,k;BYTE rxdata[20480],rxtemp[20480]={0},top[20480],down[20480],jm[20480],jm1[20480]; //设置BYTE数组An 8-bit integerthat is not signed.CString strtemp,test,test1;if (m_ctrlComm.GetCommEvent() == 2) //事件值为2表示接收缓冲区内有字符{ // CString rw="rw";////////以下你可以根据自己的通信协议加入处理代码variant_inp = m_ctrlComm.GetInput(); //读缓冲区safearray_inp = variant_inp; //VARIANT型变量转换为ColeSafeArray型变量len = safearray_inp.GetOneDimSize(); //得到有效数据长度for(k = 0;k < len;k++){safearray_inp.GetElement(&k,rxdata+k);//转换为BYTE型数组}if(rxdata[0] == 'r'&&rxdata[1] == 'e'&&rxdata[2] == 'c'&&rxdata[3] == 'i'&&rxdata[4] == 'v'&&rxdata[5] == 'e'){m_TestFlag = "已被成功接收";}else{m_ctrlComm.SetOutput(COleVariant("recive"));}for (k=0;k<5;k++){top[k]=rxdata[k];}for(k=0;k<4;k++){down[k]=rxdata[len-4+k];}if(top[0] == 'b' && top[1] == 'e' && top[2] == 'g' && top[3] == 'i' && top[4] == 'n' && down[0] == 'o' && down[1] == 'v' && down[2] == 'e' && down[3] == 'r'){for(k=0;k<len-9;k++){rxtemp[k] = rxdata[k+5];}for(k=0;k<len-9;k++){jm1[k] = (rxtemp[k] -len+9);}for(k = 0;k < len-9;k++) //将数组转换为Cstring型变量{BYTE bt = *(char*)(jm1+k); //字符型strtemp.Format("%c",bt); //将字符送入临时变量strtemp存放m_strRXData += strtemp;}}}UpdateData(FALSE); //更新编辑框内容(主要是接收编辑框中的)}void CSerilDlg::OnFasong(){long siz,k;CString SendAll,sendal;UpdateData(TRUE); //读取编辑框内容siz = strlen( m_strTXData) ;char cha[20480] ;char cha1[20480];char cha2[20480];strcpy(cha, m_strTXData);for (k=0;k<siz;k++){cha1[k] = cha[k] +siz ;}CString str(cha1,siz);SendAll = "begin" + str + "over";m_ctrlComm.SetOutput(COleVariant(SendAll)); //发送数据m_TestFlag = "数据已发送";UpdateData(FALSE); //读取编辑框内容}void CSerilDlg::OnOpenseril(){// TODO: Add your control notification handler code herem_ctrlComm.SetCommPort(comseril); //选择com口if ( m_ctrlComm.GetPortOpen() ){m_ctrlComm.SetPortOpen(FALSE);// 关闭串口// AfxMessageBox("cannot open serial port");AfxMessageBox("串口已关闭");}else{m_ctrlComm.SetPortOpen(TRUE);//打开串口AfxMessageBox("串口打开成功");SetDlgItemText(IDC_OPENSERIL,"关闭串口"); //显示串口已经关闭m_ctrlComm.SetSettings("115200,n,8,1"); //波特率9600,无校验,8个数据位,1个停止位m_ctrlComm.SetInputMode(1); //1:表示以二进制方式检取数据m_ctrlComm.SetRThreshold(1); //参数1表示每当串口接收缓冲区中有多于或等于1个字符时将引发一个接收数据的OnComm事件m_ctrlComm.SetInputLen(0); //设置当前接收区数据长度为0m_ctrlComm.GetInput(); //先预读缓冲区以清除残留数据// m_TestFlag = "未测试";UpdateData(FALSE);}}void CSerilDlg::OnCloseupCom(){comseril = m_serilcom.GetCurSel();}void CSerilDlg::OnClear(){m_strRXData = "";UpdateData(FALSE); //更新编辑框内容// TODO: Add your control notification handler code here}void CSerilDlg::OnClearsend(){// TODO: Add your control notification handler code herem_strTXData = "";UpdateData(FALSE);}、Seril.h内代码// serilDlg.h : header file////{{AFX_INCLUDES()#include "mscomm.h"//}}AFX_INCLUDES#if !defined(AFX_SERILDLG_H__1B7176B4_DDC7_45B3_B636_2597E461F275__INCLUDED_) #define AFX_SERILDLG_H__1B7176B4_DDC7_45B3_B636_2597E461F275__INCLUDED_#if _MSC_VER > 1000#pragma once#endif // _MSC_VER > 1000/////////////////////////////////////////////////////////////////////////////// CSerilDlg dialogclass CSerilDlg : public CDialog{// Constructionpublic:CSerilDlg(CWnd* pParent = NULL); // standard constructor// Dialog Data//{{AFX_DATA(CSerilDlg)enum { IDD = IDD_SERIL_DIALOG };CButton m_Opensril;CComboBox m_serilcom;CString m_strRXData;CString m_strTXData;CMSComm m_ctrlComm;CString m_TestFlag;//}}AFX_DATA// ClassWizard generated virtual function overrides//{{AFX_VIRTUAL(CSerilDlg)protected:virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support//}}AFX_VIRTUAL// Implementationprotected:HICON m_hIcon;// Generated message map functions//{{AFX_MSG(CSerilDlg)virtual BOOL OnInitDialog();afx_msg void OnSysCommand(UINT nID, LPARAM lParam);afx_msg void OnPaint();afx_msg HCURSOR OnQueryDragIcon();afx_msg void OnClear();afx_msg void OnClearsend();afx_msg void OnCloseupCom();afx_msg void OnFasong();afx_msg void OnComm();afx_msg void OnOpenseril();DECLARE_EVENTSINK_MAP()//}}AFX_MSGDECLARE_MESSAGE_MAP()};//{{AFX_INSERT_LOCATION}}// Microsoft Visual C++ will insert additional declarations immediately before the previous line.#endif// !defined(AFX_SERILDLG_H__1B7176B4_DDC7_45B3_B636_2597E461F275__INCLUDED_)日期:2013-4-10。

在VS(VC)2010中使用MSComm控件实现串口通信的详细步骤

在VS(VC)2010中使用MSComm控件实现串口通信的详细步骤
void CCommTestDlg::OnBnClickedButtonSend() {
// TODO: 在¨²此ä?添¬¨ª加¨®控?件t通ª¡§知a处ä|理¤¨ª程¨¬序¨°代䨲码? }
void CCommTestDlg::OnBnClickedButtonOpen() { // TODO: 在¨²此ä?添¬¨ª加¨®控?件t通ª¡§知a处ä|理¤¨ª程¨¬序¨°代䨲码? }
10. 添加关闭串口按钮的消息响应函数 void CCommTestDlg::OnBnClickedButtonClose() { // TODO: 在此添加控件通知处理程序代码 m_mscomm.put_PortOpen(FALSE);//关闭串口 AfxMessageBox(_T("串口 1 已关闭")); } 11. 添加发送按钮消息响应函数 void CCommTestDlg::OnBnClickedButtonSend() { // TODO: 在此添加控件通知处理程序代码 UpdateData(true); //读取编辑框内容 m_mscomm.put_Output(COleVariant(m_EditSend));//发送数据 m_EditSend.Empty(); //发送后清空输入框 UpdateData(false); //更新编辑框内容 } 12. 接收数据 void CCommTestDlg::OnCommMscomm1() { // TODO: 在此处添加消息处理程序代码 static unsigned int cnt=0; VARIANT variant_inp; COleSafeArray safearray_inp; long len,k; unsigned int data[1024]={0}; byte rxdata[1024]; //设置 BYTE 数组 CString strtemp; if(m_mscomm.get_CommEvent()==2) //值为 2 表示接收缓冲区内有字符 {

用VC++写上位机软件实现单片机串口通讯

用VC++写上位机软件实现单片机串口通讯

ucSet = (unsigned char) ((FC_RTSCTS&FC_RTSCTS) ! = 0);
ucSet = (unsigned char) ((FC_RTSCTS&FC_XONXOFF) ! = 0);
if (!SetCommState(m_hIDComDev, &dcb)‖
int _inp(unsigned shot port)
该函数从端口读取一个字节,端口号为0~65535。
写端口的函数原型为:
int _outp(unsigned shot port, int databyte)
该函数向指定端口写入一个字节。
不同的计算机串口地址可能不一样,通过向串口的控制及收发寄存器进行读写,可以实现灵活的串口通信功能,由于涉及具体的硬
!SetupComm(m_hIDComDev,10000,10000)‖
m_OverlappedRead. hEvent ==NULL‖
m_OverlappedWrite. hEvent ==NULL)
{
DWORD dwError = GetLastError();
if (m_OverlappedRead. hEvent != NULL)
}
}
1.2 接收例程
DCB ComDcb; //设备控制块
HANDLE hCom; //global handle
hCom = CreateFile ("COM1",GENERIC_READ| GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
GetCommState(m_hIDComDev, &dcb);

VC串口通讯实例

VC串口通讯实例

在VC++中有两种方法可以进行串口通讯。

一种是利用Microsoft公司提供的ActiveX 控件Microsoft Communications Control。

另一种是直接用VC++访问串口。

下面将简述这两种方法。

一、Microsoft Communications ControlMicrosoft公司在WINDOWS中提供了一个串口通讯控件,用它,我们可以很简单的利用串口进行通讯。

在使用它之前,应将控件加在应用程序的对话框上。

然后再用ClassWizard 生成相应的对象。

现在我们可以使用它了。

该控件有很多自己的属性,你可以通过它的属性窗口来设置,也可以用程序设置。

我推荐用程序设置,这样更灵活。

SetCommPort:指定使用的串口。

GetCommPort:得到当前使用的串口。

SetSettings:指定串口的参数。

一般设为默认参数"9600,N,8,1"。

这样方便与其他串口进行通讯。

GetSettings:取得串口参数。

SetPortOpen:打开或关闭串口,当一个程序打开串口时,另外的程序将无法使用该串口。

GetPortOpen:取得串口状态。

GetInBufferCount:输入缓冲区中接受到的字符数。

SetInPutLen:一次读取输入缓冲区的字符数。

设置为0时,程序将读取缓冲区的全部字符。

GetInPut:读取输入缓冲区。

GetOutBufferCount:输出缓冲区中待发送的字符数。

SetOutPut:写入输出缓冲区。

一般而言,使用上述函数和属性就可以进行串口通讯了。

以下是一个范例。

#define MESSAGELENGTH 100class CMyDialog : public CDialog{protected:VARIANT InBuffer;VARIANT OutBuffer;CMSComm m_Com;public:......}BOOL CMyDiaLog::OnInitDialog(){CDialog::OnInitDialog();m_Com.SetCommPort(1);if (!m_Com.GetPortOpen()) {m_Com.SetSettings("57600,N,8,1");m_Com.SetPortOpen(true);m_Com.SetInBufferCount(0);SetTimer(1,10,NULL);InBuffer.bstrVal=new unsigned short[MESSAGELENGTH]; OutBuffer.bstrVal=new unsigned short[MESSAGELENGTH]; OutBuffer.vt=VT_BSTR;}return true;}void CMyDiaLog::OnTimer(UINT nIDEvent){if (m_Com.GetInBufferCount()>=MESSAGELENGTH) { InBuffer=m_Com.GetInput();// handle the InBuffer.// Fill the OutBuffer.m_Com.SetOutput(OutBuffer);}CDialog::OnTimer(nIDEvent);}用该控件传输的数据是UNICODE格式。

vc++_串口上位机编程实例 附vc串口通信(接收)

vc++_串口上位机编程实例  附vc串口通信(接收)

VC++串口上位机简单例程(源码及详细步骤)VC++编写简单串口上位机程序串口通信,MCU跟PC通信经常用到的一种通信方式,做界面、写上位机程序的编程语言、编译环境等不少,VB、C#、LABVIEW等等,我会的语言很少,C语言用得比较多,但是还没有找到如何用C语言来写串口通信上位机程序的资料,在图书管理找到了用VC++编写串口上位机的资料,参考书籍,用自己相当蹩脚的C++写出了一个简单的串口上位机程序,分享一下,体验一下单片机和PC通信的乐趣。

编译环境:VC++6.0操作系统:VMWare虚拟出来的Windows XP程序实现功能:1、PC初始化COM1口,使用n81方式,波特率57600与单片机通信。

PC的COM口编号可以通过如下方式修改:当然也可以通过上位机软件编写,通过按钮来选择COM端口号,但是此次仅仅是简单的例程,就没有弄那么复杂了。

COM1口可用的话,会提示串口初始化完毕。

否则会提示串口已经打开Port already open,表示串口已经打开,被占用了。

2、点击开始转换,串口会向单片机发送0xaa,单片机串口中断接收到0xaa后启动ADC 转换一次,并把转换结果ADCL、ADCH共两个字节的结果发送至PC,PC进行数值转换后在窗口里显示。

(见文章末尾图)3、为防止串口被一只占用,点击关闭串口可以关闭COM1,供其它程序使用,点击后按钮变为打开串口,点击可重新打开COM1。

程序的编写:1、打开VC++6.0建立基于对话框的MFC应用程序Test,2、在项目中插入MSComm控件:工程->增加到工程->Components and Controls->双击Registered ActiveX Controls->选择Microsoft Communications Control, version 6.0->Insert,按默认值添加,你会发现多了个电话图标,这是增加后串口通信控件。

Vc++串口通信

Vc++串口通信
(3).波特率的设置
TMOD:工作在方式2
PCON:只有工作在方式1、2、3时,如果PCON的SMOD为高电平,则通信整度加倍。
SMOD — — —
计算定时器初值:定时器初值是由波特率=2SMOD×fosc/[32×12(256-X)]计算得到。
---- 在ClassWizard中为新创建的通信控件定义成员对象(CMSComm m_Serial),通过该对象便可以对串口属性进行设置,MSComm 控件共有27个属性,这里只介绍其中几个常用属性:
---- CommPort 设置并返回通讯端口号,缺省为COM1。
---- Settings 以字符串的形式设置并返回波特率、奇偶校验、数据位、停止位。
中断设置:
SETB ES ;开串行中断
SETB EA ;中断启动
串行中断优先级由中断优先控制寄存器IP中的PS决定。
二、VC编程实现串口通信软件
好,串口通信的基本概念和通信规则我们已经大概的有一个了解了,相信大家都已经熟记在心了。下面,我们开始编写上位机了。先让我们来了解一下串口通信上位机编写的方法有哪些以及要用到哪些技术,其实到现在为止我自己也是一窍不通,也没有具体的书参考,先我们还是这样画葫芦画下去吧,本人对VC的研究也不是很透彻,还得去学好C++,不过一步一步慢慢来吧,告诉自己坚持到底,要坚持到底!
RB8:接收数据位。方式0不使用这位。方式1下,如果SM2=0,RB8的内容是接收到的停止位。在方式2或方式3下,存放接收到的第9位数据。
TI:发送中断标志位。在方式0下,发送完第8位数据时,TI=1。在其它方式下,开始发送停止位时,TI=1。在任何工作方式下TI必须由软件清0。
RI:接收中断标志位。在方式0下,接收完第8位数据时,RI=1。在其它方式下,接收到停止位时,RI=1。在任何工作方式下RI也必须由软件清0。

VC实现串行通讯的三种途径

VC实现串行通讯的三种途径

VC实现串行通讯的三种途径介绍了串行通讯的基本原理,以及在Win98,Win2000环境下实现串行通讯的三种方法,并给出了用Visual C++6.0编写的相应的应用程序。

关键词:VC,串行通讯,CserialPort类,Win API随着计算机系统的应用和微机网络的发展,计算机同外设间的通讯功能越发显得重要。

其中,串行通讯因具有连接简单、使用灵活方便、数据传递可靠等优点,在工业监控、数据采集和实时控制系统中得到了广泛的应用。

1 串行通讯的基本原理所谓“串行通讯”是指外设和计算机间使用了数据线、控制线和地线,数据在数据线上一位一位地进行传输,每一位数据都占据一个固定的时间长度。

这种通讯方式使用的数据线少,在远距离通讯中可以节约通讯成本,当然,其传输速度比并行传输慢。

计算机与外部设备进行数据交换往往采用RS-232进行接收,上传数据和指令,如图1所示。

在Windows环境(Win98、Windows2000)下,串口是系统资源的一部分。

应用程序要使用串口进行通讯,必须在使用之前向操作系统提出资源申请要求,即打开串口,通讯完成后必须释放资源,即关闭串口。

2 利用MSComm控件2.1 简介MSComm控件MSComm控件在编程时非常方便,而且在VC、VB、Delphi等语言中均可使用。

MSCom m是Microsoft公司提供的简化Windows串行通讯编程的ActiveX控件,它为应用程序提供了处理串行通讯的两种方法:一是数据驱动方法,一是查询法。

2.2 编程实现在使用MSComm控件开发失重秤采样显示的程序中,采用了事件驱动法,这种方法是在接收到数据时触发事件并获取缓冲区的数据,下面是其实现程序:第一步,利用MFC向导建立基于对话框的应用程序CcommDlg,在项目中插入Mscomm 控件。

第二步,初始化MSComm控件的参数,现场采样与计算机进行串口通讯时采用8个数据位、1个停止位,无校验,波特率9600。

用VC6。0实现串行通讯的三种方法

用VC6。0实现串行通讯的三种方法

摘要:本文介绍了在Windows平台下串行通信的实现机制,讨论了根据不同的条件用Visual C++ 设计串行通信程序的三种方法,并结合实际,实现对温度数据的接收监控。

在实验室和工业应用中,串口是常用的计算机与外部串行设备之间的数据传输通道,由于串行通信方便易行,所以应用广泛。

依据不同的条件实现对串口的灵活编程控制是我们所需要的。

在光学镜片镀膜工艺中,用单片机进行多路温度数据采集控制,采集结果以串行方式进入主机,每隔10S向主机发送一次采样数据,主机向单片机发送相关的控制命令,实现串行数据接收,处理,记录,显示,实时绘制曲线。

串行通信程序开发环境为 VC++ 6.0。

Windows下串行通信与以往DOS下串行通信程序不同的是,Windows不提倡应用程序直接控制硬件,而是通过Windows操作系统提供的设备驱动程序来进行数据传递。

串行口在Win 32中是作为文件来进行处理的,而不是直接对端口进行操作,对于串行通信,Win 32 提供了相应的文件I/O函数与通信函数,通过了解这些函数的使用,可以编制出符合不同需要的通信程序。

与通信设备相关的结构有COMMCONFIG ,COMMPROP,COMMTIMEOUTS,COMSTAT,DCB,MODEMDEVCAPS,MODEMSETTINGS共7个,与通信有关的Windows API函数共有26个,详细说明可参考MSDN帮助文件。

以下将结合实例,给出实现串行通信的三种方法。

实现串行通信的三种方法方法一:使用VC++提供的串行通信控件MSComm 首先,在对话框中创建通信控件,若Control工具栏中缺少该控件,可通过菜单Project --> Add to Project --> Components and Control插入即可,再将该控件从工具箱中拉到对话框中。

此时,你只需要关心控件提供的对 Windows 通讯驱动程序的 API 函数的接口。

VC实现串口通信项目源码

VC实现串口通信项目源码

VC实现串口通信项目源码以下是一个简单的串口通信项目的VC实现源码,包括了串口初始化、发送数据、接收数据等基本功能。

```#include <Windows.h>#include <stdio.h>#define BUFFER_SIZE 1024HANDLE hSerial;//初始化串口参数BOOL InitSerialPort//打开串口hSerial = CreateFile("\\\\.\\COM1", GENERIC_READ ,GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);if (hSerial == INVALID_HANDLE_VALUE)printf("Failed to open serial port\n");return FALSE;}//配置串口参数DCB dcbSerialParams = { 0 };dcbSerialParams.DCBlength = sizeof(dcbSerialParams); printf("Failed to get serial port state\n"); CloseHandle(hSerial);return FALSE;}dcbSerialParams.BaudRate = CBR_9600; // 波特率为9600 dcbSerialParams.ByteSize = 8; // 8位数据位dcbSerialParams.Parity = NOPARITY; // 无奇偶校验dcbSerialParams.StopBits = ONESTOPBIT;// 1位停止位printf("Failed to set serial port state\n"); CloseHandle(hSerial);return FALSE;}//设置超时操作CloseHandle(hSerial);return FALSE;}return TRUE;//发送数据BOOL SendData(const char* data)DWORD bytesWritten;if (!WriteFile(hSerial, data, strlen(data), &bytesWritten, NULL))printf("Failed to send data\n");CloseHandle(hSerial);return FALSE;}return TRUE;//接收数据BOOL ReceiveData(char* buffer, DWORD size)DWORD bytesRead;if (!ReadFile(hSerial, buffer, size, &bytesRead, NULL))printf("Failed to receive data\n");CloseHandle(hSerial);return FALSE;}return TRUE;if (!InitSerialPort()return 1;}char sendBuffer[BUFFER_SIZE];char receiveBuffer[BUFFER_SIZE];//发送数据printf("Enter data to send: ");gets_s(sendBuffer, BUFFER_SIZE);if (!SendData(sendBuffer))return 1;}//接收数据printf("Receiving data...\n");if (!ReceiveData(receiveBuffer, BUFFER_SIZE)) return 1;}printf("Received data: %s\n", receiveBuffer); CloseHandle(hSerial);```这个项目使用了Windows的串口通信API函数来实现串口的初始化、发送数据和接收数据操作。

利用VC中的通讯控件开发串形通信程序

利用VC中的通讯控件开发串形通信程序

利用VC中的通讯控件开发串形通信程序随着信息技术的不断发展和更新,人们对通信技术的要求也越来越高。

在通信领域中,串行通信技术已经成为了一种非常重要的通信技术。

串行通信方式就是将一串字符传输到另一台计算机上,这种通信方式在嵌入式系统、工业自动化、智能控制等领域得到了广泛应用。

针对这种需求,VC中提供了通讯控件,开发人员可以利用通讯控件来实现串行通信程序的开发。

VC中的通讯控件可以为应用程序提供方便的串行通信功能,它包括文本框、串口组合框、串口设置、读写按钮等,提供了多种通信方式和参数配置。

通讯控件支持多线程,可以同时进行多个设备的通信。

通讯控件使用方便,开发人员只需要添加相应的控件到界面并进行相应的配置即可实现串行通信。

串口通信是串行通信中最常使用的通信方式之一。

它通过串口将数据传输到计算机上,串口通信一般包括了以下四个参数:波特率、数据位、停止位和奇偶校验位。

开发人员在开发串口通信程序时需要根据通讯控件提供的相关参数进行配置。

针对串口通信,我们可以通过VC中的通讯控件进行实现。

以下是开发串口通信程序的具体步骤:首先,我们需要在VC中新建MFC应用程序,进入对话框编辑器进行界面的设计。

在界面中添加文本框、串口组合框、串口设置和读写按钮等控件。

在串口数据库中可以选择相应设备的名称和相关参数进行配置。

其次,我们需要在代码中添加串口通信的实现。

在实现中,我们可以通过串口对象打开、关闭串口,读取、写入数据等操作。

在实现串口通信时,我们需要使用如下代码:CSerialPort m_SerialPort; //实例化串口对象m_SerialPort.Open(...); //打开串口...... //具体的读写操作等m_SerialPort.Close(); //关闭串口在实现串口通信时,我们需要对错误进行判断和处理,例如在读取数据时如果没有接收到数据,需要进行超时处理。

最后,我们需要对程序进行调试和测试,通过测试验证程序是否能够稳定运行。

基于VC的串口通信的实现

基于VC的串口通信的实现

四 ! 结束语 本设计使用 a’cc 提供的串行通信控件 [:’699 实 现 了 串 行通信 # 通过对串口的连接就能实现计算机与计算机之间的联 系 # 使用方便 # 灵活 ! 对串口通信程序 ’699=0><7; 进行测试时 # 将一台计算机的串口连接在一起 # 首先分别启动两个串口通信 程序 ’699=0><7; ! 然后对这两个串口通信程序 ’699=0><7; 进 行设置 # 一个作为发送方 # 端口设置为端口 $ # 例 如 # 发 送 字 符 串 设置为 $!ij# ( 一个作为接收方 # 端口设置为端口 ! ! 其他均设置 为 默 认 情 况 #单 击 %确 定 &按 钮 后 回 到 主 菜 单 #在 发 送 方 按 %自 动 发 送 &按 钮 或 %手 动பைடு நூலகம்发 送 &按 钮 后 #接 收 方 按 %开 始 接 收 &按 钮 后 # 接收方就可以在自己的接收回显编辑框中看见已接收的数据 !
一 # 前言 在 &’()*+, 应用程序的开发中 ! 常常需要面临与外围数据 源设备通信的问题 " 通过串行通信口 ! 可以设计相应的串口通信 程序 ! 完成计算机与计算机之间的数据通信任务 " 串行端口的本 质功能是作为 -./ 和串行设备间的编码转换器 " 当数据从 -./ 经过串行端口发送出去时 ! 字节数据转换为串行的位 " 在接收数 据时 ! 串行的位被转换为字节数据 " 在实验室和工业应用中 ! 串 口是常用的计算机与外部串行设备之间的数据传输通道 ! 由于 串行通信方便易行 ! 所以应用广泛 " 依据不同的条件实现对串口 的灵活编程控制是我们所需要的 " 串行口在 &’( 0! 中是作为文 件 来 进 行 处 理 的 !而 不 是 直 接 对 端 口 进 行 操 作 !对 于 串 行 通 信 ! &’( 0! 提供了相应的文件 123 函数与通信函数 ! 通过了解这些 函数的使用 ! 可以编制出符合不同需要的通信程序 " 实现串行通 信 的 方 法 有 三 种 " 方 法 一 # 使 用 4-55 提 供 的 串 行 通 信 控 件 67-*88 $ 方 法 二 # 在 单 线 程 中 实 现 自 定 义 的 串 口 通 信 类 $ 方 法 三 多线程下实现串行通信 " 本设计中采用第一种方法来实现对 串行通信的编程 ! 即使用 4-55 提供的串行通信控件 67-*88 ! 通过对串口的连接就能实现计算机与计算机之间的联系 ! 使用 方便 ! 灵活 " 二 ##$%&’’ 控件串口编程基本流程 4-559:% 提供的 67-*88 控件通过串行端口发送和接收数 据 ! 为应用程序提供串行通信功能 " 3 & 在当前 4516789 中插入 /0+122 控件 打开 %.;*<=>?@AB)) ?* .;*<=>?CA-*8D*(=(?, E() -*(?;*F,CA G=H’,?=;=) B>?’I=J -*(?;*F, CAK 菜 单 选 择 -*8D*(=(?,L6’>;*,*M? -*88N(’>E?’*(, -*(?;*FOI=;,’*( 9:% 命 令 插 入 到 当 前 的 .;*<=>? 中 " 结 果 就 添 加 了 类 -67-*88 的 相 关 文 件 8,>*88:P 和 8,>*88:>DD 也一并加入 .;*<=>? 中 " 如果 .;*<=>? 中的视类是基于 -M*;84’=+ 的 ! 那么创建 -6! 7-*88 类是相当简单的 " 只需在 -M*;84’=+ 对应的对话框窗体 中插入 67-*88 控件 ! 再在视类的 -FE,,&’QE;) 中为该控件声明 一 个 变 量 即 可 ! 本 文 中 设 为 8R-*8 " 这 样 在 程 序 运 行 中 ! 该 67-*88 控件都将是有效的 " 在对话框中创建 67-*88 控件的 过程也是相类似的 " 如果视类不是基于 -M*;84’=+ 的 ! 那么就需 要建立一个 67-*88 控件 " 创建的方法与普通的 B>?’I=J 控件 的创建相类似 " ! & 初始化并打开串口 对串口进行初始化一般说来要完成以下几个设置 # 设定通信端口号 ! 即 -*88.*;? 属性 " 设定通信协议 ! 即 SE()7PET’(H 属性 " 设定传输速率等参数 ! 即 7=??’(H, 属性 " 设定其他参数 ! 有必要时再加上其他的属性设定 " 打开通信端口 ! 即将 .*;?3D=( 属性设为 UG/V " $ & 关闭串口 在使用完 67-*88 通信对 象 后 ! 需 要 将 通 信 端 口 关 闭 " 当 然如果窗体注销 !67-*88 控件注销同样可以完成这一功能 " 可 以下面的语句来实现这个功能 #

VC++串口通信详解

VC++串口通信详解

VC++串口通信详解串口是常用的计算机与外部串行设备之间的数据传输通道,由于串行通信方便易行,所以应用广泛。

本文以VC++为平台进行串口通信编程串口通讯在VC++下实现方式有很多,控件自然是最简单话的方式了,但由于控件只支持对话框程序,有些场合又不需要对话框,所以用Windows API实现是比较好的方式串行通信的操作方式1.同步方式同步方式中,读串口的函数试图在串口的接收缓冲区中读取规定数目的数据,直到规定数目的数据全部被读出或设定的超时时间已到时才返回MTIMEOUTS timeOver;//COMMTIMEOUTS结构用于设置读写函数的等待时间。

2.memset(&&timeOver,0,sizeof(timeOver));3.DWORD timeMultiplier,timeConstant;4.timeOver.ReadTotalTimeoutMultiplier=timeMultiplier;5.timeOver.ReadTotalTimeoutConstant=timeConstant;6.SetCommTimeouts(hComport,&&timeOver);7.……8.ReadFile(hComport,//串口句柄9. inBuffer,//缓冲10. nWantRead,//每次调用ReadFile时,函数试图读出的字节数11. &&nRealRead,//实际读出的字节数12. NULL);//代表ReadFile将采用同步文件读写的方式如果所规定的待读取数据的数目nWantRead较大且设定的超时时间也较长,而接收缓冲区中数据较少,则可能引起线程阻塞。

解决这一问题的方法是检查COMSTAT结构的cbInQue 成员,该成员的大小即为接收缓冲区中处于等待状态的数据的实际个数。

如果令nWantRead 的值等于COMSTAT.cbInQue,就能较好地防止线程阻塞。

基于VC的串口通信的设计与实现-精品

基于VC的串口通信的设计与实现-精品

课程论文首页基于VC++的串口通信的设计与实现中文摘要:在visual C++6.0平台下,利用MSComm控件编写串口通信程序,实现了串口通信参数设置与显示、打开和关闭串口、接收和发送数据、自动发送、十六进制发送与显示、清空接收区和发送区内容的功能。

关键词:串口 MSComm1 串口通信1.1 基本概念串行通信是指通信的发送方和接收方之间数据信息的传输是在单根数据线上,以每次一个二进制的0、1为最小单位逐位进行传输,如图1所示。

图1 串行通信串行数据传送的特点是:数据传送按位顺序进行,最少只需要一根传输线即可完成,节省传输线。

与并行通信相比,串行通信还有较为显著的优点:传输距离长,可以从几米到几千米;在长距离内串行数据传送速率会比并行数据传送速率快;串行通信的通信时钟频率容易提高;串行通信的抗干扰能力十分强,其信号间的互相干扰完全可以忽略。

但是串行通信传送速度比并行通信慢得多,并行通信时间为T,则串行时间为NT。

正是由于串行通信的接线少、成本低,因此它在数据采集和控制系统中得到了广泛的应用,产品也多种多样。

1.2 工作模式通过单线传输信息是串行数据通信的基础。

数据通常是在两个站(点对点)之间进行传送,按照数据流的方向可分成3种传送模式:单工、半双工和全双工。

(1)单工形式。

单工形式的数据传送是单向的。

通信双方中,一方固定为发送端,另一方则固定为接收端。

信息只能沿一个方向传送,使用一根传输线,如图2所示。

单工形式一般用在只向一个方向传送数据的场合。

例如,计算机与打印机之间的通信是单工形式,因为只有计算机向打印机传送数据,而没有相反的数据传送。

还有在某些通信信道中,如单工无线发送等。

图2 单工形式(2)半双工形式。

半双工通信使用同一根传输线,既可发送数据又可接收数据,但不能同时发送和接收。

在任何时刻只能由其中的一方发送数据,另一方接收数据。

因此半双工形式既可以使用一条数据线,也可以使用两条数据线,如图3所示。

VC 串口编程基础之如何用 VC 打开串口和关闭串口

VC 串口编程基础之如何用 VC 打开串口和关闭串口

VC 串口编程基础之如何用VC 打开串口和关闭串口在对串口进行操作之前都需要先打开串口,VC 串口编程方法分为利用VC 串口控件(或VC 串口类)和直接调用Windows底层API函数(我称之为VC API 串口编程)两种方法,不管哪种方法,其实质都是利用底层API函数对串口进行操作,这里我们来看怎么利用API函数来用VC 打开串口。

在Windows 32位以上操作系统(Win98以上)中,将串口(包括其它通信设备)作为文件来处理,所以串口的打开、读写和关闭所用API函数与文件操作函数一样。

所以打开串口用CreateFile,读串口用ReadFile,写串口用WriteFile,关闭串口用CloseHandle。

一、用VC 打开串口、关闭串口的API函数1、打开串口用CreateFile,其声明如下:1HANDLE CreateFile(2LPCTSTR lpFileName, // file name3DWORD dwDesiredAccess, // access mode4DWORD dwShareMode, // sha re mode5LPSECURITY_ATTRIBUTES lpSecurityAttributes, // SD6DWORD dwCreationDisposition, // how to create7DWORD dwFlagsAndAttributes, // file attributes8HANDLE hTemplateFile // handle to template file9);部分参数解释如下:●lpFileNam e:指定要打开的串口逻辑名,用字符串表示,如“COM1”和“COM2”分别表示串口1和串口2,若要知道您的电脑有哪此串口,可以打开设备管理器查看,如下图所示,或用丁丁串口调试助手,这个工具启动后会枚举系统当前存在的串口。

●dwDesiredAccess:访问类型,有读(dwDesiredAccess=GENERIC_READ)、写(dwDesiredAccess=GENERIC_WRITE)或两者兼有((dwDesiredAccess=GENERIC_READ | GENERIC_WRITE)。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

用VC 6.0实现串行通信的三种方法中国科学院王颖---- 摘要:本文介绍了在Windows平台下串行通信的实现机制,讨论了根据不同的条件用Visual C++ 设计串行通信程序的三种方法,并结合实际,实现对温度数据的接收监控。

---- 在实验室和工业应用中,串口是常用的计算机与外部串行设备之间的数据传输通道,由于串行通信方便易行,所以应用广泛。

依据不同的条件实现对串口的灵活编程控制是我们所需要的。

---- 在光学镜片镀膜工艺中,用单片机进行多路温度数据采集控制,采集结果以串行方式进入主机,每隔10S向主机发送一次采样数据,主机向单片机发送相关的控制命令,实现串行数据接收,处理,记录,显示,实时绘制曲线。

串行通信程序开发环境为VC++ 6.0。

---- Windows下串行通信---- 与以往DOS下串行通信程序不同的是,Windows不提倡应用程序直接控制硬件,而是通过Windows 操作系统提供的设备驱动程序来进行数据传递。

串行口在Win 32中是作为文件来进行处理的,而不是直接对端口进行操作,对于串行通信,Win 32 提供了相应的文件I/O函数与通信函数,通过了解这些函数的使用,可以编制出符合不同需要的通信程序。

与通信设备相关的结构有COMMCONFIG ,COMMPROP,COMMTIMEOUTS,COMSTAT,DCB,MODEMDEVCAPS,MODEMSETTINGS共7个,与通信有关的Windows API函数共有26个,详细说明可参考MSDN帮助文件。

以下将结合实例,给出实现串行通信的三种方法。

---- 实现串行通信的三种方法---- 方法一:使用VC++提供的串行通信控件MSComm 首先,在对话框中创建通信控件,若Control 工具栏中缺少该控件,可通过菜单Project --> Add to Project --> Components and Control插入即可,再将该控件从工具箱中拉到对话框中。

此时,你只需要关心控件提供的对Windows 通讯驱动程序的API 函数的接口。

换句话说,只需要设置和监视MSComm控件的属性和事件。

---- 在ClassWizard中为新创建的通信控件定义成员对象(CMSComm m_Serial),通过该对象便可以对串口属性进行设置,MSComm 控件共有27个属性,这里只介绍其中几个常用属性:---- CommPort 设置并返回通讯端口号,缺省为COM1。

---- Settings 以字符串的形式设置并返回波特率、奇偶校验、数据位、停止位。

---- PortOpen 设置并返回通讯端口的状态,也可以打开和关闭端口。

---- Input 从接收缓冲区返回和删除字符。

---- Output 向发送缓冲区写一个字符串。

---- InputLen 设置每次Input读入的字符个数,缺省值为0,表明读取接收缓冲区中的全部内容。

---- InBufferCount 返回接收缓冲区中已接收到的字符数,将其置0可以清除接收缓冲区。

---- InputMode 定义Input属性获取数据的方式(为0:文本方式;为1:二进制方式)。

---- RThreshold 和SThreshold 属性,表示在OnComm 事件发生之前,接收缓冲区或发送缓冲区中可以接收的字符数。

---- 以下是通过设置控件属性对串口进行初始化的实例:BOOL CSampleDlg:: PortOpen(){BOOL m_Opened;......m_Serial.SetCommPort(2); // 指定串口号m_Serial.SetSettings("4800,N,8,1"); // 通信参数设置m_Serial.SetInBufferSize(1024); // 指定接收缓冲区大小m_Serial.SetInBufferCount(0); // 清空接收缓冲区m_Serial.InputMode(1); // 设置数据获取方式m_Serial.SetInputLen(0); // 设置读取方式m_Opened=m_Serail.SetPortOpen(1); // 打开指定的串口return m_Opened;}---- 打开所需串口后,需要考虑串口通信的时机。

在接收或发送数据过程中,可能需要监视并响应一些事件和错误,所以事件驱动是处理串行端口交互作用的一种非常有效的方法。

使用OnComm 事件和CommEvent 属性捕捉并检查通讯事件和错误的值。

发生通讯事件或错误时,将触发OnComm 事件,CommEvent 属性的值将被改变,应用程序检查CommEvent 属性值并作出相应的反应。

在程序中用ClassWizard为CMSComm控件添加OnComm消息处理函数:void CSampleDlg::OnComm(){......switch(m_Serial.GetCommEvent()){case 2:// 串行口数据接收,处理;}}---- 方法二:在单线程中实现自定义的串口通信类---- 控件简单易用,但由于必须拿到对话框中使用,在一些需要在线程中实现通信的应用场合,控件的使用显得捉襟见肘。

此时,若能够按不同需要定制灵活的串口通信类将弥补控件的不足,以下将介绍如何在单线程中建立自定义的通信类。

---- 该通信类CSimpleComm需手动加入头文件与源文件,其基类为CObject,大致建立步骤如下:---- (1) 打开串口,获取串口资源句柄---- 通信程序从CreateFile处指定串口设备及相关的操作属性。

再返回一个句柄,该句柄将被用于后续的通信操作,并贯穿整个通信过程。

CreateFile()函数中有几个值得注意的参数设置:串口共享方式应设为0,串口为不可共享设备;创建方式必须为OPEN_EXISTING,即打开已有的串口。

对于dwFlagAndAttribute 参数,对串口有意义的值是FILE_FLAG_OVERLAPPED,该标志表明串口采用异步通信模式,可进行重叠操作;若值为NULL,则为同步通信方式,在同步方式下,应用程序将始终控制程序流,直到程序结束,若遭遇通信故障等因素,将导致应用程序的永久等待,所以一般多采用异步通信。

---- (2)串口设置---- 串口打开后,其属性被设置为默认值,根据具体需要,通过调用GetCommState(hComm,&dcb)读取当前串口设备控制块DCB(Device Control Block)设置,修改后通过SetCommState(hComm,&dcb)将其写入。

再需注意异步读写的超时控制设置,通过COMMTIMEOUTS结构设置超时,调用SetCommTimeouts(hComm,&timeouts)将结果写入。

以下是温度监控程序中串口初始化成员函数:BOOL CSimpleComm::Open( ){DCB dcb;m_hIDComDev=CreateFile( "COM2",GENERIC_READ | GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVE RLAPPED, NULL );// 打开串口,异步操作if( m_hIDComDev == NULL ) return( FALSE );dcb.DCBlength = sizeof( DCB );GetCommState( m_hIDComDev, &dcb ); // 获得端口默认设置dcb.BaudRate=CBR_4800;dcb.ByteSize=8;dcb.Parity= NOPARITY;dcb.StopBits=(BYTE) ONESTOPBIT;...... }---- (3)串口读写操作---- 主要运用ReadFile()与WriteFile()API函数,若为异步通信方式,两函数中最后一个参数为指向OVERLAPPED结构的非空指针,在读写函数返回值为FALSE的情况下,调用GetLastError()函数,返回值为ERROR_IO_PENDING,表明I/O操作悬挂,即操作转入后台继续执行。

此时,可以用WaitForSingleObject()来等待结束信号并设置最长等待时间,举例如下:BOOL bReadStatus;bReadStatus = ReadFile( m_hIDComDev, buffer,dwBytesRead, &dwBytesRead, &m_OverlappedRead );if(!bReadStatus){if(GetLastError()==ERROR_IO_PENDING){WaitForSingleObject(m_OverlappedRead.hEvent,1000);return ((int)dwBytesRead);}return(0);}return ((int)dwBytesRead);---- 定义全局变量m_Serial作为新建通信类CSimpleComm的对象,通过调用类的成员函数即可实现所需串行通信功能。

与方法一相比,方法二赋予串行通信程序设计较大的灵活性,端口的读写可选择较简单的查询式,或通过设置与外设数据发送时间间隔TimeCycle相同的定时器:SetTimer(1,TimeCycle,NULL),进行定时读取或发送。

CSampleView:: OnTimer(UINT nIDEvent){char InputData[30];m_Serial.ReadData(InputData,30);// 数据处理}---- 若对端口数据的响应时间要求较严格,可采用事件驱动I/O读写,Windows定义了9种串口通信事件,较常用的有:---- EV_RXCHAR: 接收到一个字节,并放入输入缓冲区。

---- EV_TXEMPTY: 输出缓冲区中的最后一个字符发送出去。

---- EV_RXFLAG: 接收到事件字符(DCB结构中EvtChar成员),放入输入缓冲区。

---- 在用SetCommMask()指定了有用的事件后,应用程序可调用WaitCommEvent()来等待事件的发生。

SetCommMask(hComm,0)可使WaitCommEvent()中止。

---- 方法三多线程下实现串行通信---- 方法一,二适用于单线程通信。

在很多工业控制系统中,常通过扩展串口连接多个外设,各外设发送数据的重复频率不同,要求后台实时无差错捕捉,采集,处理,记录各端口数据,这就需要在自定义的串行通信类中创建端口监视线程,以便在指定的事件发生时向相关的窗口发送通知消息。

相关文档
最新文档