首页 > 代码库 > Cpp_with_MFC官方实例----定时器的使用
Cpp_with_MFC官方实例----定时器的使用
本文使用的实例是位于程序安装目录的prj文件夹下Cpp_with_MFC项目,该项目包括两个工程,分别是Cpp_with_MFC工程和kernel工程
kernel工程主要有两个函数组成:
1. _initFunction(void* pArgs) ,该函数是用于kernel工程生成的dll文件被外部调用时的初始化代码,该函数内部没有实质内容。
2. _timerCallBack(void* pArgs, void* pContext),该函数为定时器回调函数,每进入一次则计数值+1,每达到500次则触发共享内存中的hEvent_事件。
Cpp_with_MFC工程实现配置定时器和显示定时器运行状况,其内部实现了两种定时器:
1.MFC定时器,通过SetTimer(1, 50, 0);开启一个普通的windows定时器,然后周期执行Cpp_with_MFC_Dlg::OnTimer(UINT_PTR nIDEvent) 函数,用于刷新界面显示。
2.Kithara RTS实时定时器,在函数Cpp_with_MFC_Dlg::init(bool debug)内创建并初始化定时器,然后通过点击按钮对应的函数Cpp_with_MFC_Dlg::TimerButton()开启该定时器。
定时器在初始化时,首先通过KS_loadKernel函数将kernel.dll中的程序资源载入,并通过KS_createKernelCallBack函数将kernel.dll中的_timerCallBack函数映射为一个回调函数,然后在创建定时器时KS_createTimer将回调函数与定时器关联。
MFC定时器的定时周期为50ms,而OnTimer函数中有阻塞函数等待hEvent_事件,hEvent_事件只被实时定时器关联的内核回调函数中触发,因此该50ms设置存在价值不大。
实时定时器的定时周期为1ms。
程序最后通过点击按钮,触发Cpp_with_MFC_Dlg::TimerButton()函数停止定时器,在退出时调用void Cpp_with_MFC_Dlg::clean()函数清理定时器资源。
主要代码解析:
Cpp_with_MFC_dlg.cpp文件
//------ init ------ bool Cpp_with_MFC_Dlg::init(bool debug) { int flags = debug ? 0 : KSF_DIRECT_EXEC; Error ksError; //------------------------------------------------------------------------------------------------------------ // Opening the driver is always the first step! After that, we can use other functions. If the opening fails, // no other function can be called. // // This function takes your customer number with Kithara (or "DEMO" or "BETA" if applicable) as a parameter. //------------------------------------------------------------------------------------------------------------ ksError = KS_openDriver(pCustomerNumber); //打开驱动,这是使用Kithara RTS的第一步 if (ksError) { outputErr(ksError, "KS_openDriver", "Maybe incorrect customer number?"); return false; } //------------------------------------------------------------------------------------------------------------ // If you wish to signal an application thread from the kernel level, it‘s best to have an event object, // which can be set from the DLL. Therefore we create an event object here, in order to show the handling. // It is possible to block a thread by calling KS_waitForEvent. //------------------------------------------------------------------------------------------------------------ ksError = KS_createEvent( //创建事件,该事件之后将被放入共享内存中,由内核模式中的回调函数触发 &hEvent_, // Address of event handle "MyCpp_with_MFCEvent", // Name of the event 0); // Flags, here 0 if (ksError) { outputErr(ksError, "KS_createEvent", "Unable to create required event!"); KS_closeDriver(); return false; } //------------------------------------------------------------------------------------------------------------ // Create and initialize the structure of type ‘TimerData‘, which is given to the timer callback routine as // an argument. In difference to the timer example on the application level we have to create shared memory // in order to give our callback routine some data, because normal variables are not accessible from the // kernel-mode. We can access the memory from application level using the ‘pAppPtr_‘, access from the kernel // level can be done using the ‘pSysPtr_‘. //------------------------------------------------------------------------------------------------------------ ksError = KS_createSharedMem( //创建共享内存用于用户层(非实时)与内核层(实时)进行通信,共享内存为结构体TimerData,包含一个计数器counter和一个句柄事件hEvent_ (void**)&pAppPtr_, // Address of application pointer (void**)&pSysPtr_, // Address of kernel pointer "MyCpp_with_MFCMem", // Name of shared memory area sizeof(TimerData), // Size of shared memory area 0); // Flags, here 0 (see manual) if (ksError) { outputErr(ksError, "KS_createSharedMem", "Unable to create shared memory!"); KS_closeDriver(); return false; } pAppPtr_->hEvent_ = hEvent_; // Save the created event 把事件放入共享内存中 pAppPtr_->counter_ = 0; // Clear the timer counter 计数器置0 //------------------------------------------------------------------------------------------------------------ // In order to use functions from the DLL on the kernel level, it must have been loaded first. // // Attention! The DLL must be found by the loader, so it should be placed in a directory, which is part of // the search path! // // Attention! The return value of KS_loadKernel is primarily the success condition of the loading process. // If you specify an initialization routine, the return value is furthermore the return of that // initialization function! //------------------------------------------------------------------------------------------------------------ ksError = KS_loadKernel( // 载入Kernel.dll程序资源文件,用hKernel表示该资源文件路径 &hKernel_, // Kernel handle "Kernel.dll", // Name of DLL "_initFunction", // Name of init routine debug ? pAppPtr_ : pSysPtr_, // Init parameter flags); // Flags, load where chosen if (ksError) { outputErr(ksError, "KS_loadKernel", "Unable to load and initialize DLL! Possibly the DLL is not in the search path?"); KS_closeDriver(); return false; } //------------------------------------------------------------------------------------------------------------ // Now create the callback. This one is called in the DLL every time the timer period has expired. The flag // KSF_DIRECT_EXEC is set, so the callback routine can be executed within realtime context. // // Accepted flags are: // // KSF_USER_EXEC: - execution on application level // KSF_KERNEL_EXEC: - execution on kernel level (synchronously) // KSF_DIRECT_EXEC: - execution on kernel level in realtime context // KSF_SAVE_FPU: - allow floating point calculation on kernel level //------------------------------------------------------------------------------------------------------------ ksError = KS_createKernelCallBack( // 创建将timerCallBack映射为回调函数,存入hCallBack中 &hCallBack_, // Address of callback handle hKernel_, // Handle of kernel DLL "_timerCallBack", // Name of callback function debug ? pAppPtr_ : pSysPtr_, // Reference parameter to the callback flags, // Flags, here kernel level (ISR) 16); // Priority, only used on Ring3 if (ksError) { outputErr(ksError, "KS_createKernelCallBack", "Unable to create kernel callback!"); KS_closeDriver(); return false; } //------------------------------------------------------------------------------------------------------------ // Please note, that the minimum theoretic timer period is 1 microsecond. This value is automatically // increased to a valid value, which is adjusted to the actual CPU performance. // // ATTENTION! Real-time timers are only available when having the RealTime Module! // If not: // - remove the flag KSF_REALTIME_EXEC from KS_createTimer! // //------------------------------------------------------------------------------------------------------------ // Create the timer with the chosen period. The signalization object is the ‘hCallBack_‘ parameter. Accepted // flags are: // // KSF_REALTIME_EXEC: - the real-time kernel is to be used (this is only possible after the timer resolution // has been set!) // KSF_DONT_START: - don‘t start the timer (can be started later) // KSF_ONE_SHOT: - signal timer only one time // // Please note, that the minimum timer period is 1 microsecond. //------------------------------------------------------------------------------------------------------------ ksError = KS_createTimer( // 创建定时器 &hTimer_, // Address of timer handle,定时器句柄 1 * ms, // Timer period in 100-ns-units,定时周期 hCallBack_, // Callback handle,回调函数,用于周期回调 debug ? KSF_DONT_START // Flags ,本处做了一个判断处理,如果用于调试则把定时器回调函数放在用户层执行,如果是非调试模式则放入实时模式执行 : KSF_REALTIME_EXEC | KSF_DONT_START); if (ksError) { outputErr(ksError, "KS_createTimer", "Unable to create the timer!"); KS_closeDriver(); return false; } return true; }
//按钮触发函数
void Cpp_with_MFC_Dlg::TimerButton() { Error ksError = KS_OK; CString text; (GetDlgItem(IDC_BUTTON1))->GetWindowText(text); if (!timerStarted_)//判断定时器启动状态,实现一个按钮两个功能 { //---------------------------------------------------------------------------------------------------------- // Then we restart the timer with the same period. We could program a new timer period if we want. Accepted // flags are: // // KSF_ONE_SHOT: - signal timer only one time //---------------------------------------------------------------------------------------------------------- ksError = KS_startTimer( // 启动定时器 hTimer_, // Timer handle 0, // Flags 1 * ms); // Timer period in 100-ns-units if (ksError) outputErr(ksError, "KS_startTimer", "Could not start the timer!"); else { timerStarted_ = true; GetDlgItem(IDC_BUTTON1)->SetWindowText("Stop timer!"); } KS_pulseEvent(pAppPtr_->hEvent_); } else { ksError = KS_stopTimer(hTimer_);//停止定时器 if (ksError) outputErr(ksError, "KS_stopTimer", "Unable to stop the timer!"); else { timerStarted_ = false; GetDlgItem(IDC_BUTTON1)->SetWindowText("Start timer!"); } } }
// 普通定时器回调函数
// ------ OnTimer ------ void Cpp_with_MFC_Dlg::OnTimer(UINT_PTR nIDEvent) { if (!initResult_) { GetDlgItem(IDC_LABEL1)->EnableWindow(false); GetDlgItem(IDC_EDITCOUNTER)->EnableWindow(false); GetDlgItem(IDC_BUTTON1)->EnableWindow(false); KillTimer(1); } else if (timerStarted_) { CString text; Error ksError = KS_waitForEvent(pAppPtr_->hEvent_, 0, 1000 * ms); //等待内核内的实时定时器回调函数触发该事件,然后才能执行 if (ksError == KS_OK) { text.Format("%d", pAppPtr_ == NULL ? 0 : pAppPtr_->counter_); } else if (KSERROR_CODE(ksError) == KSERROR_WAIT_TIMEOUT) { text = "Timeout occured!"; //等待事件超过1s } else { text.Format("error=%08X", ksError); //其他错误 } GetDlgItem(IDC_EDITCOUNTER)->SetWindowText(text); //设置文本框 } CDialog::OnTimer(nIDEvent); }
Kernel.cpp文件
extern "C" Error __declspec(dllexport) __stdcall _timerCallBack(void* pArgs, void* pContext) { //------------------------------------------------------------------------------------------------------------ // When the function returns a value other than 0, the timer will be cancelled. //------------------------------------------------------------------------------------------------------------ if( !_pData )// _pData为共享内存句柄,在_initFunction函数中将其映射到共享内存中 return KSERROR_BAD_PARAM; //------------------------------------------------------------------------------------------------------------ // Output on screen is not allowed, so we simply increment the counter. //------------------------------------------------------------------------------------------------------------ ++_pData->counter_; // Increment our counter //------------------------------------------------------------------------------------------------------------ // Set event, which we will wait for in the ring 3 application //------------------------------------------------------------------------------------------------------------ if(_pData->counter_ % 500 == 0)// KS_setEvent(_pData->hEvent_); //每满足500次触发事件,OnTimer函数中有等待该事件触发 //------------------------------------------------------------------------------------------------------------ // Remember: When the function returns a value other than 0, the timer will be cancelled. So, you have to // return 0 (KS_OK) in most cases! //------------------------------------------------------------------------------------------------------------ return KS_OK; }