写在前面

待更

串口通信

待更

Linux实现

标准库

1
2
3
4
5
6
#include <unistd.h> //Unix 标准函数
#include <sys/types.h> //系统类型
#include <sys/stat.h> //系统状态
#include <fcntl.h> //文件控制
#include <termios.h> //POSIX标准IO接口
#include <errno.h> //错误号

封装

功能/步骤清单 serialcom.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#ifndef _SERIALCOM_H_
#define _SERIALCOM_H_

#include <stdio.h>
#include <stdlib.h>
#include <termios.h>

class SerialCom {
private:
int fd;//串口文件
struct termios opts;
char data[512];
public:
~SerialCom();
bool setBaud(int);
bool setDatabit(int);
bool setParityStopbit(int,int);
bool getSerial(char*);
bool closeSerial();
bool recieveData();
void sendData();
void setSyn(int);
};

#endif

打开串口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
bool SerialCom::getSerial(char* addr){
//打开串口
this->fd = open(addr,O_RDWR | O_NOCTTY);
if(this->fd < 0){
perror("Failed to open serial!");
close(this->fd);
return false;
}
//获取终端参数,传给opts
if(tcgetattr(this->fd,&this->opts) != 0){
perror("Failed to get serial options!");
return false;
}
fcntl(this->fd,F_SETFL,0);
fcntl(this->fd,F_SETOWN,getpid());
/*
- 设置文件的flags:
fcntl(fd,F_SETFL,flags);
- F_SETOWN:
设置将要在文件描述词fd上接收SIGIO 或 SIGURG事件信号的进程或进程组标识
*/
return true;
}

设置波特率

1
2
3
4
5
6
7
8
9
10
11
bool SerialCom::setBaud(int baud){
int status;
cfsetispeed(&this->opts,baud);
cfsetospeed(&this->opts,baud);
status = tcsetattr(this->fd, TCSANOW, &this->opts);//不等数据传输完毕就立即改变属性
if(status != 0){
perror("set Baud Option fail!");
return false;
}
return true;
}

设置校验位和停止位

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
bool SerialCom::setParityStopbit(int p,int s){
int status;
// this->opts.c_cflag &=~ CSIZE;//先屏蔽其他标志位
switch(p){
case 1://奇校验
this->opts.c_cflag |= PARENB;//使能
this->opts.c_cflag |= PARODD;
this->opts.c_iflag |= INPCK;
break;
case 2://偶校验
this->opts.c_cflag |= PARENB;
this->opts.c_cflag &= ~PARODD;
this->opts.c_iflag |= INPCK;
break;
case 0://不校验
this->opts.c_cflag &= ~PARENB;
this->opts.c_iflag |= INPCK;
default:
perror("Error Parity bit id to Option!");
return false;
}
if(s == 1){
this->opts.c_cflag &= ~CSTOPB;
}else if(s == 2){
this->opts.c_cflag |= CSTOPB;
}else{
perror("Error Stop bit id to Option!");
return false;
}
status = tcsetattr(this->fd, TCSANOW, &this->opts);
if(status != 0){
perror("set parity&Stop Option fail!");
return false;
}
return true;
}

设置数据位

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
bool SerialCom::setDatabit(int data_bit){
int status;
this->opts.c_cflag &= ~CSIZE;//先屏蔽其他标志位
switch (data_bit){
case 7:
this->opts.c_cflag |= CS7;
break;
case 8:
this->opts.c_cflag |= CS8;
break;
default:
perror("Error data bit num to Option!");
return false;
}
status = tcsetattr(this->fd, TCSANOW, &this->opts);
if(status != 0){
perror("set data bit Option fail!");
return false;
}
return true;
}

发送与接收

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void SerialCom::sendData(){
char put[512];
printf("请输入:");
scanf("%s",put);
write(this->fd,put,strlen(put));
}
bool SerialCom::recieveData(){
int Isget;
Isget = read(this->fd,this->data,512);
if(Isget > 0){
printf("\n$ Get Message:\n\t");
this->data[Isget] = 0;
printf("%s\n",this->data);
return true;
}
return false;
}

是否相应SIGIO中断

1
2
3
4
5
6
7
void SerialCom::setSyn(int flag){
if(flag == 0){
fcntl(this->fd,F_SETFL,0);
}else{
fcntl(this->fd,F_SETFL,FASYNC);
}
}

关闭串口(析构函数)

1
2
3
SerialCom::~SerialCom(void){
close(this->fd);
}

查询方式

循环查找

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include "SerialCom_src/serialcom.h"
#include <stdio.h>
int main(void){

char path[] = "/dev/ttyS1";
SerialCom* uart = new SerialCom();

uart->getSerial(path);
uart->setBaud(B9600);
uart->setDatabit(8);
uart->setParityStopbit(2,2);

while(1){
uart->sendData();
uart->recieveData();
}
delete uart;
return 0;
}

select()函数

待更

多线程扩展

此处利用Linux下的pthread.h实现多线程处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#include "SerialCom_src/serialcom.h"
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <iostream>

using namespace std;

void* get_message(void* args){
printf("接收线程 启动!\n");
SerialCom* uart = (SerialCom*)args;
while(1){
uart->recieveData();
sleep(1);
}
pthread_exit(NULL);
}

void* send_message(void* args){
printf("发送线程 启动!\n");
SerialCom* uart = (SerialCom*)args;
while(1){
uart->sendData();
sleep(1);
}
pthread_exit(NULL);
}

int main(void){

int ret;
bool flag = false;
char path[] = "/dev/ttyS1";
pthread_t tid1,tid2;
SerialCom* uart = new SerialCom();

uart->getSerial(path);
uart->setBaud(B9600);
uart->setDatabit(8);
uart->setParityStopbit(2,2);

ret = pthread_create(&tid1,NULL,get_message,(void*)uart);
if(ret){
cout << "Error:接受消息线程创建失败 [error code:" << ret << "]" << endl;
exit(-1);
}
ret = pthread_create(&tid2,NULL,send_message,(void*)uart);
if(ret){
cout << "Error:发送消息线程创建失败 [error code:" << ret << "]" << endl;
exit(-1);
}
// delete uart;
pthread_exit(NULL);
}

信号/中断方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include "SerialCom_src/serialcom.h"

#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<sys/signal.h>

bool flag = false;

void signal_handler_IO(int status){
//printf("received SIGIO signale.\n");
flag = true;
}

int main(void){

char path[] = "/dev/ttyS1";
SerialCom* uart = new SerialCom();

struct sigaction saio;
saio.sa_handler = signal_handler_IO;
sigemptyset (&saio.sa_mask);
saio.sa_flags = 0;
saio.sa_restorer = NULL;
sigaction(SIGIO, &saio, NULL);

uart->getSerial(path);
uart->setBaud(B9600);
uart->setDatabit(8);
uart->setParityStopbit(2,2);
uart->setSyn(1);//开启中断

while(1){
usleep(100000);
if(flag){
uart->recieveData();
flag = false;
}
uart->sendData();
}
return 0;
}

仿真实践

所需软件:

  1. Virtual Serial Port Driver Pro 9.0|下载地址
  2. Uart assist|下载地址
  3. cutecom |debian系统可通过sudo apt-get install cutecom命令安装

参考

  1. 串口通信. 简小黑. 简书
  2. 串口通信详解. 泪无痕z. CSDN
  3. linux下的RS232通信实践. 平凡淡定面对生活. 博客园
  4. 主机和虚拟机通过虚拟串口通信. adgentleman. CSDN
  5. Linux系统串口接收数据编程. bg2bkk. CSDN
  6. Linux下串口编程入门. 冷烟花. 博客园