QT串口助手-ZUA课设

news/2024/5/20 22:48:19/文章来源:https://blog.csdn.net/qq_47355554/article/details/126898479

QT串口助手

  • 成品展示
  • QT全部程序构成
    • zua.pro
    • serial.h
    • main.cpp
    • serial.cpp
    • serial.ui
  • Keil全部程序构成
    • main.c
    • stm32f10x_conf.h
    • stm32f10x_it.c
    • 5.stm32f10x_it.h
    • bsp_usart.c
    • bsp_led.c
    • bsp_exit.c
    • bsp_dht11.c
    • bsp_delay.c
  • 介绍
  • 硬件
    • 野火F103指南者+DHT11温湿度传感器
  • QT全部程序构成
    • QT设计的思路
  • Keil全部程序构成
    • Keil程序设计的思路
  • 功能
    • 1.
    • 2.
    • 3.
    • 4.
    • 5.
    • 6.
    • 全部功能
    • BUG解决方法

成品展示

在这里插入图片描述

其他功能展示在文章 最后

QT全部程序构成

在这里插入图片描述

zua.pro

只添加了 QT += core gui serialport
RC_ICONS =system.ico

QT       += core gui serialportgreaterThan(QT_MAJOR_VERSION, 4): QT += widgetsCONFIG += c++11DEFINES += QT_DEPRECATED_WARNINGSSOURCES += \main.cpp \serial.cppHEADERS += \serial.hFORMS += \serial.uiRC_ICONS =system.icoqnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += targetRESOURCES += \zua.qrc

serial.h

#ifndef SERIAL_H
#define SERIAL_H#include <QMainWindow>
/*---port串口--*/
#include <QSerialPort>
#include <QSerialPortInfo>
/*---QString--*/
#include <QString>
/*---QTimer定时器--*/
#include <QTimer>
/*-----QToolBar工具栏------*/
#include <QToolBar>
/*---QDebug打印--*/
#include <QDebug>QT_BEGIN_NAMESPACE
namespace Ui { class Serial; }
QT_END_NAMESPACEclass Serial : public QMainWindow
{Q_OBJECTpublic:Serial(QWidget *parent = nullptr);~Serial();private:Ui::Serial *ui;/*------------变量----------------*/QSerialPort mSerialPort;//串口全局类声明bool mIsOpen;//是否打开串口QTimer *timer;//自动发送定时器声明/*------------函数----------------*/bool getSerialPortConfig();// 获取串口配置 打开串口//用户系统初始化void sysIint();//字符串转16进制QByteArray QString2Hex(QString str);//字符转16进制char ConvertHexChar(char ch);signals:    //自定义信号//发送使能信号void my_send_signals(bool); //触发发送信号private slots:void on_SerialPort_readyRead();// 准备接收串口数据槽,自定义的void on_btnOpen_clicked();//打开串口按键槽,使用转到槽void on_btnClose_clicked();//关闭串口按键,使用转到槽void on_BtnSend_clicked();//发送按键,使用转到槽void on_btn_clear_clicked();//清楚接收区按键,使用转到槽void on_btn_clear_send_clicked();//清空发送区按键,使用转到槽void on_checkBox_3_stateChanged(int arg1);//自动触发复选框  启动定时器和停止定时器,使用转到槽
};
#endif // SERIAL_H

main.cpp

没有改变

serial.cpp

