STM32 RAM与ROM实战解析:从原理到高效应用设计

STM32 HAL库实现ROM到RAM的DMA存储器传输 DMA(直接内存访问)是一种绕过CPU、由专用控制器自主完成数据搬运的硬件机制,广泛应用于嵌入式系统中提升实时性与能效。其核心原理是通过总线矩阵直接读写地址空间内的源与目的区域,无需CPU参与指令执行。在STM32平台,存储器到存储器(M2M)模式支持ROM(Flash)与RAM(SRAM)间的高效拷贝,技术价值在于释放CPU资源、降低功耗并保障中断响应及时性。典型应用场景包括固件升级时的代码搬移、常量表加载、Bootloader跳转前的数据预置等。本文聚焦STM32F1系列,结合CubeMX图形化配置与H 阅读详情

1. 初识STM32的RAM与ROM:不只是记忆体那么简单

记得我刚开始玩STM32的时候,总觉得RAM和ROM就是简单的存储空间,一个临时记东西,一个永久存东西。直到有一次做实时数据采集项目,因为RAM不够用导致系统频繁崩溃,我才真正意识到这俩家伙的重要性。今天我就用自己的踩坑经验,跟大家聊聊STM32的RAM和ROM到底该怎么玩。

先说个最直观的比喻:RAM就像是你办公桌的桌面空间,临时放正在处理的文件,随手就能拿到,效率高但空间有限;ROM则是文件柜,能长期存放大量资料,但每次存取都要开柜子找文件,速度慢一些。在STM32中,RAM负责存储运行时的变量、堆栈这些动态数据,而ROM则存放程序代码、常量这些静态内容。

以常见的STM32F103C8T6为例,它的RAM是20KB,ROM是64KB。看起来不大对吧?但就是这么有限的资源,通过合理配置却能完成很多复杂的任务。我见过有人用64KB ROM跑简易操作系统,也见过用20KB RAM做实时音频处理的。关键不在于容量大小,而在于你怎么用好每一字节。

2. 深入理解RAM的工作原理与实战配置

2.1 STM32的RAM架构解析

STM32的RAM可不是简单的一块内存,它是有层次结构的。以STM32H7系列为例,它就包含了TCM内存、AXI SRAM、SRAM1/2/3/4等多个存储区域。TCM内存直接挂在CPU总线上,速度最快,适合放需要极速响应的代码和数据;AXI SRAM速度次之,容量较大;普通SRAM就是常规的内存空间了。

我在做电机控制项目时,就把PID算法的核心代码和关键变量放到了TCM内存里。这样做的效果立竿见影——中断响应时间缩短了30%,控制精度也大幅提升。配置方法其实很简单,在Keil中只需要在代码里加上这么一段:

// 将函数放在ITCM内存中
__attribute__((section(".itcm_section"))) void pid_control(void)
{
    // PID算法实现
}

// 将变量放在DTCM内存中  
__attribute__((section(".dtcm_section"))) float pid_error[3];

然后在链接脚本里定义好对应的内存区域就行了。这种优化对于需要实时响应的应用特别重要。

2.2 RAM空间优化实战技巧

RAM不够用是嵌入式开发的常态,我总结了几条实用的优化经验。首先是堆栈大小的设置,很多人直接使用默认值,这其实很浪费。我通常先用调试器监测堆栈使用情况,然后精确设置大小。在STM32CubeIDE中,可以在启动文件里这样配置:

__initial_sp    EQU     0x20005000    ; 堆栈指针初始值
Heap_Size       EQU     0x00000200    ; 堆大小512字节
Stack_Size      EQU     0x00000400    ; 栈大小1KB

其次是变量的内存对齐问题。不对齐的变量访问会导致CPU需要多次内存访问,既降低速度又增加功耗。建议使用编译器指令强制对齐:

__attribute__((aligned(4))) uint8_t buffer[128]; // 4字节对齐

还有一个经常被忽视的点是内存碎片管理。在长时间运行的应用中,频繁的动态内存分配会导致碎片化。我的做法是尽量使用静态分配,必要时使用内存池技术:

// 定义内存池
#define POOL_SIZE   1024
static uint8_t memory_pool[POOL_SIZE];
static size_t pool_index = 0;

