1. 寄存器基础与开发环境搭建

各位同学,欢迎来到这门实战课程。第一节课,咱们不急着写代码,先把地基打牢。

寄存器到底是什么?说白了,它就是单片机内部一个个“开关”和“数值存储格”。你往某个地址写个1,引脚就输出高电平;你改另一个寄存器的值,定时器就开始计数。我当年刚接触单片机时,总觉得寄存器很神秘,后来发现——它就是芯片设计者留给我们的“控制面板”。

1.1 寄存器的本质:你与硬件对话的窗口

每个寄存器都有固定的地址,比如STM32F103的GPIOA_ODR寄存器地址是0x4001080C。你往这个地址写数据,就能控制PA0~PA15的电平。

核心概念:寄存器 = 地址 + 位定义。你操作的是地址,影响的是硬件。

举个例子,点亮LED通常需要两步:

  1. 配置模式:把GPIO引脚设为推挽输出(修改CRL或CRH寄存器)
  2. 输出电平:往ODR寄存器写1或0

我见过不少新手直接调用库函数,出了问题根本不知道从哪查。你想想看,如果你能直接读懂寄存器手册,定位问题会快多少?

1.2 开发板选型:别贪多,够用就好

本课程选用STM32F103C8T6(蓝色 pill 板)作为主控。为什么选它?

  • 价格便宜,几十块钱就能买到
  • 资源丰富:72MHz主频、20KB RAM、64KB Flash
  • 外设齐全:定时器、ADC、USART、SPI、I2C全都有
  • 社区资料多,遇到问题好查
外设 数量 本课程用途
GPIO 37个 LED控制、按键输入
定时器 3个通用+1个高级 PWM输出
USART 3个 串口通信
ADC 2个(10通道) 模拟量采集

我的建议:如果你手头有其他开发板,比如GD32、AT32,原理一样,只是寄存器地址不同。先拿手头的板子跑通,再换型号也不迟。

1.3 开发环境安装:Keil MDK 与 IAR

我个人习惯用Keil MDK,但IAR也有它的优势。咱们两个都讲,你选一个就行。

Keil MDK 安装步骤

  1. 从ARM官网下载MDK-Arm(5.36以上版本)
  2. 安装时选择默认路径,注意勾选“添加环境变量”
  3. 安装对应芯片的器件包(Keil.STM32F1xx_DFP)
  4. 破解(你懂的,但请支持正版)

IAR EWARM 安装步骤

  1. 下载IAR Embedded Workbench for ARM
  2. 安装时选择“Full Installation”
  3. 导入STM32F1的器件描述文件
  4. 配置许可证(试用版30天)

避坑指南:我曾经在Win10上装Keil 4,结果死活识别不了调试器。后来发现是驱动签名问题。建议用Keil 5.38以上版本,Win10/Win11都兼容。

1.4 第一个寄存器工程:点亮LED

咱们直接上手。新建一个Keil工程,选择STM32F103C8,然后写代码。

先看硬件连接:LED接在PC13(高电平点亮)。

// 寄存器方式点亮LED
// 文件: main.c

// 外设基地址
#define PERIPH_BASE       ((unsigned int)0x40000000)
#define APB2PERIPH_BASE   (PERIPH_BASE + 0x10000)
#define GPIOC_BASE        (APB2PERIPH_BASE + 0x1000)

// 寄存器偏移
#define GPIOC_CRH         (*(volatile unsigned int *)(GPIOC_BASE + 0x04))
#define GPIOC_ODR         (*(volatile unsigned int *)(GPIOC_BASE + 0x0C))

// RCC寄存器
#define RCC_BASE          (APB2PERIPH_BASE + 0x1000 - 0x1000)  // 0x40021000
#define RCC_APB2ENR       (*(volatile unsigned int *)(RCC_BASE + 0x18))

int main(void)
{
    // 1. 使能GPIOC时钟
    RCC_APB2ENR |= (1 << 4);   // 位4:IOPCEN
    
    // 2. 配置PC13为推挽输出(CRH的位20~23)
    GPIOC_CRH &= ~(0xF << 20); // 先清零
    GPIOC_CRH |= (0x3 << 20);  // 设置CNF=00, MODE=11(输出50MHz)
    
    // 3. 输出高电平
    GPIOC_ODR |= (1 << 13);    // PC13输出1
    
    while(1)
    {
        // 空循环
    }
}

这段代码做了三件事:开时钟、配模式、写电平。每一步都对应一个寄存器操作。

关键点:volatile关键字不能少。它告诉编译器,这个变量的值可能被硬件修改,不要优化掉。我见过有人忘了加,结果调试了一下午。

1.5 知识结构图:寄存器操作全流程

下面这张图帮你理清思路:从芯片手册到代码实现,每一步都离不开寄存器。

寄存器操作全流程 寄存器操作全流程 芯片参考手册 查找外设基地址 确定寄存器偏移地址 解析位定义(置位/清零) C代码实现(volatile) 常见问题 • 忘记使能时钟 • 位操作写错掩码 • 漏掉volatile 调试技巧 • 用Watch窗口看寄存器值 • 单步执行验证每一步 • 对比手册位定义

1.6 调试与故障定位:从寄存器值反推问题

代码写完了,下载到板子上,灯不亮。怎么办?

我的调试步骤:

  1. 检查时钟:在调试器里看RCC_APB2ENR寄存器的位4是不是1
  2. 检查模式:看GPIOC_CRH的位20~23是不是0x3
  3. 检查电平:看GPIOC_ODR的位13是不是1
  4. 检查硬件:用万用表量PC13引脚电压

小技巧:Keil的Watch窗口可以直接输入寄存器地址查看值。比如输入 *(unsigned int*)0x40011004 就能看到CRH寄存器的值。我调试时经常这么干,比看变量方便多了。