2. 系统时钟配置:时钟频率设置、Tick周期计算、辅助时钟与系统时钟的区别

好,咱们进入第二章。系统时钟配置,这可以说是VxWorks时间管理的基石。你想想看,整个系统的脉搏怎么跳,全靠它说了算。我刚开始接触VxWorks时,觉得这玩意儿不就是设个频率嘛,有啥好讲的?后来在项目里栽过跟头,才明白这里面的门道有多深。

2.1 时钟频率设置——别小看这一步

系统时钟频率,说白了就是硬件定时器每秒钟产生的中断次数。这个值通常在BSP(板级支持包)里定义,宏名叫SYS_CLK_RATE。我个人习惯在config.h里直接配,比如:

#define SYS_CLK_RATE    1000    /* 1000 Hz,也就是1ms一个Tick */

嗯,这里要注意。频率设得太高,系统开销会变大。为什么?因为每次时钟中断都要保存上下文、切换任务,这些都是成本。我曾经在一个项目中把频率设到10000Hz,结果系统响应是快了,但CPU有一大半时间都在处理时钟中断,业务逻辑反而跑不动了。

反过来,频率设得太低也不行。比如设成10Hz,那一个Tick就是100ms。你想想看,任务调度、超时判断,全都得等这100ms。实时性?不存在的。

经验之谈:一般嵌入式系统,100Hz到1000Hz是比较常见的范围。网络设备我习惯用100Hz,工业控制用1000Hz。具体选多少,得看你任务的实时要求。

2.2 Tick周期计算——数学其实很简单

Tick周期,就是两次时钟中断之间的时间间隔。公式特别简单:

Tick周期 = 1 / 系统时钟频率

举个例子:

系统时钟频率 Tick周期 典型应用场景
100 Hz 10 ms 网络设备、数据采集
1000 Hz 1 ms 工业控制、电机驱动
10000 Hz 0.1 ms 高频交易(慎用)

我记得有一次调试一个串口通信程序,总觉得数据接收有延迟。查了半天,发现是Tick周期设成了10ms,而串口中断每5ms就来一次。你想想看,中断来了,但任务调度要等下一个Tick才能处理,这不就白白浪费了5ms吗?后来我把频率提到1000Hz,问题就解决了。

小技巧:sysClkRateGet()可以获取当前系统时钟频率。调试时我经常用这个函数确认配置是否生效。

2.3 辅助时钟与系统时钟的区别——两个时钟,各司其职

VxWorks里其实有两个时钟:系统时钟(System Clock)和辅助时钟(Auxiliary Clock)。很多初学者搞混,我刚开始也犯过这个错。

系统时钟,是VxWorks内核的心脏。它负责:

  • 任务调度的时间片轮转
  • 任务延时(taskDelay()
  • 超时机制(比如信号量等待超时)
  • 看门狗定时器

辅助时钟,说白了就是一个额外的定时器。它不参与内核调度,纯粹给应用程序用。你可以把它理解成一个独立的秒表。

两者的核心区别:

特性 系统时钟 辅助时钟
用途 内核调度、时间管理 应用程序自定义定时
中断处理 内核自动处理 用户注册回调函数
频率设置 BSP中固定配置 运行时动态设置
精度 受Tick周期限制 可以更高精度

为什么会需要两个时钟?我举个例子你就明白了。假设你要做一个高精度的脉冲输出,周期是0.5ms。系统时钟如果设成1000Hz,Tick周期是1ms,根本没法精确控制0.5ms。这时候辅助时钟就派上用场了,你可以把它设成2000Hz,专门用来处理这个脉冲输出。

避坑指南:我曾经在一个项目里,把辅助时钟的中断优先级设得比系统时钟还高。结果辅助时钟中断太频繁,导致系统时钟中断被延迟,整个系统的任务调度都乱套了。记住,辅助时钟的中断优先级一般不要高于系统时钟。

2.4 辅助时钟的使用示例

来看看怎么用辅助时钟。代码其实不复杂:

#include <vxWorks.h>
#include <sysLib.h>
#include <auxClk.h>

/* 辅助时钟中断回调函数 */
void myAuxHandler(void)
{
    /* 这里放你的处理逻辑 */
    /* 注意:中断上下文里别做太多事 */
}

void setupAuxClock(void)
{
    /* 设置辅助时钟频率为2000 Hz */
    if (auxClkConnect(myAuxHandler, 0) == ERROR)
    {
        printf("辅助时钟连接失败\n");
        return;
    }
    
    if (auxClkRateSet(2000) == ERROR)
    {
        printf("辅助时钟频率设置失败\n");
        return;
    }
    
    /* 启动辅助时钟 */
    auxClkEnable();
    
    printf("辅助时钟已启动,频率:%d Hz\n", auxClkRateGet());
}

嗯,这里有几个要点:

  • 回调函数里别做复杂操作,中断上下文栈空间有限
  • 辅助时钟的频率不能超过硬件定时器的最大支持频率
  • 用完记得调用auxClkDisable()关闭,省电也省资源

总结一下:系统时钟是VxWorks的「心跳」,负责内核调度;辅助时钟是给应用程序的「额外工具」,用于高精度或特殊定时需求。两者配合使用,才能发挥VxWorks实时性的最大优势。

下一章咱们聊聊看门狗定时器,那玩意儿在防死机方面可是神器。到时候我会分享一个我当年差点搞砸的案例,保证让你印象深刻。