void* my_malloc(size_t size)
{
    if (pool_index + size > POOL_SIZE) return NULL;
    void* ptr = &memory_pool[pool_index];
    pool_index += size;
    return ptr;
}

3. ROM的深度应用与固件管理策略

3.1 STM32的Flash存储器特性分析

STM32的ROM实际上是基于Flash技术的,这带来了很多独特的特性。首先是擦写寿命,通常只有1万到10万次。在做数据存储时,必须考虑磨损均衡。我曾经做过一个需要频繁保存配置的项目,就是用软件实现了简单的均衡算法:

#define FLASH_PAGES    4
#define PAGE_SIZE      2048

uint32_t config_addresses[FLASH_PAGES] = {
    0x08080000, 0x08080800, 0x08081000, 0x08081800
};

static uint8_t current_page = 0;

void save_config(const void* data, size_t size)
{
    // 先擦除下一页
    uint8_t next_page = (current_page + 1) % FLASH_PAGES;
    FLASH_ErasePage(config_addresses[next_page]);
    
    // 写入新数据
    FLASH_ProgramBytes(config_addresses[next_page], data, size);
    
    // 更新当前页
    current_page = next_page;
}

其次是编程速度,Flash的写入速度比RAM慢几个数量级。批量写入时,要尽量凑齐整页数据再操作,避免频繁的小数据写入。

3.2 固件存储与升级方案

OTA升级现在是嵌入式设备的标配功能,但如何设计可靠的升级方案很有讲究。我推荐使用双bank的存储布局,一个bank运行当前固件,另一个bank用于存储新固件。STM32很多型号都支持硬件bank切换,非常方便。

在链接脚本中配置双bank布局:

MEMORY
{
    FLASH (rx)  : ORIGIN = 0x08000000, LENGTH = 128K
    FLASH2 (rx) : ORIGIN = 0x08020000, LENGTH = 128K
    RAM (xrw)   : ORIGIN = 0x20000000, LENGTH = 64K
}

升级流程要包含完整的校验机制,我通常使用CRC32校验整个固件,再加上版本号检查:

typedef struct {
    uint32_t version;
    uint32_t crc32;
    uint32_t size;
    uint8_t  reserved[116]; // 凑齐128字节
} firmware_header_t;

bool verify_firmware(uint32_t address)
{
    firmware_header_t* header = (firmware_header_t*)address;
    uint32_t calculated_crc = calculate_crc32(
        (void*)(address + sizeof(firmware_header_t)),
        header->size
    );
    return (calculated_crc == header->crc32);
}

4. 内存映射与高效数据管理实战

4.1 自定义内存布局优化

默认的内存布局可能不适合特定应用,这时候就需要自定义链接脚本。我曾经做过一个音频处理项目,需要将特定的数据段放在最快的内存中,效果非常明显。

先定义内存区域:

MEMORY
{
    FLASH (rx)  : ORIGIN = 0x08000000, LENGTH = 512K
    DTCM (rwx)  : ORIGIN = 0x20000000, LENGTH = 128K
    SRAM (rwx)  : ORIGIN = 0x24000000, LENGTH = 512K
}

然后精确安排各个段的位置:

SECTIONS
{
    .fast_data : {
        _sfast = .;
        *(.fast_data)
        _efast = .;
    } >DTCM
    
    .audio_buffers : {
        _saudio = .;
        *(.audio_buffers)
        _eaudio = .;
    } >SRAM
}

在代码中指定段位置:

// 将音频缓冲区放在SRAM中
__attribute__((section(".audio_buffers"))) 
int16_t audio_buffer[BUFFER_SIZE];

// 将实时控制变量放在DTCM中
__attribute__((section(".fast_data")))
volatile float control_params[10];

4.2 动态内存管理方案选择

嵌入式系统是否使用动态内存一直有争议。我的经验是:实时性要求高的关键代码用静态分配,其他部分可以适当使用动态内存,但要做好管理。

如果使用标准库的malloc,一定要注意堆大小的设置。更好的方案是使用内存池或自定义分配器:

typedef struct {
    uint8_t* pool;
    size_t total_size;
    size_t used_size;
} memory_pool_t;

