文章目录
1、串口
串行通信的接口
常见的数据通信的基本方式可分为:并行通信与串行通信
串行通信是指利用一条传输线将数据以比特位为单位顺序传送
特点:成本低、线路操作简单、适合远距离传输
1.1、并行传输:
字符编码的各位(比特)同时传输。
特点:
(1)传输速度快:一位(比特)时间内可传输一个字符;
(2)通信成本高:每位传输要求一个单独的信道支持;因此如果一个字符包含8个二进制位,则并行传输要求8个独立的信道的支持;
(3)不支持长距离传输:由于信道之间的电容感应,远距离传输时,可靠性较低
1.2、串行传输:
将组成字符的各位串行地发往线路。
特点:
(1)传输速度较低,一次一位;
(2)通信成本也较低,只需一个信道。
(3)支持长距离传输,目前计算机网络中所用的传输方式均为串行传输。
1.3、串行传输有两种传输方式:同步和异步
同步通信原理
同步通信是一种连续串行传送数据的通信方式,一次通信只传送一帧信息。这里的信息帧与异步通信中的字符帧不同,通常含有若干个数据字符。 采用同步通信时,将许多字符组成一个信息组,这样,字符可以一个接一个地传输,但是,在每组信息(通常称为帧)的开始要加上同步字符,在没有信息要传输时,要填上空字符,因为同步传输不允许有间隙。在同步传输过程中,一个字符可以对应5~8位。当然,对同一个传输过程,所有字符对应同样的数位,比如说n位。这样,传输时,按每n位划分为一个时间片,发送端在一个时间片中发送一个字符,接收端则在一个时间片中接收一个字符。 同步传输时,一个信息帧中包含许多字符,每个信息帧用同步字符作为开始,一般将同步字符和空字符用同一个代码。在整个系统中,由一个统一的时钟控制发送端的发送和空字符用同一个代码。接收端当然是应该能识别同步字符的,当检测到有一串数位和同步字符相匹配时,就认为开始一个信息帧,于是,把此后的数位作为实际传输信息来处理
异步通信原理
异步通信是一种很常用的通信方式。异步通信在发送字符时,所发送的字符之间的时间间隔可以是任意的。当然,接收端必须时刻做好接收的准备。发送端可以在任意时刻开始发送字符,因此必须在每一个字符的开始和结束的地方加上标志,即加上开始位和停止位,以便使接收端能够正确地将每一个字符接收下来
异步通信的好处
通信设备简单、便宜,但传输效率较低(因为开始位和停止位的开销所占比例较大)
同步通信与异步通信区别:
1.同步通信要求接收端时钟频率和发送端时钟频率一致,发送端发送连续的比特流;异步通信时不要求接收端时钟和发送端时钟同步,发送端发送完一个字节后,可经过任意长的时间间隔再发送下一个字节
2.同步通信效率高;异步通信效率较低
3.同步通信较复杂,双方时钟的允许误差较小;异步通信简单,双方时钟可允许一定误差。 4.同步通信可用于点对多点;异步通信只适用于点对点
1.4、异步串口 UART
UART->RS232/TTL
RS232:连接电脑的串口。-15v~ -3v 代表1 +3v~ +15v 代表0
TTL:芯片数据传输的常用串口。串口正极:+3.3V~5V,低电平:0V
1.5、单工、半双工、全双工
1.6、test 串口异步通信
grep “B115200” -r -n //递归查找包含 “B115200” 的文件
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <pthread.h>
#include <string.h>
#include <unistd.h>
static const char *ttySAC1 = "/dev/ttySAC1";//snd TX1
static const char *ttySAC2 = "/dev/ttySAC2";//rcv RX2
void init_uart(int fd)
{
struct termios new_cfg, old_cfg;
bzero(&new_cfg,sizeof(new_cfg));
bzero(&old_cfg,sizeof(old_cfg));
// 保存原先串口配置
tcgetattr(fd,&old_cfg);
// 激活选项(本地连接和接收使能)
new_cfg.c_cflag |= CLOCAL | CREAD;
// 设置原始模式和波特率
cfmakeraw(&new_cfg);
cfsetispeed(&new_cfg, B115200);
cfsetospeed(&new_cfg, B115200);
// 设置字符大小
new_cfg.c_cflag &= ~CSIZE; /* 用数据位掩码清空数据位设置 */
new_cfg.c_cflag |= CS8;
//设置奇偶校验
//无校验位
new_cfg.c_cflag &= ~PARENB;
//设置停止位
new_cfg.c_cflag &= ~CSTOP;/* 将停止位设置为一个比特 */
// new_cfg.c_cflag |= CSTOPB; /* 将停止位设置为两个比特 */
//设置最小字符和等待时间
new_cfg.c_cc[VTIME] = 0;
new_cfg.c_cc[VMIN] = 1;
//清除串口缓冲
tcflush(fd, TCIOFLUSH);
//激活配置
tcsetattr(fd,TCSANOW,&new_cfg);
}
void *thread_uart(void * arg)
{
int fd = *(int *)arg;
while(1)
{
//收数据
char buf[10] = {0};
read(fd,buf,10);
printf("data: %s\n",buf);
}
}
int main(int argc, char *argv[])
{
int fd1 = open(ttySAC1,O_RDWR | O_NOCTTY);
int fd2 = open(ttySAC2,O_RDWR | O_NOCTTY);
if(fd1 < 0 || fd2 < 0)
{
perror("open");
exit(0);
}
init_uart(fd1);
init_uart(fd2);
pthread_t tid;
pthread_create(&tid,NULL,thread_uart,(void *)&fd2);
while(1)
{
//发送数据
char buf[10]={0};
scanf("%s",buf);
write(fd1,buf,strlen(buf));
}
close(fd1);
close(fd2);
return 0;
}
/*
// 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]; special characters
设置奇偶校验位需要用到 termios 中的两个成员:c_cflag 和 c_iflag。首先要激活 c_cflag 中的校验位使能标志 PARENB 和是否要进行偶校验,同时还要激活 c_iflag 中 的对于输入数据的奇偶校验使能(INPCK)。
无校验位,代码如下:
new_cfg.c_cflag &= ~PARENB;
如使能奇校验时,代码如下所示:
new_cfg.c_cflag |= (PARODD | PARENB);
new_cfg.c_iflag |= INPCK;
而使能偶校验时,代码如下所示:
new_cfg.c_cflag |= PARENB;
new_cfg.c_cflag &= ~PARODD; //清除偶校验标志,则配置为奇校验
new_cfg.c_iflag |= INPCK;
tcsetattr(int fd, int optional_actions, const struct termios*termios_p);
其中参数 termios_p 是 termios 类型的新配置变量。
参数 optional_actions 可能的取值有以下 3 种:
TCSANOW:配置的修改立即生效。
TCSADRAIN:配置的修改在所有写入 fd 的输出都传输完毕之后生效。
TCSAFLUSH:所有已接受但未读入的输入都将在修改生效之前被丢弃。
该函数若调用成功则返回 0,若失败则返回-1,代码如下所示:
if ((tcsetattr(fd, TCSANOW, &new_cfg)) != 0)
{
perror("tcsetattr");
return -1;
}
*/
2、QT串口编程
QSerialPort
QSerialPortInfo
2.1、在工程文件里添加
QT += serialport
2.2、添加头文件
#include <QSerialPort>
#include <QSerialPortInfo>
2.3、获取本机串口
foreach(constQSerialPortInfo &info,QSerialPortInfo::availablePorts())
{
ui->cbb_com->addItem(info.portName());
}
2.4、创建串口对象
QSerialPort mserial;
2.5、配置串口
mserial.setBaudRate(115200);//设置波特率
mserial.setDataBits(QSerialPort::Data8);//设置数据位
mserial.setStopBits(QSerialPort::OneStop);//停止位
mserial.setParity(QSerialPort::NoParity);//无奇偶校验
mserial.setFlowControl(QSerialPort::NoFlowControl);//无流控
2.6、打开串口
mserial.setPortName(ui->comboBox->currentText());
if(!mserial.open(QIODevice::ReadWrite))
{
qDebug()<<"串口打开失败";
}
else
{
qDebug()<<"串口打开成功";
}
2.7、 读写数据
//读数据
//关联可读信号的槽函数
connect(&mserial, &QSerialPort::readyRead, this, &MainWindow::read_data);
void MainWindow::read_data()
{
QString msg = mserial.readAll();
ui->textBrowser->append(msg);
}
//写数据
void MainWindow::on_btn_send_clicked()
{
mserial.write(ui->textEdit->toPlainText().toUtf8());
}
3.8 关闭串口
mserial.close();
::read_data);
void MainWindow::read_data()
{
QString msg = mserial.readAll();
ui->textBrowser->append(msg);
}
//写数据
void MainWindow::on_btn_send_clicked()
{
mserial.write(ui->textEdit->toPlainText().toUtf8());
}
3.8 关闭串口
mserial.close();