首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >【CMake】使用 SDCC 构建 8051 工程并生成 HEX 文件

【CMake】使用 SDCC 构建 8051 工程并生成 HEX 文件

作者头像
LuckiBit
发布2025-08-15 08:44:24
发布2025-08-15 08:44:24
11300
代码可运行
举报
文章被收录于专栏:C语言C语言
运行总次数:0
代码可运行

本文将介绍如何使用 SDCC + CMake 构建一个适用于 STC8 系列(8051 架构)MCU 的嵌入式工程,从软件准备到最终生成 .hex 文件,适合初学者逐步上手。

📌 一、前提条件

1. 目标平台
  • 架构:8051 架构(如 STC8H、STC89 等)
  • 芯片:STC8 系列(如 STC8H1K08T)
2. 操作系统支持
  • ✅ Windows 10/11(需安装 MinGW)
  • ✅ Linux(如 Ubuntu/Debian)
  • ✅ macOS
3. 必备软件工具

工具

作用

要求

SDCC

编译器,支持 8051

添加到系统 PATH

CMake(3.15+)

构建系统生成工具

必须安装

make / ninja

构建执行器

Windows 推荐 MinGW 的 make,或 ninja

VSCode / Neovim

编辑器,任选其一

推荐带 C 插件支持


📂 二、项目目录结构

工程根目录形如:

代码语言:javascript
代码运行次数:0
运行
复制
your-project/
├── CMakeLists.txt         # CMake 配置文件(顶层构建脚本)
├── README.md              # 项目说明文档
│
├── build/                 # 构建输出目录(由 CMake 自动生成)
│   └── MySDCCProject.hex  # 最终生成的十六进制固件文件
│
├── cmake/                 # 自定义 CMake 脚本目录
│   └── convert_hex.cmake  # 用于将 .ihx 转换为 .hex 的脚本
│
├── include/               # 公共头文件目录
│   ├── delay.h            # 延时函数头文件
│   └── stc8h.h            # STC8H 寄存器定义头文件
│
└── src/                   # 源代码目录
    ├── delay.c            # 延时函数实现
    └── main.c             # 主程序,控制 LED 闪烁

🛠️ 三、代码说明

src/main.c
代码语言:javascript
代码运行次数:0
运行
复制
#include "stc8h.h"
#include "delay.h"

void main(void)
{
    P1M0 = 0x01;  // Set P1.0 as push-pull output mode
    P1M1 = 0x00;

    while(1)
    {
        P10 ^= 0x01;
        delay_ms(500);
    }
}
src/delay.c
代码语言:javascript
代码运行次数:0
运行
复制
void delay_ms(unsigned int ms) {
    volatile unsigned int i, j;
    for (i = 0; i < ms; i++)
    {
        for (j = 0; j < 123; j++);
    }
}
include/delay.h
代码语言:javascript
代码运行次数:0
运行
复制
#ifndef DELAY_H
#define DELAY_H

void delay_ms(unsigned int ms);

#endif
include/stc8h.h
在这里插入图片描述
在这里插入图片描述

打开STC-ISP软件,选择头文件,选择SDCC格式,复制代码即可。


⚙️ 四、构建系统:CMake

本项目使用 CMake 构建系统来组织源代码、配置编译器(如 SDCC)、管理构建过程,并生成最终的十六进制(.hex)固件文件。整个构建过程高度自动化,便于在不同平台下统一使用命令行进行构建。

1. CMakeLists.txt

这个文件是 CMake 的核心配置脚本,用于定义整个项目的构建逻辑。主要完成了以下几件事:

  • 检测 SDCC 编译器:自动查找或手动指定 SDCC 的路径,确保可以调用 sdcc 进行编译。
  • 设置包含目录和源码文件:添加 include/src/ 目录下的相关文件。
  • 编译 .c.rel 文件:为每个源文件生成中间目标文件。
  • 链接为 .ihx 文件:将多个 .rel 链接为 SDCC 的 Intel HEX 格式文件(.ihx)。
  • 调用脚本生成 .hex 文件:调用自定义 CMake 脚本 convert_hex.cmake 进行 .ihx → .hex 转换。

