用VC++.NET实现C167CR单片机与PC的串行通信
PC与单片机构成的上位机、下位机分布式控制系统是一种常见的工业控制系统,单片机作为下位机可进行现场数据采集和就地控制,并可将采集到的数据或者状态 信息传送到上位PC机,以做进一步的分析处理。在实际应用中,上位机与下位机的通信问题是首要解决的问题之一,串行通信以其高效率、可靠、标准统一的优点 成为重要的通信手段,本文即在WINDOWS XP环境下,使用Visual C++.NET中的MSComm控件实现C167CR单片机与PC之间的串行通信,其通信线路通过RS232连接(距离小于
C167CR单片机是德国Infineon公司(前西门子半导体部)开发的一种16位单片机,属于单片机中的高端产品,片内有16通道10位A/D转换 器、9个定时器、2个串行接口以及15个报文的CAN接口等功能模块。C167CR单片机有两种类型的串行接口:异步/同步串行接口(ASC0)和高速同 步串行接口(SSC),下面介绍异步/同步串行接口(ASC0)。ASC0的接口功能是通过设置几个专用寄存器来予以确定。
2.1 异步/同步串行接口(ASC0)
16位控制寄存器S0CON的各位定义如图1所示。
数据接收由接收使能位S0REN来控制,只有当波特率生成器启动位S0R置为“
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置“
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,
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,Version
第三步:删去应用程序主对话框中的静态文本和“确定”按钮,将“取消”按钮改为“退出程序”。添加两个静态文本“发送数据”和“接受数据”,以及两个编辑框、一个按钮“开始通信”和一个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;i12;i++)
sReceivearray.GetElement(i,bReceive+i); //将数据转换为BTYE型数组
for (i=0;i5;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类型,可通过一系列转换,转换为所要求的类型予以显示。
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[5];
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;n12;n++) S0TBUF=c[n]; } /*接收12个字节后发送*/
i=i+1; if(i==12) i=0;
}
void main (void) { init (); while (1) {S0RIR=0;} }
评论