嵌入式STM32学习笔记(4)——串口发送接收及qt上位机

STM32的串口发送和接收都相对简单,这里自定义了一种串口协议,可以根据这串口协议扩充添加其他功能,原理大家可以查手册或其他介绍,这里直接给代码,代码里有详细注释;

1)编译器IAR8,系统win10;

2)板子:STM32F103C8T6核心板,如下:

3)下载器:ST-LINK/V2仿真下载器;

4)串口连接器用的是USB-TTL下载器,其用的是PL2303芯片,所以要下再驱动;在网上下载安装了好几种最终这个安装成功:WIN10_ PL2303_USB-to-Serial Comm Port;网盘链接:链接: https://pan.baidu.com/s/1ZpFHvMO9HvP9HIs_ahqDcg ;提取码: 6fwj ;

5)stm32f103源码和QT源码都放在网盘:链接: https://pan.baidu.com/s/1RFc3brlS6BEWss69RU6JsQ ;提取码: rehu ;

6)板子上LED对应的引脚是GPIOC, GPIO_Pin_13;在IAR对应的stm32F103X模板DRIVER目录下添加:led.c,led.h,timer.c,timer.h,usart.c,usart.h文件,主要串口代码,usart.c,usart.h中,截图如下:

led.h

#ifndef _LED_H
#define _LED_H

/*包含相关的头文件*/
#include "stm32f10x.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_rcc.h"

void led_gpio_config(void);//声明,初始化LED对应引脚

#endif

led.c

#include "led.h"

/*LED_G 驱动 GPIO 初始化函数*/
void led_gpio_config(void)
{
  GPIO_InitTypeDef GPIO_InitStructure; //调用GPIO结构体
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); //配置RCC时钟,使得引脚使能
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13; //设置的引脚
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //设置引脚速度
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //设置引脚模式,推挽式输出
  GPIO_Init(GPIOC, &GPIO_InitStructure); //初始化引脚   
}

timer.h

#ifndef __TIMER_H_
#define __TIMER_H_

#include "stm32f10x_tim.h"
#include "stm32f10x_rcc.h"
#include "stm32f10x_it.h"
#include "misc.h"

extern __IO uint32_t TimingDelay; //计数变量,加要加“_IO”,不然会被编译优化
void Systick_Init(void); //初始化系统滴答
void TimingDelay_Decrement(void); //计数函数
void delay_ms(__IO uint32_t nTime);//延迟函数,设置为 US

extern __IO uint32_t TimingDelay2; //计数变量2
void tim2_nvic_config(void); //初始化中断
void tim2_config(void); //初始化计数器
void delay_ms2(__IO uint32_t nTime2);//延迟函数2,设置为 US
void TimingDelay_Decrement2(void); //计数函数2

#endif

tiemr.c

#include "timer.h"
__IO uint32_t TimingDelay; //计数变量,加要加“_IO”,不然会被编译优化
__IO uint32_t TimingDelay2; //计数变量2


/*SystemCoreClock / 1000000  -------   1us*/
/*SystemCoreClock / 100000   -------   10us*/
/*SystemCoreClock / 10000    -------   100us*/
/*SystemCoreClock / 1000     -------   1ms*/


//
//设置系统滴答中断延时程序//
/

void Systick_Init(void)
{
  //装载系统时钟中断计数值,系统时钟累计达到72000时候溢出产生中断
    if (SysTick_Config(72000))
    { 
      /* Capture error */ 
      while (1);
    }
}

//延时计数函数,如果不是0,每个系统滴答中断周期自减
void TimingDelay_Decrement(void)
{
    if (TimingDelay != 0x00)
    {
        TimingDelay--;
    }
}

//延迟函数,设置为 US
void delay_ms(__IO uint32_t nTime)
{
    TimingDelay = nTime;//自减初始值
    while(TimingDelay != 0);
}

//中断事件函数,原函数在stm32f10x_it.c里面,复制到这里后要将原位置里的注释掉,不然报错
void SysTick_Handler(void)
{
    TimingDelay_Decrement();
}

//
//设置定时器中断延时程序//
/

//配置嵌套中断控制器 NVCI
void tim2_nvic_config(void)
{
    NVIC_InitTypeDef NVIC_Init_Struct; //调用NVCI结构体
    
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0); //设置组优先级
    
    NVIC_Init_Struct.NVIC_IRQChannel = TIM2_IRQn; //设置定时器 2 中断
    NVIC_Init_Struct.NVIC_IRQChannelPreemptionPriority = 0; //设置抢占优先级
    NVIC_Init_Struct.NVIC_IRQChannelSubPriority = 0; //设置子优先级
    NVIC_Init_Struct.NVIC_IRQChannelCmd = ENABLE; //使能IRQ中断
    NVIC_Init(&NVIC_Init_Struct); //初始化NVIC
}


