introduction
This program is based on the upper computer made of Qt, which monitors the temperature change of the lower computer in real time. The lower computer transmits the temperature to the upper computer through the serial port. After receiving the temperature, the upper computer draws the change graph of temperature and time, and displays it on the right The temperature corresponding to each time. The specific value of the temperature can be displayed below.
The program uses QCustomPlot for drawing.
Host computer design
head File
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include <QPen> #include <QSerialPort> #include <QSerialPortInfo> #include <QMessageBox> #include <QFileDialog> #include "qcustomplot.h" QT_BEGIN_NAMESPACE namespace Ui { class MainWindow; } QT_END_NAMESPACE class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = nullptr); ~MainWindow(); void init(); //initialization void insert(QString date,QString t); //table insert data private slots: void setAxisRange(QCPRange);//x,y axis scaling or movement will not appear negative values void receData(); //Receive data slot function void on_searchButton(); //Search Serial Slot Functions void on_openButton(); //Open the serial slot function void on_closeButton(); //Close the serial port slot function void on_startButton(); //start plotting slot function void on_stopButton(); //stop drawing slot function void on_exportButton(); //export slot function void on_saveButton(); //save data slot function void on_clearButton(); //empty text slot function void drawShow(); //plot and display data private: Ui::MainWindow *ui; QPen pen; QSerialPort *serialPort; qreal temperature = 0; //get temperature QTimer *qtimer; //timer }; #endif // MAINWINDOW_H
ui interface design
initialization work
The drawing interface QCustomPlot has been written before, so I won't add it here. Here mainly write the initialization of LCD control and form control.
// ***********LCD initialization********** ui->tempNumber->setDigitCount(5); //Set the number of digits ui->tempNumber->setMode(QLCDNumber::Dec); //decimal mode ui->tempNumber->setSmallDecimalPoint(true); //show decimal point ui->tempNumber->setSegmentStyle(QLCDNumber::Flat); //display appearance
// ***********Form initialization********** ui->dataTable->setColumnCount(2); //set to 2 columns ui->dataTable->setAlternatingRowColors(true); //set interlaced color ui->dataTable->setSelectionBehavior(QAbstractItemView::SelectRows);//Select the entire row //set header QStringList header; header << tr("time") << tr("temperature"); ui->dataTable->setHorizontalHeaderLabels(header); ui->dataTable->setColumnWidth(0,80); //Set the column width of the first column ui->dataTable->setColumnWidth(1,80); //set the width of the second column
button state initialization
ui->openBtn->setEnabled(true); ui->closeBtn->setEnabled(false); ui->startBtn->setEnabled(false); ui->stopBtn->setEnabled(false);
Serial port function design
The functions of the serial port are all in the button control, here is the slot function code of the button directly.
//Search Serial Slot Functions void MainWindow::on_searchButton() { int count = ui->portCom->count(); if(count == 0){ QStringList serialPortName; foreach(const QSerialPortInfo &info,QSerialPortInfo::availablePorts()){ serialPortName.append(info.portName()); //Add available serial port name } ui->portCom->addItems(serialPortName); } }
//Open the serial port button slot function void MainWindow::on_openButton() { //baud rate QSerialPort::BaudRate baudRate = QSerialPort::Baud115200; //data bit QSerialPort::DataBits dataBits = QSerialPort::Data8; //stop bit QSerialPort::StopBits stopBits = QSerialPort::OneStop; //Record selected parameters QString baudText = ui->baudCom->currentText(); QString dataText = ui->dataCom->currentText(); QString stopText = ui->stopCom->currentText(); if(baudText == "115200") baudRate = QSerialPort::Baud115200; else if(baudText == "4800") baudRate = QSerialPort::Baud4800; else if(baudText == "9600") baudRate = QSerialPort::Baud9600; if(dataText == "8") dataBits = QSerialPort::Data8; else if(dataText == "5") dataBits = QSerialPort::Data5; else if(dataText == "6") dataBits = QSerialPort::Data6; else if(dataText == "7") dataBits = QSerialPort::Data7; if(stopText == "1") stopBits = QSerialPort::OneStop; else if(stopText == "1.5") stopBits = QSerialPort::OneAndHalfStop; else if(stopText == "2") stopBits = QSerialPort::TwoStop; //Set serial port parameters serialPort->setPortName(ui->portCom->currentText()); serialPort->setBaudRate(baudRate); serialPort->setDataBits(dataBits); serialPort->setStopBits(stopBits); serialPort->setParity(QSerialPort::NoParity); if(serialPort->open(QIODevice::ReadWrite) == true){ QMessageBox::information(this,"hint","The serial port is opened successfully!"); //change button state ui->openBtn->setEnabled(false); ui->closeBtn->setEnabled(true); ui->startBtn->setEnabled(true); ui->stopBtn->setEnabled(true); }else{ QMessageBox::warning(this,"hint","Serial port opening failed!"); } }
//Close the serial port button slot function void MainWindow::on_closeButton() { serialPort->close(); //close the serial port qtimer->stop(); //off timer QMessageBox::information(this,"hint","The serial port is closed!"); ui->openBtn->setEnabled(true); ui->closeBtn->setEnabled(false); ui->startBtn->setEnabled(false); ui->stopBtn->setEnabled(false); }
When the serial port receives the temperature data transmitted from the lower computer, it needs to use the signal and slot mechanism to receive it, as follows:
//Receive serial data connect(serialPort,SIGNAL(readyRead()),this,SLOT(receData()));
//Receive data slot function void MainWindow::receData() { QByteArray buffer = serialPort->readAll(); if(!buffer.isEmpty()){ QString s = tr(buffer); temperature = s.toDouble()/100; ui->tempNumber->display(temperature); } buffer.clear(); //clear cache }
table insert data
//table insert data void MainWindow::insert(QString date, QString t) { update(); int row_count = ui->dataTable->rowCount(); //Get the total number of rows, insert a row based on this ui->dataTable->insertRow(row_count); //insert row QTableWidgetItem *item0 = new QTableWidgetItem(); QTableWidgetItem *item1 = new QTableWidgetItem(); item0->setText(date); item1->setText(t); ui->dataTable->setItem(row_count,0,item0); ui->dataTable->setItem(row_count,1,item1); }
save table data
//save data slot function void MainWindow::on_saveButton() { QString filename = QFileDialog::getSaveFileName(); //file name QDateTime time = QDateTime::currentDateTime(); //Get the current time of the system QString date = time.toString("MM.dd.hh.mm.ss"); //Set display format filename += date; filename += ".txt"; //Create file object QFile file(filename); if(!file.open(QFile::WriteOnly | QFile::Text)){ //write-only QMessageBox::warning(this,tr("double file edit"),tr("no write").arg(filename).arg(file.errorString())); return; } //Create a file stream object QTextStream out(&file); out << "time" << "\t\t" << "temperature" << "\n"; //traverse data int romcount = ui->dataTable->rowCount(); //Get the total number of rows for(int i = 0;i < romcount;i++){ QString rowstring; for(int j = 0;j < 2;j++){ rowstring += ui->dataTable->item(i,j)->text(); rowstring += " "; } rowstring += "\n"; out << rowstring; } file.close(); //close file }
Clear form data
//empty text slot function void MainWindow::on_clearButton() { while(ui->dataTable->rowCount()){ ui->dataTable->removeRow(0); } }
start drawing
//start plotting slot function void MainWindow::on_startButton() { qtimer->start(); ui->startBtn->setEnabled(false); ui->stopBtn->setEnabled(true); }
pause drawing
//stop drawing slot function void MainWindow::on_stopButton() { qtimer->stop(); ui->startBtn->setEnabled(true); ui->stopBtn->setEnabled(false); }
graphic design
//plot and display data void MainWindow::drawShow() { QDateTime time = QDateTime::currentDateTime(); //Get the current system time qreal key = time.toMSecsSinceEpoch()/1000; static qreal lastPointKey = 0; if(key - lastPointKey > 0.2){ //Add a data at most every 2ms ui->customplot->graph(0)->addData(key,temperature);//adding data lastPointKey = key; } ui->customplot->xAxis->setRange(key,10,Qt::AlignRight);//Set the x-axis range, the number of display is 10 ui->customplot->replot(QCustomPlot::rpQueuedReplot); QString date = time.toString("hh:mm:ss"); //Set display format QString tempe = QString("%1").arg(temperature); insert(date,tempe); }
Export temperature change graph
//export slot function void MainWindow::on_exportButton() { QString filename = QFileDialog::getSaveFileName(); if(filename == ""){ QMessageBox::warning(this,"fail","Save failed!"); return; } QMessageBox::information(this,"success","Saved successfully!"); ui->customplot->savePng(filename.append(".png"),ui->customplot->width(),ui->customplot->height()); }
timer
The drawing and data display are operated by timers, so the timer object must be created first, and the drawing and data display can be performed through the overflow event of the timer. as follows:
qtimer = new QTimer; //Create a timer object qtimer->setInterval(1000); //Set the timing interval to 1s
connect(qtimer,SIGNAL(timeout()),this,SLOT(drawShow()));
Lower computer design
The board of the lower computer is stm32f103zet6. The main operation of the lower computer is to initialize and use the serial port, and the temperature is obtained by using the internal temperature sensor of stm32, which is ADC16.
Delay function design
The delay.h code is as follows:
#ifndef __DELAY_H #define __DELAY_H #include "stm32f10x.h" static u8 fac_us=0; //us delay multiplier static u16 fac_ms=0; //ms delay multiplier void delay_init(void); //delayed initialization void delay_us(u32 nus); //microsecond delay function void delay_ms(u16 nms); //Millisecond delay function #endif
The delay.c code is as follows:
#include "delay.h" void delay_init(void) { SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); //Select external clock HCLK/8 fac_us=SystemCoreClock/8000000; //1/8 of the system clock fac_ms=(u16)fac_us*1000; //Under non-OS, it represents the number of systick clocks required per ms } //Delay nus //nus is the number of us to be delayed. void delay_us(u32 nus) { u32 temp; SysTick->LOAD=nus*fac_us; //time to load SysTick->VAL=0x00; //clear counter SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ; //start counting down do { temp=SysTick->CTRL; }while((temp&0x01)&&!(temp&(1<<16))); //waiting time to arrive SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk; //off counter SysTick->VAL =0X00; //clear counter } //Delay nms //Pay attention to the range of nms //SysTick->LOAD is a 24-bit register, so the maximum delay is: //nms<=0xffffff*8*1000/SYSCLK //SYSCLK unit is Hz,nms unit is ms //Under the condition of 72M, nms<=1864 void delay_ms(u16 nms) { u32 temp; SysTick->LOAD=(u32)nms*fac_ms; //Time loading (SysTick->LOAD is 24bit) SysTick->VAL =0x00; //clear counter SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ; //start counting down do { temp=SysTick->CTRL; }while((temp&0x01)&&!(temp&(1<<16))); //waiting time to arrive SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk; //off counter SysTick->VAL =0X00; //clear counter }
Serial port design
usart.h code is as follows:
#ifndef __USART_H #define __USART_H #include "stm32f10x.h" #include "stdio.h" //Serial port 1-USART1 #define DEBUG_USARTx USART1 #define DEBUG_USART_CLK RCC_APB2Periph_USART1 #define DEBUG_USART_APBxClkCmd RCC_APB2PeriphClockCmd #define DEBUG_USART_BAUDRATE 115200 //USART GPIO pin macro definition #define DEBUG_USART_GPIO_CLK (RCC_APB2Periph_GPIOA) #define DEBUG_USART_GPIO_APBxClkCmd RCC_APB2PeriphClockCmd #define DEBUG_USART_TX_GPIO_PORT GPIOA #define DEBUG_USART_TX_GPIO_PIN GPIO_Pin_9 #define DEBUG_USART_RX_GPIO_PORT GPIOA #define DEBUG_USART_RX_GPIO_PIN GPIO_Pin_10 #define DEBUG_USART_IRQ USART1_IRQn #define DEBUG_USART_IRQHandler USART1_IRQHandler //static void NVIC_Configuration(void); //Interrupt initialization void USART_Config(void); //Serial port initialization void Usart_SendByte(USART_TypeDef* pUSARTx,uint8_t data);//send a byte of data void Usart_SendHalfWord(USART_TypeDef* pUSARTx,uint16_t data);//Send two bytes of data void Usart_SendStr(USART_TypeDef* pUSARTx,uint8_t *str);//send string #endif
usart.c code is as follows:
//Serial port initialization void USART_Config(void) { GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure; //Open serial port GPIO clock DEBUG_USART_GPIO_APBxClkCmd(DEBUG_USART_GPIO_CLK,ENABLE); //Open the serial port peripheral clock DEBUG_USART_APBxClkCmd(DEBUG_USART_CLK,ENABLE); //Configure the GPIO of USART TX as push-pull multiplexing mode GPIO_InitStructure.GPIO_Pin = DEBUG_USART_TX_GPIO_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(DEBUG_USART_TX_GPIO_PORT,&GPIO_InitStructure); //Configure the GPIO of USART RX as floating input mode GPIO_InitStructure.GPIO_Pin = DEBUG_USART_RX_GPIO_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(DEBUG_USART_RX_GPIO_PORT,&GPIO_InitStructure); //Configure the working parameters of the serial port //Configure baud rate USART_InitStructure.USART_BaudRate = DEBUG_USART_BAUDRATE; //Configuration pin data word length USART_InitStructure.USART_WordLength = USART_WordLength_8b; //configure stop bits USART_InitStructure.USART_StopBits = USART_StopBits_1; //Configuration check digit USART_InitStructure.USART_Parity = USART_Parity_No; //Configure hardware flow control USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //Configure the working mode, send and receive together USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //Complete the serial port initialization configuration USART_Init(DEBUG_USARTx,&USART_InitStructure); // //Serial port interrupt priority configuration // NVIC_Configuration(); // //Enable serial port receive interrupt // USART_ITConfig(DEBUG_USARTx,USART_IT_RXNE,ENABLE); //enable serial port USART_Cmd(DEBUG_USARTx,ENABLE); } //send a byte of data void Usart_SendByte(USART_TypeDef* pUSARTx,uint8_t data) { USART_SendData(pUSARTx,data); while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TXE) == RESET); } //Redirects the fputc function of the C library function to use the putchar function int fputc(int ch,FILE* f) { //send a byte to the serial port USART_SendData(DEBUG_USARTx,(uint8_t)ch); //wait for send while(USART_GetFlagStatus(DEBUG_USARTx,USART_FLAG_TXE) == RESET); return (ch); }
Internal Temperature Sensor Design
The temperature.h code is as follows:
#ifndef __TEMPERATURE_H #define __TEMPERATURE_H #include "stm32f10x.h" #include "delay.h" void T_Adc_Init(void); //ADC channel initialization u16 T_Get_Adc(u8 ch); //Get ADC value u16 T_Get_Temp(void); //Get the value of the internal temperature sensor sampled by the ADC u16 T_Get_Adc_Average(u8 ch,u8 times);//Get the conversion value of the channel ch short Get_Temperate(void); //get temperature value #endif
The temperature.c code is as follows:
#include "temperature.h" //ADC initialization void T_Adc_Init(void) { ADC_InitTypeDef ADC_InitStructure; //Enable GPIOA, ADC1 channel clock RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_ADC1,ENABLE); RCC_ADCCLKConfig(RCC_PCLK2_Div6); //The frequency division factor 6 clock is 72M/6 = 12MHz ADC_DeInit(ADC1); //Reset all registers of peripheral ADC1 to default values ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //Set ADC to work in independent mode ADC_InitStructure.ADC_ScanConvMode = DISABLE; //Analog-to-digital conversion works in single-channel mode ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; //Analog-to-digital conversion works in single conversion mode ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//Conversion initiated by software rather than external trigger ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //ADC data right justified ADC_InitStructure.ADC_NbrOfChannel = 1; //Number of ADC channels sequentially performing regular conversions ADC_Init(ADC1,&ADC_InitStructure); //Initialize the registers of the peripheral ADCx ADC_TempSensorVrefintCmd(ENABLE); //Turn on the internal temperature sensor ADC_Cmd(ADC1,ENABLE); //Enable ADC1 ADC_ResetCalibration(ADC1); //Reset the reset register of the specified ADC1 while(ADC_GetResetCalibrationStatus(ADC1)); //Get the status of the ADC1 reset calibration register, set the status and wait ADC_StartCalibration(ADC1); while(ADC_GetCalibrationStatus(ADC1)); //Get the calibration program of the specified ADC1, set the status and wait } //Get ADC value u16 T_Get_Adc(u8 ch) { //Channel 3 of ADC1, first conversion, sampling time is 239.5 cycles ADC_RegularChannelConfig(ADC1,ch,1,ADC_SampleTime_239Cycles5); ADC_SoftwareStartConvCmd(ADC1,ENABLE); //Enable the software conversion start function of the specified ADC1 while(!ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC)); //Wait for the conversion to complete return ADC_GetConversionValue(ADC1); //Returns the conversion result of the latest ADC1 rule group } //Get the value of the internal temperature sensor sampled by the ADC //Take 10 times and average u16 T_Get_Temp(void) { u16 temp_val = 0; u8 t; for(t = 0;t < 10;t++){ temp_val += T_Get_Adc(ADC_Channel_16); delay_ms(5); return temp_val/10; } } //Get the conversion value of the channel ch //Take times times, then average u16 T_Get_Adc_Average(u8 ch,u8 times) { u32 temp_val = 0; u8 t; for(t = 0;t < times;t++){ temp_val += T_Get_Adc(ch); delay_ms(5); } return temp_val/times; } //get temperature value short Get_Temperate(void) { u32 adcx; short result; double temperate; adcx = T_Get_Adc_Average(ADC_Channel_16,20); //Read channel 16, take the average of 20 times temperate = (float)adcx*(3.3/4096); //Voltage value temperate = (1.43 - temperate)/0.0043 + 25; //Convert to temperature value result += temperate*=100; //Expand 100 times return result; }
main function
while(1){ temp = Get_Temperate(); //get temperature value printf("%d",temp); delay_ms(3000); }
end
Friends who need source code can contact me!