【STC8A8K64D4开发板】第2-16讲:可编程计数器阵列PCA

news2024/12/22 18:40:09

第2-16讲:可编程计数器阵列PCA

    1. 学习目的
  1. 掌握STC8A8K64D4系列PCA可编程计数器阵列的原理。
  2. 掌握4个PCA外设相关寄存器配置及程序设计。
    1. PCA概述

PCA全称是可编程计数器阵列(Programable Counter Array),其中P表示可以编程控制、C表示计数器、A表示阵列,即有多路通道。他和我们前面学习的定时/计数器类似,对于初学者,可以把他理解为一个功能更加强大的定时/计数器。

PCA可以根据不同的应用需求进行编程,具有较高的灵活性和可靠性,因此他在工业自动化、仪器仪表等领域得到广泛的应用。

STC8A8K64D4 系列单片机内部集成了 4 组可编程计数器阵列模块,可用于软件定时器、外部脉冲捕获、高速脉冲输出和 PWM 脉宽调制输出,其结构图如下所示。

图1:PCA结构图

PCA 外设包含4路PCA模块,这4路PCA模块使用同一个可配置时钟源的16 位计数器, 并且他们使用的模式寄存器CCON和控制寄存器CMOD也是同一个,我们在使用时应注意这一点,因为,对他们的配置会同时对4个PCA模块有效。

除了共有的配置,每个PCA模块还有一个独立的配置寄存器“PCA 模块模式控制寄存器(CCAPMn,n=0~4)”,用于配置PCA模块的比较、捕获、高速脉冲输出和 PWM 脉宽调制输出,其中PCA模块工作于PWM模式时,还有一个寄存器“PCA 模块 PWM 模式控制寄存器(PCA_PWMn)”用于配置PWM的位宽。

PCA 模块的工作模式有4种:软件定时器、外部脉冲捕获、高速脉冲输出和 PWM 脉宽调制输出。PCA 模块工作于捕获、高速脉冲输出和 PWM时,需要通过“P_SW1”寄存器配置关联的引脚,用于连接输入的脉冲、输出高速脉冲和PWM。工作于软件定时器模式时,是没有关联引脚的。

    1. STC8A8K64D4的PCA应用步骤
      1. 软件定时器

PCA 模块工作于软件定时器时的应用流程如下图所示。

图2:PCA工作于软件定时器模式时的应用流程

        1.  配置PCA时钟源

PCA时钟源由“PCA 模式寄存器(CMOD)”中的CPS[2:0]位配置,此外,还需配置CIDL位用于确定计数器在空闲模式下是否计数,如下所示。

PCA 模式寄存器(CMOD):

  1. CIDL:空闲模式下是否停止 PCA 计数。
  1. 0:空闲模式下 PCA 继续计数。
  2. 1:空闲模式下 PCA 停止计数。
  1. CPS[2:0]:PCA 计数脉冲源选择位,可配置项如下表所示。

表1:PCA时钟源

CPS[2:0]

PCA 的输入时钟源

000

系统时钟/12

001

系统时钟/2

010

定时器 0 的溢出脉冲

011

ECI 脚的外部输入时钟

100

系统时钟

101

系统时钟/4

110

系统时钟/6

111

系统时钟/8

        1. 设置定时时间

PCA应用于软件定时器时和定时器类似,都是通过对时钟的计数达到定时的目的,所不同的是定时器设置了计数初值后,就不用软件干预了,每次溢出后硬件都会自动重装计数初值,而PCA软件定时器则需要软件干预。PCA软件定时器没有自动重装的机制,每次匹配中断后,都需要修改匹配值(在当前匹配值的基础上加上定时时间对应的计数值)。

使用PCA软件定时器时,“PCA 计数器寄存器(CL,CH)”的值通常设置为0,然后根据定时时间、PCA时钟源计算出比较值。PCA启动计数后,计数器的值向上递增,当计数器的值和比较值匹配时产生匹配中断,因此,对于PCA软件定时器来说,需要计算的是比较值。

  1. 比较值计算示例如下(定时时间10ms):

系统时钟:24MHz。

PCA时钟源:系统时钟/12 = 2Mhz,即一个时钟的时间是:1/2000000秒 = 0.5us。

比较值 = 10000us/0.5us = 20000,对应的16进制为0x4E20。因此,比较寄存器初次赋值为(CCAP0L = 0x20; CCAP0H = 0x4E;),之后,在PCA中断服务函数中,每次加上这个数值后再对比较寄存器赋值。

        1. 中断配置

中断配置包括中断的开启/关闭和中断优先级的配置。

PCA计数器溢出中断PCA的4个模块各有一个匹配/捕获中断,中断的开启和关闭由中断使能寄存器IE的位1(ET0)和位3(ET1)控制,如下图所示。

  1. ECF:PCA 计数器溢出中断允许位。
  1. 0:禁止 PCA 计数器溢出中断。
  2. 1:使能 PCA 计数器溢出中断。
  1. ECCFn:允许 PCA 模块 n 的匹配/捕获中断
  1. 0:禁止 PCA 模块 n 的匹配/捕获中断。
  2. 1:使能PCA 模块 n 的匹配/捕获中断。

PCA的中断优先级由IP和IPH寄存器位7的组合配置,如下图所示。

  1. PPCAH,PPCA:CCP/PCA/PWM中断优先级控制位
  1. 00: CCP/PCA/PWM 中断优先级为 0 级(最低级)。
  2. 01: CCP/PCA/PWM 中断优先级为 1 级(较低级)。
  3. 10: CCP/PCA/PWM 中断优先级为 2 级(较高级)。
  4. 11: CCP/PCA/PWM 中断优先级为 3 级(最高级)。

  • 中断优先级配置示例:配置PCA中断优先级为最高优先级3

IP  |= 0x80;   //中断优先级配置为最高优先级:PPCAH = 1,PPCA = 1

IPH |= 0x80;

  • 注意事项:PCA开启中断的情况下,还需要开启总中断“EA=1”,中断才能起作用。通常,我们会在主函数“main()”中开启总中断,这是因为我们开发的程序中可能会使用到多个中断,在主函数中开启一次即可。
        1. 启动和停止PCA计数器

