主機(jī)串口用到的工具是SSCOM32,虛擬機(jī)串口工具是VSPD。即通過VSPD工具,可以將二者的串口相連,可以想象成有一根串口線連接了主機(jī)和虛擬機(jī)。
第一步 確定端口
打開VSPD,如下圖,點(diǎn)擊“Port pairs”-“create pair“。我們要用到的就是COM1和COM2。此時(shí),二者狀態(tài)都是:close。
然后,打開虛擬機(jī),“虛擬機(jī)”-“設(shè)置”-“串口”-選擇端口號,并開啟,確認(rèn)。
如下圖,這樣代表該串口已打開。
再打開SSCOM,選擇“串口2”,打開串口。
同樣,在VSPD中觀察到串口已經(jīng)被打開。
第二步 測試
虛擬機(jī)串口向主機(jī)發(fā):
可以看到,主機(jī)串口收到了“hello”。
說到這里,復(fù)習(xí)一下“終端”。
1、控制臺(tái)終端:tty0~tty6,也叫虛擬終端。(tty0是當(dāng)前正在使用的虛擬終端的別名)
2、偽終端:pty(圖形終端,遠(yuǎn)程控制終端)
3、串口終端:ttyS0~ttyS4
控制終端:tty。即當(dāng)前正在使用的終端(以上的任何一種都有可能是控制終端)。
這個(gè),自己輸入輸出重定向練習(xí)練習(xí)就清楚了~
10年積累的網(wǎng)站設(shè)計(jì)、做網(wǎng)站經(jīng)驗(yàn),可以快速應(yīng)對客戶對網(wǎng)站的新想法和需求。提供各種問題對應(yīng)的解決方案。讓選擇我們的客戶得到更好、更有力的網(wǎng)絡(luò)服務(wù)。我雖然不認(rèn)識(shí)你,你也不認(rèn)識(shí)我。但先建設(shè)網(wǎng)站后付款的網(wǎng)站建設(shè)流程,更有從江免費(fèi)網(wǎng)站建設(shè)讓你可以放心的選擇與我們合作。
同時(shí),在vspd中也能看到二者傳輸?shù)男畔ⅲ?br/>
第三步 初始化串口配置信息
一般來說,我們可以手動(dòng)修改虛擬機(jī)和主機(jī)的串口配置信息(波特率、校驗(yàn)位、停止位等等),但是每次都要修改是不是很麻煩呢。所以,可以寫一個(gè)初始化串口配置信息的文件,在通信之前執(zhí)行就可以了。
初始化串口的代碼如下:
port.h
#ifndef _PORT_H_
#define _PORT_H_
#include
#include < termios.h>
#include < unistd.h>
#include < sys/types.h>
#include < sys/stat.h>
#include < fcntl.h>
/**
struct termios{
tcflag_t c_iflag; // input modes
tcflag_t c_oflag; // output modes
tcflag_t c_cflag; // control modes
tcflag_t c_lflag; // local modes
cc_t c_cc[NCCS]; // control chars
};
*/
//設(shè)置波特率
void setSpeed(struct termios *ptio,int speed);
//設(shè)置數(shù)據(jù)位
void setData(struct termios *ptio,int data);
//設(shè)置奇偶校驗(yàn)
void setParity(struct termios *ptio,int flag); //0-忽略奇偶校驗(yàn) 1-設(shè)置奇校驗(yàn) 2-設(shè)置偶校驗(yàn)
//設(shè)置停止位
void setStop(struct termios *ptio, int stop);
//初始化串口 返回值:fd
int portInit(char devname[],int speed,int data,int flag,int stop);
#endif
port.c
#include " port.h"
//設(shè)置波特率
void setSpeed(struct termios *ptio,int speed)
{
switch(speed)
{
case 9600:
cfsetispeed(ptio,B9600);
cfsetospeed(ptio,B9600);
break;
case 14400:
break;
case 19200:
cfsetispeed(ptio,B19200);
cfsetospeed(ptio,B19200);
break;
case 38400:
cfsetispeed(ptio,B38400);
cfsetospeed(ptio,B38400);
break;
case 115200:
cfsetispeed(ptio,B115200);
cfsetospeed(ptio,B115200);
break;
default:
break;
}
}
//設(shè)置數(shù)據(jù)位
void setData(struct termios *ptio,int data)
{
ptio->c_cflag &= ~CSIZE;
switch(data)
{
case 5:
ptio->c_cflag |= CS5;
break;
case 6:
ptio->c_cflag |= CS6;
break;
case 7:
ptio->c_cflag |= CS7;
break;
case 8:
ptio->c_cflag |= CS8;
break;
default:
break;
}
}
//設(shè)置奇偶校驗(yàn) 0-忽略奇偶校驗(yàn) 1-設(shè)置奇校驗(yàn) 2-設(shè)置偶校驗(yàn)
void setParity(struct termios *ptio,int flag)
{
switch(flag)
{
case 0:
ptio->c_cflag &= ~PARENB;
break;
case 1:
ptio->c_cflag |= PARENB;
ptio->c_cflag |= PARODD;
ptio->c_iflag |= (INPCK | ISTRIP);
break;
case 2:
ptio->c_iflag |= (INPCK | ISTRIP);
ptio->c_cflag |= PARENB;
ptio->c_cflag &= ~PARODD;
break;
default:
break;
}
}
//設(shè)置停止位 (若停止位為1,則清除CSTOPB;若停止位為2,則激活CSTOPB)
void setStop(struct termios *ptio, int stop)
{
switch(stop)
{
case 1:
ptio->c_cflag &= ~CSTOPB;
break;
case 2:
ptio->c_cflag |= CSTOPB;
break;
default:
break;
}
}
//初始化串口 返回值:fd
int portInit(char devname[],int speed,int data,int flag,int stop)
{
int fd;
struct termios tio = {0};
//打開串口設(shè)備
fd = open(devname,O_RDWR);
if(fd == -1)
{
printf("open port : %s failed.\n",devname);
return;
}
//獲取原有串口配置
tcgetattr(fd,&tio);
//激活選項(xiàng)有CLOCAL和CREAD,用于本地連接和接收使能
tio.c_cflag |= CLOCAL | CREAD;
//設(shè)置波特率
setSpeed(&tio,speed);
//設(shè)置數(shù)據(jù)位,需要使用掩碼設(shè)置
setData(&tio,data);
//設(shè)置奇偶校驗(yàn)
setParity(&tio,flag);
//設(shè)置停止位
setStop(&tio, stop);
//設(shè)置最少字符和等待時(shí)間
tio.c_cc[VTIME] = 0;
tio.c_cc[VMIN] = 1; //最小字符,緩沖區(qū)里達(dá)到數(shù)量時(shí)才返回
//設(shè)置不采用流控制
tio.c_cflag &= ~CRTSCTS;
//清除(輸入)緩存
tcflush(fd,TCIFLUSH);
//設(shè)置串口默認(rèn)為堵塞模式
fcntl(fd,F_SETFL,0);
//激活配置
tcsetattr(fd,TCSANOW,&tio);
return fd;
}
如何查看串口配置是否成功?要查看某個(gè)串口的波特率等信息,可以在控制臺(tái)輸入命令: stty -F /dev/ttyS0 -a #ttyS0為要查看的串口。
第四步 讀取配置信息
這個(gè),在上一篇文章中已經(jīng)展示過了,為了練手,可以從配置文件中讀取配置信息,再利用以上代碼進(jìn)行初始化,當(dāng)然也可以直接初始化啦~
以下是從文件中獲取配置信息(基于上一篇文章內(nèi)容)
配置信息:
readConfig.h
#ifndef _READCONFIG_H_
#define _READCONFIG_H_
#include < stdio.h>
#include < string.h>
#include < sys/types.h>
#include < sys/stat.h>
#include < fcntl.h>
/*串口屬性結(jié)構(gòu)體*/
struct t_port
{
char devname[20];
int speed;
int data;
int parity;
int stop;
};
//去空格
void rm_space(char *pStr);
//去注釋
void rm_annotation(char *pStr);
//獲取配置項(xiàng)信息
void getMsg(char filename[],struct t_port *port);
#endif
readConfig.c
#include " readConfig.h"
int icount = 0;
//去空格
void rm_space(char *pStr)
{
char *pos = pStr;
pos = strchr(pStr,' ');
while(pos != NULL)
{
strcpy(pos,pos+1);
pos = strchr(pos,' ');
}
}
//去注釋
void rm_annotation(char *pStr)
{
icount++;
char *pos = pStr;
char *end = NULL;
if(icount == 1) //第一行有可能頂格
{
pos = strchr(pStr,'#');
}
else
{
pos = strstr(pStr,"\n#");
}
while(pos != NULL)
{
end = strchr(pos+1,'\n');
strcpy(pos,end);
pos = strstr(pStr,"\n#");
}
}
//獲取配置項(xiàng)信息
void getMsg(char filename[],struct t_port *port)
{
int fd;
int readByte;
char buf[512] = "";
char *pos = NULL;
char *end = NULL;
char key[20] = " ";
char value[20] = " ";
char keys[10][20] = {""};
char values[10][20] = {""};
int flag = 0;
int i = 0;
//打開配置文件
fd = open(filename, O_RDWR);
readByte = read(fd,buf,512);
//處理數(shù)據(jù)
rm_space(buf);
rm_annotation(buf);
pos = strchr(buf,'\n');
end = strchr(pos,'=');
while(end != NULL)
{
memset(key,0,sizeof(key));
memset(value,0,sizeof(value));
memcpy(key,pos+1,end - (pos + 1));
pos = end;
end = strchr(pos,'\r');
if(end == NULL) //if the final data
{
flag = 1;
break;
}
memcpy(value,pos+1,end - (pos + 1));
//存key value
memcpy(keys[i],key,strlen(key));
memcpy(values[i],value,strlen(value));
i++;
pos = end + 1;
end = strchr(pos,'=');
}
if(flag)
{
end = strchr(pos,'\0');
memcpy(value,pos+1,end - (pos + 1));
memcpy(keys[i],key,strlen(key));
memcpy(values[i],value,strlen(value));
}
//進(jìn)行匹配
for(i = 0; i < 10 ;i++)
{
if(strcmp(keys[i],"dev") == 0)
{
strcpy(port->devname,values[i]);
}
else if(strcmp(keys[i],"speed") == 0)
{
port->speed = atoi(values[i]);
}
else if(strcmp(keys[i],"data") == 0)
{
port->data = atoi(values[i]);
}
else if(strcmp(keys[i],"parity") == 0)
{
port->parity = atoi(values[i]);
}
else if(strcmp(keys[i],"stop") == 0)
{
port->stop = atoi(values[i]);
}
}
}
第五步 編寫通信程序
那么,主函數(shù)只要調(diào)用以上功能能函數(shù),再調(diào)用read\write系統(tǒng)函數(shù),就可以了。
#include < stdio.h>
#include " port.h"
#include " readConfig.h"
int main()
{
int fd;
char filename[20] = "serial.cfg";
char recbuf[100] = "";
char sendbuf[100] = "";
struct t_port port = {0};
//從文件獲取配置信息
getMsg(filename,&port);
//串口初始化
fd = portInit(port.devname,port.speed,port.data,port.parity,port.stop);
//主機(jī)與虛擬機(jī)串口通信
while(1)
{
memset(recbuf,0,100);
memset(sendbuf,0,100);
//虛擬機(jī)等待主機(jī)用戶輸入,接收消息
printf("please wait...\n");
read(fd,recbuf,100);
printf("receive msg: %s\n",recbuf);
//等待虛擬機(jī)用戶輸入,發(fā)送消息給主機(jī)
printf("send msg: ");
scanf("%s",sendbuf);
if(strcmp(sendbuf,"over") == 0)
{
break;
}
write(fd,sendbuf,sizeof(sendbuf));
}
close(fd);
return 0;
}
第六步 編譯運(yùn)行
編譯運(yùn)行之后,主機(jī)(SSCOM32)虛擬機(jī)串口之間就可以通信了。如下圖:
主機(jī):hello
虛擬機(jī):world
主機(jī):12345
虛擬機(jī):over
運(yùn)行時(shí),如果出現(xiàn)主機(jī)發(fā)消息,虛擬機(jī)接收不到的情況,是因?yàn)橄?nèi)容都還在緩沖區(qū)。比如,在用write發(fā)送數(shù)據(jù)時(shí)沒有鍵入回車,信息就將發(fā)送不出去的情況,這主要是因?yàn)槲覀冊谳敵鲚斎霑r(shí)是按照 規(guī)范模式接受到回車或者換行才發(fā)送,而很多情況我們是不需要回車和換行的,這時(shí),應(yīng)當(dāng)切換到行方式輸入,tio.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);不經(jīng)處理直接發(fā)送。
當(dāng)然也可以直接在SSCOM的界面上勾選“發(fā)送新行”。
但是,可以發(fā)現(xiàn),我們只能實(shí)現(xiàn):主機(jī)發(fā)一句,虛擬機(jī)收到內(nèi)容后才能發(fā)送,然后主機(jī)收到內(nèi)容才可以繼續(xù)發(fā)送。不能做到主機(jī)和虛擬機(jī)同時(shí)發(fā)送,那么如何解決呢?多進(jìn)程就OK了。明天再寫~