QT串口通信是上位机和下位机通信常用的通信方式, 也是学习QT必须学会的基础知识, 这篇就简单介绍一下QT串口通信的简单使用.
| 创建项目
1: 创建新项目

2: 配置相关信息




3: 设计界面


4: 编写代码
目的: 通过简单实验验证串口通信.
4.1: 配置项目

4.2: 编写上位机代码
widget.h文件
#ifndef WIDGET_H #define WIDGET_H #include// 引入头文件 #include #include namespace Ui { class Widget; } class Widget : public QWidget { Q_OBJECT public: explicit Widget(QWidget *parent = 0); ~Widget(); // 定义曹函数 private slots: void on_pushButton_clicked(); void receiveInfo(); void sendInfo(); private: Ui::Widget *ui; // 串口对象指针 QSerialPort* m_serialPort; }; #endif // WIDGET_H
widget.cpp文件
#include "widget.h" #include "ui_widget.h" // 调试输出头文件 #includeWidget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) { ui->setupUi(this); // 实例化一个串口对象 m_serialPort = new QSerialPort(); // 获取可用的串口号 foreach(const QSerialPortInfo info, QSerialPortInfo::availablePorts()) { qDebug() << "Port name:" << info.portName(); ui->comboBox->addItem(info.portName()); } } Widget::~Widget() { delete ui; } // pushButton点击触发的槽函数 void Widget::on_pushButton_clicked() { if(m_serialPort->isOpen())//如果串口已经打开了 先给他关闭了 { m_serialPort->clear(); m_serialPort->close(); } m_serialPort->setPortName(ui->comboBox->currentText());//当前选择的串口名字 if(!m_serialPort->open(QIODevice::ReadWrite))//用ReadWrite 的模式尝试打开串口 { qDebug()<<"打开失败!"; return; } qDebug()<<"串口打开成功!"; m_serialPort->setBaudRate(QSerialPort::Baud115200,QSerialPort::AllDirections);//设置波特率和读写方向 m_serialPort->setDataBits(QSerialPort::Data8); //数据位为8位 m_serialPort->setFlowControl(QSerialPort::NoFlowControl);//无流控制 m_serialPort->setParity(QSerialPort::NoParity); //无校验位 m_serialPort->setStopBits(QSerialPort::OneStop); //一位停止位 // 手动绑定槽函数 connect(m_serialPort,SIGNAL(readyRead()),this,SLOT(receiveInfo())); connect(ui->pushButton_2,SIGNAL(clicked()),this,SLOT(sendInfo())); } //接收到单片机发送的数据进行解析 void Widget::receiveInfo() { qDebug()<<"接收"; QByteArray info = m_serialPort->readAll(); qDebug()<<"receive info:"< write("0x55"); m_serialPort->write("0xaa"); }
4.3: 编写下位机代码
main.c文件
#include "stm32f10x.h"
#include "stdio.h"
void led_init(void);
void usart_init(uint32_t bound);
int main( void )
{
uint32_t i = 0;
led_init();
usart_init(115200);
printf("ok
");
while(1)
{
GPIO_ResetBits(GPIOE,GPIO_Pin_5);
for(i = 0; i< 0xfffff; i++);
GPIO_SetBits(GPIOE,GPIO_Pin_5);
for(i = 0; i< 0xfffff; i++);
}
}
void led_init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;//定义结构体变量
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE,ENABLE);
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_5; //选择你要设置的IO口
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP; //设置推挽输出模式
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; //设置传输速率
GPIO_Init(GPIOE,&GPIO_InitStructure); /* 初始化GPIO */
GPIO_SetBits(GPIOE,GPIO_Pin_5); //将LED端口拉高,熄灭所有LED
}
void usart_init(uint32_t bound)
{
//GPIO端口设置
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
/* 配置GPIO的模式和IO口 */
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9;//TX //串口输出PA9
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP; //复用推挽输出
GPIO_Init(GPIOA,&GPIO_InitStructure); /* 初始化串口输入IO */
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10;//RX //串口输入PA10
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING; //模拟输入
GPIO_Init(GPIOA,&GPIO_InitStructure); /* 初始化GPIO */
//USART1 初始化设置
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); //初始化串口1
USART_Cmd(USART1, ENABLE); //使能串口1
USART_ClearFlag(USART1, USART_FLAG_TC);
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启相关中断
//Usart1 NVIC 配置
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;//串口1中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3;//抢占优先级3
NVIC_InitStructure.NVIC_IRQChannelSubPriority =3; //子优先级3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器
}
int fputc(int ch,FILE *f) //printf重定向函数
{
USART_SendData(USART1,(uint8_t)ch); //发送一字节数据
while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET); //等待发送完成
return ch;
}
void USART1_IRQHandler(void)
{
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
{
uint8_t r = USART_ReceiveData(USART1);
USART_SendData(USART1,r);
while(USART_GetFlagStatus(USART1,USART_FLAG_TC) != SET);
}
USART_ClearFlag(USART1,USART_FLAG_TC);
}
| 验证效果
把下位机代码下到开发板, 然后运行自己编写的上位机, 点击上位机发送数据, 下位机就会把收到的数据返回到上位机, 可以通过控制台查看接收到的数据;

