简介: 此模块共有3个,可用作外部中断,定时器,高速脉冲产生,PWM产生。
CCP意思是:Capture(捕获),Compare(比较),PWM(脉宽调制)。
PCA是Programmable Counter Array(可编程计数器阵列)。
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位的中断。
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中断标志。出现匹配或者捕获时该位由硬件置位。需通过软件清零。
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中断。
低8位CL和高8位CH,有点类似定时器的TL与TH,三个PCA模块共用一个计数器。
低8位CCAPnL和高8位CCAPnH。PCA模块用于捕获/比较时,用于保存各模块的16位捕捉计数值;用于PWM模式时,用于控制输出的占空比。
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位数;
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 | 无效 |
此作用和外部中断基本类似,但通过此模块可使用上升沿触发,而一般外部中断则不行。
#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; //捕获/比较中断标志位清零
//······
}
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;
//······
}
}
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);
}