#include "serial.h"
#include "ui_serial.h"Serial::Serial(QWidget *parent): QMainWindow(parent), ui(new Ui::Serial)
{ui->setupUi(this);sysIint();
}Serial::~Serial()
{delete ui;
}
// 获取串口配置 打开串口
bool Serial::getSerialPortConfig()
{//    获取串口配置QString mPortName = ui->cmd_port_name->currentText();//     端口号QString mBaudRate = ui->cmd_baud_rate->currentText();//     波特率QString mDataBits = ui->cmd_Data_Bits->currentText();//     数据位QString mParity = ui->cmd_parity->currentText();//     校验位QString mStopBits = ui->cmd_Stop_Bits->currentText();//      停止位//     设置串口//     端口号mSerialPort.setPortName(mPortName);//     波特率mSerialPort.setBaudRate(mBaudRate.toInt());/*if("9600" == mBaudRate){mSerialPort.setBaudRate(QSerialPort::Baud9600);}else if("115200" == mBaudRate){mSerialPort.setBaudRate(QSerialPort::Baud115200);}else{mSerialPort.setBaudRate(QSerialPort::Baud19200);}*///     数据位if("5" == mDataBits){mSerialPort.setDataBits(QSerialPort::Data5);}else if("6" == mDataBits){mSerialPort.setDataBits(QSerialPort::Data6);}else if("7" == mDataBits){mSerialPort.setDataBits(QSerialPort::Data7);}else{mSerialPort.setDataBits(QSerialPort::Data8);}//     校验位if("Even" == mParity){mSerialPort.setParity(QSerialPort::EvenParity);// 偶数}else if ("ODD" == mParity){mSerialPort.setParity(QSerialPort::OddParity);//奇数的}else{mSerialPort.setParity(QSerialPort::NoParity);}//      停止位if("1.5" == mStopBits){mSerialPort.setStopBits(QSerialPort::OneAndHalfStop);}else if("2" == mStopBits){mSerialPort.setStopBits(QSerialPort::TwoStop);}else{mSerialPort.setStopBits(QSerialPort::OneStop);}//      打开串口return mSerialPort.open(QSerialPort::ReadWrite);
}
//系统初始化
void Serial::sysIint()
{ui->cmd_port_name->clear();this->setWindowTitle("xxx的串口调试GUI");//窗口名字connect(&mSerialPort,&QSerialPort::readyRead,this,&Serial::on_SerialPort_readyRead);//XImIsOpen = false;ui->BtnSend->setEnabled(mIsOpen);//没连接串口按键为灰色//    智能识别当前系统的有效串口号//通过QSerialPortInfo查找可用串口foreach(const QSerialPortInfo &info, QSerialPortInfo::availablePorts()){//将可用串口添加到端口显示框ui->cmd_port_name->addItem(info.portName());}//timer 自动发送timer = new QTimer(this);connect(timer,&QTimer::timeout,[=](){emit my_send_signals(true); //触发发送信号});//QToolBar *toolBar1= addToolBar("工具栏");//QToolBar工具栏//发送信号   发送槽函数connect(this,&Serial::my_send_signals,this,&Serial::on_BtnSend_clicked);
}
//字符串转16进制
QByteArray Serial::QString2Hex(QString str)
{QByteArray senddata;int hexdata,lowhexdata;int hexdatalen = 0;int len = str.length();senddata.resize(len/2);char lstr,hstr;for(int i=0; i<len; ){hstr=str[i].toLatin1();if(hstr == ' '){i++;continue;}i++;if(i >= len)break;lstr = str[i].toLatin1();hexdata = ConvertHexChar(hstr);lowhexdata = ConvertHexChar(lstr);if((hexdata == 16) || (lowhexdata == 16))break;elsehexdata = hexdata*16+lowhexdata;i++;senddata[hexdatalen] = (char)hexdata;hexdatalen++;}senddata.resize(hexdatalen);return senddata;
}
//字符转16进制
char Serial::ConvertHexChar(char ch)
{if((ch >= '0') && (ch <= '9'))return ch-0x30;else if((ch >= 'A') && (ch <= 'F'))return ch-'A'+10;else if((ch >= 'a') && (ch <= 'f'))return ch-'a'+10;else return (-1);
}/*-----------------slot--------------------*/
// 准备接收串口数据槽
void Serial::on_SerialPort_readyRead()
{QByteArray recvData = mSerialPort.readAll();//从串口读取数据QString str_rev;if(ui->chk_rev_hex->checkState() == Qt::Checked){   //HEX 16进制str_rev = QString(recvData.toHex(' ').toUpper().append(' '));}else{str_rev =QString::fromLocal8Bit(recvData);//处理汉语显示乱码,函数返回的是String类型的数}//文本框显示接收数据ui->textRecv->insertPlainText(str_rev);//显示内容,不会自动清空//将光标定位到最后ui->textRecv->moveCursor(QTextCursor::End);
}//打开串口按键
void Serial::on_btnOpen_clicked()
{if(true == mIsOpen){// 当前串口已经打开了一个串口,这时要执行关闭串口mSerialPort.close();mIsOpen = false;ui->BtnSend->setEnabled(mIsOpen);//发送按键不用}else{// 当前串口助手没有打开串口,这时要执行打开串口动作if(true == getSerialPortConfig()){mIsOpen = true;ui->BtnSend->setEnabled(mIsOpen);//发送按键可用}else{mIsOpen = false;}}
}
//关闭串口按键
void Serial::on_btnClose_clicked()
{mSerialPort.close();//执行关闭串口ui->BtnSend->setEnabled(false);//没连接串口按键为灰色mIsOpen = false;ui->textRecv->clear();//关闭串口,同时清楚接收区
}//发送按键
void Serial::on_BtnSend_clicked()
{qDebug()<<"发送按键"<<endl;QString data = ui->textSend->toPlainText();QByteArray array;//字节数组//复选框  16 进制发送if(ui->chk_send_hex->checkState() == Qt::Checked){array = QString2Hex(data);  //HEX 16进制,QString转Hex QString转十六进制数,自己写的}else{array = data.toLatin1();    //ASCII,QString类提供的}mSerialPort.write(array);   //发送数据//发送完后,清空发送区ui->textSend->clear();
}
//清楚接收区按键
void Serial::on_btn_clear_clicked()
{qDebug()<<"清楚接收区按键"<<endl;ui->textRecv->clear();
}
//清空发送区按键
void Serial::on_btn_clear_send_clicked()
{qDebug()<<"清空发送区按键"<<endl;ui->textSend->clear();
}
//自动触发复选框  启动定时器和停止定时器
void Serial::on_checkBox_3_stateChanged(int arg1)
{if(arg1){timer->start(ui->spinBox->value()); //启动定时器}else{timer->stop();  //停止定时器}
}

槽函数slot 区分
在这里插入图片描述在这里插入图片描述

serial.ui

  • 左侧组QGroupBox
    在这里插入图片描述
  • 右侧组QGroupBox

在这里插入图片描述

Keil全部程序构成

在这里插入图片描述

main.c

#include "stm32f10x.h"
#include "./led/bsp_led.h" 
#include "./usart/bsp_usart.h" 
#include "./Key/bsp_exti.h" 
#include "./dht11/bsp_dht11.h"static void Show_Message(void);int main(void)
{	char ch;/* 初始化EXTI中断,按下按键会触发中断,*  触发中断会进入stm32f4xx_it.c文件中的函数*  KEY1_IRQHandler和KEY2_IRQHandler,处理中断,反转LED灯,发送学号姓名。*/EXTI_Key_Config(); /*初始化DTT11的引脚*/DHT11_Init ();/* 初始化RGB彩灯 */LED_GPIO_Config();/* 初始化USART 配置模式为 115200 8-N-1 */USART_Config();LED1_ON;/* 打印指令输入提示信息 */Show_Message();while(1){	/* 获取字符指令 */ch=getchar();printf("接收到字符:%c\n",ch);/* 根据字符指令控制RGB彩灯颜色 */switch(ch){case '1':LED_RED;break;case '2':LED_GREEN;break;case '3':LED_BLUE;break;case '4':LED_YELLOW;break;case '5':LED_PURPLE;break;case '6':LED_CYAN;break;case '7':LED_WHITE;break;case '8':LED_RGBOFF;break;default:/* 如果不是指定指令字符,打印提示信息 */Show_Message();break;      }   }	
}/* 打印指令输入提示信息*/
static void Show_Message(void)
{printf("\r\r这是一个通过串口通信指令控制RGB彩灯实验 \n");printf("使用  USART  参数为:%d 8-N-1 \n",DEBUG_USART_BAUDRATE);printf("开发板接到指令后控制RGB彩灯颜色\n");printf("指令对应如下:\n");printf("   指令   ------ 彩灯颜色 \n");printf("     1    ------    红 \n");printf("     2    ------    绿 \n");printf("     3    ------    蓝 \n");printf("     4    ------    黄 \n");printf("     5    ------    紫 \n");printf("     6    ------    青 \n");printf("     7    ------    白 \n");printf("     8    ------    灭 \n");  
}

stm32f10x_conf.h

注意文件中 有可能会 注释掉了一些头文件,把注释去掉就好啦

stm32f10x_it.c

在最后插入以下

void KEY1_IRQHandler(void)
{//确保是否产生了EXTI Line中断if(EXTI_GetITStatus(KEY1_INT_EXTI_LINE) != RESET) {// LED1 取反		LED1_TOGGLE;printf("\r ---学号---姓名--\n");/* 发送学号、姓名*/Usart_SendString(DEBUG_USARTx,"191xxxxxx7-xxx\n");Usart_SendString(DEBUG_USARTx,"191xxxxxx0李x\n");Usart_SendString(DEBUG_USARTx,"190xxxxxx3周xx\n");Usart_SendString(DEBUG_USARTx,"191xxxxxx5卢xx\n");	//清除中断标志位EXTI_ClearITPendingBit(KEY1_INT_EXTI_LINE);     }  
}void KEY2_IRQHandler(void)
{DHT11_Data_TypeDef DHT11_Data;//确保是否产生了EXTI Line中断if(EXTI_GetITStatus(KEY2_INT_EXTI_LINE) != RESET) {// LED2 取反		LED2_TOGGLE;/*调用DHT11_Read_TempAndHumidity读取温湿度,若成功则输出该信息*/if( DHT11_Read_TempAndHumidity ( & DHT11_Data ) == SUCCESS){printf("\r\n读取DHT11成功!\r\n\r\n湿度为%d.%d %RH ,温度为 %d.%d℃ \r\n",\DHT11_Data.humi_int,DHT11_Data.humi_deci,DHT11_Data.temp_int,DHT11_Data.temp_deci);}			else{printf("Read DHT11 ERROR!\r\n");}//清除中断标志位EXTI_ClearITPendingBit(KEY2_INT_EXTI_LINE);     }  
}

5.stm32f10x_it.h

添加了头文件,其他保留

#include "stm32f10x.h"
#include "./led/bsp_led.h" 
#include "./usart/bsp_usart.h" 
#include "./Key/bsp_exti.h"
#include "./dht11/bsp_dht11.h"

bsp_usart.c

#include "bsp_usart.h"void USART_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;// 打开串口GPIO的时钟
DEBUG_USART_GPIO_APBxClkCmd(DEBUG_USART_GPIO_CLK, ENABLE);// 打开串口外设的时钟
DEBUG_USART_APBxClkCmd(DEBUG_USART_CLK, ENABLE);// 将USART Tx的GPIO配置为推挽复用模式
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);// 将USART Rx的GPIO配置为浮空输入模式
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);// 配置串口的工作参数
// 配置波特率
USART_InitStructure.USART_BaudRate = DEBUG_USART_BAUDRATE;
// 配置 针数据字长
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
// 配置停止位
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(DEBUG_USARTx, &USART_InitStructure);// 使能串口
USART_Cmd(DEBUG_USARTx, ENABLE);    
}/*****************  发送一个字符 **********************/
void Usart_SendByte( USART_TypeDef * pUSARTx, uint8_t ch)
{
/* 发送一个字节数据到USART */
USART_SendData(pUSARTx,ch);/* 等待发送数据寄存器为空 */
while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);
}/*****************  发送字符串 **********************/
void Usart_SendString( USART_TypeDef * pUSARTx, char *str)
{
unsigned int k=0;do {Usart_SendByte( pUSARTx, *(str + k) );k++;} while(*(str + k)!='\0');/* 等待发送完成 */while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TC)==RESET){}
}/*****************  发送一个16位数 **********************/
void Usart_SendHalfWord( USART_TypeDef * pUSARTx, uint16_t ch)
{
uint8_t temp_h, temp_l;/* 取出高八位 */
temp_h = (ch&0XFF00)>>8;
/* 取出低八位 */
temp_l = ch&0XFF;/* 发送高八位 */
USART_SendData(pUSARTx,temp_h);
while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);/* 发送低八位 */
USART_SendData(pUSARTx,temp_l);
while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);
}///重定向c库函数printf到串口,重定向后可使用printf函数
int fputc(int ch, FILE *f)
{
/* 发送一个字节数据到串口 */
USART_SendData(DEBUG_USARTx, (uint8_t) ch);/* 等待发送完毕 */
while (USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_TXE) == RESET);return (ch);
}///重定向c库函数scanf到串口,重写向后可使用scanf、getchar等函数
int fgetc(FILE *f)
{
/* 等待串口输入数据 */
while (USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_RXNE) == RESET);return (int)USART_ReceiveData(DEBUG_USARTx);
}