//定时器初始化配置
void tim2_config(void)
{
    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct; //调用定时器结构体
    
    tim2_nvic_config(); //加载嵌套中断控制器 NVCI
    
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE); //配置RCC时钟,使得中断使能
    TIM_DeInit(TIM2); //将外设 TIMx 寄存器重设为缺省值,复位寄存器
    
    /*
	定时计数计算方法如下:
	发生中断时间 = (TIM_Prescaler+1)* (TIM_Period+1)/FLK
	以定时 1s 为例 TIM_Period=2000-1, TIM_Prescaler=(36000-1)
    */   
    TIM_TimeBaseInitStruct.TIM_Prescaler = 36000-1; //时钟预先分频数
    TIM_TimeBaseInitStruct.TIM_Period = 2-1;  //自动重装载寄存器的值
    TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up; //计数模式,向上计数方式
    TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1; //采样分频
    TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStruct);    //初始化TIM2配置
    TIM_ClearFlag(TIM2,TIM_FLAG_Update); //清除溢出中断标志
    TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE); //使能或者失能指定的 TIM 中断
    TIM_Cmd(TIM2,ENABLE); //开启时钟
}


//延时计数函数2,如果不是0,每个系统滴答中断周期自减
void TimingDelay_Decrement2(void)
{
    if (TimingDelay2 != 0x00)
    {
        TimingDelay2--;
    }
}

//延迟函数,设置为 US
void delay_ms2(__IO uint32_t nTime2)
{
    TimingDelay2 = nTime2;//时钟滴答数
    while(TimingDelay2 != 0);
}


//定时器2,中断事件函数
void TIM2_IRQHandler(void)
{
    if(TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)//固件库函数,判断是否发生TIM2中断
    {
      TimingDelay_Decrement2(); //调用延时计数函数
    }
    TIM_ClearITPendingBit(TIM2,TIM_FLAG_Update);//标志位清除,固件库函数
}

usart.h//关键代码

#ifndef __USART_H_
#define __USART_H_

#include "stm32f10x.h"
#include "stm32f10x_rcc.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_usart.h"

#define UNLOCK 0x00  //宏定义 串口flag,开
#define LOCK 0xff    //宏定义 串口flag,关

void usart_config(void); //串口初始化函数
void rx_stack_init(void); //串口协议栈接收初始化
void tx_stack_init(void); //串口协议栈发送初始化
void rx_stack_data_deal(void);//串口接收数据处理
void tx_stack_data_deal(void);//串口发送数据处理

//串口发送协议栈
typedef struct
{
    u8 head; //头
    u8 direction; //流向
    u8 data[4]; //数据
    u8 tail; //尾部
} ptl_stack;


//串口接收协议栈
typedef struct 
{
    u8 head; //头
    u8 direction;//流向
    u8 data[4]; //数据
    u8 tail; //尾部
    u8 data_pt; //数据位
    u8 lock_flag; //接收满标志位
} ptr_stack;

#endif

usart.c

#include "usart.h"
#include "led.h"

ptl_stack tx_stack; //声明串口协议栈结构体
ptr_stack rx_stack; //声明串口协议栈结构体

void usart_config(void)
{   
    /*1、打开GPIO,AFIO,USART1的时钟*/
    RCC_APB2PeriphClockCmd( RCC_APB2Periph_USART1 |RCC_APB2Periph_GPIOA \
                            | RCC_APB2Periph_AFIO, ENABLE);
     
    /*2\初始化相应的串口引脚*/
    GPIO_InitTypeDef GPIO_InitStruct;   
    /* 配置相应的 GPIO 口;
    USART1 对应的复用引脚为 PA9 和 PA10,
    PA9 对应的是 TXD, PA10 对应得实 RXD   */    
    /*配置PA9为复用推挽输出*/
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStruct);
    /*配置PA10为浮空输入*/
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStruct);
        
    /*3、配置串口中断*/
    NVIC_InitTypeDef NVIC_InitStructure; 
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; //设置串口 1 中断   
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //抢占优先级0
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //子优先级为 0
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能
    NVIC_Init(&NVIC_InitStructure);
        
    /*4、配置串口模式*/
    USART_InitTypeDef USART_InitStruct;//串口初始化结构图      
    USART_InitStruct.USART_BaudRate = 9600;//波特率
    USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件控制流
    USART_InitStruct.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;//发送和接收模式打开   
    USART_InitStruct.USART_WordLength = USART_WordLength_8b;  //数据位8
    USART_InitStruct.USART_Parity = USART_Parity_No;          //n,无校验位
    USART_InitStruct.USART_StopBits = USART_StopBits_1;       //停止位1      
    USART_Init(USART1, &USART_InitStruct);//配置串口参数函数   
    USART_ClearFlag(USART1,USART_FLAG_TC); //清除发送完成标志位
    USART_Cmd(USART1, ENABLE); //使能串口 1
    USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//使能接收中断
        
}