| 简单shell
main.c文件
#include "stm32f10x.h"
#include "stdio.h"
#include "string.h"
#define CMD_MAX_LEN 16 // 定义最大命令长度
char cmd_buf[CMD_MAX_LEN]; // 定义命令缓冲区
uint8_t cmd_len = 0; // 定义命令长度
uint8_t cmd_flag = 0; // 定义命令接收完成标志
void led_init(void);
void usart_init(uint32_t bound);
void user_shell_irq(void);
int main( void )
{
led_init();
usart_init(115200);
printf("ok
");
while(1)
{
if (cmd_flag)
{
// 匹配指令
if (strcmp(cmd_buf, "led on") == 0)
{
printf("led on");
}
// 清理缓存
cmd_len = 0; // 清零命令长度
memset(cmd_buf, 0, CMD_MAX_LEN); // 清空命令缓冲区
cmd_flag = 0; // 清除命令接收完成标志
}
}
}
void led_init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;//定义结构体变量
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE,ENABLE);
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_5; //选择你要设置的IO口
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP; //设置推挽输出模式
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; //设置传输速率
GPIO_Init(GPIOE,&GPIO_InitStructure); /* 初始化GPIO */
GPIO_SetBits(GPIOE,GPIO_Pin_5); //将LED端口拉高,熄灭所有LED
}
void usart_init(uint32_t bound)
{
//GPIO端口设置
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
/* 配置GPIO的模式和IO口 */
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9;//TX //串口输出PA9
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP; //复用推挽输出
GPIO_Init(GPIOA,&GPIO_InitStructure); /* 初始化串口输入IO */
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10;//RX //串口输入PA10
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING; //模拟输入
GPIO_Init(GPIOA,&GPIO_InitStructure); /* 初始化GPIO */
//USART1 初始化设置
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); //初始化串口1
USART_Cmd(USART1, ENABLE); //使能串口1
USART_ClearFlag(USART1, USART_FLAG_TC);
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启相关中断
//Usart1 NVIC 配置
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;//串口1中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3;//抢占优先级3
NVIC_InitStructure.NVIC_IRQChannelSubPriority =3; //子优先级3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器
}
int fputc(int ch,FILE *f) //printf重定向函数
{
USART_SendData(USART1,(uint8_t)ch); //发送一字节数据
while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET); //等待发送完成
return ch;
}
void USART1_IRQHandler(void)
{
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
{
// shell
user_shell_irq();
}
}
// 获取
void user_shell_irq(void)
{
uint8_t temp = USART_ReceiveData(USART1);
if (temp == '
' || temp == '
')
{
cmd_buf[cmd_len] = '�';
cmd_flag = 1;
}
else
{
cmd_buf[cmd_len++] = temp;
if (cmd_len >= CMD_MAX_LEN)
{
// 清理缓存
cmd_len = 0;
memset(cmd_buf, 0, CMD_MAX_LEN);
}
}
}
验证:

简单介绍了QT的串口如何与下位机通信, 同时也简单通过shell交互, 进一步拓展了串口通信场景.
全部0条评论
快来发表一下你的评论吧 !