STM32F03C8T6通过AT指令获取天气API-下篇

这里写目录标题

堆栈大小换算与修改说明

一、十六进制到十进制的换算

1.1 换算公式

复制代码
十六进制到十进制换算:
0x400 = 4 × 16² = 4 × 256 = 1024
0x1000 = 1 × 16³ = 1 × 4096 = 4096
0x200 = 2 × 16² = 2 × 256 = 512
0x2000 = 2 × 16³ = 2 × 4096 = 8192

1.2 换算结果

十六进制 十进制 字节 KB
0x400 1024 1024字节 1KB
0x1000 4096 4096字节 4KB
0x200 512 512字节 0.5KB
0x2000 8192 8192字节 8KB

二、修改前后的对比

修改前(原始配置):

  • Stack_Size = 0x400 = 1KB(栈大小)
  • Heap_Size = 0x200 = 0.5KB(堆大小)
  • 总计:1.5KB RAM

修改后(新配置):

  • Stack_Size = 0x1000 = 4KB(栈大小)
  • Heap_Size = 0x2000 = 8KB(堆大小)
  • 总计:12KB RAM

三、STM32F103C8T6的内存限制

STM32F103C8T6的RAM大小为20KB(0x5000字节)

内存区域 地址范围 大小
总RAM 0x20000000-0x20004FFF 20KB
栈(Stack) 向下生长 4KB(修改后)
堆(Heap) 向上生长 8KB(修改后)
全局/静态变量 中间区域 8KB(剩余)
复制代码
内存布局示意图(修改后):
0x20005000
  ↑
  │ 栈(Stack) - 4KB (向下生长)
  │
  │
  │
  │
  │
  │
  │
  │
  │
  │
  │
  │
  │
  │
  │
  │
  │
  │
  │
  │
  │
  │
  │
  │
0x20004000
  ├─────────┤
  │ 全局变量   │
  │ 静态变量   │
  │ 已分配内存 │
  ├─────────┤
0x20002000
  ↑
  │ 堆(Heap) - 8KB (向上生长)
  │
0x20000000

四、为什么需要调整堆栈大小?

4.1 原始设置(1KB栈+0.5KB堆)的问题:

  1. 栈太小

    • 函数调用层次有限
    • 局部变量不能太大
    • 中断嵌套可能溢出
    • cJSON递归解析可能溢出
  2. 堆太小

    • cJSON动态分配内存不够
    • 网络数据缓冲区不足
    • 字符串操作受限
    • 无法使用标准库的malloc

4.2 建议设置(4KB栈+8KB堆)的好处:

  1. 栈(4KB)

    • 支持较深的函数调用
    • 可定义较大的局部数组
    • 中断处理更安全
    • 支持cJSON的递归解析
  2. 堆(8KB)

    • cJSON有足够内存解析完整JSON
    • 可创建较大的动态缓冲区
    • 支持标准库函数
    • 网络数据处理更灵活

五、完整的startup文件修改示例

assembly 复制代码
; startup_stm32f103xe.s
; 堆栈配置部分

                IF      :DEF:__MICROLIB
                
                EXPORT  __initial_sp
                EXPORT  __heap_base
                EXPORT  __heap_limit
                
                ELSE
                
                IMPORT  __use_two_region_memory
                EXPORT  __user_initial_stackheap
                 
__user_initial_stackheap

                LDR     R0, =  Heap_Mem
                LDR     R1, =(Stack_Mem + Stack_Size)
                LDR     R2, =(Heap_Mem +  Heap_Size)
                LDR     R3, = Stack_Mem
                BX      LR

                ALIGN

                ENDIF

; ==========================================================================
; 修改前:Stack_Size EQU 0x00000400
; 修改后:Stack_Size EQU 0x00001000
Stack_Size      EQU     0x00001000   ; ← 修改这里,改为4KB
                
                AREA    STACK, NOINIT, READWRITE, ALIGN=3
Stack_Mem       SPACE   Stack_Size
__initial_sp

; ==========================================================================
; 修改前:Heap_Size  EQU 0x00000200
; 修改后:Heap_Size  EQU 0x00002000
Heap_Size       EQU     0x00002000   ; ← 修改这里,改为8KB
                
                AREA    HEAP, NOINIT, READWRITE, ALIGN=3
__heap_base
Heap_Mem        SPACE   Heap_Size
__heap_limit

                PRESERVE8
                THUMB

六、不同内存需求对应的推荐配置

应用场景 栈大小 堆大小 总RAM需求 说明
裸机简单应用 1KB 0.5KB 1.5KB 无动态分配,简单控制
中等复杂度 2KB 4KB 6KB 有动态分配,简单网络
JSON解析+网络 4KB 8KB 12KB 推荐配置
FreeRTOS简单 4KB 8KB 12KB+ 多任务需要更多栈
FreeRTOS复杂 6KB 12KB 18KB+ 接近芯片极限