//初始化接收变量
void rx_stack_init(void)
{
    u8 i;
    rx_stack.head = 0;
    rx_stack.direction = 0;
    for(i = 0; i <=3; i++)
    {
        rx_stack.data[i] = 0;
    }
    rx_stack.data_pt = 0;
    rx_stack.tail = 0;
    rx_stack.lock_flag =0; //UNLOCK;
//    usart_config();    
}

//初始化发送变量
void tx_stack_init(void)
{
    u8 i;
    tx_stack.head = 0xaa;//头
    tx_stack.direction = 0xf0;//f0代表单片机发送电脑,f9代表电脑发送单片机
    for(i = 0; i <=3; i++)
    {
        tx_stack.data[i] = 0x00;//数据初始化
    }
    tx_stack.tail = 0xdd;//尾部
//    usart_config();
}


//串口中断处理函数
void USART1_IRQHandler(void)
{
    u8 receive_data;//接收存储变量
        
    if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)//如果不是空
    {
        receive_data = USART_ReceiveData(USART1); //接收单个字节的串口数据
//        USART_SendData(USART1,receive_data);//将接收的发送
		
	 if(rx_stack.lock_flag == UNLOCK)          //如果未锁住,则没有接收完成
        {
            if(receive_data == 0xaa) //如果头等于aa,则接收
            {
                rx_stack.head = receive_data; //接收头数据
            }
            else if(receive_data == 0xf9) //方向判断
            {
                rx_stack.direction = receive_data; //接收方向
            }
            else if(receive_data == 0xdd) //尾部判断
            {
                rx_stack.tail = receive_data; //接收尾部
            }
            else
            {
	      //数据处理,存储,data_pt数据指针数
                rx_stack.data[rx_stack.data_pt] = receive_data;
                rx_stack.data_pt ++;//储存后下移动
            }
            
	    //如果数据接收满,且到达尾部,则锁住,不接收,待接收完毕后解锁
            if((rx_stack.data_pt >= 4) && (rx_stack.tail == 0xdd))
            {
                rx_stack.lock_flag = LOCK;//锁住数据
            }
        }     
		
    }
       
    USART_ClearITPendingBit(USART1, USART_IT_RXNE);
}


void rx_stack_data_deal(void)//串口接收数据解析
{
     
        for(u8 i = 0; i <=3; i++)
    {
        tx_stack.data[i] = rx_stack.data[i];
		
    }
     
    tx_stack_data_deal();//发送数据
    rx_stack_init(); 
    rx_stack.lock_flag = UNLOCK;//初始化
      

}

void tx_stack_data_deal(void)//串口发送数据处理
{
    u8 i;
    USART_SendData(USART1,tx_stack.head);//发送头
    while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);//等待发送完成
    
    USART_SendData(USART1, tx_stack.direction);
    while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);//等待发送完成
    
    for(i = 0; i <= 3; i++)//遍历数据并发送
    {
        USART_SendData(USART1, tx_stack.data[i]);
        while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);//等待发送完成
    }
    USART_SendData(USART1, tx_stack.tail);//发送尾部
    while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);//等待发送完成
}



//void USART1_IRQHandler(void)//不走协议时候
//{
//    u8 receive_data;
//    if(USART_GetITStatus(USART1,USART_IT_RXNE))//
//    {
//	receive_data= USART_ReceiveData(USART1);//接收
//	USART_SendData(USART1,receive_data);//将接收的发送
//    }
//
//}

main.c

#include "led.h"
#include "timer.h"
#include "usart.h"

extern ptl_stack tx_stack;//串口发送变量声明
extern ptr_stack rx_stack;//串口接收变量声明