bsp_led.c

#include "./led/bsp_led.h"   void LED_GPIO_Config(void)
{
/*定义一个GPIO_InitTypeDef类型的结构体*/
GPIO_InitTypeDef GPIO_InitStructure;/*开启LED相关的GPIO外设时钟*/
RCC_APB2PeriphClockCmd( LED1_GPIO_CLK | LED2_GPIO_CLK | LED3_GPIO_CLK, ENABLE);
/*选择要控制的GPIO引脚*/
GPIO_InitStructure.GPIO_Pin = LED1_GPIO_PIN;/*设置引脚模式为通用推挽输出*/
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;   /*设置引脚速率为50MHz */   
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; /*调用库函数,初始化GPIO*/
GPIO_Init(LED1_GPIO_PORT, &GPIO_InitStructure);/*选择要控制的GPIO引脚*/
GPIO_InitStructure.GPIO_Pin = LED2_GPIO_PIN;/*调用库函数,初始化GPIO*/
GPIO_Init(LED2_GPIO_PORT, &GPIO_InitStructure);/*选择要控制的GPIO引脚*/
GPIO_InitStructure.GPIO_Pin = LED3_GPIO_PIN;/*调用库函数,初始化GPIOF*/
GPIO_Init(LED3_GPIO_PORT, &GPIO_InitStructure);/* 关闭所有led灯*/
GPIO_SetBits(LED1_GPIO_PORT, LED1_GPIO_PIN);/* 关闭所有led灯*/
GPIO_SetBits(LED2_GPIO_PORT, LED2_GPIO_PIN); /* 关闭所有led灯*/
GPIO_SetBits(LED3_GPIO_PORT, LED3_GPIO_PIN);
}void assert_failed(uint8_t* file, uint32_t line)
{
// 断言错误时执行的代码
LED1_ON;
}