七、验证堆栈是否足够的方法

7.1 在代码中添加堆栈使用检查

c 复制代码
// 在main.c中添加堆栈使用检查
extern uint32_t __heap_base;
extern uint32_t __heap_limit;
extern uint32_t __initial_sp;
extern uint32_t __StackTop;
extern uint32_t __StackLimit;

void check_stack_heap_usage(void) {
    // 获取当前栈指针
    register uint32_t* stack_ptr asm ("sp");
    
    // 计算栈使用量
    uint32_t stack_top = (uint32_t)&__StackTop;     // 栈顶
    uint32_t stack_usage = stack_top - (uint32_t)stack_ptr;
    uint32_t stack_free = (uint32_t)stack_ptr - (uint32_t)&__StackLimit;
    
    // 计算堆使用量
    uint32_t heap_base = (uint32_t)&__heap_base;
    uint32_t heap_limit = (uint32_t)&__heap_limit;
    
    printf("=== 内存使用情况 ===\r\n");
    printf("栈大小: %lu bytes (%.1fKB)\r\n", Stack_Size, Stack_Size/1024.0);
    printf("栈已用: %lu bytes\r\n", stack_usage);
    printf("栈剩余: %lu bytes\r\n", stack_free);
    printf("堆大小: %lu bytes (%.1fKB)\r\n", Heap_Size, Heap_Size/1024.0);
    printf("堆起始: 0x%08lX\r\n", heap_base);
    printf("堆结束: 0x%08lX\r\n", heap_limit);
    printf("===================\r\n");
}

// 在main函数中定期调用
int main(void) {
    // 初始化...
    
    while(1) {
        check_stack_heap_usage();
        HAL_Delay(10000);  // 每10秒检查一次
    }
}

7.2 在Keil/IDE中查看内存使用

复制代码
1. 编译后查看.map文件
2. 查找以下信息:
   Total RO  Size (Code + RO Data)       xxxx
   Total RW  Size (RW Data + ZI Data)    xxxx
   Total ROM Size (Code + RO Data + RW Data) xxxx
3. RW + ZI ≈ RAM使用量

八、针对您之前报错的解决方案

您之前的编译错误确实与startup文件有关,但不是堆栈设置的问题,而是:

  1. 中文字符编码问题:字符串中的中文字符导致编译器无法识别
  2. 解决方案:使用纯ASCII字符的JSON字符串进行测试
c 复制代码
// 错误的(有中文字符):
char *json_data = "{\"name\":\"合肥\",\"weather\":\"阴\"}";

// 正确的(纯ASCII):
char *json_data = "{\"name\":\"Beijing\",\"weather\":\"Cloudy\"}";

九、修改建议总结

  1. 必须修改

    • Stack_Size: 0x400 → 0x1000 (1KB → 4KB)
    • Heap_Size: 0x200 → 0x2000 (0.5KB → 8KB)
  2. 原因

    • cJSON需要动态内存分配
    • 网络数据需要缓冲区
    • 函数调用需要栈空间
  3. 注意事项

    • STM32F103C8T6只有20KB RAM
    • 修改后总共使用12KB,还有8KB给全局变量
    • 实际使用中监控堆栈使用情况
  4. 如果还不够用

    • 优化代码,减少栈使用
    • 使用静态分配代替动态分配
    • 减少递归深度
    • 优化网络缓冲区大小

这样修改后,您的JSON解析和网络通信应该就能正常工作了。

相关推荐
思慕很大很大2 分钟前
浏览器基础知识-进程与线程
前端·浏览器
猩猩程序员7 分钟前
dial9:一个强悍的 Tokio 调试工具!!!
前端
CODE_RabbitV15 分钟前
【3min 解决】keil5 编译stm32 出现一堆 core_cm3.c 报错问题
c语言·stm32·嵌入式硬件
gyx_这个杀手不太冷静26 分钟前
OpenCode 深度解析:架构设计、工具链集成与工程化实践
前端·架构·ai编程
【 STM32开发 】41 分钟前
【STM32 + CubeMX 教程】RTC 实时时钟 之 闹钟唤醒 -- F407篇
stm32·嵌入式硬件·实时音视频
m0_459252461 小时前
fastadmin动态渲染统计信息
开发语言·前端·javascript·php
该怎么办呢1 小时前
Source/Core/Matrix4.js
前端·javascript
小江的记录本1 小时前
【MyBatis-Plus】Spring Boot + MyBatis-Plus 进行各种数据库操作(附完整 CRUD 项目代码示例)
java·前端·数据库·spring boot·后端·sql·mybatis
BT-BOX1 小时前
第6章《Stm32CubeMX+Proteus仿真入门》LCD1602显示
stm32·嵌入式硬件·proteus
chao1898441 小时前
STM32F103C8T6驱动LDC1614测试程序
stm32·单片机·嵌入式硬件