void pool_init(memory_pool_t* pool, uint8_t* buffer, size_t size)
{
    pool->pool = buffer;
    pool->total_size = size;
    pool->used_size = 0;
}

void* pool_alloc(memory_pool_t* pool, size_t size)
{
    if (pool->used_size + size > pool->total_size)
        return NULL;
    
    void* ptr = pool->pool + pool->used_size;
    pool->used_size += size;
    return ptr;
}

对于有实时性要求的任务,我建议完全避免动态分配,在系统启动时就分配好所有需要的内存。

5. 低功耗设计中的存储器件优策略

5.1 RAM保持状态下的功耗优化

低功耗设备中,如何降低存储器的功耗很关键。STM32提供了多种低功耗模式,不同的模式对RAM的保护程度不同。

在Stop模式下,可以选择保持全部RAM或部分RAM内容。如果应用只需要保存少量状态数据,选择部分RAM保持能显著降低功耗:

void enter_stop_mode(void)
{
    // 设置需要保持的RAM区域
    __HAL_RCC_GPIOA_CLK_ENABLE();
    HAL_PWREx_EnableRAMRetention(PWR_SRAM1_RETENTION);
    
    // 进入Stop模式
    HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI);
}

测量数据显示,只保持32KB RAM比保持全部128KB RAM的功耗低40%左右。这个优化对电池供电设备特别重要。

5.2 Flash睡眠模式配置

很多人不知道Flash在运行期间也可以配置为低功耗模式。通过设置适当的等待状态和预取策略,能在性能和功耗间取得平衡:

void configure_flash_low_power(void)
{
    FLASH->ACR &= ~FLASH_ACR_LATENCY;
    FLASH->ACR |= FLASH_ACR_LATENCY_2WS; // 2等待状态
    
    // 开启预取指和指令缓存
    FLASH->ACR |= FLASH_ACR_PRFTEN | FLASH_ACR_ICEN;
    
    // 降低Flash功耗
    FLASH->ACR |= FLASH_ACR_RUN_PD;
}

在实际项目中,我通常会在系统空闲时降低Flash性能,需要高性能时再恢复,这样能节省不少功耗。

6. 实战案例:智能手环的存储器设计

去年我参与了一个智能手环项目,硬件平台是STM32L4系列,RAM只有128KB,Flash只有512KB,却要实现运动追踪、心率监测、消息通知等复杂功能。

首先是内存分配规划:我们用了64KB RAM作为数据缓冲区,32KB用于系统堆栈,剩下的32KB留给应用程序。Flash方面,256KB存放固件,128KB用于用户数据存储,64KB作为OTA升级缓冲区,剩下的64KB备用。

数据存储策略上,我们设计了分层存储方案:实时运动数据放RAM中,每分钟汇总一次写入Flash;健康数据采用环形缓冲区存储,最多保存7天数据;系统配置放在单独的Flash页,采用磨损均衡算法。

最棘手的是OTA升级功能,我们实现了双bank切换,确保升级失败也能回退到旧版本。关键代码是这样的:

void jump_to_firmware(uint32_t address)
{
    // 禁用中断
    __disable_irq();
    
    // 设置堆栈指针
    __set_MSP(*(__IO uint32_t*)address);
    
    // 跳转到新固件
    uint32_t jump_address = *(__IO uint32_t*)(address + 4);
    ((void(*)(void))jump_address)();
}

这个项目让我深刻体会到,有限的资源通过精心规划也能完成复杂任务。关键是要理解应用场景,做出合理的权衡取舍。

7. 调试技巧与性能优化建议

干了这么多年嵌入式开发,我总结出一些存储相关的调试经验。首先是内存泄漏的检测,可以在链接脚本中定义调试段:

SECTIONS
{
    .debug_heap (NOLOAD) : {
        . = ALIGN(4);
        _sheap = .;
        . = . + Heap_Size;
        _eheap = .;
    } >RAM
}

然后在代码中定期检查堆的使用情况:

