门牙会稍息
原创
关注
3点赞·53人阅读
前言:
最近在学习嵌入式qt开发,然后跟着教程编写了一个简单的串口上位机程序,在编写的时候还算比较顺利,但在调试的时候花了点功夫,折腾了一下午。最后还是理清了思路,解决了问题,特写此博客进行记录和总结。
串口上位机界面设计:
整个软件的界面我都是用ui来设计的,其实也可以用代码,但是想了想有好多布局相互嵌套比较麻烦。最后就使用了ui界面来设计。
ui界面设计
串口上位机程序功能设计:
然后像串口对象初始化,槽函数,一些逻辑关系都用代码来实现,头文件就只有一些变量、槽的定义。
头文件
#include "widget.h"
#include "ui_widget.h"
#include <QMessageBox>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this)
//lcd屏的分辨率是1024X600
this->setFixedSize(QSize(1024, 600))
//new 一个QSerialPort对象
serialPort = new QSerialPort(this)
//通过foreach语句将windows或imx6ull可用串口识别出来,并添加至对应的下拉选择框
QStringList serialList
foreach(const QSerialPortInfo &info, QSerialPortInfo::availablePorts()){
serialList += info.portName()
}
ui->comboBox->addItems(serialList)
//设置串口的信号与槽
connect(serialPort, SIGNAL(readyRead()), this, SLOT(readData()))
}
Widget::~Widget()
{
delete ui
}
void Widget::on_radioButton_clicked(bool checked)
{
//点击“打卡串口”button之后的一些串口配置 *** 作,和一些逻辑关系
if(checked){
//设置串口端
serialPort->setPortName(ui->comboBox->currentText())
//设置波特率
serialPort->setBaudRate(ui->comboBox_2->currentText().toInt())
//设置停止位
serialPort->setStopBits(QSerialPort::StopBits(ui->comboBox_4->currentText().toInt()))
//设置数据位
serialPort->setDataBits(QSerialPort::DataBits(ui->comboBox_6->currentText().toInt()))
//设置校验位
switch(ui->comboBox_5->currentIndex()){
case 0:
serialPort->setParity(QSerialPort::Parity::NoParity)
break
case 1:
serialPort->setParity(QSerialPort::Parity::EvenParity)
break
case 2:
serialPort->setParity(QSerialPort::Parity::OddParity)
break
case 3:
serialPort->setParity(QSerialPort::Parity::SpaceParity)
break
case 4:
serialPort->setParity(QSerialPort::Parity::MarkParity)
break
default:
break
}
serialPort->setFlowControl(QSerialPort::NoFlowControl)
if(!serialPort->open(QSerialPort::ReadWrite)){
QMessageBox::about(this, "串口打开错误提示", "可能被占用了")
return
}
//打开串口之后其他的选择按钮设置成不可用
ui->comboBox->setEnabled(false)
ui->comboBox_2->setEnabled(false)
ui->comboBox_4->setEnabled(false)
ui->comboBox_5->setEnabled(false)
ui->comboBox_6->setEnabled(false)
ui->radioButton->setText("关闭串口")
}
else{
serialPort->close()
ui->comboBox->setEnabled(true)
ui->comboBox_2->setEnabled(true)
ui->comboBox_4->setEnabled(true)
ui->comboBox_5->setEnabled(true)
ui->comboBox_6->setEnabled(true)
ui->radioButton->setText("打开串口")
}
}
void Widget::readData()
{
//将串口中的数据打印到textBrowser中
ui->textBrowser->insertPlainText(serialPort->readAll())
}
void Widget::on_pushButton_clicked()
{
//点击“发送”button之后,将textEdit中的内容写入串口
serialPort->write(ui->textEdit->toPlainText().toUtf8())
}
void Widget::on_pushButton_2_clicked()
{
//清屏 *** 作
ui->textEdit->clear()
ui->textBrowser->clear()
}
登录后复制
在windows端编写好程序之后,将工程文件发送到ubuntu进行qmake、make最后通过scp将ARM的可执行文件发送到开发板,接下来就是验证了
我用的是正点原子出厂的系统,所以在验证的时候需要使用到一个串口来连接到开发板执行编写好的上位机程序,所以一个串口就被占用了,正点原子教程视频就用开发板的另一个串口来进行测试
正点原子教程测试方式
因为放假回了家,我也没有带太多的东西,usb转ttl模块放在了学校。所以我在想怎么就用一个串口来完成实验。困扰我的就是唯一的一个串口必须留个上位机,然后要怎么执行开发板上的串口上位机程序?最初我想到了可以使用网络通过Xshell远程连接到开发板就可以执行,唯一的串口就拿来验证。
解决完上位机软件怎么在imx6ull上执行的问题,接下来就是验证了。验证的时候又出现了一些问题,上位机软件不像想象的那样一边发数据,一边就接收对应的数据,而出现了一些imx6ull的信息,好像还可以输入命令,感到非常奇怪。
我以为我的软件有问题,就在windows上换了一个串口软件,结果还是出现了类似的情况
最后也是在不断猜想和测试之后找到了原因,就是应因为我在给开发板上电的时候接入了串口线,然后先打开了windows上的串口,然后就使用到了串口,导致就相当于有一个串口控制imx6ull开发板,像Xshell中通过串口连接开发板一样。然后我尝试在windows的上位机软件输入命令想打开一个qt程序,最后也是成功打开证实了猜想
执行./list命令打开了蛇姐list程序(qt程序的路径是/home/root/qt_project/list)
如果想要实现实验最初windows和imx6ull两个上位机互换数据的效果的话。要先通过windows中的上位机软件输入命令来打开imx6ull的上位机软件,这样相当于windows中的上位机连接的就是imx6ull的上位机了,而不是直接控制imx6ull了,之后就可以正常收发数据了。
总结:
学了qt快半个月了,这个串口上位机算是一个比较综合的练习了,结合了ui和代码设计。加上最后的调试也是收获颇多,如果有usb-ttl模块的话验证步骤就会更简单。
这是基本的C语言哈。|= 就是“或等于”,跟 += 是一个道理,按位或你肯定知道哈。
1. newtio.c_cflag |=PARENB 相当于 newtio.c_cflag = netwtio.c_cflag | PARENB
意思就是netwtio.c_cflag 或 上 PARENB 的结果赋给netwtio.c_cflag
2. |=的含义跟上面相同, ~的含义是按位取反
newtio.c_cflag |=~PARENB 相当于 newtio.c_cflag = netwtio.c_flag | (~PARENB)
这有个友善的串口例程,参考下吧,用gcc编译可以在linux下用# include <stdio.h>
# include <stdlib.h>
# include <termio.h>
# include <unistd.h>
# include <fcntl.h>
# include <getopt.h>
# include <time.h>
# include <errno.h>
# include <string.h>
int CommFd, TtyFd
static void Error(const char *Msg)
{
fprintf (stderr, "%s\n", Msg)
fprintf (stderr, "strerror() is %s\n", strerror(errno))
exit(1)
}
static void Warning(const char *Msg)
{
fprintf (stderr, "Warning: %s\n", Msg)
}
static int SerialSpeed(const char *SpeedString)
{
int SpeedNumber = atoi(SpeedString)
# define TestSpeed(Speed) if (SpeedNumber == Speed) return B##Speed
TestSpeed(1200)
TestSpeed(2400)
TestSpeed(4800)
TestSpeed(9600)
TestSpeed(19200)
TestSpeed(38400)
TestSpeed(57600)
TestSpeed(115200)
TestSpeed(230400)
Error("Bad speed")
return -1
}
static void PrintUsage(void)
{
fprintf(stderr, "comtest - interactive program of comm port\n")
fprintf(stderr, "press [ESC] 3 times to quit\n\n")
fprintf(stderr, "Usage: comtest [-d device] [-t tty] [-s speed] [-7] [-c] [-x] [-o] [-h]\n")
fprintf(stderr, " -7 7 bit\n")
fprintf(stderr, " -x hex mode\n")
fprintf(stderr, " -o output to stdout too\n")
fprintf(stderr, " -c stdout output use color\n")
fprintf(stderr, " -h print this help\n")
exit(-1)
}
static inline void WaitFdWriteable(int Fd)
{
fd_set WriteSetFD
FD_ZERO(&WriteSetFD)
FD_SET(Fd, &WriteSetFD)
if (select(Fd + 1, NULL, &WriteSetFD, NULL, NULL) <0) {
Error(strerror(errno))
}
}
int sendUart(char c)
{
WaitFdWriteable(CommFd)
return write(CommFd, &c, 1)
}
char recUart()
{
char c='\0'
if (FD_ISSET(CommFd, &ReadSetFD))
{
if(read(CommFd, &c, 1) == 1) return c
else printf("No data to receive.\n")
}
}
int main(int argc, char **argv)
{
struct termios TtyAttr
struct termios BackupTtyAttr
int DeviceSpeed = B115200
int TtySpeed = B115200
int ByteBits = CS8
const char *DeviceName = "/dev/ttyS0"
const char *TtyName = "/dev/tty"
int OutputHex = 0
int OutputToStdout = 0
int UseColor = 0
printf("Now we start.\n")
opterr = 0
for () {
int c = getopt(argc, argv, "d:s:t:7xoch")
if (c == -1)
break
switch(c) {
case 'd':
DeviceName = optarg
break
case 't':
TtyName = optarg
break
case 's':
if (optarg[0] == 'd') {
DeviceSpeed = SerialSpeed(optarg + 1)
} else if (optarg[0] == 't') {
TtySpeed = SerialSpeed(optarg + 1)
} else
TtySpeed = DeviceSpeed = SerialSpeed(optarg)
break
case 'o':
OutputToStdout = 1
break
case '7':
ByteBits = CS7
break
case 'x':
OutputHex = 1
break
case 'c':
UseColor = 1
break
case '?':
case 'h':
default:
PrintUsage()
}
}
if (optind != argc)
PrintUsage()
CommFd = open(DeviceName, O_RDWR, 0)
if (CommFd <0)
Error("Unable to open device")
if (fcntl(CommFd, F_SETFL, O_NONBLOCK) <0)
Error("Unable set to NONBLOCK mode")
memset(&TtyAttr, 0, sizeof(struct termios))
TtyAttr.c_iflag = IGNPAR
TtyAttr.c_cflag = DeviceSpeed | HUPCL | ByteBits | CREAD | CLOCAL
TtyAttr.c_cc[VMIN] = 1
if (tcsetattr(CommFd, TCSANOW, &TtyAttr) <0)
Warning("Unable to set comm port")
TtyFd = open(TtyName, O_RDWR | O_NDELAY, 0)
if (TtyFd <0)
Error("Unable to open tty")
TtyAttr.c_cflag = TtySpeed | HUPCL | ByteBits | CREAD | CLOCAL
if (tcgetattr(TtyFd, &BackupTtyAttr) <0)
Error("Unable to get tty")
if (tcsetattr(TtyFd, TCSANOW, &TtyAttr) <0)
Error("Unable to set tty")
for () {
unsigned char Char = 0
fd_set ReadSetFD
void OutputStdChar(FILE *File) {
char Buffer[10]
int Len = sprintf(Buffer, OutputHex ? "%.2X " : "%c", Char)
fwrite(Buffer, 1, Len, File)
}
FD_ZERO(&ReadSetFD)
FD_SET(CommFd, &ReadSetFD)
FD_SET( TtyFd, &ReadSetFD)
# define max(x,y) ( ((x) >= (y)) ? (x) : (y) )
if (select(max(CommFd, TtyFd) + 1, &ReadSetFD, NULL, NULL, NULL) <0) {
Error(strerror(errno))
}
# undef max
if (FD_ISSET(CommFd, &ReadSetFD)) {
while (read(CommFd, &Char, 1) == 1) {
WaitFdWriteable(TtyFd)
if (write(TtyFd, &Char, 1) <0) {
Error(strerror(errno))
}
if (OutputToStdout) {
if (UseColor)
fwrite("\x1b[0134m", 1, 8, stdout)
OutputStdChar(stdout)
if (UseColor)
fwrite("\x1b[00m", 1, 8, stdout)
fflush(stdout)
}
}
}
if (FD_ISSET(TtyFd, &ReadSetFD)) {
while (read(TtyFd, &Char, 1) == 1) {
static int EscKeyCount = 0
WaitFdWriteable(CommFd)
if (write(CommFd, &Char, 1) <0) {
Error(strerror(errno))
}
if (OutputToStdout) {
if (UseColor)
fwrite("\x1b[0131m", 1, 8, stderr)
OutputStdChar(stderr)
if (UseColor)
fwrite("\x1b[00m", 1, 8, stderr)
fflush(stderr)
}
if (Char == '\x1b') {
EscKeyCount ++
if (EscKeyCount >= 3)
goto ExitLabel
} else
EscKeyCount = 0
}
}
}
ExitLabel:
if (tcsetattr(TtyFd, TCSANOW, &BackupTtyAttr) <0)
Error("Unable to set tty")
return 0
}
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)