微控制器技术(MSP430)期末复习文档


2. C 语言位运算符在 MSP430 中的含义

2.1 四种基本位运算符

运算符 名称 运算规则 MSP430 最常见用法
& 按位与(AND) 两位都为 1,结果才为 1 读状态、清位(配合 ~)
| 按位或(OR) 只要有一位为 1,结果就为 1 置位、合并标志
^ 按位异或(XOR) 两位不同结果才为 1 翻转位(toggle)
~ 按位取反(NOT) 1 变 0,0 变 1 构造掩码,用于清位

2.2 术语对照

  • 置位(Set) → 将某位设为 1 → 使用 |
  • 清位 / 清零(Clear) → 将某位设为 0 → 使用 & ~

2.3 四种运算符详解

2.3.1 & — 按位与(Bitwise AND)

规则: 两位都为 1,结果才为 1。

MSP430 典型用途:

  • 读取某一位的状态(屏蔽不关心的位)
  • 清除特定位(和 ~ 配合使用)
1
2
3
4
5
6
7
// 读取 P1IN 的第 3 位(按键状态)
if (P1IN & BIT3) {
// 按键未按下(上拉时)
}

// 清除 P1OUT 的第 0 位(LED 灭)
P1OUT &= ~BIT0; // 等效于 P1OUT = P1OUT & (~BIT0)

2.3.2 | — 按位或(Bitwise OR)

规则: 只要有一位为 1,结果就为 1。

MSP430 典型用途:

  • 设置某一位为 1(置位)
  • 合并多个标志位
1
2
3
4
5
6
7
8
// 设置 P1OUT 的第 0 位(LED 亮)
P1OUT |= BIT0; // 等效于 P1OUT = P1OUT | BIT0

// 同时设置第 0 位和第 6 位
P1OUT |= (BIT0 | BIT6);

// 配置引脚为输出
P1DIR |= BIT0; // P1.0 设为输出

2.3.3 ^ — 按位异或(Bitwise XOR)

规则: 两位不同,结果才为 1。(相同为 0,不同为 1)

MSP430 典型用途:

  • 翻转特定位(toggle)
1
2
// 翻转 P1OUT 的第 0 位(LED 状态取反)
P1OUT ^= BIT0; // 每执行一次,LED 亮/灭切换

2.3.4 ~ — 按位取反(Bitwise NOT)

规则: 1 变 0,0 变 1(求反码)。

MSP430 典型用途:

  • 和 & 配合,清除特定位
1
2
// 清除 P1OUT 的第 0 位
P1OUT &= ~BIT0; // ~BIT0 使第 0 位为 0,其他位为 1,然后 & 只清除第 0 位

2.4 BITx 宏说明

MSP430 头文件(如 msp430f5529.h)中预定义了 BIT0~`BIT7、BITF` 等宏,本质就是位移运算的结果,方便直接和位运算符配合操作寄存器:

1
2
3
4
5
6
7
8
#define BIT0   (1 << 0)   // 0x01 = 0000 0001
#define BIT1 (1 << 1) // 0x02 = 0000 0010
#define BIT2 (1 << 2) // 0x04 = 0000 0100
#define BIT3 (1 << 3) // 0x08 = 0000 1000
#define BIT4 (1 << 4) // 0x10 = 0001 0000
#define BIT5 (1 << 5) // 0x20 = 0010 0000
#define BIT6 (1 << 6) // 0x40 = 0100 0000
#define BIT7 (1 << 7) // 0x80 = 1000 0000

2.5 常见操作模式速查

操作 写法 说明
置位(某位置 1) REG |= BITx 不影响其他位
清位(某位置 0) REG &= ~BITx 不影响其他位
翻转(某位取反) REG ^= BITx 不影响其他位
读取某位 if (REG & BITx) 判断该位是否为 1
多位同时置位 REG |= (BIT0 | BIT3 | BIT7) 同时置多个位
多位同时清位 REG &= ~(BIT0 | BIT3 | BIT7) 同时清多个位

3. MSP430 单片机 CPU 与存储器——MSP430F5529 系列单片机的中央处理器

本课程考试内容基于 MSP430F5529 平台。

3.1 概述

MSP430F5529 采用 16 位 RISC 架构,属于德州仪器 MSP430 系列中的高性能型号。其 CPU 拥有七大核心特征:精简指令集与正交架构、丰富寄存器资源、单周期寄存器操作、20 位地址总线、16 位数据总线、直接的存储器到存储器访问、字节/字/20 位三种操作方式。


3.2 存储器结构

待补充


3.3 CPU 核心特征

3.3.1 精简指令集(RISC)& 正交架构

RISC(Reduced Instruction Set Computer) 意味着:

  • 指令数量少,指令格式规整、长度一致
  • 大多数指令可在单周期内执行
  • 硬件设计简化,功耗极低

正交架构(Orthogonal Architecture) 意味着:

  • 所有指令可以应用于任意寻址方式
  • 源操作数和目的操作数地位平等,可以使用同样的寻址模式
  • 编程灵活,规则统一,没有”这条指令只能用这种寻址方式”的例外

对比: CISC(Complex Instruction Set Computer,如 x86)指令复杂、长度可变;非正交架构中不同指令支持的寻址方式各不相同。


3.3.2 CPU 的寄存器资源

MSP430F5529 拥有 16 个 16 位寄存器(R0~R15),其中 4 个为特殊用途寄存器:PC、SP、SR、CG2。


(1)程序计数器 PC(Program Counter)—— R0

PC 是 MSP430 单片机 CPU(Central Processing Unit,中央处理器)中最核心的寄存器,作用是存放下一条要执行指令的地址。

工作流程:

  • ⚫ 执行指令时,先由 PC 将指令地址送到地址总线
  • ⚫ PC 送完一条指令地址后,其内容自动 +1,指向下一条指令地址(顺序执行)
  • ⚫ 当发生转移、调用或执行中断时,PC 将被植入新的数值,程序走向发生变化
1
2
顺序执行:PC → PC+1 → PC+2 → PC+3 → ...
跳转时: PC → 被植入新地址(如 JMP(Jump)跳转目标地址、中断向量地址)

(2)堆栈指针 SP(Stack Pointer)—— R1

SP 指向堆栈中最后一个压入的数据单元地址,用于管理堆栈这种特殊存储结构。

堆栈(Stack)的特性:

  • ⚫ 堆栈是一种具有**”后进先出”(LIFO, Last In First Out)**访问属性的存储结构
  • ⚫ 数据在堆栈中逐个存入(**”压入”,PUSH)或取出(“弹出”,POP**)
  • ⚫ SP 始终指向最后一个压入堆栈的数据所在的数据单元地址

核心用途——保护现场:

  • ⚫ 在执行中断程序时,用于**”保护现场”**,即保存 PC 等寄存器的数据
  • ⚫ 中断发生 → 将当前 PC、SR 等压入堆栈(PUSH)→ 执行中断服务程序 → 中断返回时弹出恢复(POP)
1
2
3
4
5
6
7
8
9
10
PUSH 操作:SP → SP-2(先移动指针),再写入数据(栈向低地址增长)
POP 操作:先读出数据,SP → SP+2(再移动指针)

高地址 ┌─────────┐
│ 旧数据 │
├─────────┤
SP → │ 栈顶数据 │ ← SP 指向这里
├─────────┤
│ 空 │
低地址 └─────────┘

记忆要点: MSP430 堆栈向低地址方向增长(递减堆栈),每次 PUSH/POP 以 字(2 字节) 为单位。


(3)寄存器全表

寄存器索引 名称 用途
R0 PC(Program Counter) 程序计数器,存放下一条指令地址
R1 SP(Stack Pointer) 堆栈指针,指向栈顶
R2 SR(Status Register) 状态寄存器(也用作 CG1(Constant Generator 1)常量发生器)
R3 CG2(Constant Generator 2) 常量发生器
R4~R15 — 通用寄存器,自由使用

(4)状态寄存器 SR(Status Register)—— R2

SR 是一个特殊的多功能寄存器,具有双重身份:正常使用时作为状态/控制寄存器,特定寻址模式下作为常量发生器 CG1(Constant Generator 1)。

(a)SR 作为状态寄存器——存放状态标志位与控制位:

SR 中每一位都有特定含义,用于反映指令执行结果和控制 CPU 运行状态:

位 名称 含义
0 C(Carry) 进位/借位标志:加法有进位=1,减法有借位=1
1 Z(Zero) 零标志:运算结果为 0 时置 1
2 N(Negative) 负标志:运算结果为负时置 1
3 GIE(Global Interrupt Enable) 全局中断使能:置 1 则允许响应可屏蔽中断
4 CPUOFF(CPU Off) CPU 关断:置 1 则 CPU 停止工作,进入低功耗模式
5 OSCOFF(Oscillator Off) 振荡器关断:置 1 时关闭 LFXT1(Low Frequency Crystal Oscillator 1)晶振
6 SCG0(System Clock Generator 0) 系统时钟发生器控制位 0
7 SCG1(System Clock Generator 1) 系统时钟发生器控制位 1
8 V(Overflow) 溢出标志:有符号数运算溢出时置 1
1
2
3
4
5
SR 寄存器位布局(16 位):
┌──┬──┬─┬─┬─┬─┬─┬──┬──┬──┬──┬──┐
│ 保留 │V│SCG1│SCG0│OSCOFF│CPUOFF│GIE│N│Z│C│
└──┴──┴─┴─┴─┴─┴─┴──┴──┴──┴──┴──┘
15 9 8 7 6 5 4 3 2 1 0

考试重点: C、Z、N、V 四个算术标志位 + GIE 中断使能位。

(b)SR 作为 CG1(常量发生器 1)——生成常量 4 和 8:

当指令以特定寻址方式使用 R2 作为源操作数时,硬件不会真的去读 R2 的值,而是直接生成常量:

R2 的寻址方式 生成的常量
间接寄存器模式(As=10) 4
间接自增模式(As=11) 8

(5)常量发生器 CG2(Constant Generator 2)—— R3

R3 专门用作常量发生器。和 R2/CG1 一样,当指令以特定寻址方式使用 R3 作为源操作数时,硬件拦截读取操作,直接生成常量而不是读取 R3 寄存器内容。

R3 的寻址方式 生成的常量
寄存器模式(As=00) 0
变址模式(As=01) 1
间接寄存器模式(As=10) 2
间接自增模式(As=11) -1(即 0xFFFF)

(6)常量发生器原理总结

CG1(R2)和 CG2(R3)配合,通过复用寻址方式编码来实现常量生成,不消耗额外指令周期,不需要立即数。

寄存器 寻址模式 As=00 As=01 As=10 As=11
R2 作为 SR 读 作为 SR 读 CG1 → 4 CG1 → 8
R3 CG2 → 0 CG2 → 1 CG2 → 2 CG2 → −1(0xFFFF)

为什么这样设计?

  • 程序中经常出现 0、1、2、4、8、−1 这些常数(用于初始化、地址偏移、位掩码、减 1 循环等)
  • 传统做法是嵌入立即数,占用额外代码空间和取指时间
  • 常量发生器通过硬件直接生成,无需额外周期,节省代码空间,提升执行效率
1
2
3
4
5
6
; 示例:常量发生器的实际效果
MOV.W R3, R5 ; R3 在寄存器模式下生成 0 → R5 = 0
MOV.W @R3, R5 ; R3 在间接寄存器模式下生成 2 → R5 = 2
MOV.W @R3+, R5 ; R3 在间接自增模式下生成 -1 → R5 = 0xFFFF
MOV.W @R2, R5 ; R2 在间接寄存器模式下生成 4 → R5 = 4
MOV.W @R2+, R5 ; R2 在间接自增模式下生成 8 → R5 = 8

一句话理解: CPU 看到你用 R2/R3 的某些寻址方式,就直接在硬件里”变出”一个常用数字给你,而不是真的去读寄存器——这是 MSP430 的硬件加速技巧。


(7)关键点:

  • R0R3 为特殊功能寄存器,**R4R15 共 12 个**完全通用的寄存器,可用于数据存储、地址指针、临时变量等
  • 相比 8051 等只有累加器 A 少数寄存器的 MCU(Microcontroller Unit,微控制器),MSP430 的寄存器资源非常丰富
  • R2(SR)存放状态标志位(C, Z, N, V 等),同时兼任 CG1
  • R3(CG2)与 R2/CG1 配合,可直接生成常用常量(0, 1, 2, 4, 8, -1),省去立即数取指周期

3.3.3 单周期寄存器操作

  • 绝大多数寄存器级指令在一个 MCLK(Master Clock)周期内完成
  • 这是 RISC 架构的典型优势,使得 MSP430 在低时钟频率下也能获得较好的性能
  • 例如:MOV R4, R5、ADD R4, R5 等寄存器间操作只需 1 个时钟周期

意义: 单周期执行意味着指令执行时间是确定的,便于精确时序控制;同时低主频下仍能高效运行,有利于低功耗设计。


3.3.4 20 位地址总线

  • 地址总线宽度:20 位
  • 寻址范围:0x00000 ~ 0xFFFFF,即 1MB 线性地址空间
  • 这是 MSP430F5xx/6xx 系列的重要升级(F1xx/2xx/4xx 系列为 16 位地址总线,仅 64KB)

1MB 地址空间典型分配:

地址范围 用途
0x00000 ~ 0x0000F SFR(Special Function Register,特殊功能寄存器)
0x00100 ~ 0x00FFF 外设寄存器(8 位)
0x01000 ~ 0x011FF 外设寄存器(16 位)
0x01200 ~ 0x023FF 外设寄存器(保留)
0x02400 ~ 0x0FFFF 扩展外设 / RAM(Random Access Memory,随机存取存储器)
0x10000 ~ 0x3FFFF Flash 存储器
0x40000 ~ 0xFFFFF 保留 / 扩展

3.3.5 16 位数据总线

  • 数据总线宽度:16 位
  • CPU 一次可以读取或写入 16 位(1 个字)
  • 与 16 位寄存器宽度匹配,数据在总线和寄存器之间高效传输

MSP430F5529 是 16 位 CPU:

  • 基本数据类型 int 为 16 位
  • 所有寄存器为 16 位宽
  • 地址需要 20 位,因此使用扩展寄存器(如 PCX(Program Counter Extension)、SRX(Status Register Extension))来存储高 4 位地址

3.3.6 直接的存储器到存储器访问

  • MSP430 支持 Memory-to-Memory 数据传输
  • 源操作数和目的操作数都可以位于存储器中(不限于寄存器)

对比:

  • 传统累加器架构(如 8051):必须先将存储器数据加载到累加器 A,处理后才能存回存储器
  • ARM/RISC-V 的 Load/Store 架构:数据必须先从存储器 Load 到寄存器,处理后再 Store 回存储器
  • **MSP430:可直接 MOV &src, &dst**,一条指令完成存储器到存储器的拷贝