void check_heap_usage(void)
{
    extern uint8_t _sheap, _eheap;
    uint8_t* start = &_sheap;
    uint8_t* end = &_eheap;
    
    size_t total_size = end - start;
    size_t used_size = get_current_heap_size();
    
    printf("Heap usage: %zu/%zu bytes (%.1f%%)\n",
           used_size, total_size,
           (float)used_size/total_size*100);
}

其次是栈溢出检测,可以在栈底放置魔数,定期检查:

#define STACK_MAGIC 0xDEADBEEF

extern uint32_t _estack;
uint32_t* stack_bottom = &_estack;

void stack_check_init(void)
{
    *stack_bottom = STACK_MAGIC;
}

bool is_stack_overflow(void)
{
    return (*stack_bottom != STACK_MAGIC);
}

性能优化方面,我习惯用DWT周期计数器来测量关键代码段的执行时间:

uint32_t start_time, end_time;

start_time = DWT->CYCCNT;
// 执行需要测量的代码
critical_function();
end_time = DWT->CYCCNT;

printf("Execution time: %u cycles\n", end_time - start_time);

这些调试技巧帮我在多个项目中快速定位和解决了存储相关的问题。

记得有次做一个工业控制器,系统偶尔会死机,最后发现是栈溢出导致的。通过魔数检测很快定位了问题,调整栈大小后系统就稳定了。这种问题如果不用合适的工具检测,可能要花好几天才能找到原因。

存储器的优化是个持续的过程,需要结合具体应用不断调整。我习惯在项目初期就预留足够的调试接口,后期优化时事半功倍。每次优化都要测量实际效果,不要凭感觉做决策。

嵌入式存储技术全解析:从RAM、ROM到Flash与NVM的选型与应用 存储器是计算机系统的核心组件,其性能直接影响系统运行效率与数据可靠性。从原理上,存储器主要依据易失性与可写入性进行分类:易失性存储器如RAM,依赖持续电力维持数据,读写速度快,常用于运行内存;非易失性存储器如ROM、Flash、EEPROM,断电后数据仍可保存,适用于程序与数据存储。其中,Flash存储器以其高密度、低成本优势,成为嵌入式系统程序存储与大容量数据存储的主流选择,而EEPROM则因字节级擦写特性,适合保存配置参数等小数据。在嵌入式开发中,理解Nor Flash与NAND Flash的接口差异、 阅读详情

相关推荐

嵌入式系统RAM、ROM与Flash存储介质详解与优化

在嵌入式系统开发中,存储介质的选择与优化直接影响系统性能和可靠性。RAM(随机存取存储器)作为易失性存储器,提供高速数据访问能力,常用于实时数据处理;ROM(只读存储器)存储固化程序,具有高可靠性;Flash存储器则结合了非易失性和可重复编程特性,适用于固件存储。理解这些存储介质的原理与差异,是进行嵌入式系统设计的基础。通过内存映射、空间优化和混合存储架构等技术,可以显著提升系统效率。特别是在STM32等MCU开发中,合理利用RAM和Flash资源,结合LittleFS等文件系统,能够有效管理存储空间,满足

weixin_27869497的博客 349

STM32存储架构解析:RAM与ROM的协同设计原理

本文深入解析STM32存储架构中RAM与ROM的协同设计原理,涵盖内存映射、启动过程、代码执行优化及实战管理技巧。通过分析STM32的存储器特性,帮助开发者优化内存使用,避免栈溢出等常见问题,提升嵌入式系统性能与可靠性。

y4z5a6b7的博客 633

STM32 IAP升级中栈顶地址校验原理与实战解析

在嵌入式系统开发中,内存地址校验是确保程序稳定运行的基础环节,尤其在Bootloader与应用程序切换时至关重要。其核心原理在于验证关键指针是否指向有效的内存区域,以防止因非法内存访问导致的硬件错误。这一技术通过位运算与掩码操作高效实现,在资源受限的微控制器中兼顾了安全性与性能。对于采用Cortex-M内核的STM32系列,片上SRAM通常映射在0x20000000起始的地址空间。IAP(在应用编程)作为固件无线升级的关键技术,在跳转到用户程序前,必须对应用程序映像中的栈顶指针进行合法性校验。本文以STM3

virusswb的专栏 426

嵌入式系统中的数据存储:ROM与RAM如何协同工作?

