【pythonserial虚拟串⼝通信】发送端python代码实现--接收端C代码验证python虚拟串⼝模块serial安装
2.解压:tar -zxvf pyserial-
3.
3.进⼊解压⽬录:cd pyserial-3.4/
4.安装sudo python setup.py install(这⾥以ubuntu为例,其他linux操作系统可切换在root权限下进⾏安装操作)
程序设计需求
【虚拟串⼝的建⽴形式】
根据python serial库的特殊性质,它可以产⽣两个相互短接的虚拟串⼝,通过对这两个串⼝进⾏读写,可以实现消息的收发。因此,笔者进⾏学习调研后,在下⾯的代码中,运⽤这个serial库的相关函数,打开了⼀个虚拟串⼝,同样也实现了发送端和接收端在同⼀个串⼝进⾏收发消息的功能。
由虚拟串⼝实现原理可以发现,它的设计是⼀个while(true)死循环,因为它要不停地检测在此串⼝下的数据流。
【发送端程序实现形式】
代码编写语⾔:python
对于串⼝实现的消息收发,python也有os.read()和os.write()这类针对数据读写的函数,因此发送端的设计采⽤raw_input()接收来⾃终端的消息,通过os.write()写⼊串⼝内的缓存,同时通过os.read()⼀次性读取接收端反馈的消息;
另外,考虑到实际⼯程需求,笔者将虚拟串⼝和发送端集成到⼀起,这样⼀来,只需要运⾏集成后的发送端代码,就可以同时开启虚拟串⼝和发送消息;
考虑到虚拟串⼝建⽴是⼀个不能被中断的死循环,因此,在集成代码时,将虚拟串⼝的建⽴作为⽗线程。要实现不停发送消息的⼯程需求,发送端也是⼀个死循环,它作为⼦线程依赖于⽗线程运⾏,⼀旦⼦线程break了,⽗线程发现⼦线程死了,那么⽗线程也结束。
【接收端验证程序】
代码编写语⾔采⽤C语⾔
设计模式是:接收端⼀旦在串⼝中读到数据,则向串⼝中发回执消息,向发送端通知消息已经成功接收。
python虚拟串⼝代码分析
下⾯的代码是笔者在补充学习python serial虚拟串⼝建⽴过程中,淘到的有意思的代码,贴出来做⼀个分享,同时结合笔者在开发过程中遇到的问题,对代码做⼀些浅显的分析。(后⾯笔者贴出的发送端代码也是基于这个代码的学习进⾏编写的)
笔者的理解:
在创建虚拟串⼝的mkpty()函数中,master, slave = pty.openpty() ⽅法⽤于打开⼀个新的伪终端对。在调试程序时发现,若改成在slave 端进⾏消息的收发, 发现消息发不出去,当然也收不到回执的OK消息,python发送端和c接收端的收发都是read/write,说明master是read/write、slave是port_recv, 也就是说 pty对应master ,⽤于read write ;tty对应slave⽤于port_recv…
为避免别的设备占⽤tty的slave⼝,笔者曾想着把slave这个端⼝强制关闭。
pty.openpty()分别为主机和从机端返回⼀对⽂件描述符(pty,tty)。后来对这两个描述符进⾏思考发现:
master和slave就像钥匙⼀样,它俩其实是随机的,跟最终⽣成的端⼝没有必然的规律。但是发送⽅和对端只有匹配了master和slave,才能打开它俩建⽴的“锁”—-/dev/pts/num。所以,根据这个发现,别的设备不会与我的指定设备占⽤tty的slave⼝,也不⽤关闭slave ⼝,否则发送⽅就没法与对端通过master和slave建⽴的虚拟端⼝通信了。
#! /usr/bin/env python
#coding=utf-8
import pty
import os
import select
def mkpty ():
master1, slave = pty.openpty()
slaveName1 = os.ttyname(slave)
master2, slave = pty.openpty()
slaveName2 = os.ttyname(slave)
print '\nslave device names: ', slaveName1, slaveName2
return master1, master2
if __name__ == "__main__":
master1, master2 = mkpty()
while True :
rl, wl, el = select.select([master1,master2], [], [], 1)
for master in rl:
data = os.read(master, 128)
print "read %d data." % len(data)
if master==master1:
os.write(master2, data)
else :
os.write(master1, data)
从实际测试来看,创建虚拟串⼝虽然随机,但是不会同时建两个⼀样的串⼝,只要最终创建的虚拟串⼝不同,slave1和slave2即使相同也不会占⽤。
serial虚拟串⼝建⽴+发送端python实现
笔者经过思考后,对上⾯的代码进⾏修改,结合实际的⼯程需求,将建⽴虚拟串⼝和消息的发送集成到了⼀起,通过开辟不同的线程,让两者能同时正常运⾏。
下⾯贴出源代码:
import serial
import sys
import pty
import os
import time
import select
from time import ctime
from time import sleep
import threading #multi thread working mode
python怎么读取串口数据#send & recv msg using mkpty port
def Vpsend(slaveName,master):#slaveName is the parameter from mkpty()
print"\n"
print" Open the port.\n"
sleep(1)
ser=serial.Serial(slaveName,9600,timeout=0.5) #pass parameter:slaveName
print"Open port successful! the port information:"
print ser
print"\n"
while ser.isOpen(): #the return is True or Faulse
print"please write the msg(exit to break)"
msg=raw_input()
#add a break reason:::kill the child thread
if msg == 'exit':
print"\n"
print"Please waiting to close "
sleep(1)
break;
msg=msg + '\r' + '\n'#AT form define
#data=ser.write(msg)
os.write(master, msg)
sys.stdout.flush() #flush the buffer
print"\n"
print ("waiting to recv ")
sleep(2)
msg_recv = os.read(master,128)
print ("\n")
print ("\tOK! The recv msg is %s"%(msg_recv))
#create only one virtual port
def mkpty():
#make pair of pseudo tty
master, slave = pty.openpty()
slaveName = os.ttyname(slave)
print"slave device names:", slaveName
#set the Vpsend() as the child thread and set the 'slaveName' as pass parameter, Vpsend will use 'slaveName' t=threading.Thread(target=Vpsend,args=(slaveName,master))
t.start() #start this thread
while True:
sleep(1)
if t.is_alive() == False: #when the child thread killed, then this father
break
mkpty()
(ps:由于实际⼯程平台中⽂会产⽣乱码,英⽂注解有点蹩脚,稍微将就⼀下。。。)
在设计上⾯代码的时候,笔者发现:
原参考的创建虚拟串⼝代码中,主线程⾥本⾝就有对该串⼝进⾏os.read和os.write的读写操作,再加上⼦线程也有对此串⼝的ad和ser.write读写操作,以及对端(接收端)对串⼝中的数据的read和write操作,使得⼦线程在接收对端数据时,会与主线程的os.read产⽣竞争。
针对此,笔者的解决⽅案是:删除主线程⾥对串⼝进⾏os.read和os.write的读写操作,只保留⼦线程与对端的通信联系。
接收端C代码实现
为了测试我们的发送端主代码是否能正常⼯作,笔者设计了⼀个C的接收程序,源代码如下:
代码中,默认打开的端⼝是3,可以在命令⾏传参更改打开端⼝,执⾏命令如下:
gcc receive.c -o recv
./recv -p 4 //假设发送端打开的端⼝是4,接收端也打开4才能与发送端通信
//receive.c
#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <termios.h>
#include <math.h>
#include <stdlib.h>
#define MAX_BUFFER_SIZE 512
int fd, s;
char * g_pts = "/dev/pts/3";
int opt = -1;
/*open port*/
int open_port()
{
fd = open(g_pts, O_RDWR|O_NOCTTY|O_NDELAY);
if(fd == -1)
{
perror("open serial port error!\n");
return -1;
}
printf("open /dev/ttyS0.\n");
return0;
}
int main(int argc, char* argv[])
{
char hd[MAX_BUFFER_SIZE], *rbuf;
int flag_close, result;
struct termios option;
while((opt = getopt(argc, argv,"p:")) != -1)
{
switch(opt)
{
case'p':/*hook bind pts number*/
{
char pts[] = "/dev/pts/0";
int len = sizeof(pts);
char * tmp = (char *)malloc(100*sizeof(char));
memcpy(tmp, pts, len);
char * rec = optarg;
strcpy(tmp+len-2,rec );
g_pts = tmp;
break;
}
case'?':
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论