文件内容示例:

代码语言:javascript
代码运行次数:0
运行
复制
# CMakeLists.txt
cmake_minimum_required(VERSION 3.15)
project(MySDCCProject NONE)

# === Step 1: Find SDCC ===
if(NOT DEFINED SDCC_PATH)
    find_program(SDCC_EXECUTABLE sdcc)
    if(SDCC_EXECUTABLE)
        get_filename_component(SDCC_BIN_DIR "${SDCC_EXECUTABLE}" DIRECTORY)
        if(WIN32)
            get_filename_component(SDCC_ROOT "${SDCC_BIN_DIR}/.." ABSOLUTE)
            set(SDCC_PATH "${SDCC_ROOT}/bin")
            set(SDCC_INCLUDE_PATH "${SDCC_ROOT}/include")
        else()
            set(SDCC_PATH "${SDCC_BIN_DIR}")
            if(APPLE)
                set(SDCC_INCLUDE_PATH "/usr/local/share/sdcc/include")
            else()
                set(SDCC_INCLUDE_PATH "/usr/share/sdcc/include")
            endif()
        endif()
    else()
        message(FATAL_ERROR "SDCC not found. Please install SDCC or set -DSDCC_PATH manually.")
    endif()
else()
    if(NOT IS_ABSOLUTE "${SDCC_PATH}")
        set(SDCC_PATH "${CMAKE_SOURCE_DIR}/${SDCC_PATH}")
    endif()
    if(NOT DEFINED SDCC_INCLUDE_PATH)
        if(WIN32)
            set(SDCC_INCLUDE_PATH "${SDCC_PATH}/../include")
        elseif(APPLE)
            set(SDCC_INCLUDE_PATH "/usr/local/share/sdcc/include")
        else()
            set(SDCC_INCLUDE_PATH "/usr/share/sdcc/include")
        endif()
    endif()
endif()

file(TO_CMAKE_PATH "${SDCC_PATH}" SDCC_PATH)
file(TO_CMAKE_PATH "${SDCC_INCLUDE_PATH}" SDCC_INCLUDE_PATH)

if(NOT EXISTS "${SDCC_PATH}/sdcc" AND NOT EXISTS "${SDCC_PATH}/sdcc.exe")
    message(FATAL_ERROR "SDCC executable not found at ${SDCC_PATH}")
endif()

message(STATUS "Using SDCC from: ${SDCC_PATH}")
message(STATUS "Using SDCC include: ${SDCC_INCLUDE_PATH}")

# === Step 2: Include paths ===
include_directories(${SDCC_INCLUDE_PATH} ${CMAKE_SOURCE_DIR}/include)

# === Step 3: Source files ===
set(SRC_DIR ${CMAKE_SOURCE_DIR}/src)
set(SRC_FILES
    ${SRC_DIR}/main.c
    ${SRC_DIR}/delay.c
)

# === Step 4: Compile .c to .rel ===
set(REL_FILES "")
foreach(SRC_FILE ${SRC_FILES})
    get_filename_component(FILE_NAME ${SRC_FILE} NAME_WE)
    set(REL_FILE "${CMAKE_CURRENT_BINARY_DIR}/${FILE_NAME}.rel")

    if(FILE_NAME STREQUAL "main")
        set(MAIN_REL ${REL_FILE})
    else()
        list(APPEND REL_FILES ${REL_FILE})
    endif()

    add_custom_command(
        OUTPUT ${REL_FILE}
        COMMAND ${SDCC_PATH}/sdcc
            -mmcs51
            --std-c99
            --opt-code-size
            --debug
            -I${SDCC_INCLUDE_PATH}
            -I${CMAKE_SOURCE_DIR}/include
            -c ${SRC_FILE}
        DEPENDS ${SRC_FILE}
        COMMENT "[Compiling] ${FILE_NAME}.c -> ${FILE_NAME}.rel"
        VERBATIM
    )
endforeach()

