CubeIDE1.8 c/c++混合编程

使用CubeMX在生成代码时,会生成main.c文件。如果使用c++语言编程,将main.c改为main.cpp。CubeMX再次生成代码,会新建一个main.c文件。所以在重新生成代码前,需要将main.cpp改为main.c,代码更新后再将main.c改为main.cpp。 这样频繁的修改文件名,让人厌烦。

这里将实现c调用c++方法,避免修改文件名,实现CubeIDE1.8 c/c++混合编程。

使用CubeIDE生成项目时,选择c++语言,就可以编译c++代码。

使用串口DMA方式收发数据为例,说明如何使用c/c++混合编程。

新建项目,并且配置好DMA和UART1。

新增3个类:

RunCPP:c代码使用这个文件提供的方法调用c++的类方法。严格来说RunCPP不是类。

McuCPP:全局类,单例模式。

SerialPort:串口类,管理接收缓冲与发送缓冲。

类文件保存目录如下:

RunCPP源码

RunCPP.h

#ifndef RUNCPP_H_
#define RUNCPP_H_

#include "stm32f1xx_hal.h"

#ifdef __cplusplus   //使用C语言的方式编译方法名。
extern "C" {
#endif

void CPP_UART1_Init(UART_HandleTypeDef* huart,DMA_HandleTypeDef* hdma_rx,DMA_HandleTypeDef* hdma_tx);  //建立SerialPort、缓冲区。
void ResponseUart1Data();  //接收到数据后中断处理函数调用的方法。

#ifdef __cplusplus
}
#endif

#endif /* RUNCPP_H_ */

RunCPP.cpp

#include "RunCPP.h"
#include "McuCPP.h"

void CPP_UART1_Init(UART_HandleTypeDef* huart,DMA_HandleTypeDef* hdma_rx,DMA_HandleTypeDef* hdma_tx)
{
	McuCPP::GetInstance().CPP_UART1_Init(huart,hdma_rx,hdma_tx);
}

void ResponseUart1Data()
{
	McuCPP::GetInstance().GetUart1()->ResponseUartData();
}

McuCPP类源码

McuCPP.h

#ifndef MCUCPP_H_
#define MCUCPP_H_

#include <stdio.h>
#include "main.h"
#include "stm32f1xx_it.h"
#include "SerialPort.h"

class McuCPP {

public:
	//单例模式
	static McuCPP&  GetInstance();
	virtual ~McuCPP();

protected:
	McuCPP();
	//禁止拷贝构造
	McuCPP(const McuCPP& mcu);
	//禁止赋值
	McuCPP& operator = (const McuCPP& mcu);

private:
	SerialPort* huart1;

public:
	SerialPort* GetUart1() {return huart1;}

	void CPP_UART1_Init(UART_HandleTypeDef* huart,DMA_HandleTypeDef* hdma_rx,DMA_HandleTypeDef* hdma_tx)
	{
		huart1 = new SerialPort(100);
		huart1->SetUart(huart,hdma_rx,hdma_tx);
	}

	void CPP_UART1_Dispose()
	{
		if(huart1 != nullptr) { delete huart1; huart1 = nullptr;}
	}
};

#endif /* MCUCPP_H_ */

McuCPP.cpp

#include "McuCPP.h"

// Return the instance pointer
McuCPP& McuCPP::GetInstance()
{
    static McuCPP instance;
    return instance;
}

McuCPP::McuCPP():
		huart1(nullptr)
{
}

McuCPP::~McuCPP() {
}

SerialPort类源码

SerialPort.h

#ifndef SERIALPORT_H_
#define SERIALPORT_H_

#include <stdio.h>
#include "main.h"
#include "stm32f1xx_it.h"
#include <cstring>