int main(void)
{
    SystemInit();  //初始化系统时钟
    Systick_Init(); //配置系统时钟滴答参数
    led_gpio_config();  //配置GPIO
    tim2_config();//配置定时器
    
    usart_config();//初始化串口
    tx_stack_init();//初始化发送缓冲区
    rx_stack_init();//初始化接收缓冲区
    
    while(1)
    {
      
//      //调用系统滴答延时函数做LED灯的闪烁//
//        GPIO_SetBits(GPIOC, GPIO_Pin_13);    //将PB13设置成高电平
//        delay_ms(100);                    //调用系统滴答延时函数
//        GPIO_ResetBits(GPIOC, GPIO_Pin_13);    //将PB13设置成低电平
//        delay_ms(100);                       //调用系统滴答延时函数
      
        //调用定时器延时函数做LED灯闪烁//
	GPIO_SetBits(GPIOC, GPIO_Pin_13);    //将PB13设置成高电平
	delay_ms2(500);                     //调用定时器延时函数
	GPIO_ResetBits(GPIOC, GPIO_Pin_13);   //将PB13设置成低电平
	delay_ms2(220);                     //调用定时器延时函数

	
//	USART_SendData(USART1,0xff);
	delay_ms(100);
	
//	tx_stack.data[0]=0x01;
//	tx_stack.data[1]=0x02;
//	tx_stack.data[2]=0x03;
//	tx_stack.data[3]=0x04;	
//	tx_stack_data_deal();//串口发送数据处理
	  	  	  
	 if(rx_stack.lock_flag == LOCK)   // 接受满
        {
            rx_stack_data_deal();//运行协议解析函数
        }		            
    }
    return 0;
}

下面是QT上位机的源码,主要文件如下:

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include<QtSerialPort/QSerialPort>
#include<QtSerialPort/QSerialPortInfo>
#include "usart.h"

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

private slots:
    void ReadData();
    void on_pushButton_clicked();
    void on_pushButton_2_clicked();

private:
    Ui::MainWindow *ui;
    QSerialPort *serial;

};

#endif // MAINWINDOW_H

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QMessageBox>
#include <QDebug>
#include "usart.h"

#pragma execution_character_set("utf-8")

extern ptl_stack tx_stack;
extern ptr_stack rx_stack;


MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    //设置下拉菜单,波特率
    ui->comboBox_2->addItem("1200");
    ui->comboBox_2->addItem("2400");
    ui->comboBox_2->addItem("4800");
    ui->comboBox_2->addItem("9600");
    ui->comboBox_2->addItem("19200");
    ui->comboBox_3->addItem("8");
    ui->comboBox_4->addItem("0");
    ui->comboBox_5->addItem("1");
    ui->comboBox_5->addItem("2");

    //设置波特率下拉菜单默认显示第0项
    ui->comboBox_2->setCurrentIndex(3);



    //查找可用的串口
    foreach (const QSerialPortInfo &info,QSerialPortInfo::availablePorts())
    {
        QSerialPort serial;
        serial.setPort(info);
        if(serial.open(QIODevice::ReadWrite))
        {
            ui->comboBox->addItem(serial.portName());
            serial.close();
        }
    }

}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::on_pushButton_clicked()
{
    if(ui->pushButton->text()==tr("打开串口"))
    {
        serial=new QSerialPort;
        serial->setPortName(ui->comboBox->currentText());//设置串口名称
        serial->open(QIODevice::ReadWrite);//打开串口

        //设置波特率
        //      serial->setBaudRate(QSerialPort::Baud4800);
        switch (ui->comboBox_2->currentIndex())
        {
        case 0:
            serial->setBaudRate(QSerialPort::Baud1200);
            break;
        case 1:
            serial->setBaudRate(QSerialPort::Baud2400);
            break;
        case 2:
            serial->setBaudRate(QSerialPort::Baud4800);
            break;
        case 3:
            serial->setBaudRate(QSerialPort::Baud9600);
            break;
        case 4:
            serial->setBaudRate(QSerialPort::Baud19200);
            break;
        default:
            break;
        }

        //设置校验位
        switch (ui->comboBox_4->currentIndex())
        {
        case 0:
            serial->setParity(QSerialPort::NoParity);
            break;
        default:
            break;
        }
        //设置停止位
        switch (ui->comboBox_5->currentIndex())
        {
        case 1:
            serial->setStopBits(QSerialPort::OneStop);//停止位设置为1
            break;
        case 2:
            serial->setStopBits(QSerialPort::TwoStop);//
            break;
        default:
            break;
        }

        //设置流控制
        serial->setFlowControl(QSerialPort::NoFlowControl);//设置为无流控制
        ui->comboBox->setEnabled(false);
        ui->comboBox_2->setEnabled(false);
        ui->comboBox_3->setEnabled(false);
        ui->comboBox_4->setEnabled(false);
        ui->comboBox_5->setEnabled(false);
        ui->pushButton->setText(tr("关闭串口"));


    }
    else
    {
        //关闭串口
        serial->clear();
        serial->close();
        serial->deleteLater();

        ui->comboBox->setEnabled(true);
        ui->comboBox_2->setEnabled(true);
        ui->comboBox_3->setEnabled(true);
        ui->comboBox_4->setEnabled(true);
        ui->comboBox_5->setEnabled(true);
        ui->pushButton->setText(tr("打开串口"));
    }

    //连接信号槽
    QObject::connect(serial,&QSerialPort::readyRead,this,&MainWindow::ReadData);
}