1
2
3
// C 语言层面(编译器自动利用此特性)
int a, b;
a = b; // 可能编译为一条 MOV 指令,直接从 b 的地址拷贝到 a 的地址

优点: 减少指令数,提高代码密度和执行效率。


3.3.7 字节、字和 20 位操作方式

MSP430F5529 支持三种数据操作宽度:

后缀 操作宽度 数据范围 示例
.B 字节(Byte,8 位) 0x00 ~ 0xFF MOV.B R4, R5
.W(默认) 字(Word,16 位) 0x0000 ~ 0xFFFF MOV.W R4, R5 或简写 MOV R4, R5
.A 地址/20 位(Address,20 位) 0x00000 ~ 0xFFFFF MOVA(Move Address) R4, R5

三种操作宽度对比:

1
2
3
MOV.B  #0xFF, &P1OUT    ; 字节操作:只操作 P1OUT 寄存器低 8 位
MOV.W #0x1234, R5 ; 字操作(默认):16 位数据
MOVA #0x12345, R5 ; 20 位操作:加载 20 位地址到扩展寄存器

.A 后缀用于 20 位地址操作,这是 F5xx/6xx 系列为支持 1MB 地址空间而引入的。在 C 语言层面,指针变量为 20 位,编译器会自动使用 .A 后缀的指令处理地址。


3.4 CPU 特征总结表

特征 说明 考试要点
RISC(Reduced Instruction Set Computer)+ 正交架构 指令少而规整,任意指令配任意寻址方式 与 CISC(Complex Instruction Set Computer)、非正交架构对比
16 个 16 位寄存器 4个特殊:PC(R0), SP(R1), SR(R2), CG2(R3);12个通用:R4~R15 必记:PC、SP、SR、CG2
单周期寄存器操作 寄存器间操作 1 周期 低功耗、确定性时序
20 位地址总线 寻址 1MB(0x00000~0xFFFFF) F5xx 系列核心升级点
16 位数据总线 一次读写 16 位 与 16 位 CPU 匹配
存储器到存储器 MOV(Move)指令可直接两个存储器操作数 与 Load/Store(加载/存储)架构对比
B/W/A 三种操作 Byte(字节,8位)、Word(字,16位)、Address(地址,20位) .B .W .A 后缀含义

4. MSP430 中断系统

4.1 中断的基本概念

4.1.1 中断的定义

中断(Interrupt) 是暂停 CPU 正在运行的程序,转去执行相应的中断服务程序,完毕后返回被中断的程序继续运行的现象和技术。

1
2
3
4
5
正常执行:  主程序 → 主程序 → 主程序 → 主程序 → ...
↓
中断发生: 主程序 → 主程序 → ⚡中断事件⚡
↓
中断服务程序 ISR → ISR 结束 → 返回主程序继续执行

核心关键词:

  • 中断服务程序 ISR(Interrupt Service Routine):中断发生后 CPU 转去执行的特定程序
  • 中断返回:ISR 执行完毕后,CPU 返回被中断的程序继续运行

4.1.2 断点与中断现场

(1)断点(Breakpoint):

  • ⚫ 断点是指 CPU 执行现行程序被中断时的下一条指令的地址,又称断点地址
  • ⚫ 中断返回时,CPU 从断点处继续执行被中断的程序

(2)中断现场(Interrupt Context):

  • ⚫ 中断现场是指 CPU 在转去执行中断服务程序前的运行状态,包括 CPU 状态寄存器(SR)和断点地址(PC)等
  • ⚫ 保护现场:在执行中断服务程序之前,将当前 SR、PC 等寄存器的值压入堆栈保存
  • ⚫ 恢复现场:中断服务程序执行完毕后,从堆栈中弹出之前保存的数据,恢复 CPU 到中断前的状态
  • ⚫ 保护现场和恢复现场由堆栈(Stack)来实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
中断响应过程:

主程序执行中
│
↓ (中断请求)
保护现场:PUSH SR → PUSH PC(自动压入堆栈)
│
↓
执行 ISR
│
↓
恢复现场:POP PC → POP SR(自动从堆栈弹出)
│
↓
返回主程序继续执行

4.1.3 中断向量表

中断向量是指中断服务程序的入口地址。

MSP430F5529 中:

  • ⚫ 每个中断向量被分配给 4 个连续的字节单元(2 个字)
  • ⚫ MSP430X(F5xx/6xx)支持 20 位地址,需要 4 字节存储完整的中断服务程序入口地址
  • ⚫ 为了让 CPU 方便地查找到对应的中断向量,需要在内存中建立一张查询表,即中断向量表(Interrupt Vector Table)
1
2
3
4
5
6
7
8
9
10
中断向量表结构(每个向量占 4 字节):

高地址 ┌──────────────────┐
│ 入口地址高字节 │ ← 向量地址 + 2(高字)
│ 入口地址次高字节 │
├──────────────────┤
│ 入口地址低字节 │ ← 向量地址(低字)
│ 入口地址次低字节 │
低地址 └──────────────────┘
共 4 字节 = 20 位地址

MSP430F5529 中常见中断向量示例:

中断源 向量地址 说明
复位(Reset) 0xFFFE 上电 / 复位后第一条指令地址
NMI(Non-Maskable Interrupt,不可屏蔽中断) 0xFFFC 振荡器故障、Flash 访问违规等
Timer0_A0 0xFFEC 定时器 A0 的 CCR0(Capture/Compare Register 0)
Timer0_A1 0xFFEA 定时器 A0 的 CCR1~CCR4(Capture/Compare Register 1-4)+ 溢出
USCI_A0(Universal Serial Communication Interface) 0xFFE8 串行通信接口 A0(支持 UART/SPI)
ADC12(12-bit Analog-to-Digital Converter) 0xFFEA 12 位模数转换器
Port1 0xFFE4 P1 端口中断
Port2 0xFFE2 P2 端口中断

MSP430 特色: 多个中断源可共享一个向量(如 Timer_A1),进入 ISR 后需软件查询具体是哪个子中断源。


4.1.4 中断源

中断源是指引起中断的原因,或者能够发出中断请求信号的来源。

MSP430 单片机包含 3 类中断源:

类型 说明 优先级
系统复位中断源(System Reset) 上电复位(POR)、上电清除(PUC)、看门狗、复位引脚等 最高
不可屏蔽中断源 NMI(Non-Maskable Interrupt) 振荡器故障、Flash 访问违规、硬件 NMI 引脚 中
可屏蔽中断源(Maskable) 大部分外设中断(定时器、GPIO、串口、ADC 等) 由向量表决定

4.1.5 中断优先级(Interrupt Priority)

为什么需要优先级? 如果多个中断源同时发出请求,不同中断代表不同事件,响应应有轻重缓急。

MSP430 中断优先级规则:

  • ⚫ 中断优先级由中断向量表定义,由硬件固定,不可改变
  • ⚫ 当同时出现多个中断请求,CPU 按照中断优先级的高低顺序依次响应
  • ⚫ 高优先级的中断可以中断低优先级的 ISR(中断嵌套)
  • ⚫ 低优先级的中断不可中断高优先级的 ISR
  • ⚫ 同优先级的中断服务程序之间互相不可打断
优先级(高→低) 中断类型
最高 复位(Reset)
↓ NMI(不可屏蔽中断)
↓ 各外设中断(由向量地址决定优先级,地址越高优先级越高)
最低 主程序

向量地址与优先级的关系: 在 MSP430 中,中断向量地址越高,对应的优先级越高。例如 0xFFFE(复位)> 0xFFFC(NMI)> 0xFFEC(Timer0_A0)。


4.1.6 触发中断的条件

必须同时满足以下三个条件,CPU 才会响应中断:

1
2
3
4
5
┌─────────────────────────────────┐
│ ① XXXIE = 1 特定外设中断使能位 │ → "分闸"——打开特定中断开关
│ ② GIE = 1 全局中断使能位 │ → "总闸"——打开全局中断开关
│ ③ XXXIFG = 0 中断标志位已清除 │ → 清除标志,避免重复进入
└─────────────────────────────────┘

详细说明:

条件 位名称 含义 操作
① XXXIE(Interrupt Enable) 特定外设中断使能位 = 1 打开特定中断的”分开关”
② GIE(Global Interrupt Enable) 全局中断使能位(SR 第 3 位) = 1 打开全局中断的”总开关”
③ XXXIFG(Interrupt Flag) 相应中断标志位 = 0 必须先清除,否则 CPU 会重复进入同一中断

类比: GIE 是家里电表总闸,XXXIE 是每个房间的分闸。要灯亮(中断响应),总闸和分闸都得合上。同时要确保不会”反复亮灯”——必须清除中断标志位。

GIE 的操作方法:

1
2
3
__bis_SR_register(GIE);   // GIE = 1,开启全局中断(合总闸)
__bic_SR_register(GIE); // GIE = 0,关闭全局中断(拉总闸)
// 等效宏:_EINT()(Enable Interrupt)和 _DINT()(Disable Interrupt)

4.1.7 中断初始化示例

以 P1.1 按键 S2 中断初始化 为例:

1
2
3
4
5
6
7
8
/* 配置 按键 S2 (P1.1) 中断初始化 */
P1DIR &= ~BIT1; // ① 设置 P1.1 为输入模式
P1REN |= BIT1; // ② 开启上拉/下拉电阻
P1OUT |= BIT1; // ③ 选择上拉电阻(按键未按下时引脚为高电平)
P1IES |= BIT1; // ④ 选择下降沿触发中断(按下时高→低)
P1IFG &= ~BIT1; // ⑤ 清除中断标志位(IFG:Interrupt Flag)
P1IE |= BIT1; // ⑥ 使能 P1.1 中断(IE:Interrupt Enable)"分闸"
__bis_SR_register(GIE); // ⑦ 全局中断使能(GIE:Global Interrupt Enable)"总闸"

初始化步骤口诀:

1
2
3
4
5
6
7
1. DIR 配方向(输入/输出)
2. REN 开电阻(上拉/下拉)
3. OUT 选模式(上拉/下拉)
4. IES 选边沿(上升沿/下降沿)
5. IFG 清标志(必须先清!)
6. IE 开分闸(外设中断使能)
7. GIE 合总闸(全局中断使能)

4.1.8 中断服务程序 ISR 的编写要点

1
2
3
4
5
6
7
8
9
10
11
12
13
// P1.1 按键中断服务程序示例
#pragma vector = PORT1_VECTOR // 指定中断向量(对应 P1 端口)
__interrupt void Port1_ISR(void) // Port1_ISR 是用户自定义函数名(可任意取名),__interrupt 声明为 ISR
{
// ① 判断中断源(多个引脚共用一个向量时需逐一判断)
if (P1IFG(Port 1 Interrupt Flag Register) & BIT1) {
// ② 处理中断事件(例如翻转 LED)
P1OUT ^= BIT6; // 翻转 P1.6 LED 状态
// ③ 清除中断标志(重要!否则会反复触发)
P1IFG &= ~BIT1;
}
}
// ④ 编译器自动添加 RETI(Return from Interrupt)指令返回

关于 PORT1_VECTOR——端口中断共享向量机制:

PORT1_VECTOR 是 P1 端口所有 8 个引脚(P1.0~P1.7)共用的中断向量。任何一个 P1 引脚触发中断,CPU 都会跳转到同一个 ISR。

1
2
3
4
5
6
7
8
                ┌── P1.0 触发 ──┐
│ P1.1 触发 │
│ P1.2 触发 │
PORT1_VECTOR ←──┼── P1.3 触发 ──┼──→ 同一个 ISR
│ P1.4 触发 │ (需用 P1IFG 判断来源)
│ P1.5 触发 │
│ P1.6 触发 │
└── P1.7 触发 ──┘

因此 ISR 内部必须逐个检查 P1IFG 的每一位来确定是哪个引脚触发了中断。同理,PORT2_VECTOR 对应 P2.0~P2.7 的全部 8 个引脚。

常见的共享向量:

向量名 共享的中断源 判断方法
PORT1_VECTOR P1.0 ~ P1.7 检查 P1IFG 各位
PORT2_VECTOR P2.0 ~ P2.7 检查 P2IFG 各位
TIMER0_A1_VECTOR TA0CCR1~CCR4 + TA0溢出 检查 TA0IV 寄存器
USCI_A0_VECTOR UART 发送/接收 检查 UCA0IFG 各位

编写 ISR 的关键规则:

规则 说明
必须用 __interrupt 修饰 告诉编译器这是中断函数,非普通函数
必须用 #pragma vector = xxx 将 ISR 与对应的中断向量绑定
必须软件清除中断标志位 大部分外设的 IFG 需要手动清除,否则 ISR 会反复执行
ISR 应尽量短小 只做必要处理(如置标志位),复杂工作留给主程序
注意共享向量 同一向量的多个子中断源需在 ISR 内用 if 逐一判断
自动关/开 GIE 进入 ISR 时 CPU 自动清除 GIE(防止中断嵌套),退出时自动恢复

4.1.9 中断处理完整流程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
① 中断请求(Interrupt Request)
外设向 CPU 发出中断请求信号,对应的 IFG 位置 1
↓
② 中断响应条件判断
CPU 完成当前指令后检查:XXXIE=1? GIE=1? 优先级允许?
↓ (三个条件同时满足)
③ 保护现场(Context Save)
硬件自动将 PC(断点地址)和 SR(状态寄存器)压入堆栈
↓
④ 查找中断向量(Vector Fetch)
根据中断源查中断向量表,获取 ISR 入口地址 → 加载到 PC
↓
⑤ 执行 ISR(Interrupt Service Routine)
运行用户编写的中断处理代码
⚠ 进入 ISR 时 GIE 自动清零,禁止其他可屏蔽中断
↓
⑥ 恢复现场(Context Restore)
执行 RETI 指令,从堆栈弹出 SR 和 PC,恢复中断前的状态
↓
⑦ 返回主程序
CPU 从断点处(被中断时的下一条指令)继续执行

低功耗唤醒: MSP430 在低功耗模式下可以被中断唤醒。执行 ISR 后会根据 SR 中保存的低功耗模式位决定返回后是否继续休眠。


4.2 中断相关指令/操作速查表

4.2.1 GPIO 端口中断配置寄存器

