文章目录

  • 前言
  • 一、开发步骤
  • 二、项目实现
    • 1.STM32实现串口通信
    • 2.STM32的计算逻辑
    • 3.Qt界面设计
      • 3.1 界面的实现
      • 3.2 通讯部分的实现
  • 三、总结

前言

本篇博客主要介绍自己开发一个计算器小项目的过程以及自己在开发过程中遇到的一些问题以及解决的方法。
基于STM32的计算器开发有如下需求:
1.操作界面在电脑端,用C++编写,只负责按键和显示;
2.计算部分在STM32端,用c语言编写,实现计算功能。
概括一下就是在电脑上编写一个上位机程序,主要负责发送数据,计算功能通过32实现。使用到的软件有keil5,QT,需要的基本知识有QT界面开发,C++编程基础,串口通讯等。


提示:此计算器可能存在一些bug和缺点,仅供大家学习参考。如果有新的想法以及问题,欢迎大家前来交流。

一、开发步骤

分为STM32和QT两部分完成,首先我们完成STM32的部分,在STM32上我们需要编写如下功能:
1.数据的接收与计算结果的发送
2.对接收数据的处理
QT上需要实现如下功能:
1.发送数据(相当于我们平时用的串口小程序)
2.接收计算结果并显示

明白了基本需求,我们接下来就开始一步一步的实现这些功能吧!!!

二、项目实现

1.STM32实现串口通信

STM32的串口通讯实现很简单,都是一个套路。网络上也有很多相关的资料,这里就不具体赘述,只简单的叙述一下串口初始化的步骤以及数据收发的操作。
首先我们需要初始化串口,基本步骤如下:
1.串口时钟使能,GPIO 时钟使能
2.复位串口
3.GPIO 端口模式的设置
4.串口参数初始化
5.中断设置初始化
6.使能串口

代码如下:

//这里使用USART1作为我们的串口
void uart_init(u32 bound)
{GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
//串口时钟使能,GPIO 时钟使能
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|
RCC_APB2Periph_GPIOA, ENABLE); //使能 USART1,GPIOA 时钟
//串口复位
USART_DeInit(USART1); //复位串口1
//GPIO 端口模式设置
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //ISART1_TX PA.9
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化 GPIOA.9GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; //USART1_RX PA.10
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入
GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化 GPIOA.10
//④串口参数初始化
USART_InitStructure.USART_BaudRate = bound; //波特率设置
USART_InitStructure.USART_WordLength = USART_WordLength_8b; //字长为 8 位
USART_InitStructure.USART_StopBits = USART_StopBits_1; //一个停止位
USART_InitStructure.USART_Parity = USART_Parity_No; //无奇偶校验位
USART_InitStructure.USART_HardwareFlowControl
= USART_HardwareFlowControl_None; //无硬件数据流控制
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;//收发模式
USART_Init(USART1, &USART_InitStructure); //初始化串口

初始化好串口后,需要设置数据接收的结束标志位,这里我们设置输入的结束为“/n/r”,所有从上位机发来的数据必须以“/n/r”结尾,每接收一次数据单片机都会响应一次中断,所以我们的接收数据程序在中断程序中实现。
其中USART_RX_STA用于计算接收数据的位数,其中0-13位为有效数据位,14,15用于存储我们的结束标志位。