本文深入解析嵌入式系统中ROM与RAM的协同工作机制,以STM32G431为例,详细阐述Flash与SRAM在代码存储、数据运行中的分工与配合。通过内存管理策略、启动流程优化及实时数据处理案例,帮助开发者提升系统性能和资源利用率,适用于嵌入式竞赛和实际项目开发。

xx56789的博客 198

STM32 Keil5 Debug断点设置操作详解

深入讲解STM32在Keil5debug调试怎么使用过程中的断点设置技巧,涵盖软件断点与硬件断点的配置方法,提升调试效率,帮助开发者精准定位程序运行问题。

weixin_42602726的博客 1111

Keil调试实战:如何用SAVE命令导出STM32内存数据到Excel(附HEX386解析技巧)

本文详细介绍了在Keil调试环境中,如何使用SAVE命令将STM32内存数据导出为HEX386格式文件,并提供了多种解析技巧以将数据导入Excel进行可视化分析。文章重点解析了HEX386格式结构,并分享了手动处理、Python脚本自动化以及MATLAB解析三种实用方法,帮助开发者高效完成从内存导出到数据分析的全流程。

transformer2023的博客 1137

ROM LIB

本文介绍了ROM库在嵌入式系统中的实现方法,以STM32L432为例详细说明了如何生成和使用ROM库。主要内容包括:存储器资源规划(56KB FLASH和16KB RAM2)、ROM库的链接脚本配置(定义.text、.data和.bss段)、源代码实现(使用特殊属性标记ROM代码和数据)以及测试验证过程。通过分析.map文件验证了内存分配与预期一致,展示了ROM库函数调用和数据访问的方法。该技术可用于优化嵌入式系统资源利用,将稳定功能模块固化在ROM中执行。

老Z先生的博客 1121

STM32 USB下载程序全攻略:从DFU/HID原理到CubeProgrammer实战

在嵌入式开发中,固件升级是连接软件与硬件、开发与部署的关键环节。其核心原理在于通过特定的通信协议,将编译后的程序代码安全、可靠地写入微控制器的非易失性存储器中。这项技术对于产品的迭代更新、现场维护和用户体验至关重要。从早期的串口ISP到现代的USB接口,固件升级方式在不断演进,旨在追求更高的速度、更低的硬件成本和更便捷的操作体验。其中,利用微控制器内置的USB接口进行程序下载,因其硬件普及性高、传输速率快,已成为一种极具价值的技术方案。本文将聚焦于STM32系列MCU,深入解析如何利用其内置的ROM Boo

weixin_30420305的博客 374

嵌入式内存管理全解析:从ROM、RAM到Linux虚拟内存与优化实战

内存是计算机系统的核心组件,负责程序与数据的存储与交换。其工作原理基于物理存储介质与地址映射,通过高效管理直接影响系统性能与稳定性。在嵌入式开发领域,内存优化具有极高的技术价值,能有效降低硬件成本、提升能效并保障系统可靠运行。应用场景广泛覆盖从单片机实时系统到嵌入式Linux的复杂设备,涉及启动代码、动态分配、缓存策略及多进程协同等关键环节。本文聚焦**嵌入式内存**的深度剖析,结合**内存泄露**等典型问题,系统阐述从物理介质特性到软件层管理的完整知识体系与工程实践方法。

weixin_30628801的博客 404

C语言与STM32的内存结构解析

嵌入式开发中,内存管理是关键环节。C语言在运行时将内存划分为栈区(函数调用相关)、堆区(动态分配)、全局区(静态变量)、常量区(只读数据)和代码区(指令存储)。STM32系列MCU采用哈佛结构,程序和数据存储器分离,Flash存储代码和常量,SRAM存储栈、堆和全局变量。通过STM32F103实验验证,栈变量地址从高向低增长,堆地址逐步上升,全局变量位于RAM起始区域,常量和代码位于Flash中。理解内存分区机制有助于优化内存布局,提升程序健壮性。

硬核科技 929

STM32模拟曲射电磁炮电子设计大赛项目解析

随着现代军事技术的发展,电磁炮作为一种先进的动能武器,其研发和应用日益受到全球关注。与传统火炮相比,电磁炮以其发射初速高、射程远、精度高、无污染等优势,在未来海陆空战争中显示出巨大的潜在价值。

