访问电脑版页面

导航:老古开发网手机版其他

用Win32 API实现PC机与多单片机的串行通信

导读:
关键字:
用Win32 API实现PC机与多单片机的串行通信* 东南大学黄波张晓晨 摘要介绍在32位Windows下PC机和多MCS\ 51单片机组成的多微机串行通信系统,并给出硬件构成及部分通信软件。 关键词MCS\ 51单片机串行通信异步通信 用1台IBM\ PC或其兼容机作为主机,多台MCS\ 51单片机作为从机,通过RS\ 232C总线互连而成的主从式多微机串行通信系统,为开发小型分布式控制系统创造了良好的硬件环境。本文结合笔者在工作中的实际经验,介绍在32位Windows操作系统下,用VC++6.0和MCS\ 51汇编语言来开发PC机和多MCS\ 51单片机通信软件的一些技巧和方法。 一、 系统硬件结构 如图1所示,以1台IBM\ PC为主机,2台MCS\ 51单片机为从机所组成的总线型多微机串行通信系统为例。IBM\ PC通过机内的异步通信适配器挂在总线上, 异步通信适配器的核心是8250芯片。但图1用1台PC与2台MCS\ 51组成串行通信系统在Win32编程下,程序员通过Win32 API应用程序接口函数来和通信硬件接口打交道,因此,本文对8250芯片的工作原理不予介绍。 每台MCS\ 51都是通过片内的串行接口再经过电平转换器后挂在总线上。IBM\ PC的异步通信适配器符合RS\ 232C标准。MCS\ 51串行口提供的信号在功能上支持RS\ 232总线标准,但在电平上不符合其规定,必须经过MC\ 1488、MC\ 1489变换。但由于MC\ 1488的输出不能连在一起,所以2台MCS\ 51发送端的MC\ 1488都须经过二极管隔离后再互连。 二、 通信协议 主PC机承担主控任务,负责控制参数的设定,程序由VC++6.0编写。2台MCS\ 51单片机接收PC机指令,并根据指令信息来控制被控对象或上传数据。通信协议如下: 采用RS\ 232C串口异步通信,1位起始位;8位字长;把数据第9位设定为“固定奇偶位”,用来支持PC和MCS\ 51的相互通信,当第9位为0,表示主机发送的是“数据/命令帧”;当第9位为1,表示主机发送的是“呼叫帧”;1位停止位。波特率为9600baud。 三、 主机通信软件 在32位Windows环境下,Win32 API提供了接口函数来与通信硬件接口。通信函数是中断驱动的:发送数据时先把数据放入缓冲区,串口准备好以后将其发出;传来的数据申请中断,使Windows接收并将其存入缓冲区,以供读取和解析。在编写通信程序时,用CreateFile打开通信资源,SetupComm()设置输入输出队列的大小,GetCommState()获得端口参数当前配置,SetCommState()设置端口参数,ReadFile()及WriteFile()读、写端口,最后用CloseFile()关闭端口。函数的使用请参阅MSDN。为了便于读者熟悉VC++6.0的通信编程,在此简要地给出部分用VC++6.0编写的主机通信软件: //创建一工程—Comm,在CommView.h中定义变量 HANDLE hComm,hEvent; HWND hwCommWnd; BOOL Error,Result,Success,threadFlag; DCB dcb; //定义数据块结构参数 DWORD dwEvtMask,dwLength; OVERLAPPED CommRead,CommRead; COMSTAT ComState; char ReadBuffer\[num\]=“”; //根据需要设置num char *send,*Receive; //在文件头中加入 #define WM_COMM_READ WM_USER+5 //Generated message map functions //{{AFX_MSG(CCommView) afx_msg LONG OnCommRead(UNIT wParam,LONG lParam); //}}AFX_MSG DECLARE_MESSAGE_MAP() }; BEGIN_MESSAGE_MAP(CCommView,CFormView) //{{AFX_MSG_MAP(CCommView) ON_MESSAGE(WM_COMM_READ,OnCommRead) //}}AFX_MESSAGE_MAP END_MESSAGE_MAP() #include “stdafx.h” #include “CommView.h” #include “math.h” #include “stdlib.h” #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE\[\]=_FILE_; #endif IMPLEMENT_DYNCREATE(CCommView,CFormView) CCommView::CCommView():CFormView(CCommView::IDD) { //{{AFX_DATA_INIT(CCommView) //}}AFX_DATA_INIT } CCommView::~CCommView() { } void CCommView::OnInitialUpdate() { CFormView::OnInitialUpdate(); //TODO:Add your specialized code here and/or call the base //class hComm=CreateFile(“COM2”, GENERIC_READ GENERIC_WRITE, //允许读写 0, //此行必须为零 NULL, //无安全参数 OPEN_EXISTING, //设置产生方式 FILE_FLAG_OVERLAPPED, //异步方式 NULL); if(hComm==INVALID_HANDLE_VALUE) { MessageBox(“端口设置错误”,“警告”,MB_OK); } Success=SetCommMask(hComm,EV_RXFLAG); If(!Success) { MessageBox(“SetCommMask Error!”,“警告”,MB_OK); } Error=SetupComm(hComm,1024,1024);//设定输入/出缓冲大小 If(!Error) { MessageBox(“SetupComm Error!”,“警告”,MB_OK); } Error=GetCommState(hComm,&dcb); //获得串口设置 If(!Error) { MessageBox(“GetCommState Error!”,“警告”,MB_OK); } dcb.BaudRate=9600; dcb.ByteSize=8; dcb.Parity=NOPARITY; dcb.StopBits=ONESTOPBIT; Error=SetCommState(hComm,&dcb); If(!Error) { MessageBox(“SetupCommState Error!”,“警告”,MB_OK); } hEvent=CreateEvent(NULL, //无安全属性 TRUE, //手工重置事件 TRUE, //初态无信号 NULL //初态无名字 ); if(m_Comm) { threadFlag=TRUE; m_Comm->ResumeThread(); ::WaiteForSingleObject(m_Comm->m_hThread,INFINITE); delete m_Comm; } m_Comm=AfxBegineThread(ComReceive,&m_hWnd,THREAD_PRIORITY_NORMAL,0, CREATE_SUSPENDED,NULL); m_Comm->m_bAutoDelete=FALSE; threadFlag=FALSE; m_Comm->ResumeThread(); hwComWnd=m_hWnd; } UINT CommReceive(LPVOID m_View) { DWORD dwRead; MemSet(&CommRead,0,sizeof(OVERLAPPED)); If(!SetCommMask(hCom,EV_RXCHAR)) { DWORD error=GetLastError(); Return(FALSE); } while(1) { dwRead=0; WaitCommEvent(hComm,&dwRead,&CoRead); if(dwRead&EV_RXCHAR)==EV_EVENT) WaitForSingleObject(hEvent,OxFFFFFFFF); ResetEvent(hEvent); PostMessage(hEvent,WM_COMM_READ,NULL,NULL); } return 0; } LONG CCommView::OnCommEvent(UNIT wParam,LONG lParam) { ClearCommError(hComm,&dwEvtMask,&comState; DwLength=comState.cbInQue; If(dwLength>=7) Error=ReadFile(hComm,ReadBuffer,dwLength, &dwLength,&CommRead); If(!Error) { MessageBox(“读串口出错!”,“警告”,MB_OK); } SetEvent(hEvent); Return 0; } void CCommView::Sent() { char SendBuffer=“&ASKQ?*”; Send=SendBuffer; Error=WriteFile(hComm,Send,7,&dwLength,&CommWrite); If(!Error) { MessageBox(“写串口出错!”,“警告”,MB_OK); } } void( CCommView::OnDestroy() { CFormView::OnDestroy(); CloseHandle(hComm); } 四、 从机通信软件 MCS\ 51单片机串口首先进行初始化,把定时器T1设置为9600baud的波特率发生器、数据格式为1位起始位,8位字长,第9位为呼叫帧与数据/命令帧区别位,1位停止位的11位异步方式,与IBM\ PC一致。采用中断方式控制CPU与串行口的数据交换,串行口方式设置为3。MCS\ 51程序清单如下: 主程序清单 COMM1:〖〗MOV〖〗TMOD,#20H〖2〗MOV〖〗TH1,#0FDH〖2〗MOV〖〗TF1,#0FDH ;T1设置为9600baud的波特 ;率发生器〖2〗SETB〖〗TR1 ;启动T1〖2〗SETB〖〗EA ;开中断〖1〗RPT:〖〗SETB〖〗ES ;允许串口中断〖2〗MOV〖〗SCON, #0F8H;串口设位方式3,第9位为1〖2〗MOV〖〗PCON, #80H ;波特率系数选择〖2〗MOV〖〗23H, #0CH ;设置接收数据指针〖2〗MOV〖〗22H, #00H 〖2〗MOV〖〗21H, #08H ;设置发送数据指针〖2〗MOV〖〗20H, #00H〖2〗MOV〖〗R5, #00H ;累加和SUM清零〖2〗MOV〖〗R6, 25H ;取传送字节数〖2〗MOV〖〗R7, 26H〖2〗INC〖〗R6〖2〗INC〖〗R7〖1〗PRTT:〖〗SJMP〖〗PRTT ;循环等待中断〖1〗PRTR:〖〗CLR〖〗ES ;关中断〖1〗PRTR1:〖〗SJMP〖〗PRTR1 ;结束〖2〗〖2〗ORG〖〗0023H〖2〗LJMP〖〗INPU〖2〗中断服务程序 INPU:〖〗JBC〖〗RI, RI1 ;若RI=1,转RI1接收,并RI=0〖1〗INTUR:〖〗JBC〖〗TI, INTUR1 ;若TI=1,转INTUR,并TI=0〖1〗INTUR1:〖〗RETI〖〗;返回〖1〗RI1:〖〗JNB〖〗SM2, RI3;SM2=1,呼叫帧,M2=0, ;数据/命令帧〖2〗MOV〖〗A, SBUF ;读入呼叫帧〖2〗CLR〖〗C 〖2〗SUBB〖〗A, 27H ;(27H)中为本机号,进行对号〖2〗JNZ〖〗RI2 ;若机号不等,转RI2〖2〗MOV〖〗SBUF, #00H ;对上号向主机发回00应答〖2〗CLR〖〗TB8 ;使第9位为零〖2〗CLR〖〗SM2 ;使SM2=0〖1〗RI2:〖〗RETI 〖1〗RI3:〖〗DJNZ〖〗R6 ,RI4 ;传送数据字节数完成否〖2〗DJNZ〖〗R7,RI4 ;〖2〗MOV〖〗24H,SBUF ;最后收到的是SUM累加和〖2〗AJMP〖〗TI1 ;转TI1进行累加和校验〖1〗RI4:〖〗MOV〖〗A,SBUF ;接收数据〖2〗MOV〖〗DPH,23H ;把数据放接收缓冲区〖2〗MOVX〖〗@DPTR,A〖2〗ADD〖〗A,R5 ;累加和〖2〗MOV〖〗R5,A ;〖2〗INC〖〗DPTR ;接收指针加1〖2〗MOV〖〗23H,DPH〖2〗MOV〖〗22H,DPL〖2〗AJMP〖〗TI4〖1〗TI1:〖〗MOV〖〗A,24H ;(24H)中为发送来的累加和〖2〗XRL〖〗A,R5 ;累加和校验〖2〗JZ〖〗TI3 ;正确转TI3〖1〗TI2:〖〗POP〖〗ACC ;错误,把原保存断点弹出〖2〗POP〖〗ACC〖2〗MOV〖〗DPTR,#RPT〖2〗PUSH〖〗DPL;把#RPT压栈作为新断点〖2〗PUSH〖〗DPH〖2〗MOV〖〗SBUF,#0FFH ;用“0FFH”做出错应答〖2〗RETI〖1〗TI3:〖〗POP〖〗ACC ;检验正确,原断点弹出〖2〗POP〖〗ACC〖2〗MOV〖〗DPTR,#RPTR 〖2〗PUSH〖〗DPL ;新断点压栈〖2〗PUSH〖〗DPH〖2〗MOV〖〗SBUF ;发00H作为主机应答〖2〗RETI〖1〗TI4:〖〗MOV〖〗DPH,21H ;发送指针放DPTR〖2〗MOV〖〗DPL,20H〖2〗MOVX〖〗A,@DPTR〖2〗INC〖〗DPTR ;发送指针加1〖2〗MOV〖〗21H,DPH 〖2〗MOV〖〗20H,DPL〖2〗MOV〖〗SBUF,A ;发送完数据〖1〗TI5:〖〗RETI结束语 利用PC机作上位主机,利用多台单片机作下位从机,通过RS\ 232C或RS\ 422构成主从式总线型多微机串行通信系统,在实时控制系统中广为应用。MES 参考文献 1邱公伟,赵祥元,巫淑萍等著实时控制与智能仪表多微机系统的通信技术北京:清华大学出版社,1995 2吴华,岳晋生Windows NT Win32软件开发使用详解北京:电子工业出版社,1995 3David J.Kjuglinski,Scot Wingo,George Sheperd.Visual C++ 6.0技术内幕.第五版(修订版).北京:北京希望出版社,2001
来源:单片机与嵌入式系统应用   作者:东南大学 黄波 张晓晨  2006/2/12 0:00:00
栏目: [ ]

相关阅读

安森美推出新的高功率图腾柱PFC控制器,满足具挑战的能效标准

动态功耗低至60μA/MHz!助力设备超长续航,首选国民技术低功耗MCU!