环境
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库微秒延时-优快云博客):
#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;
}
}