LPC804开发(4. CTIMER使用)

1.前言

昨天晚上画完板子,还剩点时间就再翻了翻手册,大致清楚了时钟树的运行,顺带搞清楚了定时的使用,那就出一份教程吧。

如果各位在此之前没有接触过LPC单片机,还是建议先把程序直接贴进自己的项目,稍微改改先把功能实现了,定时器能动起来再说,因为LPC的定时器和其他单片机还是有很大不同的。

2.图形化配置时钟树

在开始前有些东西要先讲一下,首先是如何打开图形化配置时钟树,我们在项目资源管理器的右上角有一个绿色X的按钮,点击一下就会生成工程对应的mex文件,这个就是图形化配置文件。第一次使用时点击按钮我们就会进入图形配置界面,然后工程会自动生成一个mex文件,后续如果还想再修改配置就可以双击mex文件进入

6a0d791c1e6641eeae335c5d668529b9.png

然后我们就会进入下图的这个界面,这是管脚配置界面,大家有需要可以自行配置。

0897c0c6ffc44a0db01be0af1946f47b.png

我们将右手的界面向下滑,找到一个像pwm波的图标,点击进去就是时钟树

13611b3f97a04bbaabd2b3a045fb695e.png

然后我们就会进入如图的界面

09e0ba7d50044352981966499e58609d.png

如果各位直接创建的新工程,芯片的主频设置的是18Mhz

4277e1390f3742b58fca5ec8cdbd0f2e.png我们双击最左边fro_osc框进行主频修改

292726a698554160b0e14fce9da57ab8.png

我们将芯片主频设定为最高(30Mhz)

eeded1ec770549e6a5bd9b6813d5105c.png

设置完成后点击页面顶端的更新源代码

0f04ec094033452ca7483562e5ac0912.png

我们可以大致了解到哪些更改了,哪些没有改动,没有问题后点击确定完成设置。

ce2101aa6d8a4bc88138803f135e1760.png

退回到程序开发界面后点击编译就可以了。

64ad0b4a500a4e80b30c8bdce6359fda.png

我们这次使用的ctimer挂在这条时钟树下面

281e2a1db94043318e0b7bce8c186a83.png 可以看到其中有一个2分频,因此我们的ctimer的默认频率是15Mhz

3.初始化

首先说一下在804芯片里只有一个ctimer0,还是有点蛋疼的,再加上一个systick就两个传统意义上的定时器,有些情况下还是不够用的,这点最开始选型的时候慎重一点,有复杂的定时器控制的项目上建议用其他芯片。

0eb8850a881c43c5a17003b557dfe755.png

 ctimer0初始化代码如下,这部分需要重点说说。

ctimer_config_t config;

CTIMER_GetDefaultConfig(&config);

CTIMER_Init(CTIMER0, &config);

/* Configuration 0 */
matchConfig0.enableCounterReset = true;
matchConfig0.enableCounterStop  = false;
matchConfig0.matchValue         = CLOCK_GetFreq(kCLOCK_CoreSysClk) / 1000;
matchConfig0.outControl         = kCTIMER_Output_NoAction;
matchConfig0.outPinInitState    = false;
matchConfig0.enableInterrupt    = true;


CTIMER_RegisterCallBack(CTIMER0, &ctimer_callback_table[0], kCTIMER_MultipleCallback);
CTIMER_SetupMatch(CTIMER0, kCTIMER_Match_0, &matchConfig0);
CTIMER_StartTimer(CTIMER0);

首先,第一行是获取默认配置,函数原型如下。

34eb5d4c764a4453a0c0b35293f4a7e5.png

这里默认配置下,设定是的模式是定时器模式,输入模式0,这两个没啥好说的,一般也不会需要改,之后prescale是分频系数的设置,默认是没有的,那么此时我们的频率就是15Mhz,这里如果大家需要其他频率就要改了,但是不建议直接在库里面改。我们可以在主函数里像下图这样改,我这里就不动了。

90a8905605c24768b8e01dcfdf825982.png

