简介: 此模块共有3个,可用作外部中断,定时器,高速脉冲产生,PWM产生
CCP意思是:Capture(捕获),Compare(比较),PWM(脉宽调制)。
PCA是Programmable Counter Array(可编程计数器阵列)。

一.所用寄存器

1.CMOD PCA工作模式寄存器

SFR name Address bit B7 B6 B5 B4 B3 B2 B1 B0
COMD D9H name CIDL CPS2 CPS1 CPS0 ECF

CIDL: 空闲模式时是否停止PCA计数的控制位/0—停止,1—继续工作;

CPS2、CPS1、CPS0: PCA计数时钟源选择位。

CPS2 CPS1 CPS0 时钟来源选择
0 0 0 系统时钟/12,SYSclk/12
0 0 1 系统时钟/2,SYSclk/2
0 1 0 定时器0的溢出脉冲,T0可工作于1T模式,所以最快可达到系统时钟频率。改变T0的溢出率可改变PWM的频率
0 1 1 ECI/P1.2(或P3.4或2.4,由P_SW1寄存器控制)脚输入的外部时钟,最大为SYSclk/2
1 0 0 系统时钟,SYSclk
1 0 1 系统时钟/4,SYSclk/4
1 1 0 系统时钟/6,SYSclk/6
1 1 1 系统时钟/8,SYSclk/8

注: 如果想得到系统时钟的其他分频,只需使用定时器0的溢出脉冲作为时钟源,改变其溢出率即可;

ECF: PCA计数溢出中断使能位。0—禁止CCON中CF位的中断,1—允许CCON中CF位的中断。

2.CCON PCA控制寄存器

SFR name Address bit B7 B6 B5 B4 B3 B2 B1 B0
CCON D8H name CF CR CCF2 CCF1 CCF0

CF: PCA计数器溢出标志位。当PCA计数器溢出时,CF由硬件置1。需通过软件清零。当CMOD寄存器中的ECF置1时,可通过此位置1产生中断。

CR: PCA计数器使能位。0—关闭,1—打开;

CCF2: PCA模块2中断标志。出现匹配或者捕获时该位由硬件置位。需通过软件清零。
CCF1: PCA模块1中断标志。出现匹配或者捕获时该位由硬件置位。需通过软件清零。
CCF0: PCA模块0中断标志。出现匹配或者捕获时该位由硬件置位。需通过软件清零。

3.CCAPM0 PCA比较/捕获寄存器(CCAPM1、CCAPM2与此类似)

SFR name Address bit B7 B6 B5 B4 B3 B2 B1 B0
CCAPM0 DAH name ECOM0 CAPP0 CAPN0 MAT0 TOG0 PWM0 ECCF0

ECOM0: 允许比较器功能控制位。1—允许;

CAPP0: 正捕获控制位。1—允许上升沿捕获;
CAPN0: 负捕获控制位。1—允许下降沿捕获;
两个位可同时置1,即边沿捕获;

MAT0: 匹配控制位。1—PCA计数值与模块的比较/捕获寄存器的值的匹配将置位CCON寄存器的CCF0;

TOG0: 翻转控制位。1—PCA高速脉冲输出模式,PCA计数器的值与模块的比较/捕获寄存器的值的匹配将使CCP0脚翻转;

PWM0: 脉宽调制模式。1—允许CCP0脚作为PWM输出;

ECCF0: 1—使能CCF0中断。

4.CL和CH PCA的16位计数器

低8位CL和高8位CH,有点类似定时器的TL与TH,三个PCA模块共用一个计数器。

5.CCAPnL和CCAPnH(n=0、1、2) PCA捕捉/比较寄存器

低8位CCAPnL和高8位CCAPnH。PCA模块用于捕获/比较时,用于保存各模块的16位捕捉计数值;用于PWM模式时,用于控制输出的占空比。

6.PCA_PWM0 PCA模块的PWM寄存器(PCA_PWM1、PCA_PWM2类似)

SFR name Address bit B7 B6 B5 B4 B3 B2 B1 B0
PCA_PWM0 F2H name EBS0_1 EBS0_0 EPC0H EPC0L

EBS0_1、EBS0_0: PCA模块0工作于PWM模式时的功能选择位。

EBS0_1 EBS0_0 功能选择
0 0 PCA模块0工作于8位PWM功能
0 1 PCA模块0工作于7位PWM功能
1 0 PCA模块0工作于6位PWM功能
1 1 无效,PCA模块0仍工作于8位PWM功能

EPC0H: 在PWM模式下,与CCAP0H组成9位数;

EPC0L: 在PWM模式下,与CCAP0L组成9位数;

7.AUXR1(P_SW1) PCA功能管脚切换寄存器

SFR name Address bit B7 B6 B5 B4 B3 B2 B1 B0
P_SW1 A2H name CCP_S1 CCP_S0

CCP_S1 CCP_S0 管脚选择
0 0 CCP在[P1.2/ECI,P1.1/CCP0,P1.0/CCP1,P3.7/CCP2]
0 1 CCP在[P3.4/ECI_2,P3.5/CCP0_2,P3.7/CCP1_2,P3.7/CCP2_2]
1 0 CCP在[P2.4/ECI_3,P2.5/CCP0_3,P2.7/CCP1_3,P3.7/CCP2_3]
1 1 无效

二.CCP/PCA/PWM模块的应用(均以模块0为例)

1.用作外部中断

此作用和外部中断基本类似,但通过此模块可使用上升沿触发,而一般外部中断则不行。

#include "stc15.h"

