串口的数据格式为:
规定传输的数据格式由起始位(start bit)、数据位(data bit)、奇偶校验位(parity bit)和停止位(stop bit)组成,如图1所示(该图中未画出奇偶校验位,因为奇偶检验位不是必须有的,如果有奇偶检验位,则奇偶检验位应该在数据位之后,停止位之前)。
(1)起始位:起始位必须是持续一个bit时间的逻辑0电平,标志传输一个字符的开始,接收方可用起始位使自己的接收时钟与发送方的数据同步。
(2)数据位:数据位紧跟在起始位之后,是通信中的真正有效信息。数据位的位数可以由通信双方共同约定,一般可以是5位、7位或8位,标准的ASCII码是0~127(7位),扩展的ASCII码是0~255(8位)。传输数据时先传送字符的低位,后传送字符的高位。
(3)奇偶校验位:奇偶校验位仅占一位,用于进行奇校验或偶校验,奇偶检验位不是必须有的。如果是奇校验,需要保证传输的数据总共有奇数个逻辑高位;如果是偶校验,需要保证传输的数据总共有偶数个逻辑高位。举例来说,假设传输的数据位为01001100,如果是奇校验,则奇校验位为0(要确保总共有奇数个1),如果是偶校验,则偶校验位为1(要确保总共有偶数个1)。由此可见,奇偶校验位仅是对数据进行简单的置逻辑高位或逻辑低位,不会对数据进行实质的判断,这样做的好处是接收设备能够知道一个位的状态,有可能判断是否有噪声干扰了通信以及传输的数据是否同步。
(4)停止位:停止位可以是是1位、1.5位或2位,可以由软件设定。它一定是逻辑1电平,标志着传输一个字符的结束。这里所说的位并不是bit,所谓的停止位实际上是一个时间长度。这个时间长度与串口通信的波特率有关,通信所用波特率的倒数值即为1位,它在实际中表示为一个时间段。由于数据是在传输线上定时的,并且每一个设备有其自己的时钟,很可能在通信中两台设备间出现了小小的不同步。因此停止位不仅仅是表示传输的结束,并且提供计算机校正时钟同步的机会。适用于停止位的位数越多,不同时钟同步的容忍程度越大,但是数据传输率同时也越慢。
(5)空闲位:空闲位是指从一个字符的停止位结束到下一个字符的起始位开始,表示线路处于空闲状态,必须由高电平来填充。
串口数据的发送和接收
3.1、发送数据的具体步骤如下
- 初始化后或者没有数据需要发送时,发送端输出逻辑1,可以有任意数量的空闲位;
- 当需要发送数据时,发送端首先输出逻辑0,作为起始位;
- 接着开始输出数据位,发送端首先输出数据的最低位D0,然后是D1,最后是数据的最高位;
- 如果设有奇偶检验位,发送端输出检验位;
- 最后,发送端输出停止位(逻辑1);
- 如果没有信息需要发送,发送端输出逻辑1(空闲位),如果有信息需要发送,则转入步骤2;
- 如果是以232电平发送的,示波器上看到的发送端信号应是上述数据包取反后的结果(负逻辑);
3.2、接收数据的具体步骤如下,其中假设串口通信的波特率为B(每秒传送数据的位数),则由T=1/B即可得出每发送或者接受一个位所需的时间。发送与接收的波特率必须相同,才能保证发送与接收的同步。
- 开始通信时,信号线为空闲(逻辑1),当检测到由1到0的跳变时,开始计数;
- 接收端检测到起始位后,隔T时间对输入信号检测一次,把对应的值作为D0位数据;
- 再隔T时间,对输入信号检测一次,把对应的值作为D1位数据,直到全部数据位都输入;
- 再过T时间,接受奇偶校验位;
- 接收到规定的数据位个数和校验位之后,通信接口电路希望收到停止位(逻辑1),若此时未收到逻辑1,说明出现了错误,在状态寄存器中置“帧错误”标志;若没有错误,对全部数据位进行奇偶校验,无校验错时,把数据位从移位寄存器中取出送至数据输入寄存器,若校验错,在状态寄存器中置“奇偶错”标志;
- 本帧信息全部接收完,把线路上出现的高电平作为空闲位;
- 当信号再次变为低时,开始进入下一帧的检测,重复步骤2~6;
参数代码测试
自己手上暂时没有单片机,就只能用arm板将串口tx和rx连在一起,然后做一个软件做自发自收测试
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QTime>
#include <QDebug>
#include <QTimer>
#include <QSerialPort>
#include <QMainWindow>
#include <QElapsedTimer>
#include <QCoreApplication>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
bool CreateSerialPort(QIODevice::OpenMode model,
QSerialPort::BaudRate baudrate,
QSerialPort::FlowControl flowCtrl,
QSerialPort::DataBits databits,
QSerialPort::Parity parity,
QSerialPort::StopBits stopbits);
void CloseSerialPort();
void WaitTaskInfo(int msec);
public slots:
QByteArray readData();
void on_pushButton_clicked();
private:
Ui::MainWindow *ui;
QSerialPort *myCom;
};
#endif // MAINWINDOW_H
mainwindow.c
#include "mainwindow.h"
#include "ui_mainwindow.h"
const QString portName = "/dev/ttyO1";
//#define data_bit_5 1
#define data_bit_6 1
//#define data_bit_7 1
//#define data_bit_8 1
#if data_bit_5
#define data_bit 5
#define data_mask 0x7
#define port_data_bits QSerialPort::Data5
#elif data_bit_6
#define data_bit 6
#define data_mask 0x3
#define port_data_bits QSerialPort::Data6
#elif data_bit_7
#define data_bit 7
#define data_mask 0x1
#define port_data_bits QSerialPort::Data7
#elif data_bit_8
#define data_bit 8
#define data_mask 0x0
#define port_data_bits QSerialPort::Data8
#endif
#define serial_port_mode QIODevice::ReadWrite
#define serial_port_baud QSerialPort::Baud115200
#define serial_port_flow QSerialPort::NoFlowControl
//#define serial_port_flow QSerialPort::HardwareControl
//#define serial_port_flow QSerialPort::SoftwareControl
#define serial_port_data port_data_bits
#define serial_port_parity QSerialPort::NoParity
//#define serial_port_parity QSerialPort::OddParity
//#define serial_port_parity QSerialPort::EvenParity
#define serial_port_stop QSerialPort::OneStop
//#define serial_port_stop QSerialPort::OneAndHalfStop
//#define serial_port_stop QSerialPort::TwoStop
//#define serial_port_stop QSerialPort::UnknownStopBits
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
qDebug() << "cur serial port data bit = " << data_bit;
myCom = new QSerialPort(this);
if(!CreateSerialPort(serial_port_mode,serial_port_baud,
serial_port_flow,serial_port_data,
serial_port_parity,serial_port_stop)){
qDebug() << QString("%1 open fail!!!").arg(portName);
}else{
qDebug() << QString("%1 open success!!!").arg(portName);
}
}
MainWindow::~MainWindow()
{
CloseSerialPort();
delete ui;
}
void MainWindow::CloseSerialPort()
{
if (myCom->isOpen()){
myCom->close();
}
}
bool MainWindow::CreateSerialPort(QIODevice::OpenMode model,QSerialPort::BaudRate baudrate,
QSerialPort::FlowControl flowCtrl,QSerialPort::DataBits databits,
QSerialPort::Parity parity,QSerialPort::StopBits stopbits)
{
myCom->setPortName(portName);
if (myCom->open(model)) {
myCom->setBaudRate(baudrate);
myCom->setFlowControl(flowCtrl);
myCom->setDataBits(databits);
myCom->setParity(parity);
myCom->setStopBits(stopbits);
QTimer::singleShot(100,this,SLOT(on_pushButton_clicked()));
return true;
}
return false;
}
void MainWindow::WaitTaskInfo(int msec)
{
QElapsedTimer t;
t.start();
while(t.elapsed() < msec)
{
QCoreApplication::processEvents();
}
}
QByteArray MainWindow::readData()
{
QByteArray ba = myCom->readAll();
QByteArray newBa;
char temp;
newBa.append(ba.at(0));
if(ba.at(0) == 0x01){
newBa = ba;
}else if(ba.at(0) == 0x02){
for(int i = 1;i < ba.count();){
temp = 0x00;
char h_data = ba.at(i);
char l_data = ba.at(i+1);
temp = (h_data << data_bit | l_data);
i += 2;
newBa.append(temp);
}
}
return newBa;
}
void MainWindow::on_pushButton_clicked()
{
QByteArray ba,merge_before_ba,back_ba;
/* 第一位0x01表示一个字节, 范围0-11111 */
uchar buff[12] = {0x01,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F};
uchar buff2[12] = {0x02,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE};
merge_before_ba.append((char*)buff);
ba.append((char*)buff);
qDebug() << "1/write ba = " << ba;
myCom->write(ba);
/* delay 1s */
WaitTaskInfo(1000);
back_ba = readData();
qDebug() << "2/read ba = " << back_ba;
if(merge_before_ba == back_ba){
qDebug() << "1/Send and receive successfully!!!";
}else{
qDebug() << "1/Send and receive fail!!!";
}
/* 第一位0x02表示两个字节, 范围0-1111111111 */
ba.clear();
ba.append((char)buff2[0]);
merge_before_ba.clear();
merge_before_ba.append((char*)buff2);
for(int i = 1;i < 11;i++){
/* 高位在前低位在后 */
ba.append(buff2[i] >> data_bit);
/* 清除高三位 */
ba.append(buff2[i] &= ~(data_mask << data_bit));
}
qDebug() << "2/write ba = " << merge_before_ba;
myCom->write(ba);
/* delay 1s */
WaitTaskInfo(1000);
back_ba = readData();
qDebug() << "2/read ba = " << back_ba;
if(merge_before_ba == back_ba){
qDebug() << "2/Send and receive successfully!!!";
}else{
qDebug() << "2/Send and receive fail!!!";
}
}