PCA是通过置位“PCA 控制寄存器(CCON)”中的“CR”位启动PCA计数器、通过清零“CR”位停止PCA计数器的,如下所示。

PCA 控制寄存器(CCON):

  1. CR:PCA 计数器允许控制位。
  1. 0:停止 PCA 计数。
  2. 1:启动 PCA 计数。
      1. 输出高速脉冲

PCA工作于输出高速脉冲模式时和软件定时器类似,区别是高速脉冲模式需要配置PCA模块的功能引脚,用于输出脉冲。

图3:PCA工作于输出高速脉冲模式时的应用流程

PCA的各个模块工作于外部脉冲捕获、高速脉冲输出和 PWM 脉宽调制输出模式时,需要配置功能引脚,工作于软件定时器模式时无需配置。

PCA功能引脚由“外设端口切换控制寄存器 1(P_SW1)”中的CCP_S[1:0]位配置,如下所示。

外设端口切换控制寄存器 1(P_SW1):

应用流程图中的“设置定时时间”决定了脉冲的频率/周期,定时时间计算比较值的方式和软件定时器一样。比较值写入捕获值/比较值寄存器并启动PCA计数后,当 PCA 计数器的计数值与PCA模块捕获值/比较值寄存器的值相匹配时,PCA 模块关联的引脚输出将发生翻转。需要注意的是:一个周期需要2倍的定时时间(输出方波),如下图所示。

图4:输出脉冲的周期

      1. 捕获测量脉冲宽度

PCA 模块工作于捕获模式时,对模块的关联引脚输入跳变进行采样。当采样到有效跳变时,PCA 控制器立即将 PCA 计数器 CH 和 CL 中的计数值装载到模块的捕获寄存器中 CCAPnL 和 CCAPnH,同时将 CCON 寄存器中相应的 CCFn 置 1。若 CCAPMn 中的 ECCFn 位被设置为 1,将产生中断。

中断服务程序中,读出PCA计数值并保存,以便于计算两次上升沿或两次下降沿之间计数值的差,由这个差值即可计算出两次上升沿或两次下降沿之间的时间间隔。PCA工作于脉宽测量模式时的应用流程如下所示。

图5:PCA工作于脉宽测量模式时的应用流程

捕获脉宽需要注意以下两个方面:

  1. PCA工作于脉宽测量模式时只能设置为捕获上升沿或者捕获下降沿,不能设置同时捕获上升沿和下降沿。
  2. PCA计数器溢出。
  1. 示例:测量一个周期为10ms的方波,PCA配置为上升沿捕获、系统时钟24MHz,PCA时钟源为系统时钟/12(即一个计数值对应的时间是:0.5us),示意图如下所示。

图6:输出脉冲的周期

第一个上升沿到来后,PCA进入中断,在中断服务函数中读出PCA 计数器的值,存储到变量“cnt_value_last”。第二个上升沿到来后,同样在中断服务函数中读出PCA 计数器的值,存储到变量“cnt_value_current”,求出变量“cnt_value_current”和“cnt_value_last”的差值,再乘以一个计数值对应的时间即为测量的脉宽。

在计算两次上升沿之间的计数值的时候需要考虑PCA计数器的溢出问题,通常,我们会开启PCA的溢出中断用来跟踪PCA计数器的溢出情况,详细的处理方式见实验程序。

      1. 输出PWM

PCA 模块工作于PWM模式时,可配置为6/7/8/10 位 PWM。 PCA计数器启动后, PCA计数器的值向上递增,当PCA计数器的值小于设置的比较值时,配置的功能引脚输出低电平;当PCA计数器的值大于等于设置的比较值时,配置的功能引脚输出高电平;当PCA计数器溢出后,比较值自动重装,由此,实现无需软件干预的PWM输出。

图7:PCA工作于PWM模式时的应用流程

PCA工作于PWM模式时的时钟源和功能引脚配置和其他模式一样,本节中我们重点关注PWM位数、频率(周期)和占空的配置。

PWM的位数由“PCA 模块 PWM 模式控制寄存器(PCA_PWMn)”中的CPS[2:0]位配置,如下图所示。

PCA 模块 PWM 模式控制寄存器(PCA_PWMn):

PWM可配置为6、7、8或10 位,PWM配置的位数不同,他的重载值和比较值的组成也是不一样的,如下图所示。

  1. PWM频率(周期)

PCA工作于PWM模式时,PWM的频率由PWM配置的位数和时钟源决定,另外注意PCA的4个通道共用同一个时钟源,因此,PCA的各个模块工作于PWM模式时,不能单独设置各个模块的PWM频率。

PWM频率计算公式如下,其中n是PWM的位数,可取的值为6、7、8、10:

  • 注:下列情况PWM输出固定电平:
  1. 当EPCnH=0,XCCAP0H=0及CCAPnH=00H时, PWM固定输出高。
  2. 当EPCnH=1,XCCAP0H=3及CCAPnH=FFH时, PWM固定输出低。

  1. PWM占空比

PWM频率确定后,PWM的位数、比较值和重装值的位数也就确定了,同时,一个PWM周期包含多少个计数也确定了,因此,设置比较值和重装值即可设置一个PWM周期内高电平的时间,即PWM的占空比。(PCA计数器的初值通常在初始化时设置为0,计数器启动后向上计数,当PCA计数器的值小于设置的比较值时,配置的功能引脚输出低电平;当PCA计数器的值大于等于设置的比较值时,配置的功能引脚输出高电平)。

  1. 示例:6位PWM,占空比:50%

PWM为6位时,一个周期包含的计数值为64,如果要占空比为50%,把比较值和重装值设置为64的一半即可,即32,对应的16进制为0x20。

//PWM占空比为50%

CCAP0L = 0x20;           //PCA模块0的PWM比较值    

CCAP0H = 0x20;           //PCA模块0的PWM重装值

  1. 示例:6位PWM,占空比:20%

//PWM占空比为25%

CCAP0L = 0x10;           //PCA模块0的PWM比较值    

CCAP0H = 0x10;           //PCA模块0的PWM重装值

    1. 软件设计
      1. 软件定时器实验
  • 注:本节的实验是在“实验2-1-3:流水灯(自编驱动文件方式)”的基础上修改,本节对应的实验源码是:“实验2-16-1:PCA软件定时器实验”。
        1. 实验内容

