用VC++.NET实现C167CR单片机与PC的串行通信
发布时间:2010-11-5 19:53
发布者:techshare
1 引言 PC与单片机构成的上位机、下位机分布式控制系统是一种常见的工业控制系统,单片机作为下位机可进行现场数据采集和就地控制,并可将采集到的数据或者状态 信息传送到上位PC机,以做进一步的分析处理。在实际应用中,上位机与下位机的通信问题是首要解决的问题之一,串行通信以其高效率、可靠、标准统一的优点 成为重要的通信手段,本文即在WINDOWS XP环境下,使用Visual C++.NET中的MSComm控件实现C167CR单片机与PC之间的串行通信,其通信线路通过RS232连接(距离小于15m)。 2 C167CR单片机串行接口简介 C167CR单片机是德国Infineon公司(前西门子半导体部)开发的一种16位单片机,属于单片机中的高端产品,片内有16通道10位A/D转换 器、9个定时器、2个串行接口以及15个报文的CAN接口等功能模块。C167CR单片机有两种类型的串行接口:异步/同步串行接口(ASC0)和高速同 步串行接口(SSC),下面介绍异步/同步串行接口(ASC0)。ASC0的接口功能是通过设置几个专用寄存器来予以确定。 2.1 异步/同步串行接口(ASC0) 16位控制寄存器S0CON的各位定义如图1所示。 数据接收由接收使能位S0REN来控制,只有当波特率生成器启动位S0R置为“1”时,才能进行串行数据的发送和接收。 2.2 ASC0波特率寄存器S0BG 寄存器S0BG具有双重功能,可用作波特率生成器和重载寄存器,它具有13位的重载能力,不同的重载值对应不同的波特率。读SOBG时,返回的是定时器的内容(15~13位返回为0),写SOBG时,将更改重载寄存器的值(15~13位无效)。 2.3 缓存寄存器 串行口ASC0有两个缓存寄存器:接收缓存寄存器S0RBUF和发送缓存寄存器S0TBUF。发送时只要发送器空闲,装载到S0TBUF中的数据将立即转送到发送移位寄存器进行发送。将S0R 和S0REN置位,可直接从接收缓存寄存器S0RBUF读取数据。 2.4 中断寄存器 串行口ASC0有4个可位寻址的中断控制寄存器,发送中断寄存器S0TIC,发送缓存器中断寄存器S0TBIC,接收中断寄存器S0RIC,串行口ASC0错误中断寄存器S0EIC。只有当总中断允许位IEN置“1”时,这些中断寄存器才能进行控制。 3 Visual C++.NET串行通信控件 MSComm介绍 在WINDOWS环境下,用户不能直接对PC的串行端口进行操作。Visual C++.NET中,通过使用微软公司提供的Microsoft Comm Control控件(简称MSComm),可以方便地实现PC与外部设备之间的串行通信,编程工作量相对较少。注意Visual C++.NET中控件MSComm的函数与Visual C++6.0中的控件函数有所不同。MSComm有二十多个属性,其中主要的属性有: CommPort:设置和返回通信端口号,CommPort=1即使用串行端口Com1。 PortOpen:打开或关闭通信端口。 InBufferSize:设置接收缓冲区大小。 OutBufferSize:设置发送缓冲区大小。 Input:读取并删除缓存区中的数据。 Output:将数据写入发送缓存区。 Settings:设置波特率、奇偶校验、数据位和停止位参数,默认值为“9600,N,8,1”,即波特率9600b/s、不进行奇偶校验、8个数据位、1个停止位。 InputLen:设置每次从缓存区读取的字节数。 InputMode:设置和返回数据类型,设置为0时读取的数据为文本形式,设置为1时读取的数据为二进制数据。PC与单片机通信时,InputMode属性常设置为二进制数据形式。 Rthreshold:设置OnComm事件发生前,接收缓存区可以接收的字符数。若设置为0,则不产生OnComm事件。 串行通信控件MSComm有二种处理通信的工作方式:事件驱动方式和查询工作方式。事件驱动方式是指:当串行端口接收或发送完指定数量数据以及发生通信错 误等情况时,MSComm控件触发OnComm事件,作出相应处理。查询工作方式是指:通过查询控件的某些属性值(如InBufferCount属性)来 作出进一步的处理。以下的程序实例采用事件驱动方式来接收数据。 4 串行通信程序实例 4.1程序功能 本程序是在WINDOWS XP环境下进行数据的发送和接收,PC一次性向C167CR单片机发送12字节(ASCII字符)的数据,单片机接收完数据后,再返回所接收到的所有数据,通过比较PC发送和接收到的数据,验证串行通信的可靠性。 4.2 PC通信程序设计 4.2.1 实现步骤 第一步:启动“Visual Studio.NET”,选择新建项目,在项目类型窗口中选择“Visual C++项目”,模板窗口选择“MFC应用程序”。输入项目名称,单击“确定”按钮。“应用程序类型”选择“基于对话框”,其他设置皆为默认值,单击“完成”按钮。 第二步:选择“工具”菜单下子菜单“自定义工具箱”中COM组件中的“Microsoft Communication Control,Version6.0”,单击“确定”按钮,插入MSComm控件。这与Visual C++6.0的插入方法不同。 第三步:删去应用程序主对话框中的静态文本和“确定”按钮,将“取消”按钮改为“退出程序”。添加两个静态文本“发送数据”和“接受数据”,以及两个编辑框、一个按钮“开始通信”和一个MSComm控件。 第四步:添加变量和事件处理程序。由于Visual C++.NET没有ClassWizard,添加方法与Visual C++6.0不同。右键单击控件,通过子菜单“添加变量”和“添加事件处理程序”实现此步骤。为两个编辑框分别添加CString型全局变量m_Send 和m_Receive,并为“开始通信”按钮添加BN_CLICKED事件处理函数OnSendData(),为MSComm控件添加CMSComm型变 量m_Com和OnComm事件处理函数OnCommMscomm()。其中函数OnSendData()用来发送数据,函数OnCommMscomm ()用来接收数据。 窗体界面如图2所示。 ![]() 4.2.2 Visual C++.NET程序代码 在OnInitDialog()函数中进行串行口初始化 BOOL CserialDlg::OnInitDialog() {//省略自动生成的代码 // TODO:在此添加额外的初始化代码 m_Com.put__CommPort(1); //设置串口为COM1 m_Com.put_InBufferSize(1024); //设置输入缓存区的大小,Bytes m_Com.put_OutBufferSize(512); //设置发送缓存区的大小,Bytes m_Com.put_PortOpen(true); // 打开串口 m_Com.put_InputMode(1); //以二进制方式接收数据 m_Com.put_Settings(“9600,n,8,1”); //设置数据传输速率等参数 m_Com.put_RThreshold(12); //表示收到12个字符引发一个OnComm事件 m_Com.put_InputLen(0); //一次读出接收缓存区的字符 m_Com.get_Input(); //清空接收缓存区 return TRUE; // 除非设置了控件的焦点,否则返回 TRUE } 数据发送程序代码 void CserialDlg::OnSendData() { // TODO: 在此添加控件通知处理程序代码 if(!m_Com.get_PortOpen()) m_Com.put_PortOpen(true); //若没打开串口,则打开 UpdateData(true); //将编辑框中的数据传递给变量 m_Com.put_Output(COleVariant(m_Send)) ; //将编辑框中的字符串数据转换 VARIANT类型,并发送出去 } 数据接收程序代码 void CserialDlg::OnCommMscomm() { // TODO: 在此添加消息处理程序代码 VARIANT vReceive; COleSafeArray sReceivearray; long k , i; BYTE bReceive[1024]; CString str; m_Receive=""; k=m_Com.get_CommEvent(); switch(k){ case 2: //接收到Rthreshold个数据 vReceive=m_Com.get_Input(); //读取缓存区内的数据 sReceivearray=vReceive; //将数据由VARIANT型转换为SafeArray型 for(i=0;i<12;i++) sReceivearray.GetElement(&i,bReceive+i); //将数据转换为BTYE型数组 for (i=0;i<5;i++) { char a=*(char*)(bReceive+i); str.Format("%c",a); m_Receive+=str; } //将数据转换为CString型,传递给变量m_Receive UpdateData(false); //更新编辑框内容 break; default: break; } } 程序中的put_Output()函数要求VARIANT型数据作为参数,可以调用类ColeVariant的构造函数将多种类型数据(如CString,int等)转换为VARIANT类型数据。同时数据接收函数get_Input()接收到的数据为VARIANT类型,可通过一系列转换,转换为所要求的类型予以显示。 4.3 C167CR单片机通信程序设计 C167CR单片机串行通信程序采取8位数据异步发送工作方式,接收数据使用中断方式,接收完12字节数据后再将全部数据发送出去。具体C语言程序如下。 初始化程序: #include <reg167.h> void init(void) { P3 |= 0x0400; /*设置输入、输出引脚*/ DP3 |= 0x0400; DP3 &= 0xF7FF; S0BG = 0x40; /*设置波特率为9600*/ S0CON = 0x8011; /*设置串行口状态:8位数据异步工作方式,1位停止位等*/ S0RIC=0x0044; /*设置中断允许位、中断优先级*/ IEN=1; } /*中断全局使能*/ 主程序: #include <reg167.h> extern void init(void); static unsigned int i=0; static unsigned char c; unsigned int n; void serialcom (void) interrupt 0x2B using s_rbank{ /*中断接收数据*/ if(i==0) c[0]=S0RBUF; else c[ i]=S0RBUF; if(i==11) { for(n=0;n<12;n++) S0TBUF=c[n]; } /*接收12个字节后发送*/ i=i+1; if(i==12) i=0; } void main (void) { init (); while (1) {S0RIR=0;} } |
网友评论