weixin_42629522的博客 885

告别Flash等待:手把手教你将STM32程序下载到RAM中调试(Keil5实战)

本文详细介绍了如何在Keil5环境下将STM32程序下载到RAM中进行高效调试,显著提升开发效率。通过对比Flash与RAM的性能差异,解析RAM调试的底层原理,并提供STM32F103C8T6的实战配置步骤,帮助开发者实现毫秒级下载和实时断点响应。文章还涵盖了内存布局优化、常见问题解决及高级调试技巧,是提升嵌入式开发效率的实用指南。

weixin_33671935的博客 263

【项目实战-MATLAB】:基于机器学习的虹膜识别系统设计

虹膜识别主要包括虹膜定位、虹膜裁剪、极坐标变换、归一化、HOG特征提取、虹膜识别六个主要步骤。本系统采用MATLAB作为开发工具实现 主要算法:霍夫变换预处理 HOG特征提取 SVM进行识别

qq_45047246的博客 6537

嵌入式内存管理全解析:从ROM/RAM到DDR与内存泄漏实战

内存是计算机系统的核心组件,负责程序与数据的存储与高速访问。其工作原理基于地址总线寻址与数据总线传输,CPU通过内存控制器与各类存储介质交互。在嵌入式系统中,高效的内存管理直接决定了系统的稳定性、实时性与能效,是保障复杂功能可靠运行的技术基石。应用场景涵盖从低功耗单片机到高性能多核处理器的各类电子设备,尤其在物联网终端、工业控制和消费电子等领域至关重要。本文聚焦嵌入式开发中的内存实战,深入剖析ROM与RAM的选型、DDR硬件设计难点、链接脚本的内存映射原理,并针对内存泄漏、栈溢出等工程常见问题,提供诊断工具

weixin_30764771的博客 350

华为云Stack 8.X 流量模型分析(一)

​ 当内部需要提供对外服务时(如对外发布Web网站),外部地址发起主动连接,由路由器或者防火墙上的网关接收这个连接,然后将连接转换到内部,此过程是由带有公网IP的网关替代内部服务来接收外部的连接,然后在内部做地址转换,此转换称为DNAT,主要用于内部服务对外发布。​ 内部地址要访问公网上的服务时(如Web访问),内部地址会主动发起连接,由路由器或者防火墙上的网关对内部地址做个地址转换,将内部地址的私有IP转换为公网的公有IP,网关的这个地址转换称为SNAT,主要用于内部共享IP访问外部。

Ciyaso的博客 3244

【一起学UniGUI】--UniGUI的部署选项(5)

uniGUI支持Windows平台下所有主要部署选项。 1.Standalone Server (独立服务器) 最简单的部署方法是独立服务器。在这种模式下,应用程序服务器像桌面应用程序一样直接运行。它也是用于调试应用程序的模式。运行应用程序可执行文件后(它是一个EXE文件),它将最小化到托盘图标,并运行到用户手动终止为止。见下图: 一个独立的应用程序可以...

5777

从零到Offer:嵌入式开发必学的STM32+C组合拳

在嵌入式开发领域,STM32 微控制器和 C 语言的组合堪称经典,是众多企业招聘时极为看重的技能组合。STM32 以其高性能、低功耗、丰富的外设等特点,成为嵌入式开发的热门选择;而 C 语言作为一种高效、灵活且可移植性强的编程语言,是开发 STM32 项目的首选语言。掌握 STM32+C 的开发技能,能让你在嵌入式开发的求职之路上脱颖而出,顺利拿到心仪的 Offer。本文将详细介绍从零开始学习 STM32+C 开发的必学内容和步骤。

星辰夜语的博客 1002

VCS的增量和分离编译

vcs的增量和分离编译

yunduor909的博客 3302

嵌入式内存管理全解析:从ROM、RAM到DDR,实战避坑与性能优化