//读取接收到的信息
void MainWindow::ReadData()
{
    QByteArray buf; //二进制
    buf=serial->readAll();//读取串口数据,注意,返回的并不是一帧一帧的,需要处理

    if(!buf.isEmpty()) ///接收处理函数
    {
        for(int i=0;i<buf.length();i+=1)//将数据一帧一帧分离,hex二进制是一字节
        {
            QByteArray buf_rx=buf.mid(i,1);//每次取i后一个字节
            bool ok;//函数需要
            rx_stack_data_deal((quint8)buf_rx[0]);//解析串口函数,强制转换即可quint8=unsigned char;
            //             qDebug() <<"强制转换数据:"<<(quint8)buf_rx[0];
        }
    }

    QString buffer_1;//存储
    if(!buf.isEmpty())//在电脑ui中显示数据
    {
        QString str=buf.toHex().data();//hex为16进制数
        str=str.toUpper();//转换成大写
        for(int i=0;i<str.length();i+=2)//转换完成显示16进制需要2字节
        {
            QString str_1 = str.mid (i,2);//每次取i后两个字节
            buffer_1 += str_1;//转换二进制
            buffer_1 += " ";//后面加空
        }

        QString receive = ui->textEdit->toPlainText();//读取ui之前显示数据
        ui->textEdit->clear();    //清空显示
        receive += QString(buffer_1);  //叠加
        ui->textEdit->append(receive);//重新显示
        buffer_1.clear();
    }

    buf.clear();//清空
}

//发送按钮槽函数
void MainWindow::on_pushButton_2_clicked()
{

    if(ui->pushButton->text()=="关闭串口")
    {
        //        serial->write(ui->lineEdit->text().toLatin1().append("/"));
        //          //Latin1是ISO-8859-1的别名,单片机仅能识别ASCII码
        //        serial->write(ui->lineEdit->text().toLatin1());
        //         //Latin1是ISO-8859-1的别名,单片机仅能识别ASCII码
        //test
        //        QString tmp=ui->lineEdit->text().toUtf8();
        //        qDebug() <<"utf8: "<<tmp ;
        //        qDebug() <<"toLatin1(): "<<tmp.toLatin1() ;
        //        qDebug() <<"toLocal8Bit(): "<<tmp.toLocal8Bit()  ;
        //        qDebug() << ui->lineEdit->text().toLatin1() ;
        //

        //        QByteArray bax; //二进制 实验
        //        bax[0]=0xaa;
        //        bax[1]=0xf9;
        //        bax[2]=0xff;
        //        bax[3]=0x02;
        //        bax[4]=0x03;
        //        bax[5]=0x04;
        //        bax[6]=0xdd;
        //        serial->write(bax);//串口发送数据
        //        qDebug() <<"发送数据:"<<bax.toHex();//二进制强制转换char ?

        QByteArray bax2; //二进制
        tx_stack_data_deal();//调取usart.cpp函数初始化数据
        //以下为数据,用append顺序不能乱,append是在末尾添加
        bax2.append(tx_stack.head);//发送头
        bax2.append(tx_stack.direction);//发送流向
        bax2.append(tx_stack.data[0]);//发数据0
        bax2.append(tx_stack.data[1]);//发数据1
        bax2.append(tx_stack.data[2]);//发数据2
        bax2.append(tx_stack.data[3]);//发数据3
        bax2.append(tx_stack.tail);//发尾部
        serial->write(bax2);//串口发送数据
        qDebug() <<"发送数据16进制:"<<bax2.toHex();//二进制强制转换char ?
        qDebug() <<"发送数据2进制:"<<bax2;//二进制强制转换char ?


        ui->lineEdit->clear();//清空控件数据
    }
    else
    {
        ui->pushButton_2->setEnabled(true);
        QMessageBox::about(NULL, "提示", "串口未打开");
    }

}