class SerialPort {
public:
	SerialPort(int bufferlength);
	virtual ~SerialPort();

protected:
	//禁止拷贝构造
	SerialPort(const SerialPort& serialport);
	//禁止赋值
	SerialPort& operator = (const SerialPort& serialport);

private:
	UART_HandleTypeDef* huart;  //串口句柄
	DMA_HandleTypeDef* dma_rx;
	DMA_HandleTypeDef* dma_tx;
	uint8_t* rx_buffer;  //接收数据缓冲区地址
	uint8_t* tx_buffer;  //发送数据缓冲区地址
	int bufferlength;  //接收数据缓冲区长度


public:
	void SetUart(UART_HandleTypeDef* huart,DMA_HandleTypeDef* dma_rx,DMA_HandleTypeDef* dma_tx)
	{
		this->huart = huart;
		this->dma_rx = dma_rx;
		this->dma_tx = dma_tx;
		__HAL_UART_ENABLE_IT(this->huart, UART_IT_IDLE); //使能IDLE中断
		HAL_UART_Receive_DMA(this->huart,rx_buffer,bufferlength);  //设置串口接收缓冲,开始接收数据
	}

	void ResponseUartData()
	{
		if(huart != nullptr)
		{
			uint32_t tmp_flag = __HAL_UART_GET_FLAG(huart,UART_FLAG_IDLE); //获取IDLE标志
			if((tmp_flag != RESET))//idle标志被置位
			{
				__HAL_UART_CLEAR_IDLEFLAG(huart);//清除标志位
				HAL_UART_DMAStop(huart); //
				uint32_t temp =  __HAL_DMA_GET_COUNTER(dma_rx);// 获取DMA中未传输的数据个数
				int rx_len =  bufferlength - temp; //总计数减去未传输的数据个数,得到已经接收的数据个数

				if(rx_len>0)
				{
					memcpy(tx_buffer,rx_buffer,rx_len);
					HAL_UART_Transmit_DMA(huart, tx_buffer, rx_len);
					memset(rx_buffer,0,rx_len);
				}
				HAL_UART_Receive_DMA(huart,rx_buffer,bufferlength);//重新打开DMA接收
			}
		}
	}
};

#endif /* SERIALPORT_H_ */

SerialPort.cpp

#include <SerialPort.h>
#include <stdlib.h>

SerialPort::SerialPort(int bufferlength):
huart(nullptr),
rx_buffer(nullptr),
bufferlength(bufferlength)
{
	rx_buffer = (uint8_t*)malloc(bufferlength);
	tx_buffer = (uint8_t*)malloc(bufferlength);
}

SerialPort::~SerialPort()
{
	if(rx_buffer != nullptr) { delete rx_buffer; rx_buffer = nullptr; }
	if(tx_buffer != nullptr) { delete tx_buffer; tx_buffer = nullptr; }
	if(huart!= nullptr)	{huart = nullptr;}
	bufferlength = 0;
}

增加include目录:

在CubeIDE生成的代码中使用c++类:

main.h

/* USER CODE BEGIN Includes */
#include "RunCPP.h"
/* USER CODE END Includes */

main.c

int main(void)
{
......
  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_DMA_Init();   //注意初始化顺序
  MX_USART1_UART_Init();  
  /* USER CODE BEGIN 2 */
  //初始化串口类SerialPort、缓冲
  CPP_UART1_Init(&huart1,&hdma_usart1_rx,&hdma_usart1_tx);
  /* USER CODE END 2 */
......
}

stm32f1xx_it.c

void USART1_IRQHandler(void)
{
  /* USER CODE BEGIN USART1_IRQn 0 */
  /* USER CODE END USART1_IRQn 0 */
  HAL_UART_IRQHandler(&huart1);
  /* USER CODE BEGIN USART1_IRQn 1 */
  if(USART1 == huart1.Instance)
     {
	     ResponseUart1Data();  //调用c++的处理方法。
     }
  /* USER CODE END USART1_IRQn 1 */
}

        通过以上的实现方式,串口中断处理程序放到了SerialPort类的ResponseUartData方法里,将接口的设置与数据处理解耦,CubeIDE生成的代码用于接口设置,SerialPort类代码用于数据的业务处理。

        SerialPort是C++类,可以使用STL库快速的实现复杂的数据缓冲,例如多个串口使用同一个数据缓冲,或者多个不同的接口使用同一个数据缓冲,也可以使用C++设计模式,实现业务逻辑。

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值