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解析和网络通信应该就能正常工作了。

相关推荐
开开心心_Every2 小时前
无广告输入法推荐:内置丰富词库免费皮肤
服务器·前端·学习·决策树·edge·powerpoint·动态规划
卓怡学长3 小时前
m111基于MVC的舞蹈网站的设计与实现
java·前端·数据库·spring boot·spring·mvc
C_心欲无痕8 小时前
前端实现水印的两种方式:SVG 与 Canvas
前端·安全·水印
尾善爱看海10 小时前
不常用的浏览器 API —— Web Speech
前端
TEC_INO11 小时前
stm32_13:RFID-RC522项目代码
stm32·单片机·嵌入式硬件
美酒没故事°11 小时前
vue3拖拽+粘贴的综合上传器
前端·javascript·typescript
jingling55512 小时前
css进阶 | 实现罐子中的水流搅拌效果
前端·css
悟能不能悟14 小时前
前端上载文件时,上载多个文件,但是一个一个调用接口,怎么实现
前端
可问春风_ren14 小时前
前端文件上传详细解析
前端·ecmascript·reactjs·js