指令/操作 含义 说明
P1DIR |= BIT7; P1.7 口设为输出模式 DIR=1 输出,DIR=0 输入
P1DIR &= ~BIT7; P1.7 口设为输入模式 中断通常需先配置为输入
P1REN |= BIT7; P1.7 口开启上拉/下拉电阻 使能内部电阻,避免引脚浮空
P1OUT |= BIT7; P1.7 口选择上拉电阻 结合 REN,OUT=1 上拉,OUT=0 下拉
P1OUT &= ~BIT7; P1.7 口选择下拉电阻 结合 REN,将引脚默认拉低
P1IES |= BIT7; P1.7 口下降沿触发中断 IES=1 下降沿(高→低),IES=0 上升沿(低→高)
P1IES &= ~BIT7; P1.7 口上升沿触发中断 上升沿:引脚从低电平变为高电平时触发
P1IFG &= ~BIT7; 清除 P1.7 口中断标志位 进入 ISR 前必须清除,否则 CPU 反复进入
P1IE |= BIT7; P1.7 口中断使能(分闸) 打开该引脚的中断开关
P1IE &= ~BIT7; P1.7 口中断禁用 关闭该引脚的中断开关
P1IFG & BIT7 判断 P1.7 口是否触发中断 ISR 内用于判断中断来源

速记: IES = Interrupt Edge Select(边沿选择)、IFG = Interrupt Flag(中断标志)、IE = Interrupt Enable(中断使能)

P1IFG 寄存器详解:

1
2
3
4
5
P1IFG(Port 1 Interrupt Flag Register)— 16 位寄存器
┌──────┬──┬──┬──┬──┬──┬──┬──┬──┐
│ 保留 │P1.7│P1.6│P1.5│P1.4│P1.3│P1.2│P1.1│P1.0│
└──────┴──┴──┴──┴──┴──┴──┴──┴──┘
15-8 第7位 ... 第0位
  • ⚫ 每一位对应一个 P1 端口引脚(BIT0 → P1.0,BIT7 → P1.7)
  • ⚫ 引脚电平满足触发条件(如下降沿)→ 硬件自动将对应的 IFG 位置 1 → 向 CPU 发出中断请求
  • ⚫ CPU 不会自动清除 IFG,必须在 ISR 内手动写 0:P1IFG &= ~BITx;
  • ⚫ 若不清除 → ISR 返回后 IFG 仍为 1 → CPU 立即再次进入同一 ISR → 死循环

4.2.2 全局中断控制

指令/操作 含义 说明
__bis_SR_register(GIE); 开启全局中断(合总闸) GIE = Global Interrupt Enable,SR 第 3 位置 1
__bic_SR_register(GIE); 关闭全局中断(拉总闸) SR 第 3 位清 0,所有可屏蔽中断不响应
_EINT(); 开启全局中断(宏) 等价于 __bis_SR_register(GIE)
_DINT(); 关闭全局中断(宏) 等价于 __bic_SR_register(GIE)

4.2.3 低功耗模式控制

指令/操作 含义 说明
__bis_SR_register(LPM0_bits + GIE); 进入 LPM0 + 开中断 CPU 关断,MCLK 关断,SMCLK/ACLK 运行
__bis_SR_register(LPM1_bits + GIE); 进入 LPM1 + 开中断 CPU 关断,MCLK 关断,DC 发生器关断
__bis_SR_register(LPM2_bits + GIE); 进入 LPM2 + 开中断 CPU/MCLK/SMCLK 关断,DCO 关断
__bis_SR_register(LPM3_bits + GIE); 进入 LPM3 + 开中断 CPU/MCLK/SMCLK/DCO 关断,仅 ACLK 运行(常用)
__bis_SR_register(LPM4_bits + GIE); 进入 LPM4 + 开中断 所有时钟停止,仅外部中断可唤醒(最低功耗)
__low_power_mode_off_on_exit(); ISR 返回后退出低功耗 在 ISR 内调用,返回主程序时恢复活动模式

低功耗模式速查:

模式 CPUOFF SCG0 SCG1 OSCOFF CPU MCLK SMCLK ACLK 唤醒方式
Active 0 0 0 0 ✅ ✅ ✅ ✅ —
LPM0 1 0 0 0 ❌ ❌ ✅ ✅ 任意中断
LPM1 1 0 0 1 ❌ ❌ ✅ ✅ 任意中断
LPM2 1 0 1 0 ❌ ❌ ❌ ✅ 任意中断
LPM3 1 1 0 0 ❌ ❌ ❌ ✅ 任意中断(最常用低功耗)
LPM4 1 1 1 0 ❌ ❌ ❌ ❌ 仅外部中断

+ GIE 的意义: 进入低功耗时同时开启全局中断,确保外设中断能够唤醒 CPU。如果不加 + GIE,CPU 进入低功耗后无法被中断唤醒,只能靠复位。


4.2.4 中断初始化完整步骤速查

1
2
3
4
5
6
7
8
9
步骤  操作                      含义                   记忆
────────────────────────────────────────────────────────────
① PxDIR &= ~BITx; 设为输入模式 DIR → 方向
② PxREN |= BITx; 开启上下拉电阻 REN → 电阻使能
③ PxOUT |= BITx; 选择上拉(或 &= ~选下拉) OUT → 输出值
④ PxIES |= BITx; 选择下降沿触发 IES → 边沿选择
⑤ PxIFG &= ~BITx; 清除中断标志 IFG → 标志清除
⑥ PxIE |= BITx; 使能外设中断(分闸) IE → 中断使能
⑦ __bis_SR_register(GIE); 开启全局中断(总闸) GIE → 全局使能

缩写记忆表:

缩写 全称 中文 功能
DIR Direction 方向寄存器 0=输入,1=输出
REN Resistor Enable 电阻使能 1=开启内部上下拉
OUT Output 输出寄存器 配合REN:1=上拉,0=下拉
IES Interrupt Edge Select 中断边沿选择 1=下降沿,0=上升沿
IFG Interrupt Flag 中断标志寄存器 1=有中断请求,需手动清 0
IE Interrupt Enable 中断使能 1=开启该引脚中断(分闸)
GIE Global Interrupt Enable 全局中断使能 SR 第 3 位,总闸
LPMx Low Power Mode x 低功耗模式 x 配合 CPUOFF/SCGx 控制功耗

5. MSP430 时钟系统

5.1 时钟系统结构与原理

5.1.1 通用时钟系统(UCS,Universal Clock System)结构

MSP430F5529 采用 UCS(Universal Clock System,通用时钟系统),为 CPU 和各个外设提供灵活、多级的工作时钟。


(1)5 个时钟来源

UCS 模块内部包含 5 个独立时钟源,构成整个系统的时钟基础:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
                       UCS 通用时钟系统
┌─────────────────────────────────────────────────────┐
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ XT1CLK │ │ VLOCLK │ │ REFOCLK │ │
│ │ 低频/高频 │ │ 超低功耗 │ │ 低频参考 │ │
│ │ 外部振荡器│ │ ~12kHz │ │ ~32768Hz │ │
│ └────┬─────┘ └────┬─────┘ └────┬─────┘ │
│ │ │ │ │
│ ┌────┴─────┐ ┌────┴──────────────┴─────┐ │
│ │ DCOCLK │ │ FLL │ │
│ │ 内部数控 │ │ (锁频环) 稳频 │ │
│ │ 振荡器 │ │ │ │
│ └────┬─────┘ └────────────┬─────────────┘ │
│ │ │ │
│ ┌────┴──────────────────────┴─────┐ │
│ │ 时钟分配网络 │ │
│ └────┬──────────┬──────────┬──────┘ │
│ │ │ │ │
│ ┌────┴──┐ ┌────┴──┐ ┌────┴──┐ │
│ │ MCLK │ │ SMCLK │ │ ACLK │ │
│ │主时钟 │ │子主时钟│ │辅助时钟│ │
│ └───────┘ └───────┘ └───────┘ │
└─────────────────────────────────────────────────────┘

各时钟源详细说明:

# 时钟源 全称 频率 来源 特点 典型用途
① XT1CLK XT1 Crystal Clock 32768Hz 或 4~32MHz 外部引脚(XIN/XOUT) 可用手表晶振、标准晶体、谐振器或外部时钟源 LF 模式→ACLK;HF 模式→MCLK/SMCLK
② VLOCLK VLO Clock 典型 12kHz 内部(无需外部元件) 超低功耗,精度低但省电 看门狗定时器(WDT)、低功耗后台运行
③ REFOCLK REFO Clock 典型 32768Hz 内部(无需外部元件) 内部校准,精度高于 VLO,低于外部晶振 不接外部晶振时代替 XT1 提供精确 ACLK
④ DCOCLK DCO Clock 可编程,典型数 MHz 内部数控振荡器 核心高速源,可经 FLL 稳频 CPU 主频(MCLK),高速外设
⑤ XT2CLK XT2 Crystal Clock 4~32MHz 外部引脚(XT2IN/XT2OUT) 专用高频外部源 需要高精度高速时钟时使用

各时钟源对照:

对比维度 XT1CLK VLOCLK REFOCLK DCOCLK XT2CLK
类型 外部 内部 内部 内部 外部
精度 高(晶振) 低 中 中(FLL 稳频后高) 高(晶振)
功耗 低(LF)/ 中(HF) 极低 低 中 中
启动时间 慢(ms 级) 快 快 极快(μs 级) 慢(ms 级)
需要外部元件 是(晶振+电容) 否 否 否 是(晶振+电容)
频率稳定性 极好 差(温漂大) 好 好(FLL 锁定后) 极好

关于 FLL(Frequency Locked Loop,锁频环):

FLL 是 UCS 内部的硬件稳频电路,作用是自动校准 DCOCLK,使它的频率稳定在精确值:

1
2
3
4
5
6
7
8
9
10
11
12
REFOCLK / XT1CLK (精确参考,如 32768Hz)
│
▼
┌──────────┐ 比较 ┌──────────┐
│ 分频器 │ ──────────────→ │ FLL │
│ ÷ N │ "差了多少?" │ 锁频环 │ ← 硬件自动
└──────────┘ └────┬─────┘
↑ │ 调整
┌─────┴─────┐ ┌─────┴─────┐
│ DCOCLK │ ←─────────── │ DCOCLK │
│ (当前值) │ 修正后输出 │ (稳定值) │
└───────────┘ └───────────┘
  • ⚫ DCOCLK 启动极快(微秒级),但频率随温度、电压漂移
  • ⚫ FLL 以 REFOCLK 或 XT1CLK(精确 32768Hz)为参考基准,不断比较 DCOCLK 分频后的输出与参考值的差异
  • ⚫ 发现偏差后,FLL 自动调整 DCO 的参数,将其”锁定”到目标频率
  • ⚫ 锁频后,DCOCLK 既拥有内部振荡器的快速启动优势,又获得接近外部晶振的频率精度

类比: DCO 像一个跑步不匀速的人,FLL 像一个教练拿着秒表在边上不断喊”快了!慢了!”,把速度校准到准确配速。

考试重点: 区分 5 个时钟源的来源(内部/外部)、典型频率值、各自的应用场景。


(2)时钟系统原理——各时钟源工作机制


① VLO(Very Low-frequency Oscillator,超低功耗低频振荡器)

1
2
3
VLO 原理:
内部 RC 电路 → 产生 ~12kHz 振荡 → 直接输出 VLOCLK
无需外部元件,上电即起振
  • ⚫ 纯内部 RC 振荡器,位于芯片内部,不需要任何外部元件
  • ⚫ 频率典型值 12kHz,功耗极低(nA 级)
  • ⚫ 精度较差(受温度、电压影响大),不适合需要精确时间的场合
  • ⚫ 通常在系统不接外部晶振时,作为 ACLK 的最省电选择
  • ⚫ 典型用途:看门狗定时器(WDT)、低功耗运行(LPM3/LPM4)

考试关键词: 内部、~12kHz、超低功耗、精度低


② REFO(REference Oscillator,内部参考振荡器)

1
2
3
REFO 原理:
内部校准 RC 电路 → ~32768Hz → 直接输出 REFOCLK
出厂已校准,无需外部晶振即可获得较准确的 32kHz
  • ⚫ 内部 RC 振荡器,出厂时经 TI 工厂校准至约 32768Hz
  • ⚫ 精度优于 VLO(但仍不如外部晶振),功耗低
  • ⚫ 核心作用: 不接外部 32768Hz 晶振时,REFO 可作为 FLL 的参考时钟源来稳频 DCOCLK
  • ⚫ 典型用途:FLL 参考源、ACLK 精度要求不高但优于 VLO 的场合

考试关键词: 内部、~32768Hz、出厂校准、FLL 参考源


③ XT1(XT1 Crystal Oscillator,XT1 晶振)

1
2
3
XT1 原理:
外部晶振 + 内部振荡驱动电路 → 稳定振荡
有两种工作模式:LF 模式(32768Hz)/ HF 模式(4~32MHz)
  • ⚫ 连接在 XIN / XOUT 引脚上,需要外接晶振 + 负载电容
  • ⚫ LF(Low Frequency)模式:
    • 使用 32768Hz 手表晶振,功耗极低
    • 是 ACLK 的经典选择,可提供高精度低频时钟
  • ⚫ HF(High Frequency)模式:
    • 使用 4~32MHz 标准晶振或谐振器
    • 可提供高精度高频时钟给 MCLK/SMCLK
  • ⚫ 优点: 频率精度极高(ppm 级),稳定性好
  • ⚫ 缺点: 起振慢(毫秒级),需要外部元件,增加 BOM 成本和 PCB 面积

考试关键词: 外部、高精度、LF(32768Hz)/HF(4~32MHz)、需晶振+电容、起振慢


④ XT2(XT2 Crystal Oscillator,XT2 高频晶振)

1
2
3
XT2 原理:
专用高频外部晶振 → 4~32MHz → XT2CLK
与 XT1 独立,可同时使用
  • ⚫ 连接在 XT2IN / XT2OUT 引脚,仅支持高频(4~32MHz)
  • ⚫ 与 XT1 完全独立,两者可同时存在(如 XT1 接 32768Hz 手表晶振,XT2 接 16MHz 高速晶振)
  • ⚫ 适合需要独立高精度高速时钟源的场合(如 USB、RF 通信)
  • ⚫ 与 XT1 HF 类似:高精度、起振慢、需外部元件

考试关键词: 外部、仅 HF(4~32MHz)、与 XT1 独立


⑤ FLL(Frequency Locked Loop,锁频环)+ MODOSC(Modulator Oscillator)

1
2
3
4
5
6
7
8
9
10
11
12
13
FLL + MODOSC 原理:

┌────────────────────────────────────┐
│ FLL 闭环控制 │
│ │
参考源 │ ┌──────────┐ ┌───────────┐ │
(REFO/ ├─→│ FLL 比较 │───→│ DCO 调整 │ │
XT1) │ │ + 分频器 │←───│ + MODOSC │ │
│ └──────────┘ │ (调制振荡器)│ │
│ └─────┬─────┘ │
└─────────────────────────┼───────────┘
│
DCOCLK(稳定输出)

FLL 的工作原理:

  • ⚫ FLL 以 REFO 或 XT1(精确 32768Hz)为参考基准
  • ⚫ 内部有一个分频器将 DCOCLK 分频后与参考频率比较
  • ⚫ 比较结果控制 DCO 向上或向下调整 → 最终锁定到设定频率

