通知:所有Qt源码和文档会在后面公布。敬请期待… |
常见的硬件通信接口协议
1.硬件通信接口协议
很多硬件传感器需要用到如下的通信协议
串口(上层应用的串口代码编写,不是底层的串口代码编写)
-
SPI
-
IIC
-
CAN
-
USB
2.使用串口的传感器
串口蓝牙,串口wifi
开发板跟电脑
串口通信的代码实现
常见的硬件校验算法有哪些?算法原理是怎么样?
-
CRC校验 –》循环冗余校验
-
哈希校验
1.两个版本
QT中的串口编程(既可以在window上运行,也能在ARM平台,linux平台都能运行)
linux中的串口编程(只能在ARM平台,linux平台运行)
波特率: 串口传输数据的速度 115200表示每一秒钟传输115200个比特位
数据位:串口传输一帧数据的位数
奇偶校验:校验–》检查数据收发是否发生了错误
奇校验
偶校验
停止位:标记数据的结尾
流控: 当数据的接收端无法收到数据的时候,会通知发送端停止发送
2.QT中的串口编程
类和方法
添加的库.pro: serialport
QSerialPortInfo //获取当前系统中所有的串口信息
QSerialPort //表示串口
(1)代码思路
第一步:获取当前系统所有的串口信息
[static] QList<QSerialPortInfo> QSerialPortInfo::availablePorts()
返回值: QList存放的就是所有的串口信息
QString QSerialPortInfo::description() const
返回:串口的描述信息
QString QSerialPortInfo::portName() const
返回:串口的名字
第二步:创建QSerialPort 串口对象,配置串口的参数
QSerialPort::QSerialPort(const QString &name)
参数:name --》串口的名字
bool setBaudRate(qint32 baudRate)
参数:baudRate --》你要设置的波特率 QSerialPort::Baud115200
bool setDataBits(QSerialPort::DataBits dataBits)
参数:dataBits --》QSerialPort::Data8 8位数据位
bool setParity(QSerialPort::Parity parity)
参数:parity --》QSerialPort::NoParity 无奇偶校验
QSerialPort::EvenParity 偶校验
QSerialPort::OddParity 奇校验
bool setStopBits(QSerialPort::StopBits stopBits)
参数:stopBits --》QSerialPort::OneStop 1位停止位
QSerialPort::OneAndHalfStop 1.5位停止位
bool setFlowControl(QSerialPort::FlowControl flowControl)
参数:flowControl --》QSerialPort::NoFlowControl 无流控
QSerialPort::HardwareControl 硬件流控
QSerialPort::SoftwareControl 软件流控
第三步:打开串口
bool QSerialPort::open(QIODevice::OpenMode mode)
第四步:读写串口数据
读串口–》接收对方从串口发送过来的数据
[signal] void QIODevice::readyRead() //关联这个信号,在槽函数中读取数据
read/readAll
写串口–》你把数据从串口发送给对方
write
第五步:关闭串口
void QSerialPort::close()
3.实际开发使用串口的时候,参数究竟配置成什么样??
答案:认真阅读传感器厂家提供的使用说明书–》清楚地告诉你串口该如何配置
linux中串口编程
1.重要的结构体
struct termios
{
里面都是标志位,用来设置串口参数
c_cflag //控制模式标志位
}
2.思路和方法
第一步:打开串口的驱动
连接电脑 –》/dev/ttySAC0
右上角第一排 –》/dev/ttySAC1
右上角第二排 –》/dev/ttySAC2
右上角第三排 –》/dev/ttySAC3
open()
第二步:配置串口
#include <termios.h>
#include <unistd.h>
int tcgetattr(int fd, struct termios *termios_p); //获取当前串口的配置信息
参数: fd --》串口的文件描述符
termios_p --》结构体指针,用来保存串口配置信息
(1)设置串口工作在原始模式(串口只用于数据的收发,不用做其它功能)
struct termios myios;
bzero(&myios,sizeof(myios));
myios.c_cflag |= CLOCAL | CREAD;
void cfmakeraw(struct termios *termios_p);
(2)设置波特率,数据位,停止位,奇偶校验…….
波特率:
int cfsetispeed(struct termios *termios_p, speed_t speed);
int cfsetospeed(struct termios *termios_p, speed_t speed);
参数:speed --》你要设置的波特率B115200 B数字(就是波特率)
数据位:
myios.c_cflag &= ~CSIZE; /* 用数据位掩码清空数据位设置 */
myios.c_cflag |= CS8; //CS5 CS6 CS7 CS8
奇偶校验:
奇校验
myios.c_cflag |= (PARODD | PARENB);
myios.c_iflag |= INPCK;
偶校验
myios.c_cflag |= PARENB;
myios.c_cflag &= ~PARODD;/* 清除奇校验标志,则配置为偶校验*/
myios.c_iflag |= INPCK;
无校验
myios.c_cflag &= ~PARENB; //使能 --》开启 失能 --》关闭
停止位
myios.c_cflag &= ~CSTOPB; 1位停止位
myios.c_cflag |= CSTOPB; 2位停止位
设置最少读取的字符数量和最长等待时间
myiosc_cc[VTIME] = 0;
myios.c_cc[VMIN] = 4;
让刚才的设置生效(激活配置)
int tcflush(int fd, int queue_selector);
参数: fd --》串口的文件描述符
queue_selector --》TCIOFLUSH 刷新串口的输入输出缓冲区
tcsetattr(int fd, int optional_actions, const struct termios*termios_p);
参数: fd --》串口的文件描述符
optional_actions --》TCSANOW 设置立即生效
第三步:收发数据
发送 write()
接收 read()
第四步:关闭串口
close()
串口的应用–》通过串口读写获取RFID的卡号
1.分析RFID的通信协议
通信协议:硬件传感器依照什么样的数据格式去发送/接收数据
类似于tcp通信发送字符串/发送表情包
2.分析ISO14443A命令
A命令(请求): 激活RFID读卡模块,使之能够对外发射电磁场,当有卡靠近模块的时候,模块能够感应到卡的存在
char abuf[7];
abuf[0]=0x07; //帧长
abuf[1]=0x02; //ISO14443A
abuf[2]='A';// A命令
abuf[3]=0x01; //信息长度
abuf[4]=0x52; //ALL模式
abuf[5]=校验和;
abuf[6]=0x03; //帧结束标记
//发送A命令给模块
write(fd,abuf,7); //串口发送A命令给RFID读卡模块 主机--》从机 命令
//接收模块回复的应答信息
char rbuf[8];
read(fd,rbuf,8); 从机--》主机 状态
//判断接收的应答信息是否正确
if(rbuf[2]==0x00) //应答成功
printf('A命令发送成功了!n');
else
printf('A命令没有发送成功了!n');
B命令(防碰撞): 防止多张卡同时进入磁场范围,出现读写冲突的问题(只会挑选其中一张来读写)
char bbuf[8];
bbuf[0]=0x08; //帧长
bbuf[1]=0x02; //ISO14443A
bbuf[2]='B';// B命令
bbuf[3]=0x02; //信息长度
bbuf[4]=0x93; //一级防碰撞
bbuf[5]=0x00;
bbuf[6]=校验和;
bbuf[7]=0x03; //帧结束标记
//发送B命令给模块
write(fd,bbuf,8); //串口发送B命令给RFID读卡模块 主机--》从机 命令
//接收模块回复的应答信息
charrbuf[10];
read(fd,rbuf,10); 从机--》主机 状态
//判断接收的应答信息是否正确
if(rbuf[2]==0x00) //应答成功
printf('B命令发送成功了,同时得到了序列号!n'); //卡的序列号 rbuf[4]rbuf[5]rbuf[6]rbuf[7]
else
printf('B命令没有发送成功了!n');
练习:(源码下节公布)
1.循环给RFID模块发送AB命令,打印得到的卡序列号
int main()
{
open('/dev/ttySAC1')// 串口驱动
//配置串口
while(1)
{
发送A命令
发送B命令
}
}
老师给的参考代码:
第一个:以非阻塞的方式打开串口(无论串口是否有数据可读,read去读取串口数据的时候都不会阻塞)
fd = open('/dev/ttySAC1', O_RDWR | O_NOCTTY | O_NONBLOCK);
第二个:使用了多路复用监测串口是否有数据可读(可读就调用read去读取模块的响应信息)
第三个:延时–》while(1)执行速度太快了,串口的读写速度跟不上,所以适当延时一下