KRTS实时定时器

管理定时器和实时定时器



管理时间数据

  • 在 Kithara RealTime Suite 中,所有时间值均以 100 ns 为单位给出:这不仅适用于定时器的安装,也适用于阻塞函数的超时值 (‘KS_waitForEvent’) 等。

  • 为了在对源代码进行编程时使用可管理的数字,可以给出倍数为 10000 的毫秒值。为了进一步简化此过程,还可以在程序代码的中心位置预定义值 10000,例如:

    const int ms = 10000;
    int timeout = 200 * ms;
    ...
    

通用定时器编程

要创建计时器,您需要创建一些依赖对象:

计时器安装需要生成的句柄。如果句柄指向回调或任务对象,则当计时器触发时,将执行此对象的例程。在这种情况下,是要确保使用的所有数据和对象都位于同一个地址空间(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 };       // 控制周期 单位us

typedef 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");
	}

	// 指定内核程序执行的CPU
	KSSystemInformation 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;
	}


	// 加载内核DLL
	KSHandle 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);  // 1ms
		if (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
...
  • 14
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值