管理定时器和实时定时器
目录
- 管理定时器和实时定时器
- 管理时间数据
- 通用定时器编程
- 初始化计时器
- 删除计时器
- 停止/启动/调整定时器
- 备注
- RealTimer 备注
- 项目实例
- 项目结构
- 项目源码
- 示例更多:
管理时间数据
-
在 Kithara RealTime Suite 中,所有时间值均以 100 ns 为单位给出:这不仅适用于定时器的安装,也适用于阻塞函数的超时值 (‘KS_waitForEvent’) 等。
-
为了在对源代码进行编程时使用可管理的数字,可以给出倍数为 10000 的毫秒值。为了进一步简化此过程,还可以在程序代码的中心位置预定义值 10000,例如:
const int ms = 10000;int timeout = 200 * ms;...
通用定时器编程
要创建计时器,您需要创建一些依赖对象:
-
事件对象 (KS_createEvent)
-
回调对象 (KS_createCallBack)
-
任务 (KS_createTask)
计时器安装需要生成的句柄。如果句柄指向回调或任务对象,则当计时器触发时,将执行此对象的例程。在这种情况下,是要确保使用的所有数据和对象都位于同一个地址空间(ring3 或 ring0)中!
初始化计时器
可以使用函数 KS_createTimer 初始化计时器。可编程定时器频率取决于可用的功能。使用定时器模块,可以以近似毫秒的间隔对定时器周期进行编程,使用实时模块可以编程更高的频率。RealTime 模块是自定义驱动程序的可选组件。
非实时计时器的延迟周期始终四舍五入到 1 毫秒。如果创建的计时器不是一次性计时器,它将一直运行,直到计时器函数返回不等于 0 的值(例如错误值)。尽管存在中断,但稍后仍必须使用 KS_removeTimer 删除计时器。对于频繁的停止和重新启动计时器,建议改用 KS_startTimer/KS_stopTimer。
删除计时器
如果不再使用计时器对象,则必须将其删除。若要删除计时器对象并释放所有已用资源,必须调用 KS_removeTimer。
停止/启动/调整定时器
可以使用 KS_stopTimer 随时停止计时器。定时器在调用"KS_stopTimer"时运行,这不会影响定时器功能,只会停止任何进一步的信号。
要重新启动或首次启动使用标志"KSF_DONT_START"创建的计时器,应使用函数 KS_startTimer。使用"KS_startTimer"也可以编程新周期。如果计时器未停止并调用"KS_startTimer",则计时器将使用新周期重新启动。
要在不重新启动计时器的情况下调整计时器周期,可以使用 KS_adjustTimer。新周期用于下一个周期。
备注
-
稍后启动计时器:在各种情况下,首先安装计时器并稍后启动它可能会很有用。为此,在安装回调函数时会提供"KSF_DONT_START"标志。在这种情况下,准备好的计时器处于休眠状态,将等待函数"KS_startTimer"的调用。优点:分配资源的耗时过程已经完成,计时器可以更快地启动。
-
只需一次计时器调用:标志"KSF_ONE_SHOT"可用于"KS_createTimer"和"KS_startTimer"功能,以确保计时器只会发射一次(“一发”)。使用"KS_startTimer"也可以在每次呼叫时提供新的延迟。
-
看门狗监控:要重新启动看门狗计时器,可以调用"KS_startTimer"。
RealTimer 备注
要求:
-
时钟模块和实时模块可用
-
PC 使用 APIC 控制器(高级可编程中断控制器)。所有多核 CPU 都是这种情况,包括超线程处理器和 SMP 计算机,以及最新的单核 CPU。
-
必须使用适合内核的对象(例如,使用"KSF_DIRECT_EXEC"创建的回调或内核任务)。
-
硬件定时器频率高的定时器必须特别小心地编程:确定是否应执行已安装的软件定时器功能需要 CPU 性能。这种对基本系统的影响可能会占用 CPU 性能的百分之几或更多。这可能导致系统不稳定。因此,在不同的 PC 系统上运行的能力可能会有所不同!超过 100 kHz 的频率通常是不现实的。但大多数情况下 10 kHz 应该没有问题。
-
当前执行的实时定时器例程不会自行中断。这意味着在安装的不同实时计时器之间没有优先级。因此,在实时定时器可能出现抖动的情况下,必须考虑安装的其他实时定时器例程的执行时间。实时定时器本身在系统中具有最高优先级,并且只能通过禁用中断接受来延迟。可以使用多任务模块实现运行优先级代码,有关详细信息,请参阅:使用多个任务(优先级、信号量、多个 CPU 内核)进行编程
项目实例
项目结构
项目源码
SharedData.h
#pragma once
#include <KrtsDemo.h>// 内核层数据需要1字节对齐
#pragma pack(1)constexpr int CONTROL_PERIOD{ 1000 }; // 控制周期 单位ustypedef struct SharedData { KSHandle timer_call_back = NULL; // 定时器回调KSHandle timer_handle = NULL; // 定时器int timer_count; // 计时器触发次数
}SharedData;
#pragma pack()
KitharaDemo.cpp
#include <iostream>
#include "../KitharaDll/SharedData.h"
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>const char customerNumber[256] = "DEMO";
SharedData* app_data_ptr_ = nullptr; // 应用层共享内存指针
SharedData* sys_data_ptr_ = nullptr; // 内核层共享内存指针// 应用层不能使用内核层指针!!!void OutputErr(KSError error, const char* pFuncName, const char* pComment)
{if (error == KS_OK)return;const char* pError;KS_getErrorString(error, &pError, KSLNG_DEFAULT);printf("ERROR (%08X = \'%s\') - %s: %s\n", error, pError, pFuncName, pComment);
}int main()
{KSError error;error = KS_openDriver(customerNumber); // 所有Kithar项目的第一步if (error != KS_OK){error = 1;OutputErr(error, "KS_openDriver", "Unable to open the driver!");}else{printf("Hello Kithara! \n");}// 指定内核程序执行的CPUKSSystemInformation systemInfo;systemInfo.structSize = sizeof(KSSystemInformation); error = KS_getSystemInformation(&systemInfo, KSF_NO_FLAGS);if (error != KS_OK){OutputErr(error, "KS_getSystemInformation", "");KS_closeDriver();return 0;}int cpu = systemInfo.numberOfCPUs - 1;error = KS_setTargetProcessor(cpu, KSF_NO_FLAGS);if (error != KS_OK){OutputErr(error, "KS_setTargetProcessor", "");KS_closeDriver();return 0;}// 创建共享内存error = KS_createSharedMem(reinterpret_cast<void**>(&app_data_ptr_), reinterpret_cast<void**>(&sys_data_ptr_), "KitharaDemo", sizeof(SharedData), 0);if (error != KS_OK){OutputErr(error, "KS_createSharedMem", "failed to allocate shared memory");KS_closeDriver();return 0;}// 加载内核DLLKSHandle kermel_handle;error = KS_loadKernel(&kermel_handle, "KitharaDll.dll", nullptr, nullptr, KSF_KERNEL_EXEC | KSF_SAVE_FPU);if (error != KS_OK){OutputErr(error, "KS_loadKernel", "load dll failed!");KS_closeDriver();return 0;}// 初始化内核层error = KS_execKernelFunction(kermel_handle, "_initFunction", sys_data_ptr_, KS_INVALID_HANDLE, KSF_NO_FLAGS);if (error != KS_OK){OutputErr(error, "KS_execKernelFunction", "load dll failed!");KS_closeDriver();return 0;}Sleep(100);if (app_data_ptr_->timer_handle == NULL){printf("timer_handle is NULL \n");}else{// 计时器启动error = KS_startTimer(app_data_ptr_->timer_handle, KSF_NO_FLAGS, 0); // 1msif (error != KS_OK){OutputErr(error, "KS_startTimer", "");KS_closeDriver();return 0;}}int timer_out = 10;while (timer_out){if (app_data_ptr_ != nullptr){printf("Timer Count: %d \n", app_data_ptr_->timer_count);}Sleep(100);timer_out--;}// 移除计时器if (app_data_ptr_->timer_handle != NULL){KS_stopTimer(app_data_ptr_->timer_handle);KS_removeTimer(app_data_ptr_->timer_handle);}// 移除回调if (app_data_ptr_->timer_call_back != NULL){KS_removeCallBack(app_data_ptr_->timer_call_back);}// 资源内核error = KS_freeKernel(kermel_handle);if (error != KS_OK){OutputErr(error, "KS_freeKernel", "");KS_closeDriver();return 0;}// 资源共享内存error = KS_freeSharedMem(app_data_ptr_);if (error != KS_OK){OutputErr(error, "KS_freeSharedMem", "");KS_closeDriver();return 0;}// 关闭驱动error = KS_closeDriver();if (error != KS_OK){OutputErr(error, "KS_closeDriver", "");KS_closeDriver();return 0;}Sleep(1000);return 0;
}
KitharaDll.cpp
#include "SharedData.h"
#include <cstdint>SharedData* sys_data_ptr_ = nullptr; // 计时器回调
KSError __stdcall _timerCallBack(void* /*pArgs*/, void* /*pContext*/);// 初始化函数
extern "C" KSError __declspec(dllexport) __stdcall _initFunction(void* pArgs, void* /*pContext*/) {sys_data_ptr_ = (SharedData*)pArgs;if (sys_data_ptr_ == nullptr){return -1;}// 计时器回调KSError error = KS_createCallBack(&sys_data_ptr_->timer_call_back, _timerCallBack, nullptr, KSF_DIRECT_EXEC, 0);if (error != KS_OK){return error;}// 创建计时器error = KS_createTimer(&sys_data_ptr_->timer_handle, CONTROL_PERIOD * 10, sys_data_ptr_->timer_call_back, KSF_REALTIME_EXEC | KSF_DONT_START);if (error != KS_OK){return error;}return KS_OK;
}// 计时器回调
KSError __stdcall _timerCallBack(void* /*pArgs*/, void* /*pContext*/) {if (sys_data_ptr_ != nullptr){sys_data_ptr_->timer_count++;}return KS_OK;
}#define WIN32_LEAN_AND_MEAN
// Windows 头文件
#include <windows.h>BOOL WINAPI DllMain(HINSTANCE hInstDll, DWORD reason, LPVOID pReserved) {return TRUE;
}
提示 : 内核层代码改动,编译应用层代码,可能不会编译内核层代码,可以添加依赖项使其代码保持同步。
示例更多:
smp\EtherCATDataExchange
smp\EtherCATBasics
smp\EtherCATBridgeConfig
smp\RealTimeJitterMeasure
smp\NetworkEthernetSend
...