完成之后就可以将配置信息放到ctimer里面就是后面一句CTIMER_Init(CTIMER0, &config);

之后就是设置匹配

f28c32ad5bb74db9b735c5e0c293389d.png

我们看到设置,其他内容相信大家可以看得懂我就不过多介绍了,大家根据需要来设置,一般不用动。这里的配置主要改的是匹配值就是第三行,这里的匹配值也STM32内所说重装值,这里就涉及到我们中断时间了。刚刚我们说到定时器的时钟频率是15Mhz。那么如果我们的匹配值是1,那么我们单次进中断的时间就是1/15000000 s。我们这里的匹配值是15000,这样一来进中断的时间就是1/15000000*15000=1ms
 

这里匹配是啥意思?LPC的定时器挺别致的,它没有中断,用的是回调函数,这个回调函数是更高级语言的一种用法,大家可以自行上网搜索,我也不是很了解,就不献丑了。其效果和中断差不多,就是没有中断优先级。

下一步就是设置回调函数了,但在此之前我们要先准备三个东西,如下图所示。从上到下依次是(1)函数声明(2)回调函数表(3)回调函数本体。一会我们初始化的时候要用到。

这里第二个ctimer_callback_t ctimer_callback_table[]就是回调函数表,我们在里面填写的内容就是回调函数名称。

862997c5012c4c97b732ffea684241c3.png

等这些都写完后我们就可以继续初始化了,下图就是定时器回调函数的配置

59dca10c112243c68784860ac21ed2e2.png

这个函数原型如下

47397bb3fed34806ad1bcb6c256aa0e2.png

第一个参数是指定哪个定时器,这里都是ctimer0,第二个参数是回调函数表的地址,第三个是回调函数的个数(单个或多个)。这里要说一下建议回调函数表里的顺序按照0,1,2这样排,因为当有多个回调函数的时候,程序会按照表里的顺序依次和匹配上。这里先将一个回调函数的情况吧,一会再将多个回调函数。

等这些都初始化完毕,我们就可以把设置的参数给ctimer了

e000019b5bd34d95b848ccec575d911d.png

而初始化的最后一句话就是开启定时器

0af9caefc39d4770941018f88e257c4d.png

 4.多重回调

因为芯片里只有一个定时器,那么我们怎么才能拓展定时器时间呢?

这里NXP芯片有一点好,那就是可以设置多个匹配数。这里我借用STM32的手册上一幅图来解释

57408870e31544bbb47906de39873644.png

在STM32里面定时器是只有一个重装值的,那么当计数器的值与设定值匹配时就会触发中断,但是在804里面ctimer最多支持4个匹配值,那么我们就可以,触发多个计数器溢出。我先把程序放在这具体解释我打算回头再写一篇文章来说。

void init_ctimer(void)
{
	ctimer_config_t config;

	CTIMER_GetDefaultConfig(&config);

	CTIMER_Init(CTIMER0, &config);

	/* Configuration 0 */
	matchConfig0.enableCounterReset = true;
	matchConfig0.enableCounterStop  = false;
	matchConfig0.matchValue         = CLOCK_GetFreq(kCLOCK_CoreSysClk) / 1000;
	matchConfig0.outControl         = kCTIMER_Output_NoAction;
	matchConfig0.outPinInitState    = false;
	matchConfig0.enableInterrupt    = true;

	/* Configuration 1 */
	matchConfig1.enableCounterReset = false;
	matchConfig1.enableCounterStop  = false;
	matchConfig1.matchValue         = 0;
	matchConfig1.outControl         = kCTIMER_Output_NoAction;
	matchConfig1.outPinInitState    = false;
	matchConfig1.enableInterrupt    = true;

	CTIMER_RegisterCallBack(CTIMER0, &ctimer_callback_table[0], kCTIMER_MultipleCallback);
	CTIMER_SetupMatch(CTIMER0, kCTIMER_Match_0, &matchConfig0);
	CTIMER_SetupMatch(CTIMER0, kCTIMER_Match_1, &matchConfig1);
	CTIMER_StartTimer(CTIMER0);
}