# === Step 5: Link to .ihx ===
set(IHX_FILE main.ihx)
add_custom_command(
    OUTPUT ${IHX_FILE}
    COMMAND ${SDCC_PATH}/sdcc
        -mmcs51
        --std-c99
        --opt-code-size
        --debug
        ${MAIN_REL} ${REL_FILES}
    DEPENDS ${MAIN_REL} ${REL_FILES}
    COMMENT "[Linking] .rel files -> ${IHX_FILE}"
    VERBATIM
)

# === Step 6: Convert IHX to HEX ===
set(HEX_FILE ${PROJECT_NAME}.hex)
add_custom_command(
    OUTPUT ${HEX_FILE}
    COMMAND ${CMAKE_COMMAND}
        -DINPUT=${IHX_FILE}
        -DOUTPUT=${HEX_FILE}
        -DSDCC_PATH=${SDCC_PATH}
        -P ${CMAKE_SOURCE_DIR}/cmake/convert_hex.cmake
    DEPENDS ${IHX_FILE}
    COMMENT "[Post] Converting ${IHX_FILE} -> ${HEX_FILE}"
)

# === Step 7: Final build target ===
add_custom_target(${PROJECT_NAME} ALL
    DEPENDS ${HEX_FILE}
    COMMENT "[Target] Building project: ${PROJECT_NAME}"
)

2. convert_hex.cmake

这是一个自定义的 CMake 脚本,用于在构建过程的最后一步,将 SDCC 生成的 .ihx 文件转换为 .hex 文件。使用的是 SDCC 自带的 packihx 工具。

该脚本主要做了什么:

  • 接收输入 .ihx 文件路径和输出 .hex 文件路径。
  • 调用 SDCC 提供的 packihx 工具进行格式转换。
  • 生成适用于烧录或仿真的 .hex 固件文件。

文件内容示例:

代码语言:javascript
代码运行次数:0
运行
复制
# convert_hex.cmake
cmake_minimum_required(VERSION 3.10)

# === Validate Required Variables ===
if(NOT DEFINED INPUT OR NOT DEFINED OUTPUT)
    message(FATAL_ERROR "Missing required variables: INPUT or OUTPUT")
endif()

# === Normalize Paths to Absolute ===
get_filename_component(INPUT "${INPUT}" ABSOLUTE)
get_filename_component(OUTPUT "${OUTPUT}" ABSOLUTE)

# === Validate Input File Existence ===
if(NOT EXISTS "${INPUT}")
    message(FATAL_ERROR "Input file not found: ${INPUT}")
endif()

# === Find packihx ===
if(DEFINED SDCC_PATH)
    find_program(PACKIHX_EXECUTABLE packihx PATHS "${SDCC_PATH}" NO_DEFAULT_PATH)
else()
    find_program(PACKIHX_EXECUTABLE packihx)
endif()

if(NOT PACKIHX_EXECUTABLE)
    message(FATAL_ERROR "Could not find 'packihx'. Please set SDCC_PATH or ensure it is in the system PATH.")
endif()

# === Logging (Optional Debug Info) ===
message(STATUS "Converting IHX to HEX")
message(STATUS "Input IHX: ${INPUT}")
message(STATUS "Output HEX: ${OUTPUT}")
message(STATUS "Using packihx: ${PACKIHX_EXECUTABLE}")

# === Execute Conversion ===
execute_process(
    COMMAND "${PACKIHX_EXECUTABLE}" "${INPUT}"
    OUTPUT_FILE "${OUTPUT}"
    RESULT_VARIABLE result
    WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
    ERROR_VARIABLE error_output
)

# === Handle Result ===
if(NOT result EQUAL 0)
    message(FATAL_ERROR "packihx failed with exit code: ${result}\nError output:\n${error_output}")
else()
    message(STATUS "Successfully generated HEX file: ${OUTPUT}")
endif()

🧱 五、编译步骤

1. Windows

确保你已经将 SDCC 和 MinGW 的路径添加到系统环境变量 PATH 中。