MODOSC 的作用:

  • ⚫ MODOSC(Modulator Oscillator)是 FLL 内部的一个辅助调制振荡器
  • ⚫ 它帮助 FLL 实现小数分频(Fractional-N),使 DCO 可以稳定在非整数倍的参考频率上
  • ⚫ 简单说:参考源 ÷ 整数部分 + MODOSC 负责小数部分微调 → 更灵活的频点选择
1
2
3
4
5
例:要得到 8MHz 的 DCOCLK
→ 32768Hz × 244.14... = 8MHz
→ 整数部分 244(分频器)
→ 小数部分 0.14...(MODOSC 调制实现)
→ FLL 锁定后:DCOCLK = 8MHz(稳定)

MODOSC 一句话: 它是 FLL 的”微调旋钮”,让 DCO 不必是参考频率的整数倍,也能精确锁定。

考试关键词: FLL 闭环稳频、参考源 32768Hz、MODOSC 实现小数倍频


5.1.2 时钟模块控制寄存器

UCS 模块共包含 9 个控制寄存器(UCSCTL0 ~ UCSCTL8),用于配置时钟源选择、分频、DCO 调校和故障检测。


寄存器总览:

寄存器 全称 主要功能 配置内容
UCSCTL0 UCS Control 0 DCO 调制控制 MOD(调制器参数),DCO(数控振荡器抽头)
UCSCTL1 UCS Control 1 DCO 范围与 FLL 分频 DCORSEL(DCO 频率范围),FLLD(FLL 环分频系数)
UCSCTL2 UCS Control 2 FLL 倍频系数 FLLN(FLL 倍频系数 N,DCOCLK = 参考频率 × N)
UCSCTL3 UCS Control 3 参考源选择与分频 SELREF(FLL 参考源),FLLREFDIV(参考源分频)
UCSCTL4 UCS Control 4 系统时钟源选择 SELM(MCLK 源),SELS(SMCLK 源),SELA(ACLK 源)
UCSCTL5 UCS Control 5 时钟分频 DIVM(MCLK 分频),DIVS(SMCLK 分频),DIVA(ACLK 分频)
UCSCTL6 UCS Control 6 振荡器开关与驱动 XT1OFF/XT2OFF,XT1DRIVE/XT2DRIVE,XCAP
UCSCTL7 UCS Control 7 振荡器故障标志 XT1LFOFFG,XT1HFOFFG,XT2OFFG,DCOFFG(故障标志位)
UCSCTL8 UCS Control 8 时钟请求使能 ACLKREQEN,MCLKREQEN,SMCLKREQEN(LPM 下是否请求)

各寄存器详解:


(1)UCSCTL0 — DCO 调制控制寄存器

1
2
3
4
位:  15-12   11-8    7-5     4-0
┌───────┬───────┬───────┬───────┐
│ 保留 │ MOD │DCO(高)│DCO(低)│
└───────┴───────┴───────┴───────┘
位 名称 含义
11-8 MOD(Modulation) FLL 调制器参数,控制 DCO 频率微调(实现小数分频)
7-5 DCO[高 3 位] DCO 频率调校值高位,与 DCORSEL 配合设定 DCO 基频
4-0 DCO[低 5 位] DCO 频率调校值低位,共 8 位分辨率

考试要点: UCSCTL0 主要配置 DCO 的 8 位调校值 + MOD 调制参数,FLL 锁定过程中硬件自动修改此寄存器。


(2)UCSCTL1 — DCO 范围与 FLL 环分频

1
2
3
4
位:   15-5     4-3        2-0
┌────────┬──────────┬──────────┐
│ 保留 │ FLLD │ DCORSEL │
└────────┴──────────┴──────────┘
位 名称 含义
4-3 FLLD(FLL Divider) FLL 环分频系数:00=÷1, 01=÷2, 10=÷4, 11=÷8
2-0 DCORSEL(DCO Range Select) DCO 频率范围选择(0~7),数值越大范围越高

考试要点: DCORSEL 决定 DCO 的粗调范围,FLLD 决定 FLL 环内分频比。


(3)UCSCTL2 — FLL 倍频系数

1
2
3
4
位:   15-11    10-0
┌───────┬──────────┐
│ 保留 │ FLLN │
└───────┴──────────┘
位 名称 含义
10-0 FLLN(FLL Multiplication Factor) FLL 倍频系数(1~1023)

频率计算公式:

1
2
3
4
5
6
7
DCOCLK = (FLLN + 1) × FLLREFCLK     (当 FLLD = 0,FLLREFDIV = 0 时)

或者更一般的形式:

DCOCLK = (FLLN + 1) × FLLREFCLK × FLLD / n
└──────────┘ └──────────┘ └─FLL 分频─┘
倍频因子 FLL 参考输入

考试要点: FLLN 是最核心的倍频参数。如要 DCOCLK = 8MHz,参考 32768Hz,FLLN ≈ 244。


(4)UCSCTL3 — 参考源选择与分频

1
2
3
4
位:   15-8    7-6        5-4     3-0
┌───────┬──────────┬───────┬──────────┐
│ 保留 │ FLLREFDIV│ 保留 │ SELREF │
└───────┴──────────┴───────┴──────────┘
位 名称 含义
7-6 FLLREFDIV(FLL Reference Divider) FLL 参考源分频:00=÷1, 01=÷2, 10=÷4, 11=÷8
3-0 SELREF(Select Reference) FLL 参考源选择:0=XT1CLK, 2=REFOCLK, 3=XT2CLK

考试要点: SELREF 选择哪个时钟源作为 FLL 参考(通常选 REFO 或 XT1),FLLREFDIV 对参考源先分频再送入 FLL。


(5)UCSCTL4 — 系统时钟源选择(最常用!)

1
2
3
4
位:   15-11    10-8       7-4     3-0
┌───────┬──────────┬───────┬──────────┐
│ 保留 │ SELA │ SELS │ SELM │
└───────┴──────────┴───────┴──────────┘
位 名称 含义
10-8 SELA(Select ACLK) ACLK 时钟源选择
7-4 SELS(Select SMCLK) SMCLK 时钟源选择
3-0 SELM(Select MCLK) MCLK 时钟源选择

时钟源选项(SELM/SELS/SELA 共用编码):

编码值 时钟源 说明
0 XT1CLK XT1 晶振输出
1 VLOCLK 超低功耗振荡器(仅 SELA 可用)
2 REFOCLK 内部参考振荡器
3 DCOCLK 内部数控振荡器(默认 MCLK 源)
4 DCOCLKDIV DCO 分频后输出
5 XT2CLK XT2 高频晶振(仅 SELS/SELM 可用)

典型配置示例:

1
2
3
UCSCTL4 = SELM__DCOCLK       // MCLK  ← DCOCLK
| SELS__DCOCLK // SMCLK ← DCOCLK
| SELA__REFOCLK; // ACLK ← REFOCLK(32768Hz)

考试重点: SELM 选 MCLK 源,SELS 选 SMCLK 源,SELA 选 ACLK 源。DCOCLK 是默认选项,考试常考”需要高频时选 DCOCLK、需要低功耗选 VLOCLK/REFOCLK”。


(6)UCSCTL5 — 时钟分频寄存器

1
2
3
4
5
6
位:   15-13    12-10     7-5       2-0
┌───────┬──────────┬───────┬──────────┐
│ 保留 │ DIVPA │ DIVA │ 保留 │
├───────┼──────────┼───────┼──────────┤
│ 保留 │ DIVM │ DIVS │ 保留 │
└───────┴──────────┴───────┴──────────┘
位 名称 含义 分频选项
12-10 DIVPA(Divider for PA) 端口 A 时钟分频 1/2/4/8/16/32
7-5 DIVA(Divider for ACLK) ACLK 分频 1/2/4/8/16/32
4-2 DIVM(Divider for MCLK) MCLK 分频 1/2/4/8/16/32
1-0 DIVS(Divider for SMCLK) SMCLK 分频 1/2/4/8/16/32

分频公式:

1
2
3
MCLK_actual  = MCLK_source / 2^DIVM
SMCLK_actual = SMCLK_source / 2^DIVS
ACLK_actual = ACLK_source / 2^DIVA
1
2
3
4
// 示例:DCOCLK = 8MHz,MCLK 不分频,SMCLK 4 分频
UCSCTL5 = DIVM__1 // MCLK = 8MHz / 1 = 8MHz
| DIVS__4 // SMCLK = 8MHz / 4 = 2MHz
| DIVA__1; // ACLK = 32768Hz / 1 = 32768Hz

考试重点: 分频公式 频率 / 2^n,n = DIVM/DIVS/DIVA 的值。DIVx=0 表示 ÷1(不分频)。


(7)UCSCTL6 — 振荡器开关与驱动能力

1
2
3
4
5
位:  15  14   13   12   11-10   9   8   7-6   5-4   3-2   1-0
┌──┬───┬────┬───┬──────┬───┬───┬─────┬─────┬─────┬──────┐
│...│XT2│XT2D│XTA│XT1DRV│XTS│XTO│XT1DR│XT2DR│XCAP │ SMCL │
│ │OFF│RIVE│LIVE│ (HF) │ │FF │ (LF)│IVE │ │ OFEN │
└──┴───┴────┴───┴──────┴───┴───┴─────┴─────┴─────┴──────┘
位 名称 含义
14 XT2OFF(XT2 Off) 1 = 关闭 XT2 振荡器
13-12 XT2DRIVE(XT2 Drive) XT2 驱动能力(0~3),频率越高需驱动越强
11 XTALIVE XT1 起振检测标志(只读)
10-9 XT1DRIVE(HF) XT1 高频模式驱动能力
8 XTS(XT1 Select) 0=LF 模式(32768Hz), 1=HF 模式(4~32MHz)
7 XT1OFF(XT1 Off) 1 = 关闭 XT1 振荡器
6-5 XT1DRIVE(LF) XT1 LF 模式驱动能力
3-2 XCAP(Capacitance) 内部负载电容选择(1/6/10/12.5pF),减少外部电容
1-0 SMCLKOFFEN SMCLK 输出使能(可用于外部引脚输出)

常用配置示例:

1
2
3
UCSCTL6 |= XT1OFF;                      // 关闭 XT1
UCSCTL6 &= ~XT2OFF; // 开启 XT2
UCSCTL6 |= XCAP_3; // 选择内部 12.5pF 负载电容

考试重点: XT1OFF/XT2OFF 控制启停,XTS 选择 XT1 模式(LF/HF),XCAP 提供内部电容。


(8)UCSCTL7 — 振荡器故障标志寄存器

1
2
3
4
5
6
7
8
位:  7   6   5   4   3   2   1   0
┌──┬──┬──┬──┬──┬──┬──┬──┐
│..│..│XT│XT│XT│XT│DC│..│
│ │ │2O│1H│1L│1L│OF│ │
│ │ │FF│FO│FO│FO│FG│ │
│ │ │G │FF│FF│FF│ │ │
│ │ │ │G │G │G │ │ │
└──┴──┴──┴──┴──┴──┴──┴──┘
位 名称 含义
3 XT2OFFG(XT2 Oscillator Fault Flag) XT2 振荡器故障标志(1=故障)
2 XT1HFOFFG(XT1 HF Oscillator Fault Flag) XT1 高频模式故障标志
1 XT1LFOFFG(XT1 LF Oscillator Fault Flag) XT1 低频模式故障标志(最常用)
0 DCOFFG(DCO Fault Flag) DCO 故障标志

使用模式——先清除再检测:

1
2
3
4
5
// 振荡器故障检测流程
do {
UCSCTL7 &= ~(XT1LFOFFG | DCOFFG); // 清除故障标志
SFRIFG1 &= ~OFIFG; // 清除振荡器故障中断标志
} while (SFRIFG1 & OFIFG); // 循环直到振荡器稳定

考试重点: XT1LFOFFG 表示外部 32768Hz 晶振是否起振失败。必须软件清除,不清除则 FLL 不工作!


(9)UCSCTL8 — 时钟请求使能寄存器

1
2
3
4
5
位:   15-3     2        1        0
┌───────┬─────────┬─────────┬─────────┐
│ 保留 │ SMCLKRE│ ACLKRE │ MCLKRE │
│ │ QEN │ QEN │ QEN │
└───────┴─────────┴─────────┴─────────┘
位 名称 含义
2 SMCLKREQEN SMCLK 在低功耗模式下是否保持请求(1=保持)
1 ACLKREQEN ACLK 在低功耗模式下是否保持请求(1=保持)
0 MCLKREQEN MCLK 在低功耗模式下是否保持请求(1=保持)

作用: 控制在 LPM 低功耗模式下,相应时钟是否可以继续供给外设。


寄存器速记对照表:

寄存器 核心功能 记忆口诀
UCSCTL0 DCO 8位调校 + MOD 调制 0 调 DCO
UCSCTL1 DCO 范围 + FLL 环分频 1 定范围
UCSCTL2 FLL 倍频系数 N 2 设倍率
UCSCTL3 FLL 参考源选择 3 选参考
UCSCTL4 ACLK/SMCLK/MCLK 源选择 4 选来源(最常用)
UCSCTL5 ACLK/SMCLK/MCLK 分频 5 做除法
UCSCTL6 晶振开关 + 驱动 + 负载电容 6 管晶振
UCSCTL7 振荡器故障标志 7 查故障
UCSCTL8 低功耗下时钟请求 8 省电忙

5.2 时钟配置实例


5.2.1 默认时钟状态(复位后)

MSP430F5529 复位后,UCS 默认配置为:

项目 默认值 说明
MCLK 源 DCOCLK ≈ 1MHz SELM=3(DCOCLK)
SMCLK 源 DCOCLK ≈ 1MHz SELS=3(DCOCLK)
ACLK 源 XT1CLK(LF 模式,需外接晶振;无晶振则 REFO 32768Hz) SELA=0
FLL 参考 XT1CLK SELREF=0
XT1 开启,LF 模式(32768Hz) XTS=0, XT1OFF=0
XT2 关闭 XT2OFF=1
VLO 关闭 —

记忆: 复位后默认跑 DCO ~1MHz。如果没接外部 XT1 晶振,FLL 参考自动切换到 REFO。


5.2.2 实例一:DCO + FLL 配置 8MHz(最常用)