void USART1_IRQHandler(void)                 //串口1中断服务程序
{u8 Res;
#if SYSTEM_SUPPORT_OS       //如果SYSTEM_SUPPORT_OS为真,则需要支持OS.OSIntEnter();
#endifif(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  //接收中断(接收到的数据必须是0x0d 0x0a结尾){Res =USART_ReceiveData(USART1); //读取接收到的数据if((USART_RX_STA&0x8000)==0)//接收未完成{if(USART_RX_STA&0x4000)//接收到了0x0d{if(Res!=0x0a)USART_RX_STA=0;//接收错误,重新开始else USART_RX_STA|=0x8000;  //接收完成了 }else //还没收到0X0D{   if(Res==0x0d)USART_RX_STA|=0x4000;else{USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ;USART_RX_STA++;if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;//接收数据错误,重新开始接收   }      }}          }

输出数据直接使用printf函数即可。

2.STM32的计算逻辑

首先我们从串口读到的数据都是数字或者计算符号的16进制ASCII代码,我们首先需要对ASCII进行转换才能得到我们所输入的数据。具体转换代码如下,change_to_dec1(u16 num_len)表示对整个数据(从下标0开始对数据进行转化),change_to_dec2(u16 num_len,u16 len)可以对数据中的某一段进行转化,num_len表示需要转换数据的长度,len表示截止位置到下标0的长度。
代码如下:

//num_len表示需要转换数据的长度
u16 change_to_dec1(u16 num_len)
{u16 change_result = 0;u16 t;for(t=0;t<num_len;t++){change_result += (USART_RX_BUF[t]-48)*pow(10,num_len-1-t);}//printf("\r\n\r\n");//printf("前面的加数是%d",change_result);return change_result;
}u16 change_to_dec2(u16 num_len,u16 len)
{u16 change_result = 0,p = 0;u16 t;for(t=len-num_len;t<len;t++){change_result += (USART_RX_BUF[t]-48)*pow(10,num_len-1-p);p++;}//printf("\r\n\r\n");//printf("后面的加数是%d",change_result);return change_result;
}

能够对数据进行转换后,需要判断我们输入数据中符号(加减乘除包括小数点)的位置以及数据的位置,所以我对读取到的数据进行了遍历,先获取小数点的位置(小数点的ASCII码是0x2E)

for(t=0;t<len;t++){if(USART_RX_BUF[t]==0x2E) //0x2E表示.{location[m]=t;m++;//printf("xiaoshu weizhi%d",t);}}

在记录完小数位置后,需要统计小数点的个数(num_2E),flag表示是否有小数计算,有小数则将标志位置1,代码如下:

         for(t=0;t<2;t++){if(location[t]!=0){//printf("小数点的位置是%u",location[t]);flag=1;num_2E++;}}

接下来,根据小数点数的个数的不同,分情况0,1,2三种情况考虑。将传入数据分为整数部分和小数部分进行转换,下面以计算加法为例。
首先进入一个判断是否存在小数计算,若存在小数计算,还要细分小数个数的位数(1,2),若小数点个数为1,则还要判断小数点是在计算符号前还是计算符号后,废话不多说,直接来看代码。

if(USART_RX_BUF[t]==0x2B & t!=0)      //0x2B表示加号
{way = 1;          //+//存在小数计算if(flag == 1){//分为整数和小数部分计算,首先确定有几个小数if(num_2E==1){for(i=0;i<2;i++){if(location[i]!=0){loc1 = location[i];}}if(loc1<t){if(USART_RX_BUF[0]==0x2D){int_num_front_len = loc1-1;num_front_len = t-loc1-1;int_num_behind_len = len-t-1;int_num_front=change_to_dec2(int_num_front_len,loc1);num_front = change_to_dec2(num_front_len,t);int_num_behind = change_to_dec2(int_num_behind_len,len);minus_flag = 1;}else{}break;}else if(loc1>t){if(USART_RX_BUF[0]==0x2D){int_num_front_len = t-1;int_num_behind_len = loc1-t-1;num_behind_len = len-loc1-1;int_num_front = change_to_dec2(int_num_front_len,t);int_num_behind = change_to_dec2(loc1-t-1,loc1);num_behind = change_to_dec2(num_behind_len,len);minus_flag = 1;}else{int_num_front_len = t;int_num_behind_len = loc1-t-1;num_behind_len = len-loc1-1;int_num_front = change_to_dec1(int_num_front_len);int_num_behind = change_to_dec2(loc1-t-1,loc1);num_behind = change_to_dec2(num_behind_len,len);}break;}}else if(num_2E==2){if(USART_RX_BUF[0]==0x2D){loc1 = location[0];loc2 = location[1];int_num_front_len =loc1-1;num_front_len = t-loc1-1;int_num_behind_len = loc2-t-1;num_behind_len = len-loc2-1;int_num_front = change_to_dec2(int_num_front_len,loc1);num_front = change_to_dec2(num_front_len,t);int_num_behind = change_to_dec2(int_num_behind_len,loc2);num_behind = change_to_dec2(num_behind_len,len);minus_flag = 1;}else{loc1 = location[0];loc2 = location[1];int_num_front_len =loc1;num_front_len = t-loc1-1;int_num_behind_len = loc2-t-1;num_behind_len = len-loc2-1;int_num_front = change_to_dec2(int_num_front_len,loc1);num_front = change_to_dec2(num_front_len,t);int_num_behind = change_to_dec2(int_num_behind_len,loc2);num_behind = change_to_dec2(num_behind_len,len);}}}//都为整数else{if(USART_RX_BUF[0]==0x2D){int_num_front_len = t-1;int_num_behind_len = len-t-1;int_num_front = change_to_dec2(int_num_front_len,t);int_num_behind = change_to_dec2(int_num_behind_len,len);minus_flag = 1;}else{int_num_front_len = t;int_num_behind_len = len-t-1;int_num_front = change_to_dec1(int_num_front_len);int_num_behind = change_to_dec2(int_num_behind_len,len);}break;}}

以上这段代码做的事情就是提取符号两边的整数和小数部分,便于接下来的计算。好了,在提取完数据后,我们来看看计算的部分,看看下面的代码吧。
这段代码中我们通过一个switch函数来判断是哪种计算方式(1 加法,2 减法,3 乘法,4 除法),minus_flag是一个用来判断第一个数据是否为负数的标志位,通过整数加上小数部分除以以10为底数小数部分长度为指数的小数即可还原出我们的原始数据,然后接下来就是简单粗暴的计算啦,其他计算方式也是差不多的处理方式,所以在这里就不重复写啦。

switch(way)
{case 1:if(flag == 1){if(minus_flag == 1){_result = -(int_num_front + num_front/pow(10,num_front_len)+(int_num_behind+num_behind/pow(10,num_behind_len));}else{_result = (int_num_front + num_front/pow(10,num_front_len)+(int_num_behind+num_behind/pow(10,num_behind_len));}printf("%f",_result);}else{if(minus_flag==1){result = -int_num_front + int_num_behind;}else{result = int_num_front + int_num_behind;}printf("%d",result);}flag=0,num_2E=0,m=0;                           num_front_len=0,num_behind_len=0,int_num_front_len=0,int_num_behind_len=0; num_front=0,num_behind=0,int_num_front=0,int_num_behind=0;location[0]=0,location[1]=0,loc1=0,loc2=0;minus_flag=0;break;}

以上就是STM32程序中的主要内容。


3.Qt界面设计

Qt中的设计主要分为两部分,一部分是界面的实现,另外一部分是串口通信的设计部分。

3.1 界面的实现

界面的实现非常简单,直接进入.ui文件里,拖出我们想要的界面,然后再在各个按钮上添加自己需要的槽函数即可。

接下来我会对按钮的槽函数进行解释。分别有以下几类功能的按钮:数字按钮(用于输入数据),小数点按钮(为数据增加小数点),计算符号按钮(用于判断是哪种计算方式),清屏按钮,后退按钮(用于修改自己的输入)。
1.数字按钮
数据按钮相当于我们的键盘,要实现如下的逻辑:首先需要开机后,按下按钮才有反应,当显示屏没有数值时,按下数据按钮会在显示屏上增添按钮对应的数字,要注意如果0是第一个字符,再次按下0后,不可以在显示屏上再增加一个0。当我们计算完计算结果后,按下数字按钮会直接清屏,然后显示我们按下的按钮,具体代码如下,其中1-10代表数字1-9,0。

void MyComputer::on_pushButton1_1_clicked()
{if(ui->pushButton1_19->text() == tr("关")){ui->lineEdit->setReadOnly(false);if(ui->lineEdit->displayText()=="0"){  ui->lineEdit->setText("1"); }else{if(ui->lineEdit->displayText().length()<8){ui->lineEdit->setText(ui->lineEdit->displayText()+"1");}}if(result!=""){ui->lineEdit->clear();ui->lineEdit->setText("1");result = "";}ui->lineEdit->setReadOnly(true);}
}void MyComputer::on_pushButton1_2_clicked()
{if(ui->pushButton1_19->text() == tr("关")){ui->lineEdit->setReadOnly(false);if(ui->lineEdit->displayText()=="0"){  ui->lineEdit->setText("2"); }else{if(ui->lineEdit->displayText().length()<8){ui->lineEdit->setText(ui->lineEdit->displayText()+"2");}}if(result!=""){ui->lineEdit->clear();ui->lineEdit->setText("2");result = "";}ui->lineEdit->setReadOnly(true);}
}void MyComputer::on_pushButton1_3_clicked()
{if(ui->pushButton1_19->text() == tr("关")){ui->lineEdit->setReadOnly(false);if(ui->lineEdit->displayText()=="0"){  ui->lineEdit->setText("3"); }else{if(ui->lineEdit->displayText().length()<8){ui->lineEdit->setText(ui->lineEdit->displayText()+"3");}}if(result!=""){ui->lineEdit->clear();ui->lineEdit->setText("3");result = "";}ui->lineEdit->setReadOnly(true);}
}void MyComputer::on_pushButton1_4_clicked()
{if(ui->pushButton1_19->text() == tr("关")){ui->lineEdit->setReadOnly(false);if(ui->lineEdit->displayText()=="0"){  ui->lineEdit->setText("4"); }else{if(ui->lineEdit->displayText().length()<8){ui->lineEdit->setText(ui->lineEdit->displayText()+"4");}}if(result!=""){ui->lineEdit->clear();ui->lineEdit->setText("4");result = "";}ui->lineEdit->setReadOnly(true);}
}void MyComputer::on_pushButton1_5_clicked()
{if(ui->pushButton1_19->text() == tr("关")){ui->lineEdit->setReadOnly(false);if(ui->lineEdit->displayText()=="0"){  ui->lineEdit->setText("5"); }else{if(ui->lineEdit->displayText().length()<8){ui->lineEdit->setText(ui->lineEdit->displayText()+"5");}}if(result!=""){ui->lineEdit->clear();ui->lineEdit->setText("5");result = "";}ui->lineEdit->setReadOnly(true);}
}void MyComputer::on_pushButton1_6_clicked()
{if(ui->pushButton1_19->text() == tr("关")){ui->lineEdit->setReadOnly(false);if(ui->lineEdit->displayText()=="0"){  ui->lineEdit->setText("6"); }else{if(ui->lineEdit->displayText().length()<8){ui->lineEdit->setText(ui->lineEdit->displayText()+"6");}}if(result!=""){ui->lineEdit->clear();ui->lineEdit->setText("6");result = "";}ui->lineEdit->setReadOnly(true);}
}void MyComputer::on_pushButton1_7_clicked()
{if(ui->pushButton1_19->text() == tr("关")){ui->lineEdit->setReadOnly(false);if(ui->lineEdit->displayText()=="0"){  ui->lineEdit->setText("7"); }else{if(ui->lineEdit->displayText().length()<8){ui->lineEdit->setText(ui->lineEdit->displayText()+"7");}}if(result!=""){ui->lineEdit->clear();ui->lineEdit->setText("7");result = "";}ui->lineEdit->setReadOnly(true);}
}void MyComputer::on_pushButton1_8_clicked()
{if(ui->pushButton1_19->text() == tr("关")){ui->lineEdit->setReadOnly(false);if(ui->lineEdit->displayText()=="0"){  ui->lineEdit->setText("8"); }else{if(ui->lineEdit->displayText().length()<8){ui->lineEdit->setText(ui->lineEdit->displayText()+"8");}}if(result!=""){ui->lineEdit->clear();ui->lineEdit->setText("8");result = "";}ui->lineEdit->setReadOnly(true);}
}void MyComputer::on_pushButton1_9_clicked()
{if(ui->pushButton1_19->text() == tr("关")){ui->lineEdit->setReadOnly(false);if(ui->lineEdit->displayText()=="0"){  ui->lineEdit->setText("9"); }else{if(ui->lineEdit->displayText().length()<8){ui->lineEdit->setText(ui->lineEdit->displayText()+"9");}}if(result!=""){ui->lineEdit->clear();ui->lineEdit->setText("9");result = "";}ui->lineEdit->setReadOnly(true);}
}void MyComputer::on_pushButton1_10_clicked()
{if(ui->pushButton1_19->text() == tr("关")){ui->lineEdit->setReadOnly(false);if(ui->lineEdit->displayText()=="0"){   }else{if(ui->lineEdit->displayText().length()<8){ui->lineEdit->setText(ui->lineEdit->displayText()+"0");}}if(result!=""){ui->lineEdit->clear();ui->lineEdit->setText("0");result = "";}ui->lineEdit->setReadOnly(true);}
}

2.小数点按钮
必须得再开机后才能使用,当计算出结果后,此按钮应该处于冻结状态,无法使用。

void MyComputer::on_pushButton1_11_clicked()
{if(ui->pushButton1_19->text() == tr("关")&result==""){ui->lineEdit->setReadOnly(false);QString component;int component_len;component = ui->lineEdit->displayText();component_len = component.length();
//    qDebug()<<component.length();//首先判断显示器上显示的位数是否为0if(component_len != 0){if(component[component.length()-1]=="."|component[component.length()-1]=="+"|component[component.length()-1]=="-"|component[component.length()-1]=="*"|component[component.length()-1]=="/"){}else{ui->lineEdit->setText(ui->lineEdit->displayText()+".");}}ui->lineEdit->setReadOnly(true);}
}

3.计算符号按钮
同样必须开机了以后才可以使用,输入的符号不可以和前一位符号相同,同时只有在计算结果为空的时候才可以输入符号。其中比较special的一点就是如果输入加(减)号后,输入减(加)号可以将前面的符号覆盖。

//+
void MyComputer::on_pushButton1_17_clicked()
{if(ui->pushButton1_19->text() == tr("关")){ui->lineEdit->setReadOnly(false);QString component;int component_len;component = ui->lineEdit->displayText();component_len = component.length();
//    qDebug()<<component.length();//首先判断显示器上显示的位数是否为0if(component_len != 0){if(component[component.length()-1]=="+"){}else{ui->lineEdit->setText(ui->lineEdit->displayText()+"+");}}if(component[component.length()-1]=="+"){component.replace(component_len-1,1,"-");ui->lineEdit->setText(component);}if(result!=""){ui->lineEdit->setText("");ui->lineEdit->setText(result+"+");result = "";}ui->lineEdit->setReadOnly(true);}
}
//-
void MyComputer::on_pushButton1_16_clicked()
{if(ui->pushButton1_19->text() == tr("关")){ui->lineEdit->setReadOnly(false);QString component;int component_len;component = ui->lineEdit->displayText();component_len = component.length();
//    qDebug()<<component.length();//首先判断显示器上显示的位数是否为0if(component[component.length()-1]=="-"){}else{ui->lineEdit->setText(ui->lineEdit->displayText()+"-");}if(component[component.length()-1]=="+"){component.replace(component_len-1,1,"-");ui->lineEdit->setText(component);}if(result!=""){ui->lineEdit->setText("");ui->lineEdit->setText(result+"-");result = "";}ui->lineEdit->setReadOnly(true);}
}//*
void MyComputer::on_pushButton1_14_clicked()
{if(ui->pushButton1_19->text() == tr("关")){ui->lineEdit->setReadOnly(false);QString component;int component_len;component = ui->lineEdit->displayText();component_len = component.length();
//    qDebug()<<component.length();//首先判断显示器上显示的位数是否为0if(component_len != 0){if(component[component.length()-1]=="*"){}else{ui->lineEdit->setText(ui->lineEdit->displayText()+"*");}}if(result!=""){ui->lineEdit->setText("");ui->lineEdit->setText(result+"*");result = "";}ui->lineEdit->setReadOnly(true);}
}// /
void MyComputer::on_pushButton1_13_clicked()
{if(ui->pushButton1_19->text() == tr("关")){ui->lineEdit->setReadOnly(false);QString component;int component_len;component = ui->lineEdit->displayText();component_len = component.length();
//    qDebug()<<component.length();//首先判断显示器上显示的位数是否为0if(component_len != 0){if(component[component.length()-1]=="/"){}else{ui->lineEdit->setText(ui->lineEdit->displayText()+"/");}}if(result!=""){ui->lineEdit->setText("");ui->lineEdit->setText(result+"/");result = "";}ui->lineEdit->setReadOnly(true);}
}

4.清屏(AC)按钮
开机后才可以使用,按下后,能够清楚显示器上的所有内容。

void MyComputer::on_pushButton1_12_clicked()
{if(ui->pushButton1_19->text() == tr("关")){ui->lineEdit->setReadOnly(false);
//    qDebug()<<ui->lineEdit->displayText();ui->lineEdit->setText("");result = "";ui->lineEdit->setReadOnly(true);}
}

5.后退(Backoff)按钮
开机后才能使用,仅在运算表达式输入时才可以使用,按下后,可以清除本次输入的字符。

void MyComputer::on_pushButton1_15_clicked()
{if(ui->pushButton1_19->text() == tr("关")&result==""){ui->lineEdit->setReadOnly(false);QString component,component_cpy;int component_len;component = ui->lineEdit->displayText();component_len = component.length();
//    qDebug()<<component.length();//首先判断显示器上显示的位数是否为0if(component_len != 0){//        component[component_len-1]='\0';for(int i=0;i<component_len-1;i++){component_cpy[i] = component[i];}ui->lineEdit->setText(component_cpy);}ui->lineEdit->setReadOnly(true);}
}

3.2 通讯部分的实现

这里我们的需求是能够完成和STM32的数据交互,由于是计算器我们把等于号作为发送数据的按钮,每点击一次等于就向32发送一次数据,当32计算完数据后,会将数据传回我们Qt程序,并在显示屏上显示。
首先我们在Qt中对串口进行初始化,使其能够与STM32进行通信,控制串口开关的按钮就是我们的开关键,其中需要注意的点是需要将我们的上位机串口配置初始化的和STM32相匹配,具体代码如下:

void MyComputer::on_pushButton1_19_clicked()
{//qDebug() << "isopen = " << serial->isOpen();QString port_name;foreach (const QSerialPortInfo &info,QSerialPortInfo::availablePorts()){QSerialPort serial;serial.setPort(info);if(serial.open(QIODevice::ReadWrite)){qDebug()<<serial.portName();port_name = serial.portName();qDebug() << "isopen = " << serial.isOpen();serial.close();qDebug() << "isopen = " << serial.isOpen();}}if(ui->pushButton1_19->text() == tr("开")){qDebug()<<"串口打开了!!!"<<endl;serial = new QSerialPort;//设置波特率serial->setPortName(port_name);serial->setBaudRate(QSerialPort::Baud115200);//设置波特率为115200serial->setDataBits(QSerialPort::Data8);//设置数据位8serial->setStopBits(QSerialPort::OneStop);//停止位设置为1serial->setParity(QSerialPort::NoParity);//无校验位serial->setFlowControl(QSerialPort::NoFlowControl);//设置为无流控制serial->open(QIODevice::ReadWrite);serial->setBaudRate(QSerialPort::Baud115200);//设置波特率为115200//qDebug() << "isopen = " << serial->isOpen();if( serial->isOpen()){ui->pushButton1_19->setText(tr("关"));}QObject::connect(serial,&QSerialPort::readyRead,this,&MyComputer::ReadData);qDebug() << "isopen = " << serial->isOpen();}else{//关闭串口serial->clear();serial->close();serial->deleteLater();ui->pushButton1_19->setText(tr("开"));ui->lineEdit->setText("");result="";qDebug()<<"串口关闭了!!!"<<endl;}
}

在与32建立连接后,我们就可以进行我们的表达式编写啦,就是通过点击我们之前编写好的按钮来实现的,最后点击等于号我们就会将我们输入的表达式发送给STM32,具体发送数据的代码如下:

void MyComputer::on_pushButton1_18_clicked()
{QString component;int ready_send = 0;component = ui->lineEdit->text();for(int i = 0;i<component.length();i++){if(component[i]=="+"|component[i]=="-"|component[i]=="*"|component[i]=="/")if(i!=component.length()-1)if(component[i+1]!=""){ready_send=1;break;}}if(ui->pushButton1_19->text() == tr("关")){ui->lineEdit->setReadOnly(false);QString sendData = ui->lineEdit->text();if(ready_send&result==""){QByteArray sendData_2 = sendData.toLatin1();sendData_2+=0x0d;sendData_2+=0x0a;/*for(int i=0;i<sendData_2.length();i++){sendData_2[i] =ConvertHexChar(sendData_2[i]);}*/qDebug() << "isopen state = " << serial->isOpen();serial->write(sendData_2);qDebug() << "serial->isReadable()" <<serial->isReadable();qDebug() << "sendData_2 = " << sendData_2;//      qDebug()<<"QIODevice::readyRead()"<<serial->readyRead();
//      ui->lineEdit->setReadOnly(false);}}
}

特别注意:数据发送一定要以/n/r结尾,不然无法收到返回数据!

发送完数据后的下一步当然是读取STM32计算好的数据,并将数据显示,这里我们首先需要将串口是否可读信号与读取信号的槽函数连接,这样当STM32发来可读信号后,我们的上位机就会将计算好的结果显示在屏幕上。

QObject::connect(serial,&QSerialPort::readyRead,this,&MyComputer::ReadData);

读取数据的函数如下:

void MyComputer::ReadData()
{qDebug()<<"正在读取数据";ui->lineEdit->setReadOnly(false);QString component;int component_len;component = ui->lineEdit->displayText();component_len = component.length();
//    qDebug()<<component.length();//首先判断显示器上显示的位数是否为0if(component_len != 0){if(component[component.length()-1]=="="){}else{ui->lineEdit->setText(ui->lineEdit->displayText()+"=");}}QByteArray buf;buf = serial->readAll();buf_remove(buf);qDebug()<<"buf_past"<<buf;buf_remove_zero(buf);qDebug()<<"buf"<<buf;result = buf;                       //用于储存每次计算结果,便于下次继续计算qDebug()<<"result:"<<result;if(!buf.isEmpty()){QString str = ui->lineEdit->text();str+=tr(buf);ui->lineEdit->clear();ui->lineEdit->setText(str);buf.clear();}ui->lineEdit->setReadOnly(true);
}

三、总结

经过上述步骤,一个简单的计算器就完成啦,能够实现基本的加减乘除计算。但是这个计算器仍然有很多不足的地方,我会在接下里的时间里进行改 进,使其具有更强大的运算功能。


这里是我的源代码供大家参考:
Qt源代码:
链接:https://pan.baidu.com/s/1rkIY63_4Fb-6KUmKEH8nrg
提取码:jon4
STM32源代码:
链接:https://pan.baidu.com/s/1bEiVfFmQOyJvuHbwX3Z7kQ
提取码:gbe9
生成的exe文件:
链接:https://pan.baidu.com/s/1d4BlyKYBJdpD-MnDNsexmw
提取码:f1z9

2.0已经完成
传送门:https://blog.csdn.net/qq_42788340/article/details/109519538

基于STM32的计算器相关推荐

  1. 基于stm32简易计算机电路图,基于STM32的简易电子计算器设计与实现(DOC).doc

    嵌入式系统设计实验综合设计报告 PAGE 四川师范大学成都学院通信工程学院 基于STM32的简易电子计算器设计与实现 实验综合设计报告 学生姓名 陶龑 学 号 2016301033 所在学院 通信工程 ...

  2. ARM开发(9)基于STM32的简单四则运算计算器

    基于STM32的简单四则运算计算器 一 计算器原理: 1.1 本实验实现基于STM32的简单四则运算计算器 1.2 实验思路:理解计算器原理(按键扫描,字符实时显示,运算表达式计算,浮点数转字符串,字 ...

  3. 基于STM32实现I2C从机的数字数学计算器:用于执行加法、减法和乘法操作的深度解析及应用

    一.引言 在许多现代电子设备中,微控制器都是至关重要的组成部分,其作用是控制和处理系统内部的各种操作.我们经常遇到一种情况,即需要微控制器与其他设备进行通信以接收或传递信息.在这种情况下,I2C(In ...

  4. 基于STM32的多功能MP3设计 毕业设计(论文)开题报告

    中国计量学院 毕业设计(论文)开题报告 学生姓名:卢杰学 号:XXXXXXXXX 专    业:电子科学与技术 班    级:10电子1 设计(论文)题目: 基于STM32的多功能MP3设计 指导教师 ...

  5. 基于STM32的智能篮球测温记分记时系统

    1.项目概述(20分) 1.1项目简介(5分) 进入21世纪,伴随着电子信息通信技术的应用与普及开发,人们对电子技术的要也越来越高.篮球作为一种体育运动进入了人们的生活.为对比赛进行规范化管理,研究一 ...

  6. 基于STM32的DS1302时钟芯片驱动

    基于STM32的DS1302时钟芯片驱动 /****************************************************************************** ...

  7. 智能手环功能模块设计_基于STM32实现智能手环设计

    龙源期刊网 http://www.qikan.com.cn 基于 STM32 实现智能手环设计 作者:付海生 陈婷婷 韩百科 涂曾兵 来源:<科学导报 · 学术> 2017 年第 10 期 ...

  8. delphi 数字识别_基于STM32单片机的车牌识别

    系统介绍    使用STM32F103RCT6作为主控,摄像头使用OV7670(带FIFO).STM32进行了16倍频.识别过程分别为:图像采集,二值化,识别车牌区域,字符分割,字符匹配. 识别过程分 ...

  9. stm32采集正弦波峰峰值_科研项目 | 基于STM32的永磁同步电机SVPWM控制设计

    点击上方蓝字,记得关注我们! 一.师资背景 指导老师毕业于中国985高校,毕业后留校工作至今,现为该校电气工程及自动化专业的教授.硕士研究生导师,多家企业研发技术顾问. 主要研究方向包括电力电子拓扑及 ...

  10. stm32捕获占空比_基于STM32超声波避障小车

    不管是对于初学者还是对于一个玩过单片机的电子爱好者来说,或多或少都接触到过小车项目,今天给大家介绍的的一个项目基于STM32超声波避障小车.这也是我曾经的一个课设,在此开源分享给大家,全文5000多字 ...

最新文章

  1. 小程序云开发更新数组的指定对象的值
  2. 多个if语句并列_P009 python基础之控制语句01
  3. Python 优化第一步: 性能分析实践 使用cporfile+gprof2dot可视化
  4. HBase 2.X版本的元数据修复及一种数据迁移方式
  5. Android v4、v7、v13 的区别
  6. 小甲鱼 OllyDbg 教程系列 (七) :VB 程序逆向分析
  7. mysql 分表_MySQL如何分库分表
  8. Linux下修改Mysql的用户(root)的密码的俩种方法
  9. 帆软Tab控件与控制组件隐藏的异同点
  10. ckeditor4.x操作之在页面中引入(一)
  11. 发送短信功能-联通接口
  12. 计算机磁盘在线分区,电脑硬盘分区知多少 怎么分区才合理?
  13. html仿qq截图,截图工具(仿QQ截图,大致功能都已实现)
  14. 使用flex让父盒子内子盒子自适应宽度
  15. dsp6657的helloworld例程测试-第一篇
  16. Linux系统中read的用法,Linux系统中read的使用技巧
  17. yum的配置文件yum.conf详解
  18. mini2440 sd卡支持
  19. [洛谷]P1535 游荡的奶牛 (#搜索 -2.7)
  20. [LayoutConstraints] Unable to simultaneously satisfy constraints.

热门文章

  1. windows安装office2016
  2. ListView刷新单条item实现方法
  3. Hibernate技术
  4. 第十八篇_Class文件
  5. u 只读 盘 突然_u盘变成只读方式了,怎么办
  6. 动态推荐系统关键技术研究(一)
  7. 如何下载四川省卫星地图高清版大图
  8. java索引越界异常_java中的字符串索引越界错误(charAt)
  9. BlockUI对话框
  10. 世界读书日 | 这11本书将颠覆技术人士的思维方式