CUBE MX结合Keil5 c/c++ STMF412混合编译调试记录

环境

CUBE MX 6.10.9

Keil 5.39

Keil编译环境设置

加载c++工程文件到keil5项目

keil5如下设置:

-xc++ -std=c++11

以上配置完即可顺利编译通过。

编译可能报错

printf重定义报错

C语言中的重定义c++不认识:解决方案->将串口printf重定义换成Retarget.cpp,

在usart.h头文件添加:

/* USER CODE BEGIN Prototypes */
// printf重定义
int  sendchar(int ch);
/* USER CODE END Prototypes */

在usart.c源文件添加:

/* USER CODE BEGIN 0 */
#include "stdio.h"
#include "string.h"

extern uint8_t rx_buffer[100];
/******************************************************************************************/
// printf重定义
int  sendchar(int ch)
{
    while ((USART1->SR & 0X40) == 0);               /* 等待上一个字符发送完成 */

    USART1->DR = (uint8_t)ch;                       /* 将要发送的字符 ch 写入到DR寄存器 */
    return ch;
}

/* USER CODE END 0 */

Retarget.cpp内容如下(注意必须包含usart.h和stdio.h):

/******************************************************************************/
/* RETARGET.C: 'Retarget' layer for target-dependent low level functions      */
/******************************************************************************/
/* This file is part of the uVision/ARM development tools.                    */
/* Copyright (c) 2005 Keil Software. All rights reserved.                     */
/* This software may only be used under the terms of a valid, current,        */
/* end user licence from KEIL for a compatible version of KEIL software       */
/* development tools. Nothing else gives you the right to use this software.  */
/******************************************************************************/
 
#include <rt_sys.h>
#include "usart.h"
#include <stdio.h> 
#ifdef __cplusplus
extern "C" {
#endif
 
extern int  sendchar(int ch);  
extern int  getkey(void);      
 
int fputc(int ch, FILE *f) {
  return (sendchar(ch));
}

 重定义串口接收
//int fgetc(FILE *f) {
//  return (sendchar(getkey()));
//}
 
FILEHANDLE _sys_open(const char * name, int openmode)
{
    return 1;  
}
int _sys_close(FILEHANDLE fh)
{
    return 0; //return success
}
int _sys_write(FILEHANDLE fh, const unsigned char * buf,
               unsigned len, int mode)
{
    return 0;   
}
int _sys_read(FILEHANDLE fh, unsigned char * buf,
              unsigned len, int mode)
{
    return 0;       
}
void _ttywrch(int ch)
{ 
}
int _sys_istty(FILEHANDLE fh)
{
    return 1; // no interactive device present
}
int _sys_seek(FILEHANDLE fh, long pos)
{
    return -1; // error
}
int _sys_ensure(FILEHANDLE fh)
{
    return 0; // success
}
long _sys_flen(FILEHANDLE fh)
{
    return 0;
}
void _sys_tmpnam(char * name, int sig, unsigned maxlen)
{
    //return 0; // fail, not supported
}
void _sys_exit(int returncode)
{
    while(1) {};
}
#ifdef __cplusplus
}
#endif

字符串(strlen、strcpy、strcat)操作函数和动态内存报错

解决方法malloc前面加(char*),strcpy\strlen报错是因为参数类型不对,将unsigned char*改为char*即可。

支持编译通过,串口正常打印。

但是,c++编译的程序比较大,且单片机运行class速度较慢,导致程序触发IWDG,单片机无限重启运行。

程序运行速度变慢

移植C++后的程序,运行速度变慢,解决方案是将优化等级调高O0->O3

cpp文件调用extern “C"修饰的cpp函数编译提示函数未定义

现象

解决办法

把被调用extern “C"修饰的cpp函数的头文件放extern “C”里面再重新编译

extern "C"
{
#include "my_string_lib.h"
}

cpp文件(c++)与c文件(c语言)混合编程注意事项

如果cpp里面的变量、类、函数需要在c文件中被调用和使用,需要在把被调用的部分放该cpp头文件的extern “C”里面,例如以下示例。