场景: 使用内部 REFO(32768Hz)作 FLL 参考,将 DCOCLK 锁定到 8MHz。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
void Clock_Init_8MHz(void)
{
// ① 配置 FLL:以 REFO(32768Hz) 为参考,倍频至 DCOCLK = 8MHz
UCSCTL3 |= SELREF__REFOCLK; // FLL 参考源 = REFOCLK(32768Hz)

UCSCTL1 = DCORSEL_5; // DCO 频率范围:4.8~10.7MHz(适合 8MHz)
UCSCTL2 = 243; // FLLN = 243,DCOCLK = (243+1)×32768Hz ≈ 8MHz

// ② 选择系统时钟源
UCSCTL4 = SELM__DCOCLK // MCLK = DCOCLK(8MHz)
| SELS__DCOCLK // SMCLK = DCOCLK(8MHz)
| SELA__REFOCLK; // ACLK = REFOCLK(32768Hz)

// ③ 时钟分频:MCLK/SMCLK 不分频,ACLK 不分频
UCSCTL5 = DIVM__1 // MCLK 分频:÷1 → 8MHz
| DIVS__1 // SMCLK 分频:÷1 → 8MHz
| DIVA__1; // ACLK 分频:÷1 → 32768Hz

// ④ 等待振荡器稳定
do {
UCSCTL7 &= ~(XT1LFOFFG | DCOFFG); // 清除 XT1/DCO 故障标志
SFRIFG1 &= ~OFIFG; // 清除振荡器故障中断标志
} while (SFRIFG1 & OFIFG); // 测试振荡器是否稳定
}

关键计算:

1
2
3
4
DCOCLK = (FLLN + 1) × FLLREFCLK
= (243 + 1) × 32768Hz
= 244 × 32768Hz
≈ 8,000,192Hz ≈ 8MHz

5.2.3 实例二:XT1 32768Hz 晶振 + DCO FLL

场景: 外接 32768Hz 手表晶振到 XT1,以此为 FLL 参考源,DCO 输出 16MHz。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
void Clock_Init_XT1_16MHz(void)
{
// ① XT1 配置(P5.4/XIN、P5.5/XOUT 引脚)
P5SEL |= BIT4 | BIT5; // 选择 XT1 功能(引脚复用)

UCSCTL6 &= ~XT1OFF; // 开启 XT1
UCSCTL6 |= XCAP_3; // 内部负载电容 = 12.5pF
UCSCTL6 &= ~XTS; // XTS=0:LF 模式(32768Hz 晶振)

// ② 等待 XT1 起振
do {
UCSCTL7 &= ~XT1LFOFFG; // 清除 XT1 LF 故障标志
} while (UCSCTL7 & XT1LFOFFG); // 等待 XT1 稳定

// ③ 配置 FLL:以 XT1 为参考,DCOCLK = 16MHz
UCSCTL3 = SELREF__XT1CLK; // FLL 参考源 = XT1CLK(32768Hz)
UCSCTL1 = DCORSEL_6; // DCO 范围:8.0~16.0MHz
UCSCTL2 = 487; // FLLN = 487,DCOCLK = (487+1)×32768Hz ≈ 16MHz

// ④ 选择系统时钟
UCSCTL4 = SELM__DCOCLK // MCLK = DCOCLK(16MHz)
| SELS__DCOCLK // SMCLK = DCOCLK(16MHz)
| SELA__XT1CLK; // ACLK = XT1CLK(32768Hz)← 高精度!

// ⑤ 分频
UCSCTL5 = DIVM__1 // MCLK = 16MHz / 1 = 16MHz
| DIVS__4 // SMCLK = 16MHz / 4 = 4MHz
| DIVA__1; // ACLK = 32768Hz / 1 = 32768Hz

// ⑥ 等待 FLL 稳定
do {
UCSCTL7 &= ~(XT1LFOFFG | DCOFFG);
SFRIFG1 &= ~OFIFG;
} while (SFRIFG1 & OFIFG);
}

5.2.4 实例三:外部 XT2 高频晶振

场景: 外接 16MHz 晶振到 XT2,直接用作 MCLK(不使用 DCO/FLL)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
void Clock_Init_XT2_16MHz(void)
{
// ① XT2 引脚配置(P5.2/XT2IN、P5.3/XT2OUT)
P5SEL |= BIT2 | BIT3; // 选择 XT2 功能

UCSCTL6 &= ~XT2OFF; // 开启 XT2 振荡器
UCSCTL6 |= XT2DRIVE_2; // XT2 驱动能力:16~24MHz 范围

// ② 等待 XT2 起振
do {
UCSCTL7 &= ~XT2OFFG; // 清除 XT2 故障标志
} while (UCSCTL7 & XT2OFFG); // 等待 XT2 稳定

// ③ 直接使用 XT2 作为系统时钟
UCSCTL4 = SELM__XT2CLK // MCLK = XT2CLK(16MHz)直接来自晶振!
| SELS__XT2CLK // SMCLK = XT2CLK(16MHz)
| SELA__REFOCLK; // ACLK = REFOCLK(32768Hz)

UCSCTL5 = DIVM__1 | DIVS__1 | DIVA__1; // 全不分频
}

5.2.5 实例四:低功耗配置(VLOCLK 作 ACLK)

场景: 不接任何外部晶振,用内部 VLOCLK(~12kHz)作 ACLK 给 WDT,CPU 跑 DCO 1MHz。

1
2
3
4
5
6
7
8
9
10
11
12
13
void Clock_Init_LowPower(void)
{
// ① 关闭所有外部晶振,省电
UCSCTL6 |= XT1OFF; // 关闭 XT1
UCSCTL6 |= XT2OFF; // 关闭 XT2

// ② ACLK 选择 VLOCLK(12kHz 超低功耗)
UCSCTL4 = SELM__DCOCLK // MCLK = DCOCLK(~1MHz 默认)
| SELS__DCOCLK // SMCLK = DCOCLK(~1MHz)
| SELA__VLOCLK; // ACLK = VLOCLK(~12kHz)← 超低功耗!

UCSCTL5 = DIVM__1 | DIVS__1 | DIVA__1;
}

5.2.6 五种配置场景对比

场景 MCLK 源 SMCLK 源 ACLK 源 FLL 参考 外部晶振 适用
默认复位 DCO ~1MHz DCO ~1MHz XT1(或REFO) XT1(或REFO) 建议有 —
实例一 DCO 8MHz DCO 8MHz REFO 32kHz REFO 无 最常用开发
实例二 DCO 16MHz DCO 4MHz XT1 32kHz XT1 XT1 32kHz 需精确计时的应用
实例三 XT2 16MHz XT2 16MHz REFO 32kHz — XT2 16MHz USB、RF等需精确高频
实例四 DCO ~1MHz DCO ~1MHz VLO ~12kHz — 无 极低功耗电池供电

5.2.7 时钟配置常见错误

错误 后果 正确做法
忘记等晶振起振 时钟不稳定或程序跑飞 do...while 循环等待故障标志清零
忘记清除 OFIFG FLL 不工作,频率不对 UCSCTL7 &= ~XXXOFFG; SFRIFG1 &= ~OFIFG;
DCORSEL 选错范围 DCO 无法锁定到目标频率 查手册选 DCORSEL 覆盖目标频率
FLLN 计算错误 DCOCLK 不是预期频率 公式:DCOCLK = (FLLN+1) × FLLREFCLK
XTS 设错 32768Hz 晶振被当高频驱动 → 不起振 XTS=0 用于 32768Hz,XTS=1 用于 4~32MHz

5.2.8 常用频率 FLLN 速查表

以 REFO / XT1 32768Hz 为参考:

目标 DCOCLK FLLN 值 DCORSEL 建议 计算
1 MHz 30 2~3 (30+1) × 32768 ≈ 1.02 MHz
4 MHz 121 4 (121+1) × 32768 ≈ 4.00 MHz
8 MHz 243 5 (243+1) × 32768 ≈ 8.00 MHz
12 MHz 365 5 (365+1) × 32768 ≈ 12.00 MHz
16 MHz 487 6 (487+1) × 32768 ≈ 16.00 MHz
20 MHz 609 6 (609+1) × 32768 ≈ 19.99 MHz
25 MHz 762 7 (762+1) × 32768 ≈ 25.00 MHz

公式: FLLN = 目标频率 / 32768 - 1


5.2.9 考试记忆策略——UCSCTL 寄存器需要背到什么程度?

结论:不需要死记每个位的偏移量,考试考查的是理解而非背诵。

实际代码中,库文件已定义了宏名(如 SELM__DCOCLK、DCORSEL_5),宏名本身自带含义,一目了然。

按记忆深度分三层:


🔴 第一层:必须掌握(高频考点)

寄存器 必须记住的内容 为什么重要
UCSCTL4 SELM 选 MCLK 源,SELS 选 SMCLK 源,SELA 选 ACLK 源 ⭐最高频,选择题/填空题/编程题必考
UCSCTL5 DIVM/DIVS/DIVA 分频,公式 f / 2^n 计算 MCLK/SMCLK/ACLK 实际频率
UCSCTL2 FLLN 倍频系数,公式 DCOCLK = (FLLN+1) × 参考频率 计算 DCO 输出频率
UCSCTL6 XT1OFF/XT2OFF 启停,XTS 选 LF/HF,XCAP 选电容 配置外部晶振
UCSCTL7 XT1LFOFFG/DCOFFG 故障标志 + 清除流程 必考的初始化流程

🟡 第二层:理解功能即可(能根据描述选对寄存器)

寄存器 理解到什么程度 典型考法
UCSCTL3 知道它选 FLL 参考源(SELREF),能认出 SELREF__REFOCLK 选择题:”设置 FLL 参考源用哪个寄存器?”
UCSCTL1 知道它设 DCO 范围(DCORSEL)和 FLL 分频(FLLD) 匹配题
UCSCTL0 知道它控制 DCO 调校值,FLL 自动维护,一般不需手动设 判断题:”UCSCTL0 是否需要手动配置?”

🟢 第三层:知道有这个东西就行(考试几乎不考)

寄存器 知道什么
UCSCTL8 低功耗下控制时钟请求,了解存在即可

宏名可读性说明——不需要背宏值:

1
2
3
4
5
6
// 以下两句,宏名本身就是含义,考试给你宏名你就能读懂:
UCSCTL4 = SELM__DCOCLK | SELS__DCOCLK | SELA__REFOCLK;
// └──MCLK选DCO └──SMCLK选DCO └──ACLK选REFO

UCSCTL5 = DIVM__1 | DIVS__4 | DIVA__1;
// └MCLK÷1 └SMCLK÷4 └ACLK÷1

真正的考试思路:

考试不考你”UCSCTL4 第几位是什么”,而是考:

考试题型 示例 需要的是
选择/填空 “MCLK 的时钟源由寄存器 __ 选择” 知道是 UCSCTL4
计算题 “FLLN=243,参考 32768Hz,求 DCOCLK” 记住公式 DCOCLK = (FLLN+1) × 32768
编程题 “写出配置 8MHz 的初始化代码” 知道用哪些寄存器 + 大致顺序
分析题 “这段代码把 SMCLK 设成了多少频率?” 能读代码,顺藤摸瓜找到分频设置

核心策略: 理解每个寄存器”管什么”,能根据功能说对寄存器名,能读懂给定宏名的代码——这比死记位布局重要得多。


5.3 教材实例分析


5.3.1 【例5.1.1】ACLK 配置为 VLOCLK 并通过 P1.0 输出

功能: 使用内部超低功耗振荡器 VLO 作为 ACLK 时钟源(约 12kHz),将 ACLK 通过 P1.0 引脚输出(MSP430F5529 中 P1.0 与 ACLK 复用)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <msp430f5529.h>

void main(void)
{
WDTCTL = WDTPW + WDTHOLD; // 关闭看门狗

UCSCTL4 |= SELA__VLOCLK; // 将 ACLK 的时钟源配置为 VLO(~12kHz)

P1DIR |= BIT0; // P1.0 设为输出
P1SEL |= BIT0; // P1.0 选择 ACLK 功能(引脚复用)

__bis_SR_register(LPM3_bits); // 进入 LPM3,MCLK/SMCLK 停止,ACLK 活动
// 不能简写成 LPM3; 必须用 __bis_SR_register()

while(1); // 程序停在此处(实际不会执行到)
}

代码分析:

关键操作 解释
SELA__VLOCLK SELA=1,ACLK 时钟源选 VLOCLK(~12kHz 超低功耗)
P1SEL |= BIT0 P1.0 引脚从 GPIO 模式切换到外设功能模式
__bis_SR_register(LPM3_bits) 设置 SR 寄存器进入 LPM3:CPU/MCLK/SMCLK/DCO 关闭,仅 ACLK 运行
无晶振 纯内部时钟,完全不需要外部元件

关于 __bis_SR_register(LPM3_bits) 为什么不能简写为 LPM3;:

1
2
3
4
5
6
7
8
9
10
// ❌ 错误写法:
LPM3; // 无效语句,编译器可能不报错但什么都不做

// ❓ 不推荐:
__bis_SR_register(LPM3); // 有些头文件 LPM3 未定义,不通用

// ✅ 标准写法:
__bis_SR_register(LPM3_bits); // LPM3_bits = CPUOFF | SCG0(宏展开为 0x0050)
// __bis_SR_register() 将这个值与 SR 寄存器做"或"
// 即:SR = SR | (CPUOFF | SCG0)

__bis_SR_register() 原理: bis = Bit Set(位置位),将参数中的位写入 SR。必须在括号内传入具体的位掩码值。

1
2
3
4
5
LPM3_bits = (CPUOFF | SCG0)
= (0x0010 | 0x0040)
= 0x0050
→ SR 的 bit4(CPUOFF) 和 bit6(SCG0) 被置 1
→ CPU 关断 + SMCLK/DCO 关断 → LPM3 模式

常用低功耗模式速记:

写法 展开 效果
LPM0_bits CPUOFF 仅关 CPU
LPM1_bits CPUOFF | SCG0 关 CPU + SMCLK/DCO
LPM2_bits CPUOFF | SCG1 关 CPU + MCLK/SMCLK
LPM3_bits CPUOFF | SCG0 | SCG1 关 CPU + MCLK/SMCLK/DCO(仅 ACLK 运行,最常用)
LPM4_bits CPUOFF | SCG0 | SCG1 | OSCOFF 全关(仅外部中断可唤醒)

关于 P1SEL 为什么能让 P1.0 输出 ACLK:

P1SEL(Port 1 Selection)是一个模式切换开关,不是功能选择器:

1
2
3
4
5
6
7
8
9
10
P1.0 引脚内部结构:
┌─────────┐
P1SEL.0 = 0 (GPIO) ──→│ P1DIR │──→ 决定输入/输出方向
│ P1OUT │──→ 输出高/低电平
│ P1IN │──→ 读取引脚电平
└─────────┘

┌─────────┐
P1SEL.0 = 1 (外设) ──→│ ACLK 输出│ ← 硬件固定连接,不可更改
└─────────┘