bsp_exit.c

#include "bsp_exti.h"static void NVIC_Configuration(void)
{NVIC_InitTypeDef NVIC_InitStructure;/* 配置NVIC为优先级组1 */NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);/* 配置中断源:按键1 */NVIC_InitStructure.NVIC_IRQChannel = KEY1_INT_EXTI_IRQ;/* 配置抢占优先级 */NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;/* 配置子优先级 */NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;/* 使能中断通道 */NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure);/* 配置中断源:按键2,其他使用上面相关配置 */  NVIC_InitStructure.NVIC_IRQChannel = KEY2_INT_EXTI_IRQ;NVIC_Init(&NVIC_InitStructure);
}/*** @brief  配置 IO为EXTI中断口,并设置中断优先级* @param  无* @retval 无*/
void EXTI_Key_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure; 
EXTI_InitTypeDef EXTI_InitStructure;/*开启按键GPIO口的时钟*/
RCC_APB2PeriphClockCmd(KEY1_INT_GPIO_CLK,ENABLE);/* 配置 NVIC 中断*/
NVIC_Configuration();/*--------------------------KEY1配置-----------------------------*/
/* 选择按键用到的GPIO */GPIO_InitStructure.GPIO_Pin = KEY1_INT_GPIO_PIN;/* 配置为浮空输入 */GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;GPIO_Init(KEY1_INT_GPIO_PORT, &GPIO_InitStructure);/* 选择EXTI的信号源 */GPIO_EXTILineConfig(KEY1_INT_EXTI_PORTSOURCE, KEY1_INT_EXTI_PINSOURCE); EXTI_InitStructure.EXTI_Line = KEY1_INT_EXTI_LINE;/* EXTI为中断模式 */EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
/* 上升沿中断 */EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;/* 使能中断 */EXTI_InitStructure.EXTI_LineCmd = ENABLE;EXTI_Init(&EXTI_InitStructure);/*--------------------------KEY2配置-----------------------------*/
/* 选择按键用到的GPIO */GPIO_InitStructure.GPIO_Pin = KEY2_INT_GPIO_PIN;/* 配置为浮空输入 */GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;GPIO_Init(KEY2_INT_GPIO_PORT, &GPIO_InitStructure);/* 选择EXTI的信号源 */GPIO_EXTILineConfig(KEY2_INT_EXTI_PORTSOURCE, KEY2_INT_EXTI_PINSOURCE); EXTI_InitStructure.EXTI_Line = KEY2_INT_EXTI_LINE;/* EXTI为中断模式 */EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
/* 下降沿中断 */EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;/* 使能中断 */EXTI_InitStructure.EXTI_LineCmd = ENABLE;EXTI_Init(&EXTI_InitStructure);
}

bsp_dht11.c