#if __cplusplus
extern "C"{
#endif
	
// 初始化环形缓冲区
void RingBuffer_Init(RingBuffer *ringBuffer);

// 环形缓冲区写操作
int RingBuffer_Write(RingBuffer *ringBuffer, uint8_t *data, uint16_t size);

// 环形缓冲区读操作
int RingBuffer_Read(RingBuffer *ringBuffer, uint8_t *data, uint16_t size);
#if __cplusplus
}
#endif

启用IWDG后调试会崩溃

现象弹窗:Debugger - Cortex-M Error   Operation not possible

解决方案1:注释掉MX_IWDG_Init();即可,HAL_IWDG_Refresh(&hiwdg);//喂狗不用管,调试完成取消MX_IWDG_Init();注释即可

  MX_GPIO_Init();
  MX_DMA_Init();
  MX_I2C2_Init();
  MX_SPI1_Init();
  MX_SPI4_Init();
  MX_TIM1_Init();
  MX_TIM7_Init();
  MX_USART2_UART_Init();
  MX_USART3_UART_Init();
  MX_USART6_UART_Init();
  MX_USART1_UART_Init();
  MX_TIM6_Init();
  MX_TIM8_Init();
  //MX_IWDG_Init();

解决方案2:debug下禁用IWDG,我无法使用,目前不清楚bug在哪里

#ifdef STM32f4
 __HAL_DBGMCU_FREEZE_WWDG()
 __HAL_DBGMCU_FREEZE_IWDG(); //调试模式时冻结看门狗

 __HAL_DBGMCU_UNFREEZE_WWDG()          
 __HAL_DBGMCU_UNFREEZE_IWDG() //调试模式时开启看门狗
#else //H7
 __HAL_DBGMCU_FREEZE_WWDG1()  
 __HAL_DBGMCU_FREEZE_IWDG1() 
 
 __HAL_DBGMCU_UnFreeze_WWDG1()
 __HAL_DBGMCU_UnFreeze_IWDG1()  
#endif

测试通过:在主函数while循环前添加__HAL_DBGMCU_FREEZE_IWDG(); /*调试模式下禁用看门狗*/即可

MX_TIM8_Init();
  MX_IWDG_Init();

  /* Initialize interrupts */
  MX_NVIC_Init();
  /* USER CODE BEGIN 2 */

  __HAL_DBGMCU_FREEZE_IWDG(); /*调试模式下禁用看门狗*/
	HAL_Delay(1000);

部分程序崩溃bug

现象:main函数主循环挂掉无法进入断点,某中断可进入断点

解决办法:仔细检查中断部分的代码程序,看是否有因为内存溢出(我是因为环形缓冲区过小,导致写入数据量大的时候缓冲区被写满,陷入死循环)、越界导致的死循环无法出来,占用了所有芯片资源。

FPGA的SPI联调问题记录

-O3变为-O0程序崩溃

现象描述:编译优化等级从-O3变为-O0时,-O3时烧写程序正常运行,但是-O1编译通过,烧写程序崩溃,无限重启。

解决方案:数组定义过小,导致在某个操作中数组越界。

-O3变为-O0程序for循环延时无效

现象描述:-O3变为-O0程序for循环延时无效

解决方案:使用系统时钟进行微秒级延时,代码如下(参考:STM32CubeMX | STM32 HAL库方式的微秒延时函数_hal库微秒延时-CSDN博客):

#define CPU_FREQUENCY_MHZ 100						// STM32时钟主频

/*用于实现微秒*/
void my_Delay_Us(int delay)
{
	int last, curr, val;
	int temp;

	while (delay != 0)
	{
			temp = delay > 900 ? 900 : delay;
			last = SysTick->VAL;
			curr = last - CPU_FREQUENCY_MHZ * temp;
			if (curr >= 0)
			{
					do
					{
							val = SysTick->VAL;
					}
					while ((val < last) && (val >= curr));
			}
			else
			{
					curr += CPU_FREQUENCY_MHZ * 1000;
					do
					{
							val = SysTick->VAL;
					}
					while ((val <= last) || (val > curr));
			}
			delay -= temp;
	}
}

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值