使用PCA模块0实现200ms的软件定时器,定时时间到了之后翻转指示灯D1的状态,即驱动指示灯D1以200ms的间隔闪烁。PCA配置如下:

  1. 系统时钟:24MHz。
  2. PCA时钟源:系统时钟/12 = 2Mhz。
  3. 中断:关闭计数器溢出中断,使能PCA模块0的匹配/捕获中断,中断优先级设置为2(较高级)。
        1. 代码编写
  1. 新建一个名称为“pca.c”的文件及其头文件“pca.h”并保存到工程的“Source”文件夹,并将“pca.c”加入到Keil工程中的“SOURCE”组。
  2. 引用头文件

因为在“main.c”文件中使用了“pca.c”文件中的函数,所以需要引用下面的头文件“pca.h”。

代码清单:引用头文件

  1. //引用pca的头文件  
  2. #include    "pca.h"  
  1. PCA初始化和启动

配置PCA时钟源为系统时钟的1/12,本例中使用的系统时钟是24MHz,即PCA时钟源为2MHz。PCA计数值初值设置为0,之后将定时10ms的比较值写入比较寄存器并开启匹配/捕获中断。因为PCA软件定时器是通过修改比较值实现的,所以,我们定义一个变量“counter_val”用于存储比较器,每次写入比较值后,“counter_val”的值增加10ms对应的计数值,以备下一次修改比较值时使用。

配置完成后,启动PCA计数器,当计数器的计数值等于比较值时,触发匹配/比较中断,代码清单如下。

代码清单:初始化PCA

  1. /************************************************************************************** 
  2.  * 描  述 : PCA初始化,初始化PCA模块0用于软件定时器,定时时间10ms 
  3.  * 参  数 : 无 
  4.  * 返回值 : 无 
  5.  **************************************************************************************/  
  6. void pca_init(void)  
  7. {  
  8.    CCON = 0x00;        //CF、CR、CCF1、CCF0~CCF3位均清零  
  9.    /*--------------------PCA模式寄存器CMOD配置--------------------------- 
  10.      位7  位6  位5  位4   位3~位1    位0 
  11.      CIDL   x    x    x    CPS[2~0]   BCF 
  12.       0     x    x    x      000       0 
  13.      CIDL=0:空闲模式下仍然计数 
  14.      CPS[2~0]=000:PCA时钟源选择:系统时钟/12 
  15.      BCF=0:关闭PCA计数器溢出中断 
  16.    -----------------------------END------------------------------------*/  
  17.    CMOD = 0x00;          
  18.    CL = 0x00;          //PCA计数器赋初值  
  19.    CH = 0x00;          //PCA计数器赋初值  
  20.       
  21.    IP &= ~0x02;        //中断优先级配置为2(较高优先级)    
  22.    IPH |= 0x02;  
  23.   
  24.    /*------------------PCA模块0模式控制寄存器CCAPM0配置------------------ 
  25.      位7  位6     位5    位4      位3    位2   位1    位0 
  26.       x   ECOM0  CCAPP0  CCAPN0   MAT0   TOG0  PWM0   ECCF0 
  27.       x     1      0      0        1       0    0       1  
  28.      ECOM0=1:允许PCA模块0的比较功能 
  29.      CCAPP0=0:关闭PCA模块0的上升沿捕获 
  30.      CCAPN0=0:关闭PCA模块0的下降沿捕获 
  31.      MAT0=1:允许PCA模块0的匹配功能 
  32.      TOG0=0:关闭PCA模块0的高速脉冲输出功能 
  33.      PWM0=0:关闭PCA模块0的脉宽调制输出功能 
  34.      ECCF0=1:允许PCA模块0的匹配/捕获中断 
  35.    -----------------------------END------------------------------------*/  
  36.    CCAPM0 = 0x49;       
  37.    //写入比较值,注意:必须先写CCAP0L,再写CCAP0H
  38.    CCAP0L = (u8)CLK_SOURCE_2MHZ_10MS;        //PCA比较值寄存器赋初值        
  39.    CCAP0H = (u8)(CLK_SOURCE_2MHZ_10MS>>8);   //PCA比较值寄存器赋初值    
  40.   
  41.    counter_val = CLK_SOURCE_2MHZ_10MS * 2;   //下一次写入比较寄存器的数值  
  42.    CR = 1;                                   //启动PCA计数器阵列计数  
  1. PCA中断服务函数

因为PCA配置的定时时间是10ms,为了达到200ms的定时,我们定义一个变量“count”来记录Timer0的溢出次数,当“count”的值等于20的时候,表示达到200ms,此时,翻转指示灯D1的状态,从而实现驱动D1以200ms间隔闪烁的目的。

代码清单:PCA中断服务函数

  1.  /************************************************************************************** 
  2.  * 描  述 : PCA中断服务程序 
  3.  * 参  数 : 无 
  4.  * 返回值 : 无 
  5.  **************************************************************************************/  
  6. void pca_isr (void) interrupt 7  
  7. {  
  8.   CCF0 = 0;                            //清PCA模块0匹配/捕获中断标志  
  9.   //写入比较值,注意:必须先写CCAP0L,再写CCAP0H
  10.   CCAP0L = (u8)counter_val;            //PCA比较值寄存器赋值        
  11.   CCAP0H = (u8)(counter_val >> 8);       
  12.   counter_val += CLK_SOURCE_2MHZ_10MS; //因为计数器的计数值不会清零,所以通过修改比较值达到定时的目的
  13.           
  14.   cnt++;                               //每10ms执行一次cnt加一的操作  
  15.   if(cnt == 20)                        //cnt加到20后,时间为200ms  
  16.   {  
  17.     led_toggle(LED_1);                 //翻转用户指示灯D1状态  
  18.     cnt = 0;  
  19.   }     
  20. }  
  1. 主函数

主函数中初始化指示灯和PCA并开启总中断,PCA计数启动后,即会按照配置的时间触发中断,代码清单如下。

代码清单:主函数

  1.  /************************************************************************************** 
  2.  * 描  述 : 主函数 
  3.  * 参  数 : 无 
  4.  * 返回值 : int类型 
  5.  **************************************************************************************/  
  6. int main(void)  
  7. {  
  8.    P2M1 &= 0x3F;   P2M0 &= 0x3F; //设置P2.6~P2.7为准双向口(指示灯D1和D2)  
  9.    pca_init();                   //初始化PCA  
  10.    EA = 1;                       //使能总中断  
  11.       
  12.    while(1)  
  13.    {  
  14.    }  
  15. }  
        1. 硬件连接

本实验需要使用LED指示灯D1,按照下图所示短接指示灯和按键的跳线帽。

图8:跳线帽短接

        1. 实验步骤
  1. 解压“…\第3部分:配套例程源码”目录下的压缩文件“实验2-16-1:PCA软件定时器实验”,将解压后得到的文件夹拷贝到合适的目录,如“D\STC8”(这样做的目的是为了防止中文路径或者工程存放的路径过深导致打开工程出现问题)。
  2. 双击“…\pca_timer\project”目录下的工程文件“pca_timer.uvproj”。
  3. 点击编译按钮编译工程,编译成功后生成的HEX文件“pca_timer.hex”位于工程的“…\pca_timer\Project\Object”目录下。
  4. 打开STC-ISP软件下载程序,下载使用内部IRC时钟,IRC频率选择:24MHz。
  5. 程序运行后,可以观察到用户指示灯D1以200mS间隔闪烁。
      1. 输出高速脉冲实验
  • 注:本节的实验是在“实验2-16-1:PCA软件定时器实验”的基础上修改,本节对应的实验源码是:“实验2-16-2:PCA输出高速脉冲实验”。
        1. 实验内容

使用PCA模块0输出100KHz的高速脉冲, PCA配置如下:

  1. PCA模块0功能引脚:P1.7。
  2. 系统时钟:24MHz。
  3. PCA时钟源:系统时钟= 24Mhz。
  4. 中断:关闭计数器溢出中断,使能PCA模块0的匹配/捕获中断,中断优先级设置为2(较高级)。
  5. 脉冲频率100KHz,对应的比较值为:24000000L/2/100000 = 120。
        1. 代码编写
  1. 引用头文件

因为在“main.c”文件中使用了“pca.c”文件中的函数,所以需要引用下面的头文件“pca.h”。

代码清单:引用头文件

  1. //引用pca的头文件  
  2. #include  " pca.h"  
  1. PCA初始化

本例中输出的脉冲频率较高,因此PCA时钟源配置为系统时钟24MHz,PCA模块0的功能引脚为P1.7,即通过引脚P1.7输出高速脉冲,代码清单如下。

代码清单:PCA初始化

  1. /*************************************************************************** 
  2.  * 描  述 : PCA初始化 
  3.  * 参  数 : 无 
  4.  * 返回值 : 无 
  5.  **************************************************************************/  
  6. void pca_init(void)  
  7. {  
  8.    CCON = 0x00;        //CF、CR、CCF1、CCF0位均清零  
  9.    P_SW1 &= ~0x30;     //PCA模块0功能引脚选择P1.7  
  10.       
  11.    /*--------------------PCA模式寄存器CMOD配置--------------------------- 
  12.      位7  位6  位5  位4   位3~位1    位0 
  13.     CIDL   x    x    x    CPS[2~0]   BCF 
  14.      0     x    x    x      100       0 
  15.      
  16.      CIDL=0:空闲模式下仍然计数 
  17.      CPS[2~0]=100:PCA时钟源选择:系统时钟 
  18.      BCF=0:关闭PCA计数器溢出中断 
  19.    -----------------------------END------------------------------------*/  
  20.    CMOD = 0x08;  
  21.       
  22.    CL = 0x00;          //PCA计数器赋初值  
  23.    CH = 0x00;          //PCA计数器赋初值  
  24.       
  25.    IP &= ~0x02;        //中断优先级配置为2(较高优先级)    
  26.    IPH |= 0x02;  
  27.    /*------------------PCA模块0模式控制寄存器CCAPM0配置------------------ 
  28.     位7   位6     位5    位4      位3    位2   位1    位0 
  29.      x   ECOM0   CCAPP0  CCAPN0    MAT0   TOG0  PWM0   ECCF0 
  30.      x     1       0       0        1       1    0       1  
  31.      
  32.     ECOM0=1:运行PCA模块0的比较功能 
  33.     CCAPP0=0:关闭PCA模块0的上升沿捕获 
  34.     CCAPN0=0:关闭PCA模块0的下降沿捕获 
  35.     MAT0=1:允许PCA模块0的匹配功能 
  36.     TOG0=1:开启PCA模块0的高速脉冲输出功能 
  37.     PWM0=0:关闭PCA模块0的脉宽调制输出功能 
  38.     ECCF0=1:允许PCA模块0的匹配/捕获中断 
  39.    -----------------------------END------------------------------------*/  
  40.    CCAPM0 = 0x4D;       
  41.   
  42.    //PCA模块0初始化部分  
  43.    counter_val = T100KHZ;           //counter_val赋值     
  44.    //写入比较值,注意:必须先写CCAP0L,再写CCAP0H      
  45.    CCAP0L = (u8)counter_val;        //PCA比较值寄存器赋初值      
  46.    CCAP0H = (u8)(counter_val >> 8); //PCA比较值寄存器赋初值   
  47.    counter_val = T100KHZ * 2;       //下一次写入比较寄存器的数值  
  48.    CR = 1;                          //启动PCA计数器阵列计数     
  49. }  
  1. PCA中断服务函数

PCA工作于输出高速脉冲模式时,输出引脚的翻转是由硬件自动完成的,因此,中断服务函数中处理比较值即可,代码清单如下。

代码清单:PCA中断服务函数

  1. /*************************************************************************** 
  2.  * 描  述 : PCA中断服务程序 
  3.  * 参  数 : 无 
  4.  * 返回值 : 无 
  5.  **************************************************************************/  
  6. void pca_isr (void) interrupt 7  
  7. {  
  8.    CCF0 = 0;                        //将PCA计数器阵列溢出标志位软件清零  
  9.    //写入比较值,注意:必须先写CCAP0L,再写CCAP0H  
  10.    CCAP0L = (u8)counter_val;        //PCA比较值寄存器赋值        
  11.    CCAP0H = (u8)(counter_val >> 8);       
  12.    counter_val += T100KHZ;          //因为计数器的计数值不会清零,所以通过修改比较值达到定时的目的
  13. }  
  1. 主函数

主函数中初始化指示灯和PCA并开启总中断,PCA计数启动后,即会按照配置的时间触发中断,代码清单如下。

代码清单:主函数

  1. /*************************************************************************** 
  2.  * 描  述 : 主函数 
  3.  * 参  数 : 无 
  4.  * 返回值 : int类型 
  5.  **************************************************************************/  
  6. int main(void)  
  7. {  
  8.   P1M1 &= 0x7F;   P1M0 &= 0x7F; //设置P1.7为准双向口  
  9.   pca_init();                   //PCA初始化
  10.   EA = 1;                       //使能总中断
  11.       
  12.   while(1)  
  13.   {  
  14.   }  
  15. }  
        1. 硬件连接

本实验通过P1.7输出100KHz高速脉冲,P1.7引脚的位置如下图所示。

图9:硬件连接

        1. 实验步骤
  1. 解压“…\第3部分:配套例程源码”目录下的压缩文件“实验2-16-2:PCA输出高速脉冲实验”,将解压后得到的文件夹拷贝到合适的目录,如“D\STC8”(这样做的目的是为了防止中文路径或者工程存放的路径过深导致打开工程出现问题)。
  2. 双击“…\pca_pulse\project”目录下的工程文件“pca_pulse.uvproj”。
  3. 点击编译按钮编译工程,编译成功后生成的HEX文件“pca_pulse.hex”位于工程的“…\pca_pulse\Project\Object”目录下。
  4. 打开STC-ISP软件下载程序,下载使用内部IRC时钟,IRC频率选择:24MHz。
  5. 程序运行后,用示波器测量P1.7,可以观察P1.7输出100KHz的方波。
      1. 测量脉冲宽度实验
  • 注:本节的实验是在“实验2-10-1:Timer0定时驱动LED闪烁”的基础上修改,本节对应的实验源码是:“实验2-16-3:PCA测量脉冲宽度实验”。
        1. 实验内容

为了方便实验,本例使用Timer0定时200ms,Timer0中断服务函数中翻转P2.6的状态,即通过P2.6输出方波周期为400ms的方波。

使用PCA模块0捕获P2.6输出的方波, PCA配置如下:

  1. PCA模块0功能引脚:P1.7。
  2. 系统时钟:24MHz。
  3. PCA时钟源:系统时钟= 24Mhz。
  4. 上升沿捕获。
  5. 中断:开启计数器溢出中断和PCA模块0的匹配/捕获中断,中断优先级设置为2(较高级)。

每次测量后,通过串口输出测量得到的计数值和计数值对应的时间(单位毫秒)。

  • 说明:关于Timer0部分的程序,读者可以阅读《第2-10讲:定时器和计数器》,这里不再赘述。
        1. 代码编写
  1. 新建一个名称为“pca.c”的文件及其头文件“pca.h”并保存到工程的“Source”文件夹,并将“pca.c”加入到Keil工程中的“SOURCE”组。
  2. 引用头文件

因为在“main.c”文件中使用了“pca.c”文件中的函数,所以需要引用下面的头文件“pca.h”。

代码清单:引用头文件

  1. //引用pca的头文件  
  2. #include  "pca.h"  
  1. PCA初始化

本例配置PCA模块0功能引脚为P1.7,测量由Timer0产生的周期为400ms的方波,PCA模块0的时钟源为系统时钟的1/12,上升沿捕获,代码清单如下。

代码清单:PCA初始化和启动

  1.  /*************************************************************************** 
  2.  * 描  述 : PCA初始化 
  3.  * 入  参 : 无 
  4.  * 返回值 : 无 
  5.  **************************************************************************/  
  6. void pca_init(void)  
  7. {  
  8.    CCON = 0x00;        //CF、CR、CCF1、CCF0位均清零  
  9.       
  10.    P_SW1 &= ~0x30;     //PCA模块0功能引脚选择P1.7  
  11.    /*--------------------PCA模式寄存器CMOD配置--------------------------- 
  12.     位7  位6  位5  位4   位3~位1    位0 
  13.     CIDL   x    x    x    CPS[2~0]    BCF 
  14.      0     x    x    x      100        0 
  15.      
  16.     CIDL=0:空闲模式下仍然计数 
  17.     CPS[2~0]=000:PCA时钟源选择:系统时钟/12 
  18.     BCF=1:开启PCA计数器溢出中断 
  19.    -----------------------------END------------------------------------*/  
  20.    CMOD = 0x01;   
  21.    CL = 0x00;          //PCA计数器赋初值  
  22.    CH = 0x00;          //PCA计数器赋初值  
  23.    IP &= ~0x02;        //中断优先级配置为2(较高优先级)    
  24.    IPH |= 0x02;  
  25.    /*------------------PCA模块0模式控制寄存器CCAPM0配置------------------ 
  26.     位7   位6    位5    位4     位3    位2   位1    位0 
  27.      x   ECOM0  CCAPP0  CCAPN0   MAT0   TOG0  PWM0   ECCF0 
  28.      x     0      1      0        0       0    0       1  
  29.      
  30.      ECOM0=0:关闭PCA模块0的比较功能 
  31.      CCAPP0=1:开启PCA模块0的上升沿捕获 
  32.      CCAPN0=0:关闭PCA模块0的下降沿捕获 
  33.      MAT0=0:关闭PCA模块0的匹配功能 
  34.      TOG0=0:关闭PCA模块0的高速脉冲输出功能 
  35.      PWM0=0:关闭PCA模块0的脉宽调制输出功能 
  36.      ECCF0=1:允许PCA模块0的匹配/捕获中断 
  37.    -----------------------------END------------------------------------*/  
  38.    CCAPM0 = 0x21;       
  39.    CCAP0L = 0x00;            //PCA比较值寄存器赋初值        
  40.    CCAP0H = 0x00;            //PCA比较值寄存器赋初值   
  41.    CR = 1;                   //启动PCA计数器阵列计数    
  42. }  
  1. 测量脉宽

为了便于计算脉宽,我们定义了如下3个变量分别用于保存两次捕获时读取的PCA计数值和他们的差值。这里,我们定义的变量是32位的,这是为了处理PCA计数器的溢出。PCA计数器是16位的,当其溢出后会从0开始计数,因此,溢出后将变量“ticks_current”的值加上0x00010000,再减去上次捕获时保存的计数值即可得到正确的差值。

代码清单:PCA初始化和启动

  1. volatile u32 tick_diff;    //存储两次捕获之间的计数值的差值 
  2. volatile u32 ticks_last;   //记录上一次的捕获值  
  3. volatile u32 ticks_current;//记录本次的捕获值  

P1.7上出现上升沿或者PCA计数器溢出会触发PCA中断,PCA中断服务程序中读取PCA计数值,并计算差值,之后将测量完成标志“flag”置位,代码清单如下。

代码清单:PCA中断服务程序

  1. /*************************************************************************** 
  2.  * 描  述 : PCA中断服务程序 
  3.  * 参  数 : 无 
  4.  * 返回值 : 无 
  5.  **************************************************************************/  
  6. void pca_isr (void) interrupt 7  
  7. {  
  8.    if(CF)                                     //PCA计数器溢出  
  9.    {  
  10.       CF = 0;                                 //清零PCA计数器溢出标志位  
  11.       ticks_current += 0x00010000;            //当前计数值变量增加一个溢出的计数值   
  12.    }     
  13.    if(CCF0)                                    //是PCA模块0匹配/捕获中断标志  
  14.    {  
  15.       CCF0 = 0;                                //清零PCA模块0匹配/捕获中断标志位 
  16.       ((u8 *)&ticks_current)[3] = CCAP0L;      //16位计数值保存到ticks_current的低16位  
  17.       ((u8 *)&ticks_current)[2] = CCAP0H;  
  18.       tick_diff = ticks_current - ticks_last;   //length保存的即为捕获的脉冲宽度量化值  
  19.       ticks_last = ticks_current & 0x0000FFFF;  //备份上一次的捕获值,备份时去掉溢出部分  
  20.       ticks_current = 0;                        //当前计数值变量清零  
  21.       flag = 1;                                 //测量完成标志置位
  22.    }  
  23. }  
  1. 串口打印测量结果

测量完成后,通过串口打印出计数差值极其对应的时间,代码清单如下。

代码清单:打印测量结果

  1. /*************************************************************************** 
  2.  * 描  述 : 串口打印计数值和脉宽 
  3.  * 参  数 : 无 
  4.  * 返回值 : 无 
  5.  **************************************************************************/  
  6. void print_pw(void)  
  7. {  
  8.    float time_ms;  
  9.    if(flag)                                  //测量完成,打印测量结果
  10.    {  
  11.       printf("counter value: %lu \r\n",length);  
  12.       //PCA时钟源使用的是:系统时钟(24MHz)/12 = 2MHz,脉宽对应的时间(秒)=length/2000000  
  13.       //这里打印的是毫秒,所以除以2000  
  14.       time_ms = (float)length / 2000;          
  15.       printf("pulse width: %.2f ms\r\n",time_ms);  
  16.       flag = 0;  
  17.    }     
  18. }  
  1. 主函数

主函数中配置引脚并调用Timer0和PCA初始化函数,完成对Timer0和PCA的初始化和启动。之后在主循环里面调用测量结果打印函数,该函数中会检查测量完成标志,如测量完成标志置位,测打印测量结果,代码清单如下。

代码清单:主函数

  1. /*************************************************************************** 
  2.  * 描  述 : 主函数 
  3.  * 参  数 : 无 
  4.  * 返回值 : int类型 
  5.  **************************************************************************/  
  6. int main(void)  
  7. {  
  8.    P1M1 &= 0x7F;   P1M0 &= 0x7F;     //设置P1.7为准双向口  
  9.    P2M1 &= 0x3F;   P2M0 &= 0x3F;     //设置P2.6~P2.7为准双向口  
  10.    P3M1 &= 0xFE;   P3M0 &= 0xFE;     //设置P3.0为准双向口(串口1的RxD)  
  11.    P3M1 &= 0xFD;   P3M0 |= 0x02;     //设置P3.1为推挽输出(串口1的TxD)  
  12.       
  13.    uart1_init();                 //串口1初始化  
  14.    timer0_init();                //定时器0初始化  
  15.    pca_init();  
  16.    timer0_start();               //启动定时器0  
  17.    EA = 1;                       //使能总中断   
  18.           
  19.    while(1)  
  20.    {  
  21.       print_pw();     //查询测量是否完成,完成后串口打印测量结果  
  22.    }  
  23. }  
        1. 硬件连接

本实验需要用拔掉指示灯D1的跳线帽,然后用杜邦线将P26连接到P17,如下图所示。

图10:硬件连接

        1. 实验步骤
  1. 解压“…\第3部分:配套例程源码”目录下的压缩文件“实验2-16-3:PCA测量脉冲宽度实验”,将解压后得到的文件夹拷贝到合适的目录,如“D\STC8”(这样做的目的是为了防止中文路径或者工程存放的路径过深导致打开工程出现问题)。
  2. 双击“…\pca_capture\project”目录下的工程文件“pca_capture.uvproj”。
  3. 点击编译按钮编译工程,编译成功后生成的HEX文件“pca_capture.hex”位于工程的“…\pca_capture\Project\Object”目录下。
  4. 打开STC-ISP软件下载程序,下载使用内部IRC时钟,IRC频率选择:24MHz。
  5. 程序运行后,可以在串口调试助手接收窗口观察到脉宽测量结果,如下图所示。

图11:串口输出的测量的计数值和对应的时间

      1. 输出PWM实验
  • 注:本节的实验是在“实验2-16-3:测量脉冲宽度实验”的基础上修改,本节对应的实验源码是:“实验2-16-4:PCA输出PWM实验”。
        1. 实验内容

配置PCA模块0工作于PWM模式, PCA配置如下:

  1. 系统时钟:24MHz。
  2. PCA时钟源:系统时钟= 24Mhz。
  3. 功能引脚:P1.7。
  4. 中断:不开启中断。
  5. PWM位数:6位。
  6. PWM频率:375KHz。
  7. PWM占空比:25%。
        1. 代码编写
  1. 新建一个名称为“pca.c”的文件及其头文件“pca.h”并保存到工程的“Source”文件夹,并将“pca.c”加入到Keil工程中的“SOURCE”组。
  2. 引用头文件

因为在“pca.c”文件中使用了“pca.c”文件中的函数,所以需要引用下面的头文件“pca.h”。

代码清单:引用头文件

  1. //引用pca的头文件  
  2. #include   " pca.h"  
  1. PCA初始化

本例中,我们配置PCA模块0工作于PWM模式,输出频率为375KHz、占空比为25%的波形,代码清单如下。

代码清单:PCA初始化

  1.  /*************************************************************************** 
  2.  * 描  述 : PCA初始化 
  3.  * 入  参 : 无 
  4.  * 返回值 : 无 
  5.  **************************************************************************/  
  6. void pca_init(void)  
  7. {  
  8.    CCON = 0x00;        //CF、CR、CCF1、CCF0位均清零  
  9.    P_SW1 &= ~0x30;     //PCA模块0功能引脚选择P1.7  
  10.    /*--------------------PCA模式寄存器CMOD配置--------------------------- 
  11.     位7  位6  位5  位4   位3~位1    位0 
  12.     CIDL  x    x    x     CPS[2~0]    BCF 
  13.      0    x    x    x      100         0 
  14.      
  15.     CIDL=0:空闲模式下仍然计数 
  16.     CPS[2~0]=100:PCA时钟源选择:系统时钟 
  17.     BCF=0:关闭PCA计数器溢出中断 
  18.    -----------------------------END------------------------------------*/  
  19.    CMOD = 0x08;   
  20.   
  21.    CL = 0x00;          //PCA计数器赋初值  
  22.    CH = 0x00;          //PCA计数器赋初值  
  23.    /*------------------PCA模块0模式控制寄存器CCAPM0配置------------------ 
  24.     位7   位6    位5    位4     位3    位2   位1    位0 
  25.      x   ECOM0  CCAPP0  CCAPN0   MAT0   TOG0  PWM0   ECCF0 
  26.       x     1      0      0        0      0     1      0  
  27.     ECOM0=1:允许PCA模块0的比较功能 
  28.     CCAPP0=0:关闭PCA模块0的上升沿捕获 
  29.     CCAPN0=0:关闭PCA模块0的下降沿捕获 
  30.     MAT0=0:关闭PCA模块0的匹配功能 
  31.     TOG0=0:关闭PCA模块0的高速脉冲输出功能 
  32.     PWM0=1:开启PCA模块0的脉宽调制输出功能 
  33.     ECCF0=0:关闭PCA模块0的匹配/捕获中断 
  34.    -----------------------------END------------------------------------*/  
  35.    CCAPM0 = 0x42;       
  36.    //PCA模块0工作于6位PWM,由此可以计算出PWM频率=24Mhz/64 = 375KHz  
  37.    PCA_PWM0 &= 0xBF;          
  38.    PCA_PWM0 |= 0x80;                 
  39.    //PWM占空比为50%   
  40.    //CCAP0L = 0x20;           //PCA模块0的PWM比较值      
  41.    //CCAP0H = 0x20;           //PCA模块0的PWM重装值  
  42.       
  43.    //PWM占空比为25%   
  44.    CCAP0L = 0x10;           //PCA模块0的PWM比较值      
  45.    CCAP0H = 0x10;           //PCA模块0的PWM重装值  
  46.    CR = 1;                  //启动PCA计数器阵列计数         
  1. 主函数

主函数中初始化PCA及其功能引脚,PCA计数启动后,PWM输出完全由硬件完成,无需软件干预,代码清单如下。

代码清单:主函数

  1.  /************************************************************************************** 
  2.  * 描  述 : 主函数 
  3.  * 参  数 : 无 
  4.  * 返回值 : int类型 
  5.  **************************************************************************************/  
  6. int main(void)  
  7. {  
  8.    P1M1 &= 0x7F;   P1M0 &= 0x7F;     //设置P1.7为准双向口  
  9.    pca_init();                       //初始化并启动PCA计数 
  10.       
  11.    while(1)  
  12.    {  
  13.    }  
        1. 硬件连接

本实验通过P1.7输出频率为375KHz、占空比为25%的PWM波形,P1.7引脚的位置如下图所示。

图12:硬件连接

        1. 实验步骤
  1. 解压“…\第3部分:配套例程源码”目录下的压缩文件“实验2-16-4:PCA输出PWM实验”,将解压后得到的文件夹拷贝到合适的目录,如“D\STC8”(这样做的目的是为了防止中文路径或者工程存放的路径过深导致打开工程出现问题)。
  2. 双击“…\pca_pwm\project”目录下的工程文件“pca_pwm.uvproj”。
  3. 点击编译按钮编译工程,编译成功后生成的HEX文件“pca_pwm.hex”位于工程的“…\pca_pwm\Project\Object”目录下。
  4. 打开STC-ISP软件下载程序,下载使用内部IRC时钟,IRC频率选择:24MHz。
  5. 程序运行后,用示波器测量P1.7,可以观察P1.7输出频率为375KHz、占空比为25%的PWM波形。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1525478.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

iTOP-3A5000主板龙芯自主指令系统 (LoongArch)的LA464微结构

性能强 采用全国产龙芯3A5000处理器,基于龙芯自主指令系统 (LoongArch)的LA464微结构,并进一步提升频率,降低功耗,优化性能。 桥片 采用龙芯 7A2000,支持PCIE 3.0、USB 3.0和 SATA 3.0.显示接口2 路、HDMI 和1路 VGA&…

【PyTorch】成功解决TypeError: iteration over a 0-d tensor

【PyTorch】成功解决TypeError: iteration over a 0-d tensor 🌈 个人主页:高斯小哥 🔥 高质量专栏:Matplotlib之旅:零基础精通数据可视化、Python基础【高质量合集】、PyTorch零基础入门教程👈 希望得到您…

【CSS】Vue2使用TailwindCSS方法及相关问题

一.安装 1.npm安装TailwindCSS npm install tailwindcssnpm:tailwindcss/postcss7-compat tailwindcss/postcss7-compat postcss^7 autoprefixer^9 2.创建配置文件 npx tailwindcss init 3.创建postcss.config.js文件 // postcss.config.js module.exports {plugins: {t…

网络统一监控运维管理解决方案

网络统一监控运维管理解决方案 1. 构建完善的网络运维体系:通过组织、流程、制度的完善、支撑手段的建设,构建低成本高效率的IT运营体系,推动IT运营工作自动化、智能化、一体化化发展。 2. 构建网络一体化监控能力:构建从设备、数…

C++ 万物起源:类与对象(一)

目录 一、C与C语言的区别 1.1类的引入 二、C类 2.1类的概念与定义 2.2类的访问限定符与封装 2.2.1C中struct和class的区别 2.3封装 2.4类的作用域与实例化 三、类对象模型 3.1类对象的存储模式 3.2结构体内存对齐规则 一、C与C语言的区别 C语言是面向过程的&#xf…

刚刚!3.15晚会点名AI换脸诈骗,曝光主板机黑产,2000元成本可20部手机同时发布

1991 年 3 月 15 日,「消费者之友专题晚会」登上央视的大荧屏,从那一年开始,「3.15 晚会」就成为了像春节联欢晚会一样的固定节目,同样聚集了亿万国人的关注。多年来,围绕老百姓衣食住行方方面面,无数家企业…

AWTK slider_circle 控件发布

slider_circle 控件。 主要特色: 支持正向和反向支持设置滑块的半径支持背景线宽和颜色支持前景线宽和颜色支持设置是否显示值的文本支持设置起始角度和结束角度支持设置格式化值的格式字符串支持使用图片填充背景和前景 界面效果: 注意: …

Android FrameWork 学习路线

目录 前言 学习路线: 1.基础知识 2、AOSP 源码学习 3. AOSP 源码编译系统 4. Hal与硬件服务 5.基础组件 6. Binder 7. 系统启动过程分析 8. 应用层框架​编辑 9. 显示系统 10. Android 输入系统 11. 系统应用 前言 Android Framework 涉及的行业相当广…

Spring Boot Actuator介绍

大家在yaml中经常见到的这个配置 management: endpoints: web: exposure: #该配置线上需要去掉,会有未授权访问漏洞 include: "*" 他就是Actuator! 一、什么是 Actuator Spring Boot Actuator 模块提供了生产级别…

享元模式实战运用

前言 享元模式,将程序中可能反复创建且种类固定的对象缓存起来,以便共享。 通常使用一个享元工厂来创建和缓存享元对象,保证享元类的一个实例只能被创建一次,客户端获取享元对象时,先查看对象是否已经创建&#xff0…

各地省级网信部门受理数据出境安全评估申报、个人信息出境标准合同备案工作的联系方式

各地省级网信部门受理数据出境安全评估申报、个人信息出境标准合同备案工作的联系方式 为了指导和帮助数据处理者规范有序申报数据出境安全评估、备案个人信息出境标准合同,国家网信办将各地省级网信部门接收申报材料、备案材料的办公地址和联系电话公布如下&#x…

基于Linux内核的socket编程(TCP)的C语言示例

原文地址&#xff1a;https://www.geeksforgeeks.org/socket-programming-cc/ 服务端&#xff1a; #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/socket.h> #include <unistd.h>#…

BI让数据分析不在困难,分解企业数据分析流程

一、数据培养 数据分析最关键的是什么&#xff1f;其实从名字上就可以看出来&#xff0c;数据是一切的关键&#xff0c;没有数据的话数据分析从何谈起呢。但数据的积累不是一天两天就能成功的&#xff0c;企业的一定要有培养数据的意识&#xff0c;在业务活动中沉淀数据&#…

【目标检测】2. RCNN

接上篇 【目标检测】1. 目标检测概述_目标检测包括预测目标的位置吗?-CSDN博客 一、前言 CVPR201 4经典paper:《 Rich feature hierarchies for accurate object detection and semantic segmentation》&#xff0c;https://arxiv.org/abs/1311.2524, 这篇论文的算法思想被称…

vue组件化开发流程梳理,拿来即用

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

Revit二次开发-导出DWG设置

Revit二次开发 笔记 导出DWG ///导出Dwg/CADIList<string> setups DWGExportOptions.GetPredefinedSetupNames(doc);//获取当前导出已设置的类型DWGExportOptions dwgoptins DWGExportOptions.GetPredefinedOptions(doc, setups.LastOrDefault());//获取指定setups nam…

MybatisPlus-Generator自定义模版生成CRUD、DTO、VO、Convert等

个人博客&#xff1a;无奈何杨&#xff08;wnhyang&#xff09; 个人语雀&#xff1a;wnhyang 共享语雀&#xff1a;在线知识共享 Github&#xff1a;wnhyang - Overview 简介 如标题所言&#xff0c;本篇文章介绍如何使用MybatisPlus-Generator自定义模版生成CRUD、DTO、V…

GRACE:梯度引导的可控检索增强基于属性的生成

在本文中&#xff0c;我们提出通过梯度引导的可控检索&#xff08;GRACE&#xff09;来增强基于属性的生成&#xff0c;考虑到目标属性&#xff08;见图1&#xff09;。具体来说&#xff0c;我们训练一个鉴别器来计算给定上下文的属性分布。我们构建了一个检索库&#xff0c;存…

用python写网络爬虫:2.urllib库的基本用法

文章目录 urllib库抓取网页data参数timeout参数更灵活地配置参数登录代理Cookies 参考书籍 建议新入门的小伙伴先看我同一专栏的文章&#xff1a;用python写网络爬虫&#xff1a;1.基础知识 urllib库 urllib是python中一个最基础的HTTP库&#xff0c;一般是内置的&#xff0c;…

数字经济时代,数据清洗不是件小事

对于企业来说&#xff0c;数据无疑是当前时代业务增长和发展决策的核心要素&#xff0c;也是数字经济探索中的基础建设。不过随着数字化的加速普及&#xff0c;企业需要存储、处理的数据越来越多&#xff0c;海量的数据已经让企业难以理解&#xff0c;很难全面进行利用。尤其是…