Qt实现与单片机直接的通信上位机+单片机代码
- 测试环境
- 项目目标
- 实现效果
- 关键通信类 QSerialport
- 总结
这是我大二下学期的单片机课设做的一个小项目,实现上位机与下位机之间的通信.
测试环境
开发环境:Qt5.96 Mingw32-bit keil3
项目目标
1、实现下位机基于STC单片机控制LED灯模块、独立键盘模块.
2、实现基于Qt的上位机与下位机进行串口通信.
3、通过上位机发送指令对下位机进行控制,如对LED灯进行亮灭控制,并通过界面方式显示.
实现效果
参数配置窗口
上位机控制界面 与窗口建立连接
上位机向单片机送消息 选择 模式1 流水灯 单片机响应
上位机同步流水灯效果
单片机按下 key2 向上位机发送消息上位机显示时时时间
关键通信类 QSerialport
这个类实现上位机和下位机通信的通信具体的关于这个类的说明可以看官方文档 https://doc.qt.io/archives/qt-5.9/qserialport.html
Qt的QSerialPortInfo类来搜寻可用的串口号
foreach(const QSerialPortInfo &info,QSerialPortInfo::availablePorts()){serialNamePort<<info.portName();
}
这个地方有一个坑千万注意上位机和单片机的波特率必须要是一样的但是同时要注意单片机的晶振频率是不是 11.0592MHz必须要是一样的否则发送信息会出现误差. 就是在这个地方搞了我好久由于单片机的晶振频率不是11.0592Mhz,弄了我两天才偶然发现,我的单片机频率是 12.526Mhz就是短短的0.1Mhz不到的误差导致一直发送乱码 后来我用一个串口误差计算器算得,当单片机的定时计数器的溢出值 0XF4 才会没有误差所以一定要注意这个
单片机参考代码
#include<reg52.h>
//--声明全局函数--////void UsartConfiguration();unsigned char ch[10]="Press_Key1";
unsigned char GET[5];
unsigned int i,j,n,flag;
unsigned char receiveData;//这几个位定义是我的板子sbit LED0 = P0^0;
sbit LED1 = P0^1;
sbit LED2 = P0^2;
sbit LED3 = P0^3;
sbit LED4 = P0^4;
sbit LED5 = P0^5;
sbit LED6 = P0^6;
sbit LED7 = P0^7;sbit KEY_1 = P3^2;
sbit KEY_2 = P3^3;
sbit KEY_3 = P3^4;
sbit KEY_4 = P3^5;void Delay10ms(unsigned int z){unsigned x,y;for(x = z;x>0;x--)for(y = 114;y>0;y--);}void Lighting(){LED0 = 0;LED1 = 0;LED2 = 0;LED3 = 0;LED4 = 0;LED5 = 0;LED6 = 0;LED7 = 1;}/*******************************************************************************
* 函 数 名 :UsartConfiguration()
* 函数功能 :设置串口
* 输 入 : 无
* 输 出 : 无
*******************************************************************************/void UsartConfiguration()
{SCON=0X50; //设置为工作方式1 0101 0000TMOD=0X20; //设置计数器工作方式2PCON=0X80; //波特率加倍,波特率加倍加快传输速率但是如果232总线太长时有可能出现丢帧TH1=0XF4; //计数器初始值设置,注意波特率是4800的,因为单片机的串口波特率不是15.092要特殊的来算TL1=0XF4;//TH1=0XFC; //TL1=0XFC;//REN = 1; //允许接受ES=1; //打开接收中断EA=1; //打开总中断TR1=1; //打开计数器 T1
}void flowLight(){P0 =0Xff;Delay10ms(100);P0 =0Xfe;Delay10ms(100);P0 =0Xfc;Delay10ms(100);P0 =0Xf8;Delay10ms(100);P0 =0XE0;Delay10ms(100);P0 =0XC0;Delay10ms(100);P0 =0X80;Delay10ms(100);P0 =0;Delay10ms(100);
}//闪光灯
void flahlight(){P0 = 0;Delay10ms(100);P0 = 0Xff;Delay10ms(100);
}//熄灯
void stoplight(){P0 =0xff;
}/*******************************************************************************
* 函 数 名 : Usart() interrupt 4
* 函数功能 : 串口函数
* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
void Usart() interrupt 4
{ unsigned char date[6] ="I get!" ;unsigned char num;Lighting(); num = SBUF; RI = 0;n = num;if(num=='A'){for( i=0;i<6;i++){SBUF = date[i];ES = 0;while(TI==0);TI=0;ES =1;}}}//流水灯void main()
{UsartConfiguration();//flag=0;//标记为0;为1时候发送" THE END ",当然不用flag直接在中断函数里写也可以KEY_1=1;KEY_2=1;KEY_3=1;KEY_4=1;flag = 0; // Lighting(); //照亮你的 while(1){//4个键实现四种功能 键盘1 我要打开计算器 键盘2我要打开5子棋 键盘3打开推箱子 键盘4打开 动态图像if(n=='f') {flahlight();}if(n=='F'){flowLight();} if(n=='s'){ stoplight(); }if(KEY_1==0){flag = 1;ch[9] ='1';Delay10ms(300);}else if(KEY_2==0){flag = 1;ch[9] ='2';Delay10ms(300);}else if(KEY_3==0){flag = 1;ch[9] ='3';Delay10ms(300);}else if(KEY_4==0){flag =1;ch[9] ='4';Delay10ms(300);}if(flag==1){for( i=0;i<10;i++){SBUF = ch[i];ES = 0;while(TI==0);TI=0;ES =1;}}flag = 0;}
}
上位机通信代码
void Widget::on_openBtn_clicked()
{//初始化按钮QSerialPort::BaudRate bauRate; //波特率QSerialPort::DataBits dataBits; //数据位QSerialPort::StopBits stopBits; //停止位QSerialPort::Parity checkBits; //校验位if(ui->baundrateCb->currentText()=="4800"){bauRate = QSerialPort::Baud4800;}else if(ui->baundrateCb->currentText()=="9600"){bauRate = QSerialPort::Baud9600;}else if(ui->baundrateCb->currentText()=="115200"){bauRate = QSerialPort::Baud115200;}else if(ui->baundrateCb->currentText()=="2400"){bauRate = QSerialPort::Baud2400;}else if(ui->baundrateCb->currentText()=="1200"){bauRate = QSerialPort::Baud1200;}if(ui->dateCb->currentText()=="5"){dataBits = QSerialPort::Data5;}else if(ui->dateCb->currentText()=="6"){dataBits = QSerialPort::Data6;}else if(ui->dateCb->currentText()=="7"){dataBits = QSerialPort::Data7;}else if(ui->dateCb->currentText()=="8"){dataBits = QSerialPort::Data8;}if(ui->stopCb->currentText()=="1"){stopBits =QSerialPort::OneStop;}else if(ui->stopCb->currentText()=="1.5"){stopBits = QSerialPort::OneAndHalfStop;}else if(ui->stopCb->currentText()=="2"){stopBits = QSerialPort::TwoStop;}if(ui->checkCb->currentText()=="none"){checkBits = QSerialPort::NoParity;}//设置端口号serialPort->setPortName(ui->serialCb->currentText());serialPort->setBaudRate(bauRate);serialPort->setDataBits(dataBits);serialPort->setStopBits(stopBits);bauRate = QSerialPort::Baud4800;dataBits =QSerialPort::Data8; //数据位stopBits =QSerialPort::OneStop; //停止位checkBits = QSerialPort::NoParity; //校验位serialPort->setParity(checkBits);serialPort->setFlowControl(QSerialPort::NoFlowControl);//设置为无流控制qDebug()<<serialPort->portName();qDebug()<<serialPort->baudRate();qDebug()<<serialPort->dataBits();qDebug()<<serialPort->parity();//QIODevice::open();if(serialPort->open(QIODevice::ReadWrite)==true){//串口打开成功QMessageBox::information(this,"提示","串口打开成功");}else{QMessageBox::critical(this,"提示","串口打开失败");}}
上位机所有程因为代码量较多和 ui文件不能直接复制出来,所以我将上位机的所有代码打包存入网盘:链接:https://pan.baidu.com/s/15vHZcHRiiYiHnGYAWpP3DQ
提取码:6666
总结
Qt 使用 QSerialport 十分方便的与单片机进行通信,通信的过程中注意的关键问题之一就是信息同步性的问题.注意通信过程中的波特率要设置对应,不仅仅是要注意波特率还有注意单片机的晶振频率是不是11.0592Mhz.