5.程序

我这里初始化了两个端口(13,22),在两个回调函数里让他们翻转,大家可以先下载程序,测试下效果。

#include "fsl_ctimer.h"
void ctimer_match0_callback(uint32_t flags);
void ctimer_match1_callback(uint32_t flags);

/* Array of function pointers for callback for each channel */
ctimer_callback_t ctimer_callback_table[] = {
    ctimer_match0_callback, ctimer_match1_callback, NULL, NULL, NULL, NULL, NULL, NULL};

/* Match Configuration for Channel 0 */
static ctimer_match_config_t matchConfig0;
/* Match Configuration for Channel 1 */
static ctimer_match_config_t matchConfig1;


void ctimer_match0_callback(uint32_t flags)
{
	GPIO_PortToggle(GPIO,0,1<<22);
	matchConfig1.matchValue=0;
	CTIMER_SetupMatch(CTIMER0, kCTIMER_Match_1, &matchConfig1);
}

void ctimer_match1_callback(uint32_t flags)
{
	LEDTOL;
	matchConfig1.matchValue+=CLOCK_GetFreq(kCLOCK_CoreSysClk) / 2000;
	CTIMER_SetupMatch(CTIMER0, kCTIMER_Match_1, &matchConfig1);
}


void init_ctimer(void)
{
	ctimer_config_t config;

	CTIMER_GetDefaultConfig(&config);

	CTIMER_Init(CTIMER0, &config);

	/* Configuration 0 */
	matchConfig0.enableCounterReset = true;
	matchConfig0.enableCounterStop  = false;
	matchConfig0.matchValue         = CLOCK_GetFreq(kCLOCK_CoreSysClk) / 1000;
	matchConfig0.outControl         = kCTIMER_Output_NoAction;
	matchConfig0.outPinInitState    = false;
	matchConfig0.enableInterrupt    = true;

	/* Configuration 1 */
	matchConfig1.enableCounterReset = false;
	matchConfig1.enableCounterStop  = false;
	matchConfig1.matchValue         = 0;
	matchConfig1.outControl         = kCTIMER_Output_NoAction;
	matchConfig1.outPinInitState    = false;
	matchConfig1.enableInterrupt    = true;

	CTIMER_RegisterCallBack(CTIMER0, &ctimer_callback_table[0], kCTIMER_MultipleCallback);
	CTIMER_SetupMatch(CTIMER0, kCTIMER_Match_0, &matchConfig0);
	CTIMER_SetupMatch(CTIMER0, kCTIMER_Match_1, &matchConfig1);
	CTIMER_StartTimer(CTIMER0);
}

int main(void)
{

    BOARD_InitBootPins();
    BOARD_InitBootClocks();
    BOARD_InitDebugConsole();

    init_ctimer();

	GPIO_PortInit(GPIO, 0);
	CLOCK_EnableClock(kCLOCK_Gpio0);

	gpio_pin_config_t LED_RED_config = {
		.pinDirection = kGPIO_DigitalOutput,
		.outputLogic = 0U,
	};
	GPIO_PinInit(GPIO, 0, 13, &LED_RED_config);
	GPIO_PinInit(GPIO, 0, 22, &LED_RED_config);

    while (1)
    {
    }
}

 对于初学者来说可以先修改下图的这个参数,这里除1000是1ms,官方除2是1s。大家可以直接改这个参数来进行定时器实际的设置。

278c30b0e559406c936e76af80aa8ddb.png

 6.实际效果

9b4fea7bd48d459cafbc6c2e283fe3d9.jpeg

1bd1075d1bad4c45993cacee9116af9e.png

7.结语

总的来说,LPC系列的定时器还是很特殊的,用过那么多单片机很少是NXP这个思路,最开始我学LPC55S69,第一次接触到回调函数这个问题也是非常懵逼的,如果各位也有这个困扰,建议大家先把回调函数视作中断,等慢慢熟悉了再去深入了解。还是那句话,有问题评论区见,我会尽量解答,那么我们下篇文章见。

 

  • 15
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值