1. STC15F2K60S2单片机CCP/PCA/PWM模块入门指南
第一次接触STC15F2K60S2单片机的CCP/PCA/PWM模块时,我也被那一堆寄存器搞得头晕眼花。但实际用起来才发现,这个模块简直是单片机开发的"瑞士军刀",一个模块就能搞定定时器、PWM、脉冲捕获等多种功能。相比传统的51单片机定时器,它的灵活性简直提升了好几个档次。
CCP/PCA/PWM模块的核心是一个16位的计数器(CL和CH寄存器),配合三个独立的模块(PCA0、PCA1、PCA2),可以实现多种功能。简单来说:
- Capture(捕获):可以精确测量外部脉冲的宽度
- Compare(比较):可以产生精确的定时中断
- PWM:可以输出可调占空比的方波信号
在蓝桥杯CT107D开发板上,这个模块的引脚默认映射在P1口:
- P1.2是ECI(外部捕获输入)
- P1.1是CCP0
- P1.0是CCP1
- P3.7是CCP2
2. 寄存器配置详解
2.1 核心寄存器功能解析
要让CCP/PCA/PWM模块工作,主要需要配置以下几个寄存器:
CCON(PCA控制寄存器):
- CR位:PCA计数器开关(1启动/0停止)
- CCF0/CCF1/CCF2:各模块中断标志
CMOD(PCA模式寄存器):
- CPS[2:0]:时钟源选择
- ECF:溢出中断使能
CCAPMn(比较/捕获寄存器):
- ECOMn:比较器使能
- CAPPn/CAPNn:上升沿/下降沿捕获
- MATn:匹配时翻转CCPn引脚
- TOGn:匹配时切换CCPn引脚
- PWMn:PWM模式使能
PCA_PWMn(PWM寄存器):
- EPCnH/EPCnL:PWM占空比设置
2.2 时钟源配置技巧
CMOD寄存器的CPS[2:0]位决定了PCA的时钟源,这是影响精度的关键:
| CPS2 | CPS1 | CPS0 | 时钟源 | 适用场景 |
|---|---|---|---|---|
| 0 | 0 | 0 | 系统时钟/12 | 普通定时 |
| 0 | 0 | 1 | 系统时钟/2 | 高速PWM |
| 0 | 1 | 0 | 定时器0溢出 | 同步定时 |
| 0 | 1 | 1 | ECI引脚输入 | 外部脉冲计数 |
| 1 | 0 | 0 | 系统时钟 | 最高精度定时 |
在蓝桥杯开发板上,如果使用12MHz晶振,选择系统时钟/12(CPS=000)时,每个计数周期就是1μs,非常方便计算。
3. 外部中断实现
3.1 配置步骤
将PCA模块配置为外部中断只需要几步:
- 设置引脚映射(P_SW1寄存器)
- 初始化CCON、CMOD寄存器
- 配置CCAPMn为捕获模式
- 开启中断(EA和ECCFn)
// PCA模块0下降沿中断配置 CCAPM0 = 0x11; // ECOM0=1, CAPP0=13.2 完整代码示例
#include "stc15f2k60s2.h" #define CCP_S0 0x10 #define CCP_S1 0x20 void PCA_Init_Exit() { // 引脚映射到P1口 ACC = P_SW1; ACC &= ~(CCP_S0 | CCP_S1); P_SW1 = ACC; CCON = 0; // 清零控制寄存器 CMOD = 0x00; // 时钟源=sysclk/12 CCAPM0 = 0x11; // 下降沿捕获 CR = 1; // 启动PCA计数器 EA = 1; // 开总中断 } void PCA_ISR() interrupt 7 { if(CCF0) { CCF0 = 0; // 清除中断标志 P55 = ~P55; // LED状态翻转 } }实测发现,PCA外部中断的响应速度比传统外部中断更快,抖动也更小。我在电机测速项目中就用这个特性实现了精准的转速测量。
4. 16位定时器应用
4.1 定时器模式配置
PCA的16位定时器模式比传统51定时器强大得多:
- 不需要像定时器0/1那样频繁重装初值
- 可以自动更新比较值
- 中断频率更稳定
关键配置:
CCAPM0 = 0x49; // 16位定时器模式4.2 精准定时实例
下面代码实现1秒精确定时(基于12MHz晶振):
unsigned int value = 65536 - 10000; // 10ms定时 void PCA_Init_Timer() { CCON = 0; CMOD = 0x00; // 时钟源=sysclk/12 value = 65536 - 10000; // 10ms@12MHz CCAP0L = value; CCAP0H = value >> 8; CCAPM0 = 0x49; // 16位定时器模式 CR = 1; EA = 1; } void PCA_ISR() interrupt 7 { static unsigned char cnt = 0; CCF0 = 0; CCAP0L = value; CCAP0H = value >> 8; if(++cnt >= 100) { // 1秒到达 cnt = 0; P55 = ~P55; // LED闪烁 } }在实际项目中,我用这个特性实现了多路ADC的定时采样,相比传统定时器,代码更加简洁稳定。
5. PWM输出实战
5.1 PWM基础配置
STC15的PWM有8位和10位两种分辨率,配置步骤:
- 设置PCA_PWMn寄存器
- 配置CCAPMn为PWM模式
- 设置CCAPnH/L初始值
// 8位PWM配置 PCA_PWM0 = 0x00; // 8位PWM CCAPM0 = 0x42; // PWM模式 CCAP0H = 0x80; // 50%占空比5.2 呼吸灯实现
下面代码实现LED呼吸灯效果:
void PWM_Init() { ACC = P_SW1; ACC &= ~(CCP_S0 | CCP_S1); P_SW1 = ACC; CCON = 0; CMOD = 0x02; // 时钟源=sysclk/2 PCA_PWM0 = 0x00; // 8位PWM CCAPM0 = 0x42; // PWM模式 CR = 1; } void main() { unsigned char duty = 0; bit dir = 0; PWM_Init(); while(1) { CCAP0H = duty; // 更新占空比 if(dir) { if(--duty == 0) dir = 0; } else { if(++duty == 255) dir = 1; } Delay_ms(10); } }在电机控制项目中,我用这个PWM模块驱动MOSFET,实现了精准的转速控制。实测发现STC15的PWM输出非常稳定,没有传统51单片机PWM的那种抖动问题。
6. 高速脉冲输出
6.1 配置技巧
要输出高频脉冲,关键是要选择高速时钟源:
CMOD = 0x02; // 时钟源=sysclk/2 CCAPM0 = 0x4D; // 匹配时翻转引脚6.2 100kHz方波输出
void PCA_Init_HighSpeed() { ACC = P_SW1; ACC &= ~(CCP_S0 | CCP_S1); P_SW1 = ACC; CCON = 0; CMOD = 0x02; // sysclk/2 value = (12000000L/2/100000)/2; // 100kHz方波 CCAP0L = value; CCAP0H = value >> 8; CCAPM0 = 0x4D; // 匹配时翻转 CR = 1; EA = 1; }这个功能在红外通信和步进电机驱动中特别有用。我曾在智能小车项目中使用这个特性生成38kHz红外载波,代码比用普通定时器实现简洁得多。
7. 脉冲宽度测量
7.1 捕获模式配置
测量脉冲宽度的关键配置:
CCAPM0 = 0x31; // 上升沿+下降沿捕获7.2 超声波测距实例
unsigned int capture_start, capture_end; void PCA_Init_Capture() { ACC = P_SW1; ACC &= ~(CCP_S0 | CCP_S1); P_SW1 = ACC; CCON = 0; CMOD = 0x00; // sysclk/12 CCAPM0 = 0x31; // 双沿捕获 CR = 1; EA = 1; } void PCA_ISR() interrupt 7 { if(CCF0) { CCF0 = 0; if(CCAPM0 & 0x02) { // 下降沿捕获 capture_end = (CCAP0H << 8) | CCAP0L; // 计算脉冲宽度 unsigned int width = capture_end - capture_start; } else { // 上升沿捕获 capture_start = (CCAP0H << 8) | CCAP0L; } } }在超声波测距模块中,我用这个方法测量回波时间,精度可以达到微秒级。相比传统的外部中断+定时器方案,这种方法更加可靠稳定。