核心原理:

  • P1SEL.x = 0 → 引脚由 GPIO 寄存器控制(P1DIR/P1OUT/P1IN)
  • P1SEL.x = 1 → 引脚交给外设模块控制,具体是什么外设由芯片设计时硬件固定
  • P1.0 的外设功能在 MSP430F5529 中被硬连到 ACLK 输出——这不是 P1SEL “选择”的,而是出厂设计写死的

类比: P1SEL 像一个拨档开关——

  • 拨到 GPIO 档(0),你自己控制引脚高低电平
  • 拨到外设档(1),引脚自动连到硬件固定好的功能

你只能选”哪一档”,不能改”外设档连到谁”。

同理,P5SEL |= BIT4 + BIT5 也是硬件固定的——P5.4 和 P5.5 在芯片设计时就被连到了 XT1 晶振(XIN/XOUT),换其他引脚不行。


时钟相关引脚速查——考试必须记住的:

功能 引脚 PxSEL 配置 说明
ACLK 输出 P1.0 P1SEL |= BIT0 示波器看 ACLK 波形
SMCLK 输出 P2.2 P2SEL |= BIT2 示波器看 SMCLK 波形
MCLK 输出 P7.7 P7SEL |= BIT7 示波器看 MCLK 波形
XT1 晶振 P5.4(XIN) + P5.5(XOUT) P5SEL |= BIT4+BIT5 外接 32768Hz 或 4~32MHz 晶振
XT2 晶振 P5.2(XT2IN) + P5.3(XT2OUT) P5SEL |= BIT2+BIT3 仅外接高频晶振(4~32MHz)

考试应对策略:

题目描述 你应该写的
“将 ACLK 通过引脚输出” P1SEL |= BIT0(只有 P1.0!)
“外接 32768Hz 晶振到 XT1” P5SEL |= BIT4+BIT5(XIN/XOUT 固定 P5.4/P5.5)
“外接高频晶振到 XT2” P5SEL |= BIT2+BIT3
“将 SMCLK 输出” P2SEL |= BIT2
“将 MCLK 输出” P7SEL |= BIT7

记忆口诀: ACLK 走 1 号口(P1.0),SMCLK 走 2 号口(P2.2),MCLK 走 7 号口(P7.7),XT1 连 5.4/5.5,XT2 连 5.2/5.3——都是固定搭配,换不了。


5.3.2 【例5.1.2】XT1 接入 32768Hz 晶振,ACLK 通过 P1.0 输出

功能: XIN/XOUT 引脚外接 32768Hz 低频手表晶振,将 ACLK 配置为 32768Hz,通过 P1.0 口输出。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <msp430f5529.h>

void main(void)
{
WDTCTL = WDTPW + WDTHOLD; // 关闭看门狗

P1DIR |= BIT0; // P1.0 设为输出
P1SEL |= BIT0; // P1.0 选择 ACLK 功能

P5SEL |= BIT4 + BIT5; // P5.4/XIN、P5.5/XOUT 选择 XT1 晶振功能

UCSCTL6 &= ~XT1OFF; // 使能 XT1 振荡器
UCSCTL6 |= XCAP_3; // 选择内部负载电容 12pF

UCSCTL3 = 0; // FLL 参考时钟源 = XT1CLK(SELREF=0)

// 测试晶振是否故障失效,并清除故障标志
do {
UCSCTL7 &= ~(XT2OFFG | XT1LFOFFG | DCOFFG); // 清除 XT2/XT1/DCO 故障标志
SFRIFG1 &= ~OFIFG; // 清除振荡器故障中断标志
} while (SFRIFG1 & OFIFG); // 等待晶振稳定

UCSCTL6 &= ~XT1DRIVE_3; // 减少 XT1 驱动能力,降低功耗

UCSCTL4 |= SELA__XT1CLK; // ACLK 时钟来源 = XT1 晶振(32768Hz)

__bis_SR_register(LPM3_bits); // 进入 LPM3

while(1);
}

代码分析:

关键操作 解释
P5SEL |= BIT4+BIT5 P5.4/P5.5 复用为 XIN/XOUT 晶振引脚
XCAP_3 选择内部负载电容(~12pF),晶振起振必需
SELREF=0 0 对应 XT1CLK 作为 FLL 参考源
SELA__XT1CLK SELA=0,ACLK 直接来自 XT1(高精度 32768Hz)
do...while(OFIFG) 标准晶振稳定等待流程,必须掌握
XT1DRIVE_3 清除 晶振起振后降低驱动能力以省电

关于为什么需要 XCAP_3 选择电容:

晶振(石英晶体)要产生稳定的振荡,必须配合负载电容。没有电容,晶体根本不起振。

1
2
3
4
5
6
7
8
9
10
11
晶振振荡电路(皮尔斯振荡器):

XIN ──┬───[ 晶振 ]───┬── XOUT
│ │
─┴─ C1 ─┴─ C2
─┬─ ─┬─
│ │
GND GND

C1 和 C2 就是负载电容,
晶振频率的准确性依赖这两个电容的值

为什么需要 XCAP?

  • 传统做法:在 PCB 上外接两颗物理电容(增加成本和面积)
  • MSP430 的做法:芯片内部集成了可编程电容,通过 XCAP 选择电容值,省掉外部电容

XCAP 选项:

XCAP 值 内部电容 适用场景
0 ~1pF 已外接电容时
1 ~6pF 轻负载晶振
2 ~10pF 标准负载
3 ~12.5pF 常见 32768Hz 手表晶振(最常用)

一句话: 晶振不是接上就能振的,必须有电容配合。XCAP_3 就是打开芯片内部的等效电容,省得你在 PCB 上焊两颗电容。不写这行 → 晶振可能不起振 → do...while(OFIFG) 死循环。


关于 UCSCTL6 &= ~XT1DRIVE_3; 为什么减少驱动(不是必须但推荐):

XT1DRIVE 控制晶振的驱动电流。驱动越大越容易起振,但也越耗电。

1
2
3
4
起振阶段:需要较大驱动 ──→ 起振后:只需微弱的维持驱动
(类似推秋千) (类似轻轻扶一下就能继续)
高驱动电流 低驱动电流
易起振 省功耗
XT1DRIVE 驱动能力 适用时机
3(最高) 最强驱动 起振阶段 / 困难起振环境(低温、低电压)
2 中 一般晶振
1 较低 起振后维持
0(最低) 最弱驱动 起振稳定后降低功耗

为什么例程这样做:

1
2
3
// 第 8 行:初始设置时,XT1DRIVE 默认可能是较高值(帮助起振)
// → 晶振已通过 do...while 确认稳定起振
UCSCTL6 &= ~XT1DRIVE_3; // 起振成功!降低驱动 → 省电

考试回答:

  • ❌ 不是强制必须——不写这行,晶振也能正常工作
  • ✅ 但是省电——32768Hz 晶振是微小器件,过度驱动会额外消耗微安级电流
  • ✅ 延长晶振寿命——高频驱动可能导致手表晶振老化加速
  • ✅ 这是 MSP430 低功耗设计理念的体现:能省一微安是一微安

考试关键词: 降低功耗、低功耗设计、非必须但推荐。


5.3.3 【例5.1.3】XT2 接入高频晶振,MCLK/SMCLK 通过引脚输出

功能: XT2IN/XT2OUT 外接高频晶振(455kHz~16MHz),将 SMCLK 和 MCLK 配置为 XT2CLK,MCLK 通过 P7.7 输出,SMCLK 通过 P2.2 输出。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <msp430f5529.h>

void main(void)
{
WDTCTL = WDTPW + WDTHOLD; // 关闭看门狗

P2DIR |= BIT2; // P2.2 设为输出
P2SEL |= BIT2; // P2.2 选择 SMCLK 功能

P7DIR |= BIT7; // P7.7 设为输出
P7SEL |= BIT7; // P7.7 选择 MCLK 功能

P5SEL |= BIT2 + BIT3; // P5.2/XT2IN、P5.3/XT2OUT 选择 XT2 功能
// 注意:晶振引脚不需要设 P5DIR!
// PxSEL=1 后引脚脱离 GPIO,PxDIR 无效

UCSCTL6 &= ~XT2OFF; // 使能 XT2 振荡器

UCSCTL3 |= SELREF__REFOCLK; // FLL 参考时钟源 = REFO(32768Hz)

UCSCTL4 = SELM__XT2CLK // MCLK = XT2CLK(高频晶振)
| SELS__XT2CLK // SMCLK = XT2CLK
| SELA__REFOCLK; // ACLK = REFOCLK(32768Hz)

// 测试晶振是否故障失效,并清除故障标志
do {
UCSCTL7 &= ~(XT2OFFG | XT1LFOFFG | DCOFFG); // 清除故障标志
SFRIFG1 &= ~OFIFG; // 清除振荡器故障中断标志
} while (SFRIFG1 & OFIFG); // 等待晶振稳定

UCSCTL6 &= ~XT2DRIVE0; // 减少 XT2 驱动能力,降低功耗

while(1); // 程序在此循环(时钟已配置完成)
}

初始化顺序说明——为什么引脚配置要写在时钟配置前面:

1
2
3
4
5
6
7
8
9
10
初始化正确顺序:
┌─────────────────────────────────────────┐
│ ① 关看门狗 WDTCTL = ... │
│ ② 引脚配置 PxDIR / PxSEL(铺路) │ ← 先铺路
│ ③ 开启晶振 UCSCTL6 &= ~XT2OFF │
│ ④ 配置参考源 UCSCTL3(FLL 参考) │ ← 再发车
│ ⑤ 选择时钟源 UCSCTL4(MCLK/SMCLK/ACLK)│
│ ⑥ 等待稳定 do...while(OFIFG) │
│ ⑦ 降驱动省电 UCSCTL6 &= ~XT2DRIVE │
└─────────────────────────────────────────┘

为什么引脚要先于时钟配置?

  • PxSEL 把引脚从 GPIO 模式切换到晶振/时钟功能
  • 晶振引脚(P5.2/P5.3):必须先设 P5SEL,否则引脚还是 GPIO 模式,XT2 使能后振荡电路无法接入引脚 → 白开晶振
  • 时钟输出引脚(P2.2/P7.7):先设 PxDIR 定方向,再设 PxSEL 接时钟,避免瞬间不确定状态

错误顺序举例:

1
2
3
// ❌ 错误:先开晶振再配引脚
UCSCTL6 &= ~XT2OFF; // 晶振已开启
P5SEL |= BIT2 + BIT3; // 这时才把引脚给 XT2 ← 晚了!晶振可能已经报故障

结论:

1
2
引脚 PxDIR/PxSEL → 一定要写在 → 时钟 UCSCTL6/UCSCTL3/UCSCTL4 之前
"先铺路" "再发车"

代码分析:

关键操作 解释
P2SEL |= BIT2 P2.2 复用为 SMCLK 输出引脚
P7SEL |= BIT7 P7.7 复用为 MCLK 输出引脚
SELM__XT2CLK MCLK 直接来自 XT2 晶振(不经 DCO/FLL)
SELA__REFOCLK ACLK 用内部 REFO,因 XT1 未使用
无 LPM 此例在活动模式运行,用于演示高频时钟

关于晶振引脚为什么不需要 PxDIR:

1
2
3
4
PxSEL = 0(GPIO 模式):               PxSEL = 1(外设模式):
PxDIR 控制方向(输入/输出) → PxDIR 不再有效!
PxOUT 控制输出电平 引脚完全由外设硬件接管
PxIN 读取引脚状态

XT1(P5.4/P5.5)和 XT2(P5.2/P5.3)是模拟引脚,连到芯片内部的晶振驱动电路:

  • 这些引脚不输出数字高低电平,而是产生/接收模拟振荡波形
  • PxSEL=1 后,引脚脱离数字 GPIO 控制,PxDIR 对这类引脚无意义
  • 同理,P1.0(ACLK 输出)也不需要设 P1DIR——有同学会问例程为什么设了,那只是防御性写法,不写也能工作

一句话规则:

1
2
PxSEL = 1  →  引脚交给外设 → PxDIR 不用管
PxSEL = 0 → 引脚是 GPIO → 必须设 PxDIR

MSP430F5529 时钟输出引脚速查:

时钟信号 输出引脚
ACLK P1.0
SMCLK P2.2
MCLK P7.7

Q1:例5.1.3 中 XT2 为什么没有 XCAP 选电容?

XT2 是高频晶振(4~32MHz),与 XT1 的低频模式设计不同:

对比 XT1 (LF 模式) XT2 (4~32MHz)
频率 32768Hz 4~32MHz
内部可编程电容(XCAP) ✅ 有(1/6/10/12.5pF) ❌ 无
负载电容来源 内部 XCAP 或外部电容 必须接外部电容(PCB 上焊接)
原因 低频下电容精度要求低,内部集成可行 高频下需要精确匹配,且电容值需求多样化
1
2
3
XT1 LF(32768Hz):                 XT2(4~32MHz):
可用内部 XCAP 省电容 必须 PCB 上外接两颗电容
或者也外接也行 芯片内部没有 XCAP 可配

考试回答: XT2 不支持内部 XCAP,负载电容需要在 PCB 上外接。例程假设 PCB 上已焊好电容,所以代码中不需要配置 XCAP。

实际上 XT1 的 HF 模式(4~32MHz)也没有 XCAP——XCAP 仅在 XTS=0(LF 模式)时有效。高频模式下 XT1 和 XT2 一样,都靠外部电容。


Q2:例5.1.3 题目没提 ACLK,为什么还要 SELA__REFOCLK?

即使题目没提到 ACLK,你也必须给它一个有效的时钟源,否则会有隐患:

1
2
3
复位后默认:SELA = 0 → ACLK 指向 XT1CLK
↑
但 XT1 没有接晶振!→ ACLK 没有时钟源 → 死路

不设 SELA 的后果:

  1. 任何依赖 ACLK 的外设(如 WDT 看门狗)不工作
  2. 即使本例不直接”使用” ACLK,它是系统时钟,应该始终有效
  3. 是一个防御性编程习惯

遇到这种情况的规则:

情况 你该设的 ACLK 源
XT1 接了晶振 SELA__XT1CLK(默认,可不写但建议写)
XT1 没接晶振 SELA__REFOCLK 或 SELA__VLOCLK(给一个内部源)

原则: 三个系统时钟(ACLK/SMCLK/MCLK)永远指向一个有效的时钟源,不能挂空挡。


Q3:什么情况下需要配置 UCSCTL3(FLL 参考时钟源)?

UCSCTL3 的 SELREF 决定 FLL 以谁为基准来校正 DCO。

必须配置 UCSCTL3 的情况:

场景 是否必须 原因
使用 DCOCLK 作 MCLK/SMCLK ✅ 必须 FLL 需要参考源来稳频 DCO
XT1 未接晶振(默认 SELREF=XT1) ✅ 必须 默认参考源 XT1 不存在,FLL 无法锁定
MCLK/SMCLK 直接用 XT1/XT2(不经过 FLL) 🟡 建议 不是必须,但不设会导致 do...while 卡在故障标志上
XT1 接了 32768Hz 晶振且用它作参考 ❌ 可不写 SELREF 默认 = 0 = XT1CLK,恰好就是 XT1