void main()
{
	P_SW1&=0xBF; //选择第一组管脚,PCA0为P1.1
	CMOD=0x00;	//时钟源为SYSclk/12,禁止计数器溢出中断
	CCON=0x00;	//初始化PCA控制寄存器,具体可查找上述寄存器				
	CCAPM0=0x11;	//设置下降沿捕获,打开捕获中断

	EA=1;	//打开总中断	
	while(1);
}

//PCA中断,此处类似于外部中断
void PCA_Int() interrupt 7
{
	CCF0=0;	//捕获/比较中断标志位清零
	//······
}

2.用作不可重装载16位定时器(2种方式:溢出和比较)

1.第一种方式利用计数器的溢出产生中断,和通用定时器原理基本相同。

#include "stc15.h"
sbit relay=P0^4;

void main()
{
	P_SW1&=0xBF;	//使用第一组管脚
	CCON=0x00;		//初始化PCA控制寄存器,具体可查找上述寄存器	
	CMOD=0x01; 		//时钟源为SYSclk/12,允许计数器溢出中断
	CCAPM0=0x00;	//关闭比较的功能,禁止比较产生中断,即只可以通过计数器溢出产生中断
	
	CL=(65535-921);	//计数器初值,1000us*11.0592/12≈921,即每1ms进入一次中断
	CH=(65535-921)>>8;
	
	CR=1;	//使能PCA模块
	EA=1;
	while(1);
}


void PCA_Int() interrupt 7
{
	static unsigned int count;
	CF=0;	//溢出中断标志位清零
	CL=(65535-921);	//重装载计数器初值
	CH=(65535-921)>>8;
	count++;
	if(count==1000)	//1s
	{
		count=0;
		P2=0xa0;
		relay=!relay;
		P2=0x00;
	}
}

2.第二种方式功能与通用定时器类似,不同点在于产生中断的条件。通用定时器是设置计数器的初值,当溢出(即65535)时将产生中断。而此种方式是通过计数器与比较器的值匹配产生中断。
此外,此方法可以稍加改变,输出高速脉冲,详见代码!

#include "stc15.h"

void main()
{
	P_SW1&=0xBF;	//使用第一组管脚
	CCON=0x00;		//初始化PCA控制寄存器,具体可查找上述寄存器	
	CMOD=0x00; 		//时钟源为SYSclk/12,禁止计数器溢出中断
	CCAPM0=0x49;	//允许比较器功能,允许比较中断。
//  CCAPM0|=0x04;   //此时如果将翻转控制位置1,每次比较都会将输出口电平翻转,
					//那么P1.1口将输出高速脉冲,其频率为500kHz
					//因为由下面设定,中断间隔时间为1ms,那么一个周期为2ms。
	
	CL=0;			//复位计数器
	CH=0;
	
	CCAP0L=921;	//设置比较值,当计数器达到此值时进入中断,1000us*12/11.0592≈921,即每1ms进入一次中断
	CCAP0H=921>>8;
	
	CR=1;	//打开PCA模块
	EA=1;
	while(1);
}


void PCA_Int() interrupt 7
{
	static unsigned int count;
	CCF0=0;		//捕获/比较中断标志位清零
	CL=0;	//复位计数器
	CH=0;
	count++;	
	if(count==1000)	//1s
	{
		count=0;
		//······
	}
}

3.用于PWM输出

PWM的频率与选择的时钟源以及位数有关,以我的代码为例,使用定时器0的溢出频率为时钟频率,此处为100kHz;而选择的是8位PWM模式(所谓8位PWM,即计数器和比较器只采用低8位进行比较,因此计数只有0~255),所以PWM的频率Freq=100kHz/256=390.625Hz。(之所以使用定时器0作为时钟源,是因为系统时钟直接分频所得的PWM频率仍然过大,无法用我STM32编的简易示波器采样显示。此外,使用定时器为时钟源可以随意控制频率,灵活度更好)

PWM的占空比由PCA计数器和比较器决定当[0,CL]<[EPCnL,CCAPnL](此处的EPCnL可翻看PCA_PWM寄存器}时,输出低电平;当[0,CL]≥[EPCnL,CCAPnL]时,输出高电平。当CL发生溢出时,[EPCnH,CCAPnH]自动装载到[EPCnL,CCAPnL]中,以此实现无干扰更新PWM。

注:
1.使用PWM模式时,一定要将PWMn和ECOMn位置1!对应代码中的CCAPM0=0x42。
2.由于3个模块共用一个计数器和时钟源,所以计数频率一定相同,只可以通过改变PWM的位数使3个模块输出不同的频率;通过改变3个模块的比较器数值,使3个模块输出不同占空比的PWM。

#include "stc15.h"

//定时器0初始化函数,用于PCA的时钟源
void Timer0Init(void)		//10us
{
	AUXR &= 0x7F;		//12T模式
	TMOD &= 0xF0;		//定时器模式
	TL0 = 0xF7;		
	TH0 = 0xFF;		
	TF0 = 0;		
	TR0 = 1;		
}

void main()
{
	Timer0Init();
	P_SW1&=0xBF;	//用第一组管脚,此处即P1.1用于PWM输出
	CCON=0x00;		//初始化,不需要中断,所以全部关闭	
	CMOD=0x04; 		//定时器0的溢出频率作为时钟频率
	PCA_PWM0=0x00;	//工作于8位PWM模式
	CCAP0H = CCAP0L = 0x80;	//占空比为(0x100-0x80)/0x100=50%
	
	CCAPM0=0x42;	//允许比较器,使用PWM输出模式
	
	CR=1;	//使能PCA模块
	while(1);
}