usart.h

#ifndef USART_H
#define USART_H


typedef unsigned char u8;//与单片机统一

#define UNLOCK 0x00  //宏定义 串口flag,开
#define LOCK 0xff    //宏定义 串口flag,关

void rx_stack_init(void);//初始化接收串口函数
void tx_stack_init(void);//初始化发送串口函数
void rx_stack_data_deal(u8 receive_data);//串口接收数据处理
void tx_stack_data_deal(void);//串口接收数据处理
//串口发送协议栈
typedef struct
{
    u8 head; //头
    u8 direction;//流向
    u8 data[4]; //数据
    u8 tail; //尾部
} ptl_stack;

//串口接收协议栈
typedef struct
{
    u8 head;//头
    u8 direction;//流向
    u8 data[4];//数据
    u8 tail;//尾部
    u8 data_pt;//记录数据指针位
    u8 lock_flag;//接收满标志位,上位机不需要中断锁住
} ptr_stack;

#endif // USART_H

usart.cpp

#include "usart.h"
#include <QDebug>

ptl_stack tx_stack;
ptr_stack rx_stack;

void rx_stack_init(void)
{
    u8 i;
    rx_stack.head = 0;
    rx_stack.direction = 0;
    for(i = 0; i <=3; i++)
    {
        rx_stack.data[i] = 0;
    }
    rx_stack.data_pt = 0;
    rx_stack.tail = 0;
    rx_stack.lock_flag = UNLOCK;
}


void tx_stack_init(void)
{
    u8 i;
    tx_stack.head = 0xaa;
    tx_stack.direction = 0x09;
    for(i = 0; i <=3; i++)
    {
        tx_stack.data[i] = 0x00;
    }
    tx_stack.tail = 0xdd;

}

void rx_stack_data_deal(u8 receive_data)
{ 
    if(rx_stack.lock_flag == UNLOCK)          //如果未锁住,则没有接收完成
    {
        if(receive_data == 0xaa) //如果头等于aa,则接收
        {
            rx_stack.head = receive_data; //接收头数据
            QByteArray b;
            qDebug() <<"我收到head:"<< rx_stack.head;//b.append(rx_stack.head).toHex();//二进制强制转换char ?
        }
        else if(receive_data == 0xf0) //方向判断f9是电脑发送到单片机,f0代表单片机发送
        {
            rx_stack.direction = receive_data; //接收方向
                QByteArray b;
            qDebug() <<"我收到direction:"<<rx_stack.direction;//b.setNum(rx_stack.direction,16);//二进制强制转换char ?
        }
        else if(receive_data == 0xdd) //尾部判断
        {
            rx_stack.tail = receive_data; //接收尾部
                QByteArray b;
            qDebug() <<"我收到tail :"<< b.setNum(rx_stack.tail,16);//二进制强制转换char ?
        }
        else
        {
            //数据处理,存储
            rx_stack.data[rx_stack.data_pt] = receive_data;//
            QByteArray b;
            qDebug() <<"deal1 data:"<< b.setNum(rx_stack.data[rx_stack.data_pt], 16);//二进制强制转换char ?
            rx_stack.data_pt ++;
        }

        //如果数据接收满,且到达尾部,清空
        if((rx_stack.data_pt >= 4) && (rx_stack.tail == 0xdd))
        {
            rx_stack.lock_flag = LOCK;//锁住数据
            tx_stack_data_deal();

        }   
    }

}

void tx_stack_data_deal(void)//串口发送数据处理
{    
    ///此处可添加其他解析函数///
    tx_stack.head = 0xaa;//设置头
    tx_stack.direction = 0xf9;
    tx_stack.data[0] = 0x1a;
    tx_stack.data[1] = 0x2b;
    tx_stack.data[2] = 0x3c;
    tx_stack.data[3] = 0x4d;
    tx_stack.tail = 0xdd;

    rx_stack.lock_flag = UNLOCK;//锁住数据
    rx_stack_init();//清空,不然数据叠加有错误
}

效果如下:

  • 9
    点赞
  • 138
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值