例5.1.3 为什么写了:

1
UCSCTL3 |= SELREF__REFOCLK;  // 即使不用 FLL,也要给它一个有效参考源

因为例程中 XT1 未接晶振,SELREF 默认指向 XT1 → FLL 没有参考 → DCOFFG 置位 → do...while(OFIFG) 检测到故障 → 死循环永远出不去!

1
2
3
4
5
6
7
如果 XT1 不接晶振且不设 SELREF:
SELREF=XT1(无晶振) → FLL 无参考 → DCOFFG=1
↓
do { 清除 DCOFFG } while(OFIFG);
↓ ↑
└──清除后FLL再次检测无参考→DCOFFG又被置1 ──┘
→ 死循环!

规则总结:

  • 没接 XT1 晶振 → 必须设 UCSCTL3,否则 do...while 死循环
  • 接了 XT1 且用它作 FLL 参考 → 可不写,默认就是 XT1
  • 不管哪种情况,显式写出来更安全,代码也更好读

— 【例5.1.4】DCO 配置为 8MHz(FLL + REFO)

功能: 使用 REFO 作 FLL 参考源,将 DCOCLK 精确配置为 8MHz,ACLK/SMCLK/MCLK 分别通过 P1.0/P2.2/P7.7 输出,P1.1 接 LED 闪烁验证。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#include <msp430f5529.h>

void main(void)
{
WDTCTL = WDTPW + WDTHOLD; // 关闭看门狗

P1DIR |= BIT1; // P1.1 设为输出(LED)

P1DIR |= BIT0; // P1.0 设为输出
P1SEL |= BIT0; // P1.0 选择 ACLK 功能

P2DIR |= BIT2; // P2.2 设为输出
P2SEL |= BIT2; // P2.2 选择 SMCLK 功能

P7DIR |= BIT7; // P7.7 设为输出
P7SEL |= BIT7; // P7.7 选择 MCLK 功能

UCSCTL3 = SELREF__REFOCLK; // FLL 参考时钟源 = REFO(32768Hz)
UCSCTL4 |= SELA__REFOCLK; // ACLK = REFOCLK(32768Hz)

UCSCTL0 = 0x0000; // DCO 和 MOD 寄存器调校值设为最低

// 清除故障标志并等待稳定
do {
UCSCTL7 &= ~(XT2OFFG | XT1LFOFFG | DCOFFG);
SFRIFG1 &= ~OFIFG;
} while (SFRIFG1 & OFIFG);

__bis_SR_register(SCG0); // 禁止 FLL(SCG0=1,才能修改 FLLN)

UCSCTL1 = DCORSEL_5; // 选择 DCO 频率范围(4.8~10.7MHz,适合 8MHz)
UCSCTL2 |= 249; // FLLN = 249
// DCOCLK = (249+1) × 32768Hz ≈ 8MHz

__bic_SR_register(SCG0); // 启用 FLL(SCG0=0,FLL 开始锁定)

__delay_cycles(250000); // 延时,等待 DCO 工作稳定

while(1)
{
P1OUT ^= BIT1; // 翻转 P1.1 LED 状态
__delay_cycles(600000); // 延时
}
}

代码分析——8MHz 配置关键步骤:

1
2
3
4
5
6
7
8
步骤     操作                        含义
─────────────────────────────────────────────
① UCSCTL3 = SELREF__REFOCLK 选参考源 32768Hz
② __bis_SR_register(SCG0) 禁止 FLL ← 必须!修改 FLLN 前要关 FLL
③ UCSCTL1 = DCORSEL_5 选 DCO 粗调范围
④ UCSCTL2 |= 249 FLLN = 249 → DCOCLK ≈ 8MHz
⑤ __bic_SR_register(SCG0) 启用 FLL ← 锁定频率
⑥ __delay_cycles(250000) 等 DCO 稳定

核心公式: DCOCLK = (FLLN + 1) × FLLREFCLK


关于例5.1.4 的六个关键问题:


Q1: SELA__REFOCLK 一定要设为 REFOCLK 吗?能改 XT1CLK 吗?

能,前提是 XT1 接了晶振。 本例设为 REFOCLK 是因为没有外接 XT1 晶振。

情况 ACLK 选什么 说明
没接 XT1 晶振(本例) SELA__REFOCLK(内部 ~32768Hz) 必须给 ACLK 一个有效源
接了 XT1 32768Hz 晶振 可以改 SELA__XT1CLK 精度更高,但需外接晶振

SELA__REFOCLK 和 SELREF__REFOCLK 不冲突——前者是 ACLK 直接选 REFO,后者是 FLL 参考源选 REFO。两者各管各的,可以同时指向同一个源。


Q2: UCSCTL0 = 0x0000; 是什么意思?

UCSCTL0 包含 DCO 的 8 位调校值(DCOx)和调制器参数(MODx):

1
2
3
UCSCTL0 = 0x0000 → DCO = 0, MOD = 0
→ DCO 从最低频率点起步
→ FLL 再从零开始向上锁定到目标频率

作用: 给 FLL 一个干净的起点。如果不写这行,DCO 可能保持上次运行残留的值,导致 FLL 锁定过程出现抖动。相当于”把频率旋钮拧回零位,让 FLL 自己调到目标”。


Q3: 为什么 __bis_SR_register(SCG0) 禁止 FLL 才能改参数?

硬件保护机制——FLL 运行时,部分寄存器写保护!

1
2
3
4
5
6
7
8
FLL 使能时(SCG0=0):
UCSCTL1 (DCORSEL) → ⛔ 写保护!改了也不生效
UCSCTL2 (FLLN) → ✅ 可以写,但会立即跳频,可能不稳

FLL 禁止时(SCG0=1):
UCSCTL1 (DCORSEL) → ✅ 可以修改
UCSCTL2 (FLLN) → ✅ 可以修改
→ 改完所有参数后,再 SCG0=0 重新开启 → FLL 平滑锁定新频率

根本原因: DCORSEL(DCO 频率范围选择)在 FLL 使能时被硬件锁定,必须先 SCG0=1 才能改写。即使只改 FLLN,也建议先关 FLL——统一改完再开启,干净利落。

考试必记: 修改 DCO 参数前 → SCG0=1(关 FLL),改完后 → SCG0=0(开 FLL)。


Q4: DCORSEL 必须选吗?不选会怎样?

必须选。 DCO 是数控振荡器,它的输出频率需要在某个”频道”内调整。DCORSEL 选频道:

1
2
3
4
5
6
7
8
DCORSEL 档位     覆盖范围         适用目标频率
─────────────────────────────────────────────
2 0.60~2.00 MHz 1 MHz
3 1.00~3.60 MHz 2 MHz
4 2.00~6.00 MHz 4 MHz
5 4.80~10.7 MHz 8 MHz ← 本例
6 8.00~16.0 MHz 12/16 MHz
7 16.00~32.0 MHz 24/25 MHz
选错了 后果
DCORSEL 太小 DCO 硬件极限够不到目标频率 → 锁不住
DCORSEL 太大 频率步进太粗 → FLL 来回抖动,精度差

选 DCORSEL 的规则: 查手册,选择目标频率落在中间偏上的档位。8MHz 落在 DCORSEL_5(4.8~10.7MHz)中间,最合适。


Q5: FLLN 到底该用 249 还是 243?教材是不是写错了?

你的计算是对的,但教材也没错——这是精度优先 vs 取整方便的区别。

1
2
教材写法:  FLLN = 249 → DCOCLK = 250×32768 = 8,192,000 Hz ≈ 8.19 MHz
你的计算: FLLN = 243 → DCOCLK = 244×32768 = 7,995,392 Hz ≈ 8.00 MHz
FLLN 实际频率 与 8MHz 偏差 评价
243 7.995 MHz ~0.06% ✅ 更精准
244 8.028 MHz ~0.35% 也可
249 8.192 MHz ~2.4% 教材常用近似值

为什么教材用 249 而不是 243?
教材常取”好看”的整数倍关系:250 × 32768 ≈ 8.19MHz,方便学生心算。实际工程中 FLL 有 MOD 调制可以微调补偿,精度差异不大。

考试建议: 按公式 FLLN = 目标频率 / 32768 - 1 计算为准。如果选项中有 243 和 249,选 243(误差更小)。式子写对比记住具体数值更重要。


6. MSP430 外设模块

6.2 模数转换模块(ADC12,12-bit Analog-to-Digital Converter)

6.2.1 模数转换概述——分辨率(Resolution)

分辨率表示输出数字量变化一个相邻数码所需输入模拟电压的变化量:

1
分辨率 = 满刻度电压 / 2^n    (n = ADC 位数)
ADC 位数 分辨率(满刻度 5V) 量化级数
8 位 5V / 256 ≈ 20 mV 256
10 位 5V / 1024 ≈ 4.9 mV 1024
12 位(F5529) 5V / 4096 ≈ 1.2 mV 4096

核心结论: ADC 位数越高,分辨率越精细,采集精度越高。MSP430F5529 内置 12 位 ADC。


6.3 比较器 B(Comp_B,Comparator B)

6.3.1 比较器 B 介绍

比较器是模拟比较电路,比较两个输入端电压的大小:

1
2
3
4
5
6
同相输入端(+) → ┌──────────┐
│ Comp_B │ → 输出端(数字电平)
反相输入端(-) → └──────────┘

V(+) > V(-) → 输出高电平(1)
V(+) < V(-) → 输出低电平(0)

基本概念:

术语 含义
输入电压(Input Voltage) 待比较的模拟电压
阈值(Threshold) 参考电压,作为比较基准
输出电平(Output Level) 比较结果,数字信号(0/1)

应用: 测量电阻、电压监测、过零检测、低功耗唤醒等。


6.4 定时器(Timers)


6.4.1 看门狗定时器(WDT,Watch Dog Timer)

背景: 工业控制现场,供电电源、电磁干扰等原因引起程序跑飞、系统死机。WDT 的作用是在系统异常后自动复位恢复。

工作原理:

1
2
3
4
5
正常程序运行:                        程序跑飞后:
主循环定期"喂狗"(清零WDT) 没有喂狗 → WDT 溢出
│ │
▼ ▼
WDT 计数器被清零,不会溢出 WDT 产生系统复位 → 程序重新启动
  • ⚫ WDT 是一个32 位增计数器,计数溢出时产生系统复位
  • ⚫ 正常运行时必须在 WDT 溢出前清零(喂狗):WDTCTL = WDTPW + WDTCNTCL;
  • ⚫ 所有例程开头都写 WDTCTL = WDTPW + WDTHOLD;——这是关闭看门狗,防止调试时意外复位

考试关键词: 程序跑飞、自动复位、32 位计数器、定期清零(喂狗)。


6.4.2 定时器 A(Timer_A)


(1)16 位定时器原理

Timer_A 是一个 16 位定时/计数器,核心寄存器:

寄存器 作用
TAxCTL 定时器控制(时钟源、工作模式、启停)
TAxR(TAR) 16 位计数器,每个时钟脉冲 ±1
TAxCCRn 捕获/比较寄存器 n(n=0~4),定义比较阈值
TAxCCTLn 捕获/比较控制寄存器 n

(2)Timer_A 四种工作模式

由 MC 控制位(TAxCTL 的 bit4-5)选择:

MC 模式 计数范围 描述
00 停止模式(Stop) — 定时器停止
01 增计数模式(Up) 0 → TAxCCR0 → 0 → … 到 CCR0 后归零重新计
10 连续计数模式(Continuous) 0 → 0xFFFF → 0 → … 计满 65535 后归零
11 增/减计数模式(Up/Down) 0 → CCR0 → 0 → … 到 CCR0 后反向减回 0

图解四种模式:

1
2
3
4
5
6
7
8
9
10
11
12
增计数模式(Up):         连续计数模式(Continuous):
CCR0 ─┐ ┌─ 0xFFFF ─┐ ┌─
│ │ │ │
│ │ │ │
0 ────┘ └──→ t 0 ────┘ └──→ t

增/减计数模式(Up/Down):
CCR0 ─┐ ┌─
│ /\ │
│ / \ │
0 ────┘/ \└──→ t
周期 = 2×CCR0

(3)捕获模式与比较模式

由 CAP 控制位(TAxCCTLn 的 bit8)选择:

CAP 模式 功能 典型用途
1 捕获模式(Capture) 捕获事件发生的时刻(记录 TAR 值) 测量脉冲宽度、频率
0 比较模式(Compare) TAR 与 CCRn 相等时触发输出动作 产生 PWM、定时中断

(4)PWM 输出——比较模式下的波形生成

PWM(Pulse Width Modulation,脉冲宽度调制)关键指标:

1
2
3
4
5
6
7
8
周期 T:
┌──────┐ ┌──────┐
│ │ │ │
│ t1 │ t2 │ t1 │
│ (高) │ (低) │ │
──┘ └──────────┘ └────
├──────┤← 脉宽
├─────────────┤← 周期 T
指标 定义 公式
周期(Period) 相邻上升沿之间的时长 T
脉宽(Pulse Width) 高电平持续时间 t1
占空比(Duty Cycle) 脉宽占周期的比例 (t1 / T) × 100%

增计数模式 PWM 周期与占空比计算:

1
2
3
4
5
TAR 从 0 计数到 TAxCCR0:
PWM 周期 = (TAxCCR0 + 1) × T_clk
PWM 占空比 = TAxCCRn / (TAxCCR0 + 1)

其中 T_clk = 1 / 定时器时钟频率

【例6.4.7】TA0 增计数模式 PWM(75% 和 25% 占空比)

功能: TA0 工作在增计数模式,ACLK 作时钟源。P1.2 输出 75% 占空比 PWM,P1.3 输出 25% 占空比 PWM。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <msp430f5529.h>

void main(void)
{
WDTCTL = WDTPW + WDTHOLD; // 关闭看门狗

P1DIR |= BIT2 + BIT3; // P1.2 和 P1.3 设为输出
P1SEL |= BIT2 + BIT3; // P1.2/P1.3 引脚功能选为定时器输出

TA0CCR0 = 512 - 1; // PWM 周期 = 512 个 ACLK 周期
// CCR0 = 511,周期 = 512

TA0CCTL1 = OUTMOD_7; // CCR1 输出模式7:复位/置位
TA0CCR1 = 384; // 占空比 = 384/512 = 75%

TA0CCTL2 = OUTMOD_7; // CCR2 输出模式7:复位/置位
TA0CCR2 = 128; // 占空比 = 128/512 = 25%

TA0CTL = TASSEL__ACLK // 时钟源 = ACLK
| MC__UP // 增计数模式
| TACLR; // 清除 TAR 计数器

__bis_SR_register(LPM3_bits); // 进入 LPM3
}

