【方法】STM32F103C8单片机在Keil 5环境下使用C++编写程序,并将printf和cout重定向到串口
发布日期:2021-06-29 10:16:54
浏览次数:4
分类:技术文章
本文共 6142 字,大约阅读时间需要 20 分钟。
程序下载地址:(提取码:s7d6)
首先,用pragma指令禁用半主机模式,防止调用printf就出现HardFault。然后在std命名空间中重写fgetc、fputc、fclose、fseek和fflush函数,还要重写__stdin、__stdout和__stderr这三个全局变量。
_sys_exit和_ttywrch也要重写,前者是main函数返回后调用的函数,_ttywrch是出现错误时往串口打印字符的函数。
_sys_exit函数不允许返回,必须以无限循环结尾。另外,工程属性里面不要勾选Use MicroLIB,这个选项和C++是不兼容的!!即使使用C语言,。
【cout.cpp】
#include#include #include "common.hpp"#pragma import(__use_no_semihosting) // 禁用半主机模式// 请不要勾选Use MicroLib#ifdef __MICROLIB#error "Please do not use MicroLib!"#endifextern "C"{ void _sys_exit(int returncode) { printf("Exited! returncode=%d\n", returncode); while (1); } void _ttywrch(int ch) { if (ch == '\n') HAL_UART_Transmit(&huart1, (uint8_t *)"\r\n", 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[i] = items.at(i).length(); for (i = 0; i < n; i++) cout << arr[i] << " "; cout << endl; delete[] arr; // 类 Test t = 50; t.display(); // 引用 Test &u = t; u.display(); // scanf输入 printf("Please input: "); scanf("%d", &n); printf("2n=%d\n", 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 printf\n"); printf("SystemCoreClock=%u\n", 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 %d\n", __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_ENABLEDextern UART_HandleTypeDef huart1;#endifvoid clock_init(void);void usart_init(int baud_rate);#endif
程序运行结果:
STM32F103C8 printfSystemCoreClock=72000000STM32F103C8 coutSystemCoreClock=72000000[i] a=15[PKc] a=thisth[IS] [IS] a string len=20size=3fooo bar welcome4 3 7num=50num=50Please input: 1232n=246Please input: -4563n=-1368Exited! returncode=0
转载地址:https://blog.csdn.net/ZLK1214/article/details/104763870 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!
发表评论
最新留言
逛到本站,mark一下
[***.202.152.39]2024年05月01日 08时12分22秒
关于作者
喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
中国35位“大国工匠”榜单出炉!西工大、西电合计占半壁江山!清华仅1人!...
2019-04-29
知乎热议:嵌入式开发中C++好用吗?
2019-04-29
2020,Python 已死?
2019-04-29
漫画:程序员相亲?哈哈哈哈哈哈
2019-04-29
30种EMC标准电路分享,再不收藏就晚了!
2019-04-29
这100道Linux常见面试题,看看你会多少?
2019-04-29
十年硬件老司机,结合实际案例,带你探索单片机低功耗设计!
2019-04-29
“2020年嵌入式软件秋招经验和对嵌入式软件未来的一点思考”
2019-04-29
嵌入式的坑在哪方面?
2019-04-29
三种常见嵌入式设备通信协议
2019-04-29
硬核,这个充电宝居然烧煤气!
2019-04-29
什么是模块化代码?如何写?
2019-04-29
STM32串口发送数据和接收数据方式总结
2019-04-29
来,看看这20个常用的宏定义!
2019-04-29
嵌入式开发中常用的几种通信接口总结
2019-04-29
为什么我那么努力,模电还是学不懂?
2019-04-29
PID系统稳定性与零极点的关系
2019-04-29
什么?电路板上还要喷漆?
2019-04-29
读博读废了是种什么样的体验?
2019-04-29
2020年,技术圈十大“翻车”事件!
2019-04-29