首先,用pragma指令禁用半主机模式,防止调用printf就出现HardFault。然后在std命名空间中重写fgetc、fputc、fclose、fseek和fflush函数,还要重写__stdin、__stdout和__stderr这三个全局变量。
_sys_exit和_ttywrch也要重写,前者是main函数返回后调用的函数,_ttywrch是出现错误时往串口打印字符的函数。
_sys_exit函数不允许返回,必须以无限循环结尾。
另外,工程属性里面不要勾选Use MicroLIB,这个选项和C++是不兼容的!!即使使用C语言,
也能在不勾选Use MicroLIB的情况下printf输出到串口
。
【cout.cpp】
#include
#include
#include "common.hpp"
#pragma import(__use_no_semihosting) // 禁用半主机模式
// 请不要勾选Use MicroLib
#ifdef __MICROLIB
#error "Please do not use MicroLib!"
#endif
extern "C"
{
void _sys_exit(int returncode)
{
printf("Exited! returncode=%dn", returncode);
while (1);
}
void _ttywrch(int ch)
{
if (ch == 'n')
HAL_UART_Transmit(&huart1, (uint8_t *)"rn", 2, HAL_MAX_DELAY);
else
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, HAL_MAX_DELAY);
}
}
namespace std
{
struct __FILE
{
int handle;
/* Whatever you require here. If the only file you are using is */
/* standard output using printf() for debugging, no file handling */
/* is required. */
};
FILE __stdin = {0};
FILE __stdout = {1};
FILE __stderr = {2};
int fgetc(FILE *stream)
{
int c = 0;
if (stream->handle == 0)
{
while (__HAL_UART_GET_FLAG(&huart1, UART_FLAG_RXNE) == RESET);
HAL_UART_Receive(&huart1, (uint8_t *)&c, 1, HAL_MAX_DELAY);
_ttywrch((c == 'r') ? 'n' : c); // 回显
return c;
}
return EOF;
}
int fputc(int c, FILE *stream)
{
if (stream->handle == 1 || stream->handle == 2)
{
_ttywrch(c);
return c;
}
return EOF;
}
int fclose(FILE * stream)
{
return 0;
}
int fseek(FILE *stream, long int offset, int whence)
{
return -1;
}
int fflush(FILE *stream)
{
if (stream->handle == 1 || stream->handle == 2)
while (__HAL_UART_GET_FLAG(&huart1, UART_FLAG_TC) == RESET);
return 0;
}
}
另外,启动文件startup_stm32f103xb.s中默认分配的堆空间太小,必须要改大,否则将无法进入main函数。如果程序运行过程中出现HardFault,说明堆空间仍然不够,还需要继续改大。
Heap_Size EQU 0x0001000
以下是测试代码:
【main.cpp】
#include
#include
#include
#include
#include
#include "common.hpp"
using namespace std;
// 类
class Test
{
private:
int num;
public:
Test(int num) : num(num) {}
void display(void)
{
cout << "num=" << num << endl;
}
};
// 函数模板
template
static void further_test(T a)
{
cout << "[" << typeid(a).name() << "] a=" << a << endl;
}
// 字符串替换
static void str_replace(string search, string replace, string &subject)
{
string::size_type pos = 0;
for (pos = 0; (pos = subject.find(search, pos)) != string::npos; pos += replace.length())
subject.replace(pos, search.length(), replace);
}
static void further_test(void)
{
// string字符串
string str = "this is";
str.append(" a string");
str_replace("is", "[IS]", str);
cout << str << " len=" << str.length() << endl;
// vector容器
vector
items;
vector
::iterator iter;
items.push_back("fooo");
items.push_back("bar");
items.push_back("welcome");
cout << "size=" << items.size() << endl;
for (iter = items.begin(); iter != items.end(); ++iter)
cout << *iter << " ";
cout << endl;
// new和delete运算符
int i;
int n = items.size();
int *arr = new int[n];
for (i = 0; i < n; i++)
arr
= items.at(i).length(); for (i = 0; i < n; i++) cout << arr<< " "; cout << endl; delete[] arr;
// 类 Test t = 50; t.display();
// 引用 Test &u = t; u.display();
// scanf输入 printf("Please input: "); scanf("%d", &n); printf("2n=%dn", 2 * n);
// cin输入 cout << "Please input: "; cin >> n; cout << "3n=" << 3 * n << endl; }
// s文件中的Heap_Size必须改大,不能采用默认值,否则进不了main函数 // 如果出现Hard Error, 则说明还需要继续改大 int main(void) { HAL_Init();
clock_init(); usart_init(115200);
printf("STM32F103C8 printfn"); printf("SystemCoreClock=%un", SystemCoreClock);
cout << "STM32F103C8 cout" << endl; cout << "SystemCoreClock=" << SystemCoreClock << endl;
// 函数重载 further_test(15); further_test("this"); further_test();
return 0; } 【common.cpp】
#include
#include
#include "common.hpp"
UART_HandleTypeDef huart1;
extern "C"
{
#ifdef USE_FULL_ASSERT
// HAL库参数错误警告
void assert_failed(uint8_t *file, uint32_t line)
{
printf("%s: file %s on line %dn", __FUNCTION__, file, line);
while (1);
}
#endif
void HardFault_Handler(void)
{
printf("Hard Error!n");
while (1);
}
void SysTick_Handler(void)
{
HAL_IncTick();
}
}
// 配置系统和总线时钟
void clock_init(void)
{
HAL_StatusTypeDef status;
RCC_ClkInitTypeDef clk = {0};
RCC_OscInitTypeDef osc = {0};
// 外部晶振为8MHz, 配置PLL倍频器倍频9倍后是72MHz
osc.OscillatorType = RCC_OSCILLATORTYPE_HSE;
osc.HSEState = RCC_HSE_ON;
osc.PLL.PLLMUL = RCC_PLL_MUL9;
osc.PLL.PLLSource = RCC_PLLSOURCE_HSE;
osc.PLL.PLLState = RCC_PLL_ON;
status = HAL_RCC_OscConfig(&osc);
// 如果外部晶振启动失败, 则改用内部的8MHz晶振, 经过2分频后倍频16倍, 变成64MHz
if (status != HAL_OK)
{
osc.HSEState = RCC_HSE_OFF;
osc.PLL.PLLMUL = RCC_PLL_MUL16;
osc.PLL.PLLSource = RCC_PLLSOURCE_HSI_DIV2;
HAL_RCC_OscConfig(&osc);
}
// ADC时钟不能超过14MHz, 所以需要6分频, 72MHz经过分频后是12MHz
__HAL_RCC_ADC_CONFIG(RCC_ADCPCLK2_DIV6);
// 配置AHB和APB2总线时钟为72MHz, APB1总线时钟为36MHz
clk.ClockType = RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
clk.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
clk.AHBCLKDivider = RCC_SYSCLK_DIV1;
clk.APB1CLKDivider = RCC_HCLK_DIV2;
clk.APB2CLKDivider = RCC_HCLK_DIV1;
HAL_RCC_ClockConfig(&clk, FLASH_LATENCY_2);
}
void usart_init(int baud_rate)
{
GPIO_InitTypeDef gpio = {0};
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_USART1_CLK_ENABLE();
gpio.Mode = GPIO_MODE_AF_PP;
gpio.Pin = GPIO_PIN_9;
gpio.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOA, &gpio);
huart1.Instance = USART1;
huart1.Init.BaudRate = baud_rate;
huart1.Init.Mode = UART_MODE_TX_RX;
HAL_UART_Init(&huart1);
}
【common.hpp】
#ifndef __COMMON_H
#define __COMMON_H
#ifdef HAL_UART_MODULE_ENABLED
extern UART_HandleTypeDef huart1;
#endif
void clock_init(void);
void usart_init(int baud_rate);
#endif
程序运行结果:
STM32F103C8 printf
SystemCoreClock=72000000
STM32F103C8 cout
SystemCoreClock=72000000
a=15 [PKc] a=this th[IS] [IS] a string len=20 size=3 fooo bar welcome 4 3 7 num=50 num=50 Please input: 123 2n=246 Please input: -456 3n=-1368 Exited! returncode=0
|