占空比验证:

1
2
CCR1 = 384 → 占空比 = 384/512 = 0.75 = 75% ✓
CCR2 = 128 → 占空比 = 128/512 = 0.25 = 25% ✓

OUTMOD_7(复位/置位模式)波形:

1
2
3
4
TAR:  0 ──→ CCRn ──→ CCR0 ──→ 0
输出: 高 低 高
└──脉宽──┘
├────── 周期 ──────┤

【例6.4.8】TA1 连续计数模式 PWM(25% 占空比)

功能: TA1 工作在连续计数模式(0→0xFFFF),ACLK 作时钟源。P2.0 输出 25% 占空比 PWM。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <msp430f5529.h>

void main(void)
{
WDTCTL = WDTPW + WDTHOLD; // 关闭看门狗

P2DIR |= BIT0; // P2.0 设为输出
P2SEL |= BIT0; // P2.0 引脚设为定时器输出

TA1CCTL1 = OUTMOD_3; // CCR1 输出模式3:置位/复位
TA1CCR0 = 16484; // 定义 PWM 周期
TA1CCR1 = 100; // PWM 变高时刻
// 占空比 = (16484-100) / 65536 = 25%

TA1CTL = TASSEL__ACLK // 时钟源 = ACLK
| MC__CONTINUOUS // 连续计数模式(0→0xFFFF)
| TACLR; // 清除 TAR 计数器

__bis_SR_register(LPM3_bits); // 进入 LPM3
}

连续计数模式占空比计算——与增计数模式不同:

1
2
增计数模式:     周期 = CCR0+1,        占空比 = CCR1/(CCR0+1)
连续计数模式: 周期 = 65536(固定), 占空比 = (CCR0-CCR1)/65536

本例验证:

1
2
3
4
CCR0=16484, CCR1=100
高电平 = 16484-100 = 16384 个时钟
周期 = 65536 个时钟(0xFFFF+1,固定不变)
占空比 = 16384/65536 = 1/4 = 25% ✓

设计思路: 先定占空比 25% → 高电平 = 65536×0.25 = 16384 个时钟 → 设 CCR1=100(变高时刻),CCR0=100+16384=16484(变低时刻)。


(5)PWM 常用输出模式速查

OUTMOD 名称 输出行为
0 输出禁止 引脚由 GPIO 控制
1 置位 TAR=CCRn 时置 1
2 翻转/复位 TAR=CCRn 翻转,TAR=CCR0 复位
3 置位/复位 TAR=CCRn 置 1,TAR=CCR0 清 0
4 翻转 TAR=CCRn 时翻转
5 复位 TAR=CCRn 时清 0
6 翻转/置位 TAR=CCRn 翻转,TAR=CCR0 置 1
7 复位/置位 TAR=CCRn 清 0,TAR=CCR0 置 1(最常用)

OUTMOD_7 与 OUTMOD_3 对比: OUTMOD_7 在 CCRn 处变低、CCR0 处变高(高电平在前);OUTMOD_3 在 CCRn 处变高、CCR0 处变低(低电平在前)。两者互为反相。


(6)Timer_A 考试要点速记

考点 关键词
四种模式 Stop(00) / Up(01) / Continuous(10) / Up/Down(11)
增计数周期 周期 = (CCR0+1) × T_clk
PWM 占空比 占空比 = CCRn / (CCR0+1)
OUTMOD_7 复位/置位——CCRn 清 0,CCR0 置 1(高→低→高)
TASSEL 时钟源选择:TASSEL__ACLK=ACLK,TASSEL__SMCLK=SMCLK
PWM 引脚 P1.2(TA0.1)、P1.3(TA0.2)、P2.0(TA1.1) 等
捕获 vs 比较 CAP=1 捕获时刻,CAP=0 比较输出

(7)Timer_A 寄存器表

寄存器 全称 功能
TAxCTL Timer_A Control 时钟源选择、工作模式、分频、启停控制
TAxR(TAR) Timer_A Counter 16 位计数器,只读,每个时钟 ±1
TAxCCTLn Capture/Compare Control n 捕获/比较模式、输出模式、中断控制(n=0~6)
TAxCCRn Capture/Compare Register n 比较阈值 / 捕获时刻存储(n=0~6)
TAxIV Timer_A Interrupt Vector 中断向量寄存器,读取时自动清除最高优先级中断标志
TAxEX0 Timer_A Expansion 0 分频扩展(÷1/2/3/4/5/6/7/8 可选)

(8)TAxCTL 控制寄存器——各控制位详解

1
2
3
4
位:   15-10     9-8         7-6       5-4     3     2       1       0
┌────────┬──────────┬──────────┬─────────┬───┬───────┬───────┬───────┐
│ 保留 │ TASSEL │ ID │ MC │保留│ TACLR │ TAIE │ TAIFG │
└────────┴──────────┴──────────┴─────────┴───┴───────┴───────┴───────┘
位 名称 含义 选项
9-8 TASSEL(Timer_A Source Select) 时钟源选择 00=TACLK, 01=ACLK, 10=SMCLK, 11=INCLK
7-6 ID(Input Divider) 时钟分频 00=÷1, 01=÷2, 10=÷4, 11=÷8
5-4 MC(Mode Control) 工作模式 00=Stop, 01=Up, 10=Continuous, 11=Up/Down
2 TACLR(Clear) 清计数器 写 1 清零 TAR + 分频器 + 计数方向(自动复位为 0)
1 TAIE(Interrupt Enable) 溢出中断使能 1=TAR 溢出时触发中断(CCR0 中断不受此位控制)
0 TAIFG(Interrupt Flag) 溢出中断标志 TAR 溢出时硬件置 1,需软件清除

考试必记: TAxCTL = TASSEL__ACLK | MC__UP | TACLR; → ACLK 作时钟 + 增计数模式 + 清计数器。


(9)TAxCCTLn 捕获/比较控制寄存器——各控制位详解

1
2
3
4
位:  15-14   13-12    11   10   9   8    7-5       4     3    2    1     0
┌──────┬────────┬─────┬────┬──┬───┬─────────┬─────┬─────┬────┬─────┬──────┐
│ CM │ CCIS │ SCS │SCCI│保留│CAP│ OUTMOD │CCIE │ CCI │OUT │ COV │CCIFG │
└──────┴────────┴─────┴────┴──┴───┴─────────┴─────┴─────┴────┴─────┴──────┘
位 名称 含义 选项
15-14 CM(Capture Mode) 捕获边沿选择 00=禁止, 01=上升沿, 10=下降沿, 11=双沿
13-12 CCIS(CCI Select) 捕获输入引脚选择 00=CCIxA, 01=CCIxB, 10=GND, 11=VCC
11 SCS(Sync Capture) 同步捕获 1=与定时器时钟同步(推荐)
10 SCCI(Synced CCI) 锁存的 CCI 值 只读
8 CAP(Capture Mode) 捕获/比较选择 0=比较模式, 1=捕获模式
7-5 OUTMOD(Output Mode) 输出模式 000~111(7 种模式,见下表)
4 CCIE(Interrupt Enable) CCRn 中断使能 1=使能 CCRn 匹配中断(分闸)
3 CCI(Capture Input) 输入信号电平 只读
2 OUT(Output) 输出电平 OUTMOD=0 时直接控制输出值
1 COV(Capture Overflow) 捕获溢出标志 上次捕获未读又发生新捕获时置 1
0 CCIFG(Interrupt Flag) CCRn 中断标志 捕获完成/比较匹配时硬件置 1,需软件清除

(10)OUTMOD 输出模式完整速查

OUTMOD 模式名称 输出行为描述 波形特点
000 输出禁止 引脚由 GPIO 控制(输出模式不工作) —
001 置位(Set) TAR=CCRn 时 OUT=1 单次置高
010 翻转/复位(Toggle/Reset) TAR=CCRn 翻转 OUT,TAR=CCR0 清 OUT=0 Toggle + Reset
011 置位/复位(Set/Reset) TAR=CCRn 置 OUT=1,TAR=CCR0 清 OUT=0 低→高→低
100 翻转(Toggle) TAR=CCRn 时 OUT 翻转 每次匹配翻转
101 复位(Reset) TAR=CCRn 时 OUT=0 单次清低
110 翻转/置位(Toggle/Set) TAR=CCRn 翻转 OUT,TAR=CCR0 置 OUT=1 Toggle + Set
111 复位/置位(Reset/Set) TAR=CCRn 清 OUT=0,TAR=CCR0 置 OUT=1 高→低→高(最常用)

OUTMOD_7 vs OUTMOD_3 对比:

1
2
3
4
5
OUTMOD_7(复位/置位):  ████▌      ████▌    ← 高在前(CCR0处变高)
0 CCRn CCR0

OUTMOD_3(置位/复位): ████▌ ████▌ ← 低在前(CCRn处变高)
0 CCRn CCR0

两者波形互为反相。


(11)TAxIV 中断向量寄存器

读取 TAxIV 会自动清除最高优先级的中断标志,用于高效 ISR 处理:

TAxIV 值 中断源 优先级
0x00 无中断 —
0x02 CCR1 CCIFG 最高
0x04 CCR2 CCIFG ↓
0x06 CCR3 CCIFG ↓
0x08 CCR4 CCIFG ↓
0x0A CCR5 CCIFG ↓
0x0C CCR6 CCIFG ↓
0x0E TAIFG(TAR 溢出) 最低

用法示例:

1
2
3
4
5
6
7
8
9
10
#pragma vector = TIMER0_A1_VECTOR
__interrupt void TA0_ISR(void)
{
switch (TA0IV) // 读取 TA0IV → 自动清除最高优先级标志
{
case 0x02: /* CCR1 处理 */ break;
case 0x04: /* CCR2 处理 */ break;
case 0x0E: /* 溢出处理 */ break;
}
}

注意: CCR0 有独立的中断向量 TIMER0_A0_VECTOR,不走 TAxIV。


附录 · 额外问题记录

以下为学习过程中额外提出的问题及其解答,持续补充。


A.1 如何求解 SVM 硬间隔原始优化问题

原问题(P123):

$$
\min_{\boldsymbol{w}, b} \frac{1}{2}|\boldsymbol{w}|^2 \quad \text{s.t.} \quad y_i(\boldsymbol{w}^T \boldsymbol{x}_i + b) \ge 1, ; i=1,\dots,m
$$

目标:找一个最大间隔(maximum margin)超平面 $\boldsymbol{w}^T\boldsymbol{x} + b = 0$ 分隔两类样本。

  • $\frac{1}{2}|\boldsymbol{w}|^2$ 最小化 → 最大化间隔(margin = $2/|\boldsymbol{w}|$)
  • $y_i(\boldsymbol{w}^T\boldsymbol{x}_i + b) \ge 1$ → 所有样本正确分类且到超平面距离 ≥ 1

(1) Lagrange 函数

为每个约束引入 Lagrange 乘子 $\alpha_i \ge 0$:

$$
L(\boldsymbol{w}, b, \boldsymbol{\alpha}) = \frac{1}{2}|\boldsymbol{w}|^2 - \sum_{i=1}^{m} \alpha_i \big[y_i(\boldsymbol{w}^T\boldsymbol{x}_i + b) - 1\big]
$$

(2) 对 $\boldsymbol{w}$ 和 $b$ 求偏导并令其为 0

$$
\frac{\partial L}{\partial \boldsymbol{w}} = \boldsymbol{w} - \sum_{i=1}^{m} \alpha_i y_i \boldsymbol{x}i = 0
\quad\Rightarrow\quad
\boxed{\boldsymbol{w} = \sum
{i=1}^{m} \alpha_i y_i \boldsymbol{x}_i}
$$

$$
\frac{\partial L}{\partial b} = -\sum_{i=1}^{m} \alpha_i y_i = 0
\quad\Rightarrow\quad
\boxed{\sum_{i=1}^{m} \alpha_i y_i = 0}
$$

(3) 对偶问题

代回 $L$ 消去 $\boldsymbol{w}, b$:

$$
\max_{\boldsymbol{\alpha}} \sum_{i=1}^{m} \alpha_i - \frac{1}{2}\sum_{i=1}^{m}\sum_{j=1}^{m} \alpha_i \alpha_j y_i y_j (\boldsymbol{x}_i^T \boldsymbol{x}_j)
$$

$$
\text{s.t.} \quad \alpha_i \ge 0, \quad \sum_{i=1}^{m} \alpha_i y_i = 0
$$

(4) KKT 条件与解结构

  • 互补松弛性:$\alpha_i\big[y_i(\boldsymbol{w}^T\boldsymbol{x}_i + b) - 1\big] = 0$

    • $\alpha_i > 0$ → 该样本是支持向量(support vector),满足 $y_i(\boldsymbol{w}^T\boldsymbol{x}_i + b) = 1$
    • $\alpha_i = 0$ → 样本在间隔边界之外,对模型无贡献
  • 最终模型:

$$
\boldsymbol{w}^* = \sum_{i \in SV} \alpha_i^* y_i \boldsymbol{x}_i
$$

$$
b^* = y_k - \sum_{i \in SV} \alpha_i^* y_i (\boldsymbol{x}_i^T \boldsymbol{x}_k) \quad\text{($k$ 为任意支持向量下标)}
$$

  • 决策函数:

$$
f(\boldsymbol{x}) = \text{sign}\left(\sum_{i \in SV} \alpha_i^* y_i (\boldsymbol{x}_i^T \boldsymbol{x}) + b^*\right)
$$

(5) 数值求解方法

方法 原理
SMO(Sequential Minimal Optimization) 每次选两个 $\alpha_i$ 优化,其余固定,解析求解
梯度投影法 在约束区域内沿梯度方向迭代
内点法 用 barrier 方法将有约束 QP 转为无约束

(6) 不可分情况(软间隔)

引入松弛变量 $\xi_i \ge 0$ 和惩罚参数 $C$:

$$
\min_{\boldsymbol{w}, b, \boldsymbol{\xi}} \frac{1}{2}|\boldsymbol{w}|^2 + C\sum_{i=1}^{m}\xi_i
$$

$$
\text{s.t.} \quad y_i(\boldsymbol{w}^T\boldsymbol{x}_i + b) \ge 1 - \xi_i, \quad \xi_i \ge 0
$$

对偶形式仅约束变为 $0 \le \alpha_i \le C$,其余不变。


求解流程小结:① 写出 Lagrange 函数 → ② 偏导置零 → ③ 消去 $\boldsymbol{w},b$ 得对偶问题 → ④ 用 SMO 等算法解对偶问题 → ⑤ 由 $\alpha_i^*$ 反推 $\boldsymbol{w}^*,b^*$ → ⑥ 得决策函数。