代码语言:javascript
代码运行次数:0
运行
复制
cmake -B build -G "MinGW Makefiles" -DSDCC_PATH="D:/sdcc/bin"
cmake --build build
2. Linux/macOS
代码语言:javascript
代码运行次数:0
运行
复制
cmake -B build -G "Unix Makefiles" -DSDCC_PATH="/usr/bin"
cmake --build build
3. Ninja(可选构建器)
代码语言:javascript
代码运行次数:0
运行
复制
cmake -B build -G "Ninja" -DSDCC_PATH="..."
cmake --build build

📦 六、生成结果

在项目完成构建后,系统会自动生成一个可用于烧录的十六进制固件文件(.hex)。这个文件是通过以下几个步骤生成的:

构建命令(以 Ninja 为例)
代码语言:javascript
代码运行次数:0
运行
复制
cmake -B build -G "Ninja"
cmake --build build
实际构建输出示例:
代码语言:javascript
代码运行次数:0
运行
复制
PS D:\B> cmake -B build -G "Ninja"
-- Using SDCC from: D:/sdcc/bin
-- Using SDCC include: D:/sdcc/include
-- Configuring done (0.3s)
-- Generating done (0.1s)
-- Build files have been written to: D:/B/build
PS D:\B> cmake --build build
[4/4] [Post] Converting main.ihx -> MySDCCProject.hex
-- Converting IHX to HEX
-- Input IHX: D:/B/build/main.ihx
-- Output HEX: D:/B/build/MySDCCProject.hex
-- Using packihx: D:/sdcc/bin/packihx.exe
-- Successfully generated HEX file: D:/B/build/MySDCCProject.hex
构建流程说明:
  • CMake 调用 SDCC(Small Device C Compiler)将 .c 源文件编译为 .rel 文件。
  • 随后,.rel 文件被链接生成 .ihx(Intel Hex)格式中间文件。
  • 通过 SDCC 附带的 packihx 工具将 .ihx 转换为标准的 .hex 文件。
  • .hex 文件即为可烧录到 MCU 的最终固件。
输出路径:
代码语言:javascript
代码运行次数:0
运行
复制
build/MySDCCProject.hex

你可以使用如 STC-ISP 工具,将该 .hex 文件烧录到你的 STC8H 单片机中。


🔥 七、烧录说明(简要)

  • 使用 STC-ISP 软件,将 .hex 文件写入 STC8 系列 MCU
  • 通信端口通常为串口(需连接 USB 转串口模块)

✅ 八、知识建议

为更好地理解该项目,建议掌握以下知识:

类别

推荐学习内容

C语言基础

函数、变量、循环、头文件

嵌入式入门

GPIO 控制、MCU 时序

Makefile / CMake

编译流程、构建系统基础

SDCC

编译参数、优化选项

8051架构

I/O 控制、寄存器操作(如 P1M0, P10)

📚 参考资源

🧩 结语

这个项目提供了一个完整的、可跨平台构建的 SDCC 工程模板,适合用于 STC8 系列 MCU 的学习与实践。使用现代工具链(如 CMake)可以大幅提高开发效率,也利于自动化部署与集成。

如果你刚开始学习 8051 嵌入式开发,本项目是一个非常好的起点。

  1. 本节内容已经全部介绍完毕,希望通过这篇文章,大家对 sdcc 有了更深入的理解和认识。
  2. 感谢各位的阅读和支持,如果觉得这篇文章对你有帮助,请不要吝惜你的点赞和评论,这对我们非常重要。
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-08-07,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 📌 一、前提条件
    • 1. 目标平台
    • 2. 操作系统支持
    • 3. 必备软件工具
  • 📂 二、项目目录结构
  • 🛠️ 三、代码说明
    • src/main.c
    • src/delay.c
    • include/delay.h
    • include/stc8h.h
  • ⚙️ 四、构建系统:CMake
    • 1. CMakeLists.txt
    • 2. convert_hex.cmake
  • 🧱 五、编译步骤
    • 1. Windows
    • 2. Linux/macOS
    • 3. Ninja(可选构建器)
  • 📦 六、生成结果
    • 构建命令(以 Ninja 为例)
    • 实际构建输出示例:
    • 构建流程说明:
    • 输出路径:
  • 🔥 七、烧录说明(简要)
  • ✅ 八、知识建议
  • 🧩 结语
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档