#include "./dht11/bsp_dht11.h"
#include "./dwt_delay/core_delay.h" /* 可以在下面的宏定义中把后面的延时函数替换换SysTick的延时函数,就是想用那个就换成那个的 */#define DHT11_DELAY_US(us)  CPU_TS_Tmr_Delay_US(us)
#define DHT11_DELAY_MS(ms)  CPU_TS_Tmr_Delay_MS(ms)static void                           DHT11_GPIO_Config                       ( void );
static void                           DHT11_Mode_IPU                          ( void );
static void                           DHT11_Mode_Out_PP                       ( void );
static uint8_t                        DHT11_ReadByte                          ( void );/*** @brief  DHT11 初始化函数* @param  无* @retval 无*/
void DHT11_Init ( void )
{DHT11_GPIO_Config ();DHT11_Dout_1;               // 拉高GPIOB10
}/** 函数名:DHT11_GPIO_Config* 描述  :配置DHT11用到的I/O口* 输入  :无* 输出  :无*/
static void DHT11_GPIO_Config ( void )
{		/*定义一个GPIO_InitTypeDef类型的结构体*/GPIO_InitTypeDef GPIO_InitStructure; /*开启DHT11_Dout_GPIO_PORT的外设时钟*/DHT11_Dout_SCK_APBxClock_FUN ( DHT11_Dout_GPIO_CLK, ENABLE );	/*选择要控制的DHT11_Dout_GPIO_PORT引脚*/															   GPIO_InitStructure.GPIO_Pin = DHT11_Dout_GPIO_PIN;	/*设置引脚模式为通用推挽输出*/GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;   /*设置引脚速率为50MHz */   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; /*调用库函数,初始化DHT11_Dout_GPIO_PORT*/GPIO_Init ( DHT11_Dout_GPIO_PORT, &GPIO_InitStructure );		  }/** 函数名:DHT11_Mode_IPU* 描述  :使DHT11-DATA引脚变为上拉输入模式* 输入  :无* 输出  :无*/
static void DHT11_Mode_IPU(void)
{GPIO_InitTypeDef GPIO_InitStructure;/*选择要控制的DHT11_Dout_GPIO_PORT引脚*/	GPIO_InitStructure.GPIO_Pin = DHT11_Dout_GPIO_PIN;/*设置引脚模式为浮空输入模式*/ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU ; /*调用库函数,初始化DHT11_Dout_GPIO_PORT*/GPIO_Init(DHT11_Dout_GPIO_PORT, &GPIO_InitStructure);	 }/** 函数名:DHT11_Mode_Out_PP* 描述  :使DHT11-DATA引脚变为推挽输出模式* 输入  :无* 输出  :无*/
static void DHT11_Mode_Out_PP(void)
{GPIO_InitTypeDef GPIO_InitStructure;/*选择要控制的DHT11_Dout_GPIO_PORT引脚*/															   GPIO_InitStructure.GPIO_Pin = DHT11_Dout_GPIO_PIN;	/*设置引脚模式为通用推挽输出*/GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;   /*设置引脚速率为50MHz */   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;/*调用库函数,初始化DHT11_Dout_GPIO_PORT*/GPIO_Init(DHT11_Dout_GPIO_PORT, &GPIO_InitStructure);	 	 }/* * 从DHT11读取一个字节,MSB先行*/
static uint8_t DHT11_ReadByte ( void )
{uint8_t i, temp=0;for(i=0;i<8;i++)    {	 /*每bit以50us低电平标置开始,轮询直到从机发出 的50us 低电平 结束*/  while(DHT11_Dout_IN()==Bit_RESET);/*DHT11 以26~28us的高电平表示“0”,以70us高电平表示“1”,*通过检测 x us后的电平即可区别这两个状 ,x 即下面的延时 */DHT11_DELAY_US(40); //延时x us 这个延时需要大于数据0持续的时间即可	   	  if(DHT11_Dout_IN()==Bit_SET)/* x us后仍为高电平表示数据“1” */{/* 等待数据1的高电平结束 */while(DHT11_Dout_IN()==Bit_SET);temp|=(uint8_t)(0x01<<(7-i));  //把第7-i位置1,MSB先行 }else	 // x us后为低电平表示数据“0”{			   temp&=(uint8_t)~(0x01<<(7-i)); //把第7-i位置0,MSB先行}}return temp;}/** 一次完整的数据传输为40bit,高位先出* 8bit 湿度整数 + 8bit 湿度小数 + 8bit 温度整数 + 8bit 温度小数 + 8bit 校验和 */
uint8_t DHT11_Read_TempAndHumidity(DHT11_Data_TypeDef *DHT11_Data)
{  /*输出模式*/DHT11_Mode_Out_PP();/*主机拉低*/DHT11_Dout_0;/*延时18ms*/DHT11_DELAY_MS(18);/*总线拉高 主机延时30us*/DHT11_Dout_1; DHT11_DELAY_US(30);   //延时30us/*主机设为输入 判断从机响应信号*/ DHT11_Mode_IPU();/*判断从机是否有低电平响应信号 如不响应则跳出,响应则向下运行*/   if(DHT11_Dout_IN()==Bit_RESET)     {/*轮询直到从机发出 的80us 低电平 响应信号结束*/  while(DHT11_Dout_IN()==Bit_RESET);/*轮询直到从机发出的 80us 高电平 标置信号结束*/while(DHT11_Dout_IN()==Bit_SET);/*开始接收数据*/   DHT11_Data->humi_int= DHT11_ReadByte();DHT11_Data->humi_deci= DHT11_ReadByte();DHT11_Data->temp_int= DHT11_ReadByte();DHT11_Data->temp_deci= DHT11_ReadByte();DHT11_Data->check_sum= DHT11_ReadByte();/*读取结束,引脚改为输出模式*/DHT11_Mode_Out_PP();/*主机拉高*/DHT11_Dout_1;/*检查读取的数据是否正确*/if(DHT11_Data->check_sum == DHT11_Data->humi_int + DHT11_Data->humi_deci + DHT11_Data->temp_int+ DHT11_Data->temp_deci)return SUCCESS;else return ERROR;}elsereturn ERROR;}

bsp_delay.c

/*使用内核寄存器精确延时*/ 
#include "./dwt_delay/core_delay.h"   /*
**********************************************************************
*         时间戳相关寄存器定义
**********************************************************************
*/
/*在Cortex-M里面有一个外设叫DWT(Data Watchpoint and Trace),该外设有一个32位的寄存器叫CYCCNT,它是一个向上的计数器,记录的是内核时钟运行的个数,最长能记录的时间为:60s=2的32次方/72000000(假设内核频率为72M,内核跳一次的时间大概为1/72M=13.8ns)当CYCCNT溢出之后,会清0重新开始向上计数。使能CYCCNT计数的操作步骤:1、先使能DWT外设,这个由另外内核调试寄存器DEMCR的位24控制,写1使能2、使能CYCCNT寄存器之前,先清03、使能CYCCNT寄存器,这个由DWT_CTRL(代码上宏定义为DWT_CR)的位0控制,写1使能*/#if USE_DWT_DELAY#define  DWT_CR      *(__IO uint32_t *)0xE0001000
#define  DWT_CYCCNT  *(__IO uint32_t *)0xE0001004
#define  DEM_CR      *(__IO uint32_t *)0xE000EDFC#define  DEM_CR_TRCENA                   (1 << 24)
#define  DWT_CR_CYCCNTENA                (1 <<  0)/*** @brief  初始化时间戳* @param  无* @retval 无* @note   使用延时函数前,必须调用本函数*/
void CPU_TS_TmrInit(void)
{/* 使能DWT外设 */DEM_CR |= (uint32_t)DEM_CR_TRCENA;                /* DWT CYCCNT寄存器计数清0 */DWT_CYCCNT = (uint32_t)0u;/* 使能Cortex-M DWT CYCCNT寄存器 */DWT_CR |= (uint32_t)DWT_CR_CYCCNTENA;
}/*** @brief  读取当前时间戳* @param  无* @retval 当前时间戳,即DWT_CYCCNT寄存器的值*/
uint32_t CPU_TS_TmrRd(void)
{        return ((uint32_t)DWT_CYCCNT);
}///**
//  * @brief  读取当前时间戳
//  * @param  无
//  * @retval 当前时间戳,即DWT_CYCCNT寄存器的值
//	* 				此处给HAL库替换HAL_GetTick函数,用于os
//  */
//uint32_t HAL_GetTick(void)
//{        
//  return ((uint32_t)DWT_CYCCNT*1000/SysClockFreq);
//}/*** @brief  采用CPU的内部计数实现精确延时,32位计数器* @param  us : 延迟长度,单位1 us* @retval 无* @note   使用本函数前必须先调用CPU_TS_TmrInit函数使能计数器,或使能宏CPU_TS_INIT_IN_DELAY_FUNCTION最大延时值为8秒,即8*1000*1000*/
void CPU_TS_Tmr_Delay_US(__IO uint32_t us)
{uint32_t ticks;uint32_t told,tnow,tcnt=0;/* 在函数内部初始化时间戳寄存器, */  
#if (CPU_TS_INIT_IN_DELAY_FUNCTION)  /* 初始化时间戳并清零 */CPU_TS_TmrInit();
#endifticks = us * (GET_CPU_ClkFreq() / 1000000);  /* 需要的节拍数 */      tcnt = 0;told = (uint32_t)CPU_TS_TmrRd();         /* 刚进入时的计数器值 */while(1){tnow = (uint32_t)CPU_TS_TmrRd();  if(tnow != told){ /* 32位计数器是递增计数器 */    if(tnow > told){tcnt += tnow - told;  }/* 重新装载 */else {tcnt += UINT32_MAX - told + tnow; } told = tnow;/*时间超过/等于要延迟的时间,则退出 */if(tcnt >= ticks)break;}  }
}#endif

介绍

1.项目名称:基于cortex-M3的QTQT串口助手
2.开发语言:C、C++
3.开发平台:Windows10
4.硬件平台:STM32F103(cortex-M3)、DHT11
5.开发工具:QT5.14.2、Keil5
6.关于项目:
项目主要实现了串行通信软件上位机(PC),和下位机(嵌入式系统)的串口通信系统,串口调试软件,向下位机发送控制信号,控制下位机RGB灯 亮起不同颜色 和 熄灭;操作下位机按键1,向上位机发送本组成员的学号和姓名;操作下位机按键2,接收下位机传来的温湿度传感器检测数据。
7.负责模块:
嵌入式系统下位机开发,按键中断发送数据,获取上位机控制信号;
QT上位机开发,上位机接收数据并做出相应的处理,向下位机发送控制信号;
8.扩展:定时向上位机发送本组成员的姓名信息(定时器中断)

硬件

野火F103指南者+DHT11温湿度传感器

在这里插入图片描述

QT全部程序构成

在这里插入图片描述

QT设计的思路

首先使用UI设计,搭建出串口调试界面,分为左右两侧GroupBox组控件,左侧数据区放置TextBrowser文本阅读器控件、PlainTextEdit纯文本编辑器控件和PushButton按键控件;右侧串口区放置Label标签控件、ComboBox组合选择框控件、CheckBox复选框控件、SpinBox数值微调器控件和PushButton按键控件;放置完成UI和对象与类如图6所示;
图6 放置完成UI和对象与类
在这里插入图片描述

其中对窗口名称设置使用this->setWindowTitle(“xxx的串口调试GUI”); 窗口图标先添加QT Resource File类文件,然后添加 .ico 格式图片,设置在zua.pro文件中添加 RC_ICONS =system.ico;
在对PushButton按键控件使用QT集成的转到槽函数,自动生成槽函数框架,再对不同操作进行逻辑编写,进而实现不同按键的功能;

Keil全部程序构成

在这里插入图片描述

Keil程序设计的思路

图2 程序设计的思路
在这里插入图片描述

按键K1向上位机发送本组成员的学号和姓名功能和按键K2向上位机发送温湿度功能,在stm32f10x_it.c文件,通过中断函数实现,逻辑图如图3所示;
图3 按键逻辑设计
在这里插入图片描述

在main.c文件中while(1)主逻辑程序,设计实现上位机发送控制信号,下位机通过switch()函数选择二极管灯发出不同颜色的光,主逻辑程序设计如图4所示;
图4 主逻辑控制RGB彩灯颜色程序

在这里插入图片描述

功能

1.

调试界面初始时,使用失能ui->BtnSend->setEnabled(false); 发送按键为灰色
在这里插入图片描述

2.

选择端口,设置波特率、数据位、停止位和校验位,打开串口,开发板按下复位键
在这里插入图片描述

3.

复位后,RGB灯为红色,向下位机发送控制信号,在发送数据区域发送2,控制下位机二极管灯发出不同颜色的光,发送2如下图10所示,下位机二极管亮起绿灯如下图11所示。
图10图10
图11 下位机二极管亮起绿灯
在这里插入图片描述
图12 发送3串口调试界面
在这里插入图片描述
图13 下位机二极管亮起蓝灯
在这里插入图片描述
图14 发送4串口调试界面
在这里插入图片描述
图15 下位机二极管亮起蓝灯
在这里插入图片描述

还有5-紫色,6-青色,7-白色,8-关闭,other-信息

4.

操作下位机按键K1,向上位机发送本组成员的学号和姓名
在这里插入图片描述

5.

操作下位机按键K2,向上位机发送温湿度,接收下位机传来的温湿度传感器检测数据
在这里插入图片描述

6.

点击关闭串口,会同时执行窗口清除ui->textRecv->clear();
在这里插入图片描述

全部功能

在这里插入图片描述
在这里插入图片描述

BUG解决方法

  • 传输学号姓名时,数据部分丢失,解决:在丢失数据部分 加一个杠 -
    在这里插入图片描述
    解决
    在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_9119.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

虚拟机中centos扩展根目录空间

文章目录一、在vmware上为centos扩展存储二、在centos上扩充在进行yum安装软件时&#xff0c;由于空间不足一直提示“文件系统根目录上从磁盘空间不足”一、在vmware上为centos扩展存储 二、在centos上扩充 运行 df -h 查看容量情况&#xff0c;发现新扩展的空间并没有加载上。…

Babel 插件:30分钟从入门到实战

动手点关注 干货不迷路 &#x1f447;Babel 是一个 source to source&#xff08;源码到源码&#xff09;的 JavaScript 编译器&#xff0c;简单来说&#xff0c;你为 Babel 提供一些 JavaScript 代码&#xff0c;Babel 可以更改这些代码&#xff0c;然后返回给你新生成的代码。…

LeetCode程序员面试金典(第 6 版)上

目录 面试题 01.01. 判定字符是否唯一 面试题 01.03. URL化 面试题 01.04. 回文排列 面试题 01.05. 一次编辑 面试题 01.06. 字符串压缩 面试题 01.07. 旋转矩阵 面试题 01.08. 零矩阵 面试题 01.09. 字符串轮转 面试题 02.01. 移除重复节点 面试题 02.02. 返回倒数第…

BI测试

关于BI测试 前言:由于之前做过一段时间大数据测试,故整理BI测试知识点以供学习。BI测试: BI是从数据接入、数据准备、数据分析、数据可视化到数bai据分发应用的一系列过程,目的是为了辅助企业高效决策。而报表虽然最终也实现了数据可视化,但是对于数据分析的维度、深度、颗…

【数据结构与算法】排序(下篇)

&#x1f431;作者&#xff1a;一只大喵咪1201 &#x1f431;专栏&#xff1a;《数据结构与算法》 &#x1f525;格言&#xff1a;你只管努力&#xff0c;剩下的交给时间&#xff01; 排序⚽归并排序⚾递归实现⚾非递归实现⚽常见排序算法的复杂度和稳定性分析⚾稳定性⚾具体分…

docker安装mysql(单体)

docker安装mysql mac的m1芯片上不支持5.7版本的镜像&#xff0c;因此可以直接选择拉取8.0及之后的版本 docker pull mysql创建mysql的宿主机数据卷挂载的文件夹 # mysql的配置文件&#xff0c;注意conf.d文件夹必须要创建&#xff0c;否则启动容器的时候&#xff0c;数据卷 …

linux 锁-- atomic per_cpu

atomic引入背景 对于 SMP 系统中&#xff0c;在开启 preempt 情况下&#xff0c;对于公共资源&#xff0c;如果存在两个 task 来进行更改&#xff0c;这就面临临界区资源竞争问题&#xff0c;此时会产生意想不到的结果&#xff0c;这是不符合预期的&#xff0c;因此需要来进行…

nginx-nginx的文件服务器的配置

nginx的文件服务器的配置location /data {charset gbk,utf-8;autoindex on;autoindex_exact_size off;autoindex_localtime on;limit_rate_after 10m;alias D:;allow all; }访问文件路径xxx/data访问成功的返回界面

CAS:385437-57-0,DSPE-PEG-Biotin,Biotin-PEG-DSPE,磷脂-聚乙二醇-生物素试剂供应

DSPE-PEG-Biotin&#xff08;磷脂-聚乙二醇-生物素&#xff09;的分子量有&#xff1a;1k&#xff0c;2k&#xff0c;3.4k等&#xff0c;其它的分子量可以定制。质量控制在95%&#xff0c;Biotin-PEG-DSPE主要用于科研实验使用&#xff0c;非药用&#xff0c;非食用。它溶于水和…

ETH 2.0 背景下的新机会与新叙事

以太坊 POW 到 POS 的转型为整个 Web3 行业的发展引入了一层新的叙事&#xff0c;即对于去中心化更深切的要求。TIPS 在 Merge - Shanghai Upgrade 的约 9 个月的小周期内&#xff0c;流通状态的 ETH 在持续单调递减&#xff1b; 从长远来看&#xff0c;未来 ETC 等 Ethhash P…

多人协作多版本开发冲突的正确解决姿势

多人版本开发工作流程&#xff1a;https://blog.csdn.net/qq_32442973/article/details/125717959 这里实际上用上一个关键命令&#xff1a;git merge --no-ff 分支名 注意&#xff1a;无论何种情况&#xff0c;都绝不允许把开发、测试、预生产的代码拉到自己分支上解决冲突&am…

Druid1.2.12版本发布,新增连接池默认配置connectTimeout和socketTimeout详解

新版本特性如下 这个版本连接池默认增加配置connectTimeout和socketTimeout&#xff0c;增强了SQL Parser 连接池DruidDataSource支持新的配置connectTimeout和socketTimeout&#xff0c;分别都是10秒。这个默认值会减少因为网络丢包时导致的连接池无法创建链接。修复连接池D…

股票量化分析工具QTYX使用攻略代码说明——高速版本地行情源v2.5.1

搭建自己的量化系统如果要长期在市场中立于不败之地&#xff01;必须要形成一套自己的交易系统。否则&#xff0c;赚钱或者亏钱我们很难归纳总结&#xff0c;往往是凭借运气赚钱&#xff0c;而不是合理的系统模型&#xff0c;一时凭借运气赚的钱长期来看会因为实力还回去。QTYX…

mac 中配置idea自带maven环境变量

1.查找 maven 地址 访达--应用程序-- idea如图&#xff1a; 2.双击 选择 显示包内容&#xff1a; 3.找到maven地址&#xff1a;/Applications/IntelliJ IDEA.app/Contents/plugins/maven/lib/maven3 4.配置环境变量 &#xff08;1&#xff09;配置环境变量 终端输入 vim …

c++ Primer 第四章 表达式

4.1 基础 略 4.2 算术运算符4.3 逻辑和关系运算符4.4 赋值运算符 略 4.5 递增和递减 ++i 先自增后运算 i++ 先运算后自增 4.6 成员访问运算符 int main() {string s1 = "a string";string *pS1 = &s1;cout << pS1->size() << endl; // 等价于(*p)…

【JavaScript设计模式】增强版发布订阅模式——Webpack的核心Tapable(一)

Tapable简介 Webpack整体架构的实现就是靠它的插件系统&#xff0c;其中Compiler和Compilation负责管理整个构建流程&#xff0c;同时暴露出一些Hook&#xff0c;然后由不同职责的插件来监听这些Hook&#xff0c;并在合适的时机完成具体的工作。Tapable是整个Webpack插件系统的…

CentOS二进制安装Containerd

Containerd有两种安装包∶ 1>. 第一种是containerd-xxx&#xff0c;这种包用于单机测试没问题&#xff0c;不包runC&#xff0c;需要提前安装。 2>. 第二种是cri-containerd-cni-xxx&#xff0c;包含runC和k8s里的所需要的相关文件。k8s集群里需要用到此包&#xff0c;…

Qt5.12.2添加mqtt模块

Qt5.12.2添加mqtt模块下载 mqtt Qt 子模块使用 Qt 编译模块并install 生成动态库qtcreator 打开解压后的 qtmqtt源码下的 pro 工程文件下载 mqtt Qt 子模块 https://download.qt.io/official_releases/qt/5.15/5.15.4/submodules/ 下载后解压&#xff1a; 使用 Qt 编译模块并…

Go语言实现网盘系统(上)

该项目将基于go-zero和xorm go-zero中文文档: https://legacy.go-zero.dev/cn/ Xorm中文文档: http://xorm.topgoer.com/ 功能划分 整个项目可以分为3个模块: 用户模块、存储池模块和文件共享模块数据库设计 用户是一个实体,建立对应的表user_basic,存储了用户信息,DDL如下:…

ViLBERT—(NeurIPS-2019)

ViLBERT(Vision-and-Language BERT)是发表于2019年的论文&#xff0c;在功能上实现了文本图像的多模态特征提取与分类。改论文的特点是使用了双流模型&#xff0c;即先各个模态特征单独自注意力&#xff0c;再经过transformer交叉注意力。单流是将不同模态特征序列先拼接起来&a…