内存管理是嵌入式系统开发的基石,深刻理解其概念与原理是构建稳定高效系统的关键。从基础层面看,内存主要分为ROM(如Flash、EEPROM)和RAM(如SRAM、DRAM),前者用于存储非易失性代码与数据,后者作为程序运行的临时工作区。其核心原理在于通过链接脚本进行内存映射,将代码段、数据段、堆栈等合理分配到物理地址空间。在资源受限的嵌入式环境中,有效的内存管理技术价值巨大,它直接决定了系统的稳定性、实时性与功耗。应用场景广泛,从单片机的串口缓冲区栈溢出,到运行Linux的SoC中DDR训练失败导致的系统不

weixin_30323631的博客 348

单片机技术入门与实战:从零基础到项目开发

单片机(MCU)作为嵌入式系统的核心组件,集成了CPU、内存和各种接口电路,广泛应用于智能家居、工业控制和汽车电子等领域。其工作原理基于实时控制和低功耗设计,通过定时器、中断系统和通信接口等功能模块实现各种控制任务。在物联网和智能硬件快速发展的背景下,掌握单片机开发技术成为电子工程师的重要技能。本文以STM32和PIC系列为例,详细解析单片机的基本概念、功能模块和选型指南,并分享从入门到项目实战的系统学习方法,帮助开发者在3-6个月内快速掌握这一关键技术。

weixin_35753291的博客 652

新手必看!手把手教你在群晖 NAS 上玩转 Docker 容器(Container Manager)!(群晖 NAS 如何创建 Docker 容器以及 Compose 部署项目)

新手必看!手把手教你在群晖 NAS 上玩转 Docker 容器(Container Manager)!(群晖 NAS 如何创建 Docker 容器以及 Compose 部署项目)

XiaoqiangClub的博客 5162

告别拷贝机器码:在Keil/IAR中,如何优雅地将STM32 Flash操作函数链接到RAM执行?

本文详细介绍了在Keil/IAR环境下,如何通过链接脚本自动重定位技术将STM32/GD32的Flash操作函数优雅地链接到RAM执行,解决Flash操作冲突问题。文章提供了具体的实现步骤和工程实践技巧,适用于BootLoader和固件升级场景,提升嵌入式开发效率。

weixin_30587927的博客 358

Isaac Lab 强化学习全身控制策略 Sim2Real 宇树人形机器人训练部署 HOVER

《IsaacLab策略训练与部署指南》提供了在仿真和真实机器人上实现HOVER全身控制策略的完整流程。主要内容包括:1) Linux环境下的IsaacLab安装与HOVER资源库配置;2) 使用1024个并行环境训练教师/学生策略的详细步骤;3) 策略测试与评估方法;4) Sim2Sim仿真验证和Sim2Real真实机器人部署方案。本教程特别针对Unitree H1仿人机器人,包含运动数据准备、策略训练、性能评估到硬件部署的全链条实现方案,为机器人控制策略开发提供标准化参考框架。

机器人控制与仿真应用 3070

STM32之LWIP网络通讯设计介绍(十四)

一般对于许多嵌入式系统或单片机,在其资源受限的环境下,要想实现网络通讯,并保证资源的高效利用和稳定的网络通信,我们一般采用一种轻量级的网络协议lwIP。TI公司的STM32芯片一般都会自带一路以太网口,用于网络通讯,但因其内存资源受限,所以都用采用一种小型化、轻量级的lwIP网络协议,只需十几KB的RAM和大约40K的ROM即可运行,既可以在无操作系统环境下工作,也可以与各种操作系统配合使用,使其成为资源受限的嵌入式系统的理想选择。一般市场上所卖的板子都带这一功能的,需准备 开发板一块和网线一根。

weixin_47006346的博客 2667

Arduino开发实例-EMG 肌肉信号传感器

在医学研究中,测量肌肉的活动、收缩和扩张非常重要。 EMG 肌肉传感器测量肌肉活动并产生信号以显示扩张和收缩量。 因此,输出取决于所选肌肉的活动量。 3 绿色、红色和黄色电极连接到模块,用于传输来自肌肉运动的电信号。

视觉与物联智能 1698

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

上一篇: STM32 SPI通信:从软件模拟到硬件外设的实战解析
下一篇: 从寄存器到库函数:深入解析STM32 GPIO翻转的底层逻辑与性能差异
gitlab7runner
博客等级 码龄4年 78粉丝 1747原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值