QT串口通信的简单使用

描述

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"

// 调试输出头文件
#include 

Widget::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交互, 进一步拓展了串口通信场景.

  审核编辑:汤梓红
 

 

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分