查看: 1941|回复: 5

[原创] CTIMER的捕获功能——脉宽解调

[复制链接]
  • TA的每日心情

    4 天前
  • 签到天数: 1481 天

    [LV.10]以坛为家III

    203

    主题

    2万

    帖子

    64

    超级版主

    Rank: 8Rank: 8

    积分
    92877
    最后登录
    2024-4-30
    发表于 2021-11-10 17:05:10 | 显示全部楼层 |阅读模式
    LPC系列控制的CTIMER,可以作为常见的定时器,或者计数器。在作为定时器的时候,常见的应用是定时执行某项操作,例如周期性的CAN报文发送,更新显示等,也可以通过对MATCH针脚的控制,产生不同周期的PWM波形,这个在很多开发板的BSP中有示例,可参考Keil\ARM\PACK\NXP\LPCXpressoXXX_BSP\X.X.X\driver_examples\ctimer中的示例。这两个示例在各种开发板中都有,连入门级的LPC8xx都有,更不用提LPC54xx,LPC55xx的开发板了,相信大家看一下都能够懂。

    不过,官方示例中并没有演示CTIMER的捕获(CAP)功能,论坛里对这个的讨论也不是太多,所以这一块儿就需要拿着用户手册好好看一下,自己摸索着比划比划。

    作为计数器的时候,可以配置为两种不同的方式,通过CCR寄存器中的CMODE,可以选用计时方式,也可以选择计数方式,两者的区别是,前一种模式下,TC寄存器是根据APB脉冲增加;而后一种模式下,TC根据CAP的行为(上升沿、下降沿或者双边沿)递增,这种模式可以说是真正意义上的计数器了。
    但是前一种模式也不是说用不上,通过对文档的阅读和理解,并自己动手测试,写了一个对PWM波的解调(Pulse Width Demodulation),计算PWM波的频率(周期)和占空比。

    这里选用LPC51U68作为测试的板子。
    先看看CAP针脚,众所周知,LPC的很多针脚都可以被配置为CTIMER的MAT或者CAP,这个时候主要是照顾开发板,看看那个针脚做了排针或者排母,方便使用,瞄了一会原理图和针脚定义,就它了:
    1.jpg


    2.jpg

    没错,就是P1.16这个针脚,位于J1的19号位,CTIMER0也就自然而然了。而且这个针脚还真不错,可以做输出(MAT),也可以做输入(CAP)

    然后是配置CTIMER0,这里直接撸寄存器:
    1. void XDCT0_Init()
    2. {
    3.         //enable clock
    4.         SYSCON->AHBCLKCTRLSET[1]=(1U<<26);
    5.        
    6.         //Reset
    7.         SYSCON->PRESETCTRLSET[1]=(1U<<26);
    8.         SYSCON->PRESETCTRLCLR[1]=(1U<<26);

    9.         //pin config
    10.         //Enable clock of the IOCON
    11.         SYSCON->AHBCLKCTRL[0]|=(1U<<13);
    12.         //P1_16 FUNC3 as CTIMER0_CAP0 P1.16@J1_19
    13.         IOCON->PIO[1][16]=0x03|(1U<<7)|(1U<<8);
    14.         //disable clock of the IOCON when finish setting to save power
    15.         SYSCON->AHBCLKCTRLCLR[0]=(1U<<13);

    16.         //Using Timer Mode
    17.         //clear TC when CH0 Rising Edge
    18.         CTIMER0->CTCR=0x00|(1U<<4);
    19.        
    20.         //R/F Edge of capture CH0, and generate INT
    21.         CTIMER0->CCR=(1U<<0)|(1U<<1)|(1U<<2);
    22.        
    23.         NVIC_EnableIRQ(CTIMER0_IRQn);
    24. }
    复制代码
    配置好了以后,CTIMER0会在CAP0(也就是P1.16针脚)采集到上升沿和下降沿的时候都产生中断,那我就在中断处理函数中加入处理:
    1. void CTIMER0_IRQHandler()
    2. {
    3.         CTIMER0->IR=(1U<<4);//clear Interrupt flag of CH0 event
    4.         GPIO_PinRead(GPIO, 1, 16)?(a=CTIMER0->CR[0]):(b=CTIMER0->CR[0]);
    5. }
    复制代码
    通常,中断处理函数应该尽可能短小简介,所以这里面只干了两件事:一是清除中断标志,个人习惯是进中断就请标志,怕后面忘记了。第二件事是读CAP针脚状态,然后针脚高电平的时候把CR[0](捕获寄存器)中的值赋值给a,针脚低电平的时候把CR中的值赋值给b。本来,我约莫着中断寄存器中应该有中断来源(上升沿或者下降沿)的标志,结果搞了一圈也没找到,后来实在没办法,测试了一下GPIO的PIN高低电平是可以读取的,所以采用了这种方式去识别到底是高电平还是低电平产生的中断。
    此外,在初始化配置的时候,我配置为每个上升沿到来时,把TC中的值载入CR[0],并清空TC寄存器,这样有两个好处:
    一个是后面计算的时候方便一些,因为每次这么一清空,那么CR[0]中的值就是周期了,而不用通过这次的值去减去上次的值;
    另外一个好处就是,TC也会溢出,这种溢出没有任何征兆,不会产生任何中断,所以只要我及时清空,就不会出现溢出的问题。下降沿的时候CR[0]值记录下来,这样我就知道了高电平持续的时间,所以a就是周期,b/a就是占空比。
    这里a,b是两个uint32_t的全局变量,为了在这个模块中把这两个值传递出去,又写了一个函数:
    1. void XDCT0_PDC(uint32_t* period_cnt,uint32_t* dc_cnt)
    2. {
    3.         *period_cnt=a;
    4.         *dc_cnt=b;
    5. }
    复制代码


    最后,在主函数里面,我们可以用比较慢的频率刷新解调结果:
    1. int main()
    2. {
    3.         float x,y;
    4.         uint32_t p,d;
    5.         BootClockPLL150M();
    6.         SysTick_Config(SystemCoreClock/1000U);
    7.         XDUART0_Init();
    8.         XDCT0_Init();
    9.         XDCT0_Start();
    10.        
    11.     while (1)
    12.     {
    13.                 SysTick_DelayTicks(500);
    14.                 memset(buffer,0x00,256);
    15.                 XDCT0_PWMD(&p,&d);
    16.                 x=SystemCoreClock*1.0f/p;
    17.                 y=100.0f*d/p;
    18.                 sprintf(buffer,"Freq=%d Hz\tDuty Cycle=%d%%\n",(uint32_t)(0.5+x),(uint32_t)(0.5+y));
    19.                 XDUART0_WriteString(buffer,strlen(buffer));
    20.     }
    21.         return 0;
    22. }
    复制代码
    接线方式很简单,把PWM输出信号与P1.16对接就OK了:
    3.jpg


    最后是测试结果:
    111.gif

    测试了一下,在300KHz情况下还可以,误差不算太大,不过拉到1MHz直接崩了,毕竟APB频率有限。


    该会员没有填写今日想说内容.
    回复

    使用道具 举报

  • TA的每日心情
    开心
    3 天前
  • 签到天数: 1336 天

    [LV.10]以坛为家III

    88

    主题

    4293

    帖子

    12

    版主

    Rank: 7Rank: 7Rank: 7

    积分
    9054
    最后登录
    2024-5-2
    发表于 2021-11-10 17:37:35 | 显示全部楼层
    用做频率计,计算出来占空比。
    那个小车车轮的位置计算是不是使用这个计数器外设也非常方便了?
    该会员没有填写今日想说内容.
    回复 支持 反对

    使用道具 举报

  • TA的每日心情

    4 天前
  • 签到天数: 1481 天

    [LV.10]以坛为家III

    203

    主题

    2万

    帖子

    64

    超级版主

    Rank: 8Rank: 8

    积分
    92877
    最后登录
    2024-4-30
     楼主| 发表于 2021-11-10 17:49:05 | 显示全部楼层
    jobszheng5 发表于 2021-11-10 17:37
    用做频率计,计算出来占空比。
    那个小车车轮的位置计算是不是使用这个计数器外设也非常方便了? ...

    是的,就是那种红外对射的传感器,用来计数非常方便,如果是霍尔传感器,获取正反转(A/B)相位,需要两个CAP
    该会员没有填写今日想说内容.
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    6

    主题

    17

    帖子

    0

    注册会员

    Rank: 2

    积分
    199
    最后登录
    2023-12-4
    发表于 2023-1-4 16:56:04 | 显示全部楼层
    请教下楼主,按照配置,发现CTIMER中断进不去,这个有啥经验吗
    回复 支持 反对

    使用道具 举报

  • TA的每日心情

    4 天前
  • 签到天数: 1481 天

    [LV.10]以坛为家III

    203

    主题

    2万

    帖子

    64

    超级版主

    Rank: 8Rank: 8

    积分
    92877
    最后登录
    2024-4-30
     楼主| 发表于 2023-1-4 17:02:05 | 显示全部楼层
    eefocus_3872435 发表于 2023-1-4 16:56
    请教下楼主,按照配置,发现CTIMER中断进不去,这个有啥经验吗

    示例中配置的是上升沿,然后您看看相关的中断开了没有?
    该会员没有填写今日想说内容.
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    6

    主题

    17

    帖子

    0

    注册会员

    Rank: 2

    积分
    199
    最后登录
    2023-12-4
    发表于 2023-7-19 14:35:13 | 显示全部楼层
    请教下楼主,
    接线方式很简单,把PWM输出信号与P1.16对接就OK了:
    能在内部进行配置吗?内部就将PWM引脚对应的输出信号连接到P1.16,而不是通过外部接线方式
    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /4 下一条

    Archiver|手机版|小黑屋|恩智浦技术社区

    GMT+8, 2024-5-4 15:34 , Processed in 0.127340 second(s), 25 queries , MemCache On.

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.

    快速回复 返回顶部 返回列表