一个串口tomcat 数据源源,发送tomcat 数据源,要2路并联的串口同时收到,请问这是否可以实现?

串行口通信(STC89C52+MAX232):&上位机发送字符x,单片机收到后返回上位机&I&get&x&
一.程序功能
在上位机上用串口调试助手发送一个字符X, 单片机收到字符后返回给上位机"I get
X",串口波特率设为9600bps.
二.程序源码
法1 (头文件法, 适用于老手)
#define uchar unsigned char
#define uint unsigned int
uchar flag, a,
uchar code table[] = "I get ";
& //定义一个字符类型编码数组
& & init();
& //初始化
& & //若检测到flag为1,
说明程序已经执行过串口中断服务程序, 即收到了数据.&
& & if (flag == 1)
&&&//手动将flag清0,方便标志位检测
& flag = 0;
&&//检测到flag为1后,即串口中断发生,先将ES清0, 原因是接下来要发送数据,
若不关闭串口中断, 发送完数据后,
&&//单片机同样会申请串口中断,再次进入中断服务程序,flag又为1,又再此发送数据,一直重复
//因此我们在发送数据前把串口中断关闭,等发送完数据再打开串口中断,这样可以安全地发送数据
& //通过for循环将前面数组中字符依次发送出去
& //由于数组table中共有6个字符,所以循环中以6作为结束个数
& for (i = 0; i & 6;
//发送字符
& & & SBUF =
//当向SBUF中写入一个数据后,使用while(!TI)等待发送完毕, 因为发送完毕后TI会由
//硬件置1,然后退出while(!TI)
& & & while
//再将TI手动清0
& & & TI =
& //向SBUF中写入从中断服务程序读回来的数据
& while (!TI); //同上
& TI = 0; & &
& ES = 1; & &
&//重新开启串口中断
& & TMOD =
0x20; &//设定定时器1为工作方式2:
8位初值自动重装的8位定时器(设定定时器1目的是其溢出率决定串口波特率)
0 & //定时器1装初值(波特率为9600)
//定时器1装初值(波特率为9600),注意:TH1,TL1初值必须相同
& & //ET1 = 1;
&这里不需要开启定时器1中断,因为定时器1工作在方式2,为8位自动重装方式,进入中断也无事可做
& & REN = 1;
&//容许串行口接收数据
& & SM0 = 0;
&//设定串口工作方式1
& & SM1 = 1;
&//设定串口工作方式1(10位异步收发,波特率可变,且由定时器1的溢出率决定)
& & EA = 1;
//开总中断
& & ES = 1;
//开串口中断
& & TR1 = 1;
&//启动定时器1
//串口中断服务程序
ser() interrupt 4
//RI为接收中断标志位, 在方式0时, 当串行接收第8位数据结束时, 或在其他方式, 串行接收停止位的
& & //中间时,
由内部硬件使RI置1, 向CPU发出中断申请, 也必须在中断服务程序中, 用软件将其清0,取消
& & //此中断申请,
以方便下一次中断申请检测, 即这样才能产生下一次中断.
& & //这里RI清0,
因为程序既然产生了串口中断, 肯定是收到或发送了数据, 在开始时没有发送任何数据
//那必然是收到了数据, 此时RI会被硬件置1, 所以进入串口中断服务程序后必须由软件清0, 这样才能
//产生下一次中断.
//将SBUF中的数据读走给a, 这是此中断服务程序最重要的目的
//将标志位flag置1, 以方便在主程序中查询判断是否已经收到数据
& & flag =
法2 (完整寄存器地址法)
//中断允许寄存器IE,字节地址位0xA8
//单片机复位时,
IE中所有位被清0
& &= 0xA8; &
//EA为全局中断允许位
1时打开全局中断控制,在这样条件下,由各个中断控制位打开或关闭相应的中断
0时关闭所有中断
& &= IE^7; &
//ET2为定时器/计数器2中断允许位
1时打开T2中断, ET2 = 0时关闭T2中断
& = IE^5; //8052 only
//ES为串行口中断允许位
1时打开串行口中断, ES = 0时关闭串行口中断
& &= IE^4;
//ET1为定时器/计数器1中断允许位
1时打开T1中断, ET1 = 0时关闭T1中断
//EX1为外部中断1中断允许位
1时打开外部中断1中断, EX1 = 0时关闭外部中断1中断
//ET0为定时器/计数器0中断允许位
1时打开T0中断, ET0 = 1时关闭T0中断
//EX0为外部中断0中断允许位
1时打开外部中断0中断, EX0 = 0时关闭外部中断0中断
//SBUF为串行数据缓冲寄存器
//51单片机中含有两个SBUF,其中一个为发送缓冲寄存器,另一个为接收缓冲寄存器
//这两个寄存器共有一个地址0x99,
但物理上是两个独立的寄存器,有指令操作决定访问哪个寄存器
//执行写指令时,
访问串行发送寄存器, 执行读指令时, 访问串行接收寄存器
//接收器具有双缓冲结构,
即在从接收寄存器中读出前一个已收到的字节之前, 便能接受第二个字节
//如果第二个字节已经接收完毕,第一个字节还没有读出,则丢失其中一个字节
//对于发送器,数据由CPU控制和发送,所以不需要考虑
//SCON为串行口控制寄存器
//SCON可位寻址,
即可以访问它的具体某一位
//SCON用以设定串行口的工作方式,
接收/发送控制以及设置状态标志
//单片机复位时SCON全部被清0
//SM0,SM1为工作方式选择位,
串行口有4中工作方式, 由SM0,SM1设定
//SM0=0,SM1=0为方式0,即同步移位寄存器方式,用于扩展I/O口
//SM0=0,SM1=1为方式1,即10位异步收发,含8位数据,波特率可变,且由定时器1的溢出率控制
//SM0=1,SM1=0为方式2,即11位异步收发,含9位数据,波特率固定
//SM0=1,SM1=1为方式3,即11位异步收发,含9位数据,波特率可变,且由定时器1的溢出率控制
& = SCON^7;
& = SCON^6;
//SM2为多机通信控制位,主要用于方式2和方式3
//当接收机的SM2=1时,可以利用收到的RB8来控制是否激活RI,即RB8=0时不激活RI,收到的信息丢弃
//RB8=1时收到的数据进入SBUF,并激活RI,进而在中断服务中将数据从SBUF读走
//当SM0=0时,不论收到的RB8是0还是1,均可以使收到的数据进入SBUF,并激活RI,即此时RB8不具有控制RI激活功能
//通过控制SM2,可以实现多机通信.
//在方式0时,SM2必须是0
//在方式1时,若SM2=1,则只有接收到有效停止位时,RI才置1
& = SCON^5;
//REN为允许串行接收位
//REN=1时允许串行口接收数据
//REN=0时禁止串行口接收数据
& = SCON^4;
//TB8为方式2,3中发送数据的第9位
//方式2或方式3中,时发送数据的第9位,可以用软件规定其作用,可以用作数据的奇偶校验位
//或在多机通信中,作为地址帧/数据帧的标志位
//方式0和方式1时,该位未用
& = SCON^3;
//RB8为方式2,3中接收数据的第9位
//方式2或方式3中,是接收数据的第9位,可作为奇偶校验位或地址帧/数据帧的标志位
//方式1时,若SM2=0,则RB8是接收到的停止位
& = SCON^2;
//TI为发送中断标志位
//方式0时,当串行发送第8位数据结束时,或在其他方式,串行发送停止位的开始时,
//由内部硬件使TI置1,向CPU发出中断申请,在中断服务程序中,必须用软件将其清0,取消此中断申请
& &= SCON^1;
//RI为接收中断标志位
//方式0时,当串行接收第8位数据结束时,或在其他方式,串行接收停止位的中间时,
//由内部邮件使RI置1,向CPU发出中断申请,也必须在中断服务程序中,用软件将其清0,取消此中断申请
& &= SCON^0;
//TMOD为定时器/计数器工作方式寄存器
//字节地址位0x89,不能位寻址
//单片机复位时TMOD全部被清0
//TMOD的高4位用于设置定时器1,低4位用于设置定时器0,
//其中高低4位均由GATE,C/T,M1,M0构成
//GATE为门控制位
//GATE=0,定时器/计数器启动与停止仅受TCON寄存器中TRX(X=0,1)来控制
//GATE=1,定时器/计数器启动与停止由TCON寄存器中TRX(X=0,1)和外部中断引脚(INT0或INT1)的电平共同控制
//C/T为定时器模式和计数器模式选择位
//C/T=1为计数器模式,C/T=0为定时器模式
//M1M0为工作方式选择位
//M1=0,M0=0为方式0,为13位定时器/计数器
//M1=0,M0=1为方式1,为16位定时器/计数器
//M1=1,M0=0为方式2,8位出值自动重装的8位定时器/计数器
//M1=1,M1=0为方式3,仅适用于T0,分成两个8位计数器,T1停止计数
//TCON为定时器/计数器控制寄存器
//TCON字节地址为88H,可位寻址
//TCON寄存器用来控制定时器的启,停,标志定时器溢出和中断
//单片机复位时TCON全部被清0
//TCON包含的TF1,TR1,TF0,TR0用于定时器/计数器
//TCON包含的IE1,IT1,IE0,IT0用于外部中断
//TF1为定时器1溢出标志位
//当计数器1计满溢出时,由硬件使TF1置1,并且申请中断,进入中断服务程序后,由硬件自动清0
//如果使用定时器的中断,那么该位完全不用人为去操作
//如果使用软件查询的方式,查询该位为1后,就需要用软件清0
& = TCON^7;
//TR1为定时器1运行控制位
//由软件清0关闭定时器1,当GATE=1,且INT1为高电平时,TR1置1启动定时器1
//当GATE=0时,TR1置1启动定时器1
& = TCON^6;
//TF0为定时器0溢出标志,功能及操作方法同TF1
& = TCON^5;
//TR0为定时器0运行控制位,其功能及操作方式同TR1
& = TCON^4;
//IE1为外部中断1请求标志
//IT1=0时,为电平触发方式,每个机器周期的S5P2采样INT1引脚,
//若INT1脚为低电平,则置1,否则IE1清0
//IT1=1时,INT1位跳变沿触发方式,当第一个机器周期采样到INT1为低电平时,则IE1置1
//IE1=1时,表示外部中断1正在向CPU申请中断,当CPU响应中断,转向中断服务程序,该位由硬件清0
& = TCON^3;
//IT1为外部中断1触发方式选择位
//IT1=0,电平触发方式,引脚INT1上低电平有效
//IT1=1,跳变沿触发方式,引脚INT1上的电平从高到低的负跳变有效
& = TCON^2;
//IE0为外部中断0请求标志,功能及操作同IE1
& = TCON^1;
//IT0为外部中断0触发方式选择位,功能及操作同IT1
& = TCON^0;
//定时器1初值高8位
//定时器1初值低8位
#define uchar unsigned
#define uint unsigned
uchar flag,
uchar code
table[] = "I get "; & //定义一个字符类型编码数组
& init(); & //初始化
& while (1)
//若检测到flag为1, 说明程序已经执行过串口中断服务程序,
即收到了数据.&
& & & if (flag
&//手动将flag清0,方便标志位检测
& & flag = 0;
& & //检测到flag为1后,即串口中断发生,先将ES清0,
原因是接下来要发送数据, 若不关闭串口中断, 发送完数据后,
//单片机同样会申请串口中断,再次进入中断服务程序,flag又为1,又再此发送数据,一直重复
//因此我们在发送数据前把串口中断关闭,等发送完数据再打开串口中断,这样可以安全地发送数据
& & ES = 0;
//通过for循环将前面数组中字符依次发送出去
//由于数组table中共有6个字符,所以循环中以6作为结束个数
& & for (i = 0; i
& //发送字符
& SBUF = table[i];
& //当向SBUF中写入一个数据后,使用while(!TI)等待发送完毕,
因为发送完毕后TI会由
& //硬件置1,然后退出while(!TI)
& while (!TI);
& //再将TI手动清0
//向SBUF中写入从中断服务程序读回来的数据
& & SBUF =
& & while (!TI);
& & TI = 0; &
& & ES = 1; &
& &//新开启串口中断
& TMOD = 0x20; &//设定定时器1为工作方式2:
8位初值自动重装的8位定时器(设定定时器1目的是其溢出率决定串口波特率)
& TH1 = 0 &
//定时器1装初值(波特率为9600)
& TL1 = 0 &
//定时器1装初值(波特率为9600),注意:TH1,TL1初值必须相同
& //ET1 = 1;
&//这里不需要开启定时器1中断,因为定时器1工作在方式2,为8位自动重装方式,进入中断也无事可做
& REN = 1; & &
&//容许串行口接收数据
& SM0 = 0; & &
&//设定串口工作方式1
& SM1 = 1; & &
&//设定串口工作方式1(10位异步收发,波特率可变,且由定时器1的溢出率决定)
& EA = 1; & &
& //开总中断
& ES = 1; & &
& //开串口中断
& TR1 = 1; & &
&//启动定时器1
//串口中断服务程序
void ser()
interrupt 4
& //RI为接收中断标志位, 在方式0时, 当串行接收第8位数据结束时, 或在其他方式,
串行接收停止位的
& //中间时, 由内部硬件使RI置1, 向CPU发出中断申请, 也必须在中断服务程序中,
用软件将其清0,取消
& //此中断申请, 以方便下一次中断申请检测,
即这样才能产生下一次中断.
& //这里RI清0, 因为程序既然产生了串口中断, 肯定是收到或发送了数据,
在开始时没有发送任何数据
& //那必然是收到了数据, 此时RI会被硬件置1, 所以进入串口中断服务程序后必须由软件清0,
& //产生下一次中断.
& //将SBUF中的数据读走给a, 这是此中断服务程序最重要的目的
& a = SBUF;
& //将标志位flag置1, 以方便在主程序中查询判断是否已经收到数据
& flag = 1;
三.程序小结
操作串行口之前,需要对单片机的一些与串口有关的特殊功能寄存器进行初始化设置, 主要是设置产生波特率
的定时器1, 串行口控制和中断控制,其主要步骤包括:
确定T1的工作方式(变成TMOD寄存器)
计算T1的初值, 装载TH1,TL1
启动T1(编程TCON中的TR1位)
确定串行口工作方式(编程SCON寄存器)
串行口工作在中断方式时, 要进行中断设置(变成IE, IP寄存器)
51单片机可以通过特殊功能寄存器SBUF对串行接收或串行发送寄存器进行访问, 两个寄存器共用一个地址
99H,但在物理上是两个独立的寄存器, 由指令操作决定访问哪一个寄存器. 执行写指令时,
访问串行发送寄存器, 执行读指令时, 访问串行接收寄存器, 接收器具有双缓冲结构,
即在从接收寄存器中读出前一个已收到
的字节之前, 便能接收第二个字节, 如果第二个字节已经接收完毕, 第一个字节还没有读出,
则丢失其中
一个字节. 对于发送器, 因为数据由CPU控制和发送的,
所以不需要考虑.
a=SBUF;代表单片机自动将串口接收寄存器中的数据取走给a.
SBUF=a;代表单片机将串口发送寄存器中的数据一位位从串口发送出去.
此程序可以用在显示串口接收的数据上.
程序几个变量的说明
主函数main中while中ES=0可以换成EA=0,ES=1可以换成EA=1(即将串口中断的临时控制改为全局中断的控制)
初始化函数init中ET1=1不能打开,即便主函数外有计数器1的子函数(函数为空)
初始化函数init中TR1=1需要打开(包括TMOD=0x20),因为需要定时器1溢出率决定串口波特率.
初始化函数init中REN=1需要打开,否则串口不会接受数据
初始化函数SM1=1需要打开,否则串口接收乱码
初始化函数ES=1需要打开,否则串口不会接受数据
法2中TH1的地址位0x8D, 与TCON中的TF0位地址一样,
这里对TH1赋值时不是会对TF0产生影响吗?
已投稿到:
以上网友发言只代表其个人观点,不代表新浪网的观点或立场。请教个串口收、发数据的问题,同一个串口可以在接收数据的同时还可以发送数据吗?
[问题点数:200分,结帖人aft_st_sd]
请教个串口收、发数据的问题,同一个串口可以在接收数据的同时还可以发送数据吗?
[问题点数:200分,结帖人aft_st_sd]
不显示删除回复
显示所有回复
显示星级回复
显示得分回复
只显示楼主
本帖子已过去太久远了,不再提供回复功能。VC上位机MFC利用串口控件发送接收数据-电子产品世界论坛
VC上位机MFC利用串口控件发送接收数据
&经过这两天的调试,基本上搞定了dsp和机器人上位机界面,先记录下我的上位机。
& & & &实验室是做机器人控制的,经常会用到上位机,我只搞过简单的上位机的编写,是基于mfc的对话框的,很多原理性的东西现在也是懵懵懂懂的,但好歹是功能也实现了。回顾自己的上位机主要涉及过的东西为一些基本控件的使用(编辑框,按钮等等),1.串口发送和接收数据,2.手柄扫描(因为实验室用手柄来遥控机器人,扫描到手柄上不同的按钮发送不同的指令和数据,这样来实现对机器人的遥控),3.usb摄像的显示(不过这东西只是一个象征性的视频回显,似乎还没真正有什么作用)。
& & & &接下来这个实验先实现串口发送和接收数据,后面实验加上手柄,至于usb摄像头的显示不是很想加上去。到时候在看看吧。开始vc6.0实现串口发送和接收数据吧!!(已实现一个串口收发为例)
指导书参考:,自己按照自己的要求修改就行了。
——回复可见内容——
选择对话框
一路next和finish即可。
删除确定,取消,TODO。
2.在项目中插入MSComm控件&
& & 选择Project菜单下Add To Project子菜单中的&Components and Controls…选项,在弹出的对话框中双击Registered ActiveX Controls项
& & 选择MicrosoftCommunications Control, version 6.0,,单击Insert按钮将它插入到我们的Project中来,接受缺省的选项。
& & 在ClassView视窗中就可以看到CMSComm类了,你在控件中可以看到多了一个跟电话一样的东西。拖入到对话框中,程序运行时,他不会出现的。
3.利用ClassWizard定义CMSComm类控制对象
& &&打开ClassWizard-&Member Viariables选项卡,选择CSCommTestDlg类,为IDC_MSCOMM1添加控制变量:m_ctrlComm,(自己取好,前后一致)这时你可以看一看,在对话框头文件中自动加入了//{{AFX_INCLUDES()#include "mscomm.h" //}}AFX_INCLUDES。
4.打开串口和设置串口参数
& & 拖入一个按钮,命名为打开串口,双击,编辑函数
if(m_ctrlComm.GetPortOpen())&&
&&&&&&&&m_ctrlComm.SetPortOpen(FALSE);&&
&&&&m_ctrlComm.SetCommPort(1);&//选择com1&&
&&&&if(&!m_ctrlComm.GetPortOpen())&&
&&&&&&&&m_ctrlComm.SetPortOpen(TRUE);//打开串口&&
&&&&&&&&AfxMessageBox("&open&serial&port&successfully");&&
&&&&else&&
&&&&&&&&AfxMessageBox("cannot&open&serial&port");&&
&&&&m_ctrlComm.SetSettings("9600,n,8,1");&//波特率9600,无校验,8个数据位,1个停止位&&
&&&&m_ctrlComm.SetInputMode(1);&//1:表示以二进制方式检取数据&&
&&&&m_ctrlComm.SetRThreshold(1);&&&
&&&&//参数1表示每当串口接收缓冲区中有多于或等于1个字符时将引发一个接收数据的OnComm事件&&
&&&&m_ctrlComm.SetInputLen(0);&//设置当前接收区数据长度为0&&
&&&&m_ctrlComm.GetInput();//先预读缓冲区以清除残留数据&&
5添加串口事件消息处理函数OnComm()
& & 打开ClassWizard-&Message Maps,选择类CSCommTestDlg,选择IDC_MSCOMM1,双击消息OnComm,将弹出的对话框中将函数名改为OnComm。
& & 这个函数是用来处理串口消息事件的,如每当串口接收到数据,就会产生一个串口接收数据缓冲区中有字符的消息事件,我们刚才添加的函数就会执行,我们在OnComm()函数加入相应的处理代码就能实现自已想要的功能了。请你在函数中加入如下代码:
VARIANT&variant_&&
&&&COleSafeArray&safearray_&&
&&&LONG&len,k;&&
&&&BYTE&rxdata[2048];&//设置BYTE数组&An&8-bit&integerthat&is&not&signed.&&
&&&CString&&&
&&&if(m_ctrlComm.GetCommEvent()==2)&//事件值为2表示接收缓冲区内有字符&&
&&&{&&&&&&&&&&&&&////////以下你可以根据自己的通信协议加入处理代码&&
&&&&&&&variant_inp=m_ctrlComm.GetInput();&//读缓冲区&&
&&&&&&&safearray_inp=variant_inp;&//VARIANT型变量转换为ColeSafeArray型变量&&
&&&&&&&len=safearray_inp.GetOneDimSize();&//得到有效数据长度&&
&&&&&&&for(k=0;k;k++)&&
&&&&&&&&&&&safearray_inp.GetElement(&k,rxdata+k);//转换为BYTE型数组&&
&&&&&&&for(k=0;k;k++)&//将数组转换为Cstring型变量&&
&&&&&&&{&&
&&&&&&&&&&&BYTE&bt=*(char*)(rxdata+k);&//字符型&&
&&&&&&&&&&&strtemp.Format("%c",bt);&//将字符送入临时变量strtemp存放&&
&&&&&&&}&&
&&&UpdateData(FALSE);&//更新编辑框内容&&
6最后的测试
& & 需要一跟串口线,一个usb转串口(这样一台电脑就可以测试了),我们要实现的功能是串口助手发送一个字节到上位机,上位机显示这个字节,并把它发送出去,串口助手接收这个字节,这里我们还需要做一些工作。
& & 我们首先要在上位机中接收的字节显示出来,添加一个编辑框就可以了,我们显示在编辑框中。
SetDlgItemTextA(IDC_EDIT1,strtemp);
m_ctrlComm.SetOutput(COleVariant(strtemp));//发送数据
& & 在OnComm()添加上面两行就可以了,
编译,运行,测试结果:
& &&串口助手发送3F,在上位机显示?(呵呵,你可以去查找一下ASCLL码表就知道了),串口收到了来自上位机发送过来的数据,实验就是这么简单。下一篇博客写手柄和串口的联合使用。
关键词:&&&&&&&&&&&&
嘿嘿& 上位机啊~~
话说使用C#开发会快很多
感觉你什么都会的样子。。。
这样子。。。我一直都用MFC来做的。
看看有没有帮助哈。
杂而不精,这是比较痛苦的一件事情
MFC并不属于快速开发软件
学习。。。。。。
匿名不能发帖!请先 [
Copyright (C) 《电子产品世界》杂志社 版权所有  本人在近期的开发工作中遇到向串口发送设备控制指令的需求,遂对串口编程进行了略微深入的钻研,在此对自己的一些心得和经验进行总结,以供大家参考与交流。
  串口全称为串行接口,一般指COM接口,是采用串行通信方式的扩展接口。其特点是数据位的传送按位顺序进行,最少只需一根传输线即可完成,成本低但传送速度慢。由于串口(COM)不支持热插拔及传输速率较低,目前部分新主板和大部分便携电脑已取消该接口。现在串口多用于工业控制和测量设备以及部分通信设备中。
  根据美国电子工业协会(EIA: Electronic Industry Association)制定的标准,串口可以分为RS-232、RS-422以及RS-485等种类,其中以RS-232类型的接口最为典型和常见,本文所使用的是RS-232类型的9针串口(RS-232类型有25接口,但是现在几乎不再使用)。如图 1所示,是RS-232类型9针串口的实物示意图。RS-232类型9针串口每一个引脚的作用说明如图 2所示。
        图 1 RS232 9针串口实物示意图
        图 2 RS232 9针串口的针脚示意图
  想更加深入了解串口知识的读者请参阅以下内容:、、、
Java对串口编程的API包
  目前比较常见的针对Java的串口包有3个来源:一是1998年SUN发布的串口通信API:comm2.0.jar(Windows环境下)和comm3.0.jar(Linux/Solaris环境下);二是IBM的串口通信API;三是一些开源的API。本文介绍的是在Windows环境下使用java语言对串口进行编程,所以选取SUN的官方API(comm2.0.jar)。comm2.0.jar和comm3.0.jar的下载地址如下:
  comm2.0.jar:
  comm3.0.jar:
对串口编程的环境搭建
软件环境搭建
  在本文写作时,本人所使用的软件开发环境为:Windows7,Jdk1.6.0_10,Eclipse3.4.1。Java对串口编程的环境搭建分为以下步骤:
  1.下载并安装jdk,本人jdk的根目录是“D:\ProgramFiles\Java\jdk1.6.0_10”,在接下来的文章中路径“D:\ProgramFiles\Java\jdk1.6.0_10”将使用“%JAVA_HOME%”来代替;
  2.下载comm2.0.jar(下载链接见上文)并将串口编程必须的3个文件拷贝到jdk对应的文件夹中:
    2.1.将win32com.dll文件拷贝到“%JAVA_HOME%\bin”以及“%JAVA_HOME%\jre\bin”目录下
    2.2 将comm.jar文件拷贝到“%JAVA_HOME%\lib”以及“%JAVA_HOME%\jre\lib\ext”目录下
    2.3 将m.properties文件拷贝到“%JAVA_HOME%\lib”以及“%JAVA_HOME%\jre\lib”下
  3 新建工程并将comm.jar添加到工程文件中:
    3.1 新建java工程serialPortProgramming,并将该工程的运行时环境(JRE)指定为步骤1中新安装的jdk。
    3.2 在工程中新建“lib”文件夹,并将comm.jar文件拷贝到该文件夹下,右键点击该文件选择【Build Path】—【Add to Build Path】。
“硬件” 环境准备
  Java对串口编程,首先设备上需要有串口(这不废话吗),但如今的大多数电脑主板上并不带串口,所以本人用Virtual Serial Port Driver软件虚拟出一对串口COM11和COM21,以方便文章的写作和实验的进行。
  下载Virtual Serial Port Driver7.1()并安装,使用压缩包中的“vspdctl.dll”文件替换软件安装根目录中的“vspdctl.dll”文件即可完成破解。安装Virtual Serial Port Driver之后用该软件创建一对端口(COM11和COM21),在此创建的一对串口将在之后的实验中再次使用到。因为串口COM11和COM21是通过软件虚拟的、相互连接的一对串口,所以从COM11发送的数据COM21会接收到,反之亦然。
  当然如果自己的设备上有串口的话也可以不用创建虚拟串口,只需要将一个串口的数据发送引脚(引脚3,如图 2所示)和另一个串口的数据接收引脚(引脚2)使用一根铜线链接即可实现数据的收发。如果设备上只有一个串口,要实现串口数据的收发,可以将串口的引脚2和引脚3使用铜线相连接,这样从本串口发送的数据就会通过本串口接收到。
实例一:获取本地串口并实现打开与关闭
  在上文创建好的工程中新建包“com.serialPort.writer”并新建类OpenerAndCloser,该类实现串口的获取、打开与关闭。
OpenerAndCloser.java
package com.serialPort.
import java.util.E
import m.CommPortI
import m.NoSuchPortE
import m.PortInUseE
import m.SerialP
import m.UnsupportedCommOperationE
* 该类实现3个功能
* 1.列举出本地所有的串口;
* 2.打开所有串口(但是未向串口中写数据);
* 3.关闭打开的串口。
public class OpenerAndCloser {
public static void main(String[] args){
CommPortIdentifier portIdentifier = null;
Enumeration&?& allPorts
= CommPortIdentifier.getPortIdentifiers();
while(allPorts.hasMoreElements()){
portIdentifier
= (CommPortIdentifier) allPorts.nextElement();
System.out.println("串口:" + portIdentifier.getName());
CommPortIdentifier com11 = null;
CommPortIdentifier com21 = null;
com11 = CommPortIdentifier.getPortIdentifier("COM11");
com21 = CommPortIdentifier.getPortIdentifier("COM21");
} catch (NoSuchPortException e) {
e.printStackTrace();
SerialPort serialCom11 = null;
SerialPort serialCom21 = null;
serialCom11
= (SerialPort)com11.open("OpenerAndCloser", 1000);
serialCom21
= (SerialPort)com21.open("OpenerAndCloser", 1000);
} catch (PortInUseException e) {
e.printStackTrace();
serialCom11.setSerialPortParams(
SerialPort.DATABITS_8,
SerialPort.STOPBITS_1,
SerialPort.PARITY_NONE
serialCom21.setSerialPortParams(
SerialPort.DATABITS_8,
SerialPort.STOPBITS_1,
SerialPort.PARITY_NONE
} catch (UnsupportedCommOperationException e) {
e.printStackTrace();
serialCom11.close();
serialCom21.close();
  在以上的代码中,有两个较为重要的类,在此做以说明,它们是类CommPortIdentifier和类SerialPort。这两个类都来自于comm.jar,CommPortIdentifier类代表本地串口,可以通过该类的静态方法getPortIdentifier或getPortIdentifiers获取本地的串口,该类的实例方法open用于打开串口。SerialPort类同样代表本地串口,不过其代表的是打开的串口,可以通过该类的实例方法close关闭已经打开的串口,也可以通过该类的实例方法获取串口的输入输出流,实现往串口数据的读写操作。
  执行Com11Writer类的main方法,就会发现控制台输出了本地机器的所有串口(包括虚拟串口和物理串口)。
实例二:串口数据的读写
向串口写数据
  在包“com.serialPort.writer”下新建Com11Writer类,该类实现往COM11写入数据“Hello World!”的功能,向串口COM11写入的数据会发送到与其相连的另一个串口COM21,并被COM21所接收,从串口接收数据的方式将在下文讲到,以下是Com11Writer的源代码:
Com11Writer.java
package com.serialPort.
import java.io.IOE
import java.io.OutputS
import m.CommPortI
import m.NoSuchPortE
import m.PortInUseE
import m.SerialP
* Com11Writer类的功能是向COM11串口发送字符串“Hello World!”
public class Com11Writer {
public static void main(String[] args) {
CommPortIdentifier com11 = null;
SerialPort serialCom11 = null;
com11 = CommPortIdentifier.getPortIdentifier("COM11");
serialCom11 = (SerialPort) com11.open("Com11Writer", 1000);
OutputStream outputStream = serialCom11.getOutputStream();
outputStream.write(new byte[]{'H','e','l','l','o',
' ','W','o','r','l','d','!'});
outputStream.flush();
outputStream.close();
serialCom11.close();
} catch (NoSuchPortException e) {
e.printStackTrace();
} catch (PortInUseException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
从串口读数据
  从串口COM11发送的数据最终将到达与其连通的串口COM21,如果COM21处于可用状态,则到达的数据将被缓存,等待程序的读取。从串口读入数据有多种模式,本文将介绍“轮询模式”和事件监听模式。
  “轮询模式”是指程序(线程)每隔固定的时间就对串口进行一次扫描,如果扫描发现串口中有可用数据,则进行读取。Com21PollingListener类使用“事件监听模式”读取串口COM21接收到的数据:
Com21PollingListener.java
package com.serialPort.
import java.io.IOE
import java.io.InputS
import m.CommPortI
import m.NoSuchPortE
import m.PortInUseE
import m.SerialP
* Com21PollingListener类使用“轮训”的方法监听串口COM21,
* 并通过COM21的输入流对象来获取该端口接收到的数据(在本文中数据来自串口COM11)。
public class Com21PollingListener {
public static void main(String[] args){
CommPortIdentifier com21 = null;
SerialPort serialCom21 = null;
InputStream inputStream = null;
com21 = CommPortIdentifier.getPortIdentifier("COM21");
serialCom21 = (SerialPort) com21.open("Com21Listener", 1000);
inputStream = serialCom21.getInputStream();
byte[] cache = new byte[1024];
int availableBytes = 0;
while(true){
availableBytes = inputStream.available();
while(availableBytes & 0){
inputStream.read(cache);
for(int j = 0;j & cache.length && j & availableB j++){
System.out.print((char)cache[j]);
System.out.println();
availableBytes = inputStream.available();
Thread.sleep(20);
}catch(InterruptedException e){
e.printStackTrace();
}catch (NoSuchPortException e) {
e.printStackTrace();
} catch (PortInUseException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
  “事件监听模式”是为串口注册一个事件监听类,当有数据到达串口的时候就会触发事件,在事件的响应方法中读取串口接收到的数据。Com21EventListener类使用“事件监听模式”读取串口COM21接收到的数据:
Com21EventListener.java
package com.serialPort.
import java.io.IOE
import java.io.InputS
import java.util.TooManyListenersE
import m.CommPortI
import m.NoSuchPortE
import m.PortInUseE
import m.SerialP
import m.SerialPortE
import m.SerialPortEventL
* Com21EventListener类使用“事件监听模式”监听串口COM21,
* 并通过COM21的输入流对象来获取该端口接收到的数据(在本文中数据来自串口COM11)。
* 使用“事件监听模式”监听串口,必须字定义一个事件监听类,该类实现SerialPortEventListener
* 接口并重写serialEvent方法,在serialEvent方法中编写监听逻辑。
public class Com21EventListener implements SerialPortEventListener {
CommPortIdentifier com21 = null;
SerialPort serialCom21 = null;
InputStream inputStream = null;
public Com21EventListener(){
com21 = CommPortIdentifier.getPortIdentifier("COM21");
serialCom21 = (SerialPort) com21.open("Com21EventListener", 1000);
inputStream = serialCom21.getInputStream();
serialCom21.addEventListener(this);
serialCom21.notifyOnDataAvailable(true);
} catch (NoSuchPortException e) {
e.printStackTrace();
} catch (PortInUseException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (TooManyListenersException e) {
e.printStackTrace();
public void serialEvent(SerialPortEvent event) {
byte[] cache = new byte[1024];
int availableBytes = 0;
if(event.getEventType() == SerialPortEvent.DATA_AVAILABLE){
availableBytes = inputStream.available();
while(availableBytes & 0){
inputStream.read(cache);
for(int i = 0; i & cache.length && i & availableB i++){
System.out.print((char)cache[i]);
availableBytes = inputStream.available();
System.out.println();
} catch (IOException e) {
e.printStackTrace();
public static void main(String[] args) {
new Com21EventListener();
读写程序的联合运行
  串口能接收到数据的前提是该串口处于打开(可用)状态,如果串口处于关闭状态,那么发送到该串口的数据就会丢失。所以在实验的过程中,如果使用铜线连接同一个串口的引脚2和引脚3,一定要注意的是千万不能在向串口发送完数据之后关闭该串口,然后再次打开串口去读取数据,一定要让串口始终处于打开状态直到程序运行结束。
  基于以上的说明,在本文所涉及到的实例中,首先运行Com21PollingListener类(或Com21EventListener类)中的main方法打开端口监听程序,然后再运行Com11Writer类的main方法通过COM11向COM21发送数据,这样程序就能从COM21读取数据。
参考与鸣谢
  在本文写作的过程中参考了很多网络资源,其中参考了如下几篇文章,在此对所有作者的无私奉献表示衷心的感谢。
  本文实例的源工程文件可以从以下链接获取:
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:1150次
排名:千里之外

我要回帖

更多关于 tomcat 数据源 的文章

 

随机推荐