timeGetTime Function

timeGetTime 函数用于获取自 Windows 启动以来经过的时间(以毫秒为单位)。此函数无需参数,并返回 DWORD 类型的系统时间值。与 timeGetSystemTime 函数不同的是,它使用 MMTIME 结构体返回时间,且开销较小。需要注意的是,返回值每过约 49.71 天会归零,因此在计算中应使用两次调用的差值。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >




timeGetTime Function

 

The timeGetTime function retrieves the system time, in milliseconds. The system time is the time elapsed since Windows was started.

Syntax

DWORD timeGetTime(void);

Parameters

This function has no parameters.

Return Value

Returns the system time, in milliseconds.

Remarks

The only difference between this function and the timeGetSystemTime function is that timeGetSystemTime uses the MMTIME structure to return the system time. The timeGetTime function has less overhead than timeGetSystemTime .

Note that the value returned by the timeGetTime function is a DWORD value. The return value wraps around to 0 every 2^32 milliseconds, which is about 49.71 days. This can cause problems in code that directly uses the timeGetTime return value in computations, particularly where the value is used to control code execution. You should always use the difference between two timeGetTime return values in computations.

Windows NT/2000: The default precision of the timeGetTime function can be five milliseconds or more, depending on the machine. You can use the timeBeginPeriod and timeEndPeriod functions to increase the precision of timeGetTime . If you do so, the minimum difference between successive values returned by timeGetTime can be as large as the minimum period value set using timeBeginPeriod and timeEndPeriod . Use the QueryPerformanceCounter and QueryPerformanceFrequency functions to measure short time intervals at a high resolution,

Windows 95: The default precision of the timeGetTime function is 1 millisecond. In other words, the timeGetTime function can return successive values that differ by just 1 millisecond. This is true no matter what calls have been made to the timeBeginPeriod and timeEndPeriod functions.

Requirements

Minimum supported clientWindows 2000 Professional
Minimum supported serverWindows 2000 Server
HeaderMmsystem.h (include Windows.h)
LibraryWinmm.lib
DLLWinmm.dll

 

#define NOMINMAX #include <windows.h> #include <stdio.h> #include <stdint.h> #include <mmsystem.h> #include <string.h> #include <stdlib.h> #include <time.h> #include <math.h> #pragma comment(lib, "winmm.lib") #pragma comment(lib, "gdi32.lib") #pragma comment(lib, "user32.lib") #define UNICODE #define _UNICODE #define LOG_FILE L"vehicle_log.txt" #define TARGET_INTERVAL 20 // 20ms目标间隔 #define LOG_BUFFER_SIZE 4096 // 日志缓冲区大小 #define MAX_ACCEPTABLE_INTERVAL 40 // 最大可接受间隔40ms // ------------------ 全局变量定义 ------------------ volatile uint16_t current_vehicle_speed = 0; uint8_t can_data[8] = {0}; volatile uint64_t total_distance_mm = 0; volatile uint32_t last_update_time = 0; const uint32_t can_update_period = 100; // CAN信号每100ms更新一次 LARGE_INTEGER frequency; volatile int is_paused = 0; HWND hStatic = NULL; HANDLE hExitEvent = NULL; HANDLE hLogThread = NULL; HANDLE hLogEvent = NULL; MMRESULT hTimerID = 0; // 日志缓冲区和索引 static wchar_t log_buffer[LOG_BUFFER_SIZE]; static size_t log_index = 0; static CRITICAL_SECTION log_cs; // 日志缓冲区临界区 // ------------------ 函数声明 ------------------ void ClearLogFile(const wchar_t* log_file); void BufferLog(uint32_t current_time, uint16_t speed, uint32_t actual_interval); void FlushLogBuffer(); void GenerateCANMessage(uint16_t speed_msg, uint8_t frame[8]); uint16_t ReadCANMessage(uint8_t frame[8]); void UpdateVehicleState(uint32_t current_time, uint32_t actual_interval); LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); DWORD WINAPI LogThread(LPVOID lpParam); void CALLBACK TimerCallback(UINT uTimerID, UINT uMsg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2); // ------------------ 清空日志文件 ------------------ void ClearLogFile(const wchar_t* log_file) { FILE* file = _wfopen(log_file, L"w"); total_distance_mm = 0; if (file) { fwprintf(file, L"Log initialized. Vehicle Logger started.\n"); fclose(file); } else { OutputDebugStringW(L"无法创建日志文件: vehicle_log.txt\n"); } } // ------------------ 缓冲日志(简化版) ------------------ void BufferLog(uint32_t current_time, uint16_t speed, uint32_t actual_interval) { SYSTEMTIME st; GetLocalTime(&st); EnterCriticalSection(&log_cs); // 计算总距离(米),四舍五入 uint64_t total_distance_m = (total_distance_mm + 500) / 1000; // 计算剩余缓冲区空间 size_t remaining = LOG_BUFFER_SIZE - log_index - 1; // 只记录时间、速度和距离(米) int written = swprintf_s(log_buffer + log_index, remaining, L"%02d:%02d:%02d.%03d - Speed: %d km/h, Total Distance: %llu m\n", st.wHour, st.wMinute, st.wSecond, st.wMilliseconds, speed, total_distance_m); if (written > 0 && written < (int)remaining) { log_index += written; } else { // 缓冲区不足,触发日志刷新 SetEvent(hLogEvent); swprintf_s(log_buffer + log_index, LOG_BUFFER_SIZE - log_index - 1, L"%02d:%02d:%02d.%03d - Speed: %d km/h, Total Distance: %llu m\n", st.wHour, st.wMinute, st.wSecond, st.wMilliseconds, speed, total_distance_m); log_index = wcslen(log_buffer); } // 如果缓冲区接近满,触发日志刷新 if (log_index > LOG_BUFFER_SIZE - 512) { SetEvent(hLogEvent); } LeaveCriticalSection(&log_cs); } // ------------------ 刷新日志缓冲区 ------------------ void FlushLogBuffer() { if (log_index == 0) return; FILE* file = _wfopen(LOG_FILE, L"a"); if (file) { fwrite(log_buffer, sizeof(wchar_t), log_index, file); fclose(file); log_index = 0; } } // ------------------ 日志线程 ------------------ DWORD WINAPI LogThread(LPVOID lpParam) { while (1) { // 等待日志事件或退出事件 HANDLE handles[2] = { hLogEvent, hExitEvent }; DWORD waitResult = WaitForMultipleObjects(2, handles, FALSE, 1000); // 1秒超时 if (waitResult == WAIT_OBJECT_0) { // 日志事件触发 EnterCriticalSection(&log_cs); FlushLogBuffer(); LeaveCriticalSection(&log_cs); } else if (waitResult == WAIT_OBJECT_0 + 1) { // 退出事件触发 break; } else if (waitResult == WAIT_TIMEOUT) { // 超时,定期刷新日志 EnterCritical极速Section(&log_cs); if (log_index > 0) { FlushLogBuffer(); } LeaveCriticalSection(&log_cs); } } // 退出前确保所有日志都写入 EnterCriticalSection(&log_cs); FlushLogBuffer(); LeaveCriticalSection(&log_cs); return 0; } // ------------------ 生成 CAN 消息 ------------------ void GenerateCANMessage(uint16_t speed_msg, uint8_t frame[8]) { memset(frame, 0, 8); uint16_t mask = (1 << 13) - 1; uint16_t encoded_speed = speed_msg & mask; for (int i = 0; i < 13; i++) { uint16_t bit_pos = 16 + i; uint8_t byte_pos = bit_pos / 8; uint8_t bit_in_byte = 7 - (bit_pos % 8); if (encoded_speed & (1 << i)) { frame[byte_pos] |= (1 << bit_in_byte); } } } // ------------------ 读取 CAN 消息 ------------------ uint16_t ReadCANMessage(uint8_t frame[8]) { uint16_t speed = 0; for (int i = 0; i < 13; i++) { uint16_t bit_pos = 16 + i; uint8_t byte_pos = bit_pos / 8; uint8_t bit_in_byte = 7 - (bit_pos % 8); if (frame[byte_pos] & (1 << bit_in_byte)) { speed |= (1 << i); } } return speed; } // ------------------ 更新车辆状态(修复速度和距离计算) ------------------ void UpdateVehicleState(uint32_t current_time, uint32_t actual_interval) { static uint32_t last_can_update_time = 0; static uint16_t last_speed = 0; // 保存上次速度 static int speed_change_counter = 0; // 速度变化计数器 const int SPEED_CHANGE_INTERVAL = 5; // 每5次CAN更新改变速度 if (is_paused) return; // 更新CAN信号(每100ms更新一次) if ((last_can_update_time == 0) || (current_time - last_can_update_time) >= can_update_period) { // 每5次CAN更新改变一次速度(约0.5秒) if (last_speed == 0 || speed_change_counter >= SPEED_CHANGE_INTERVAL) { // 生成更合理的随机速度(0-120km/h) last_speed = 10 + (rand() % 110); speed_change_counter = 0; } else { speed_change_counter++; } GenerateCANMessage(last_speed, can_data); current_vehicle_speed = last_speed; last_can_update_time = current_time; } // 使用实际间隔时间计算距离 // 单位转换:km/h -> m/s: /3.6, 毫秒->秒: /1000 double distance_m = (double)current_vehicle_speed * actual_interval / (3.6 * 1000.0); total_distance_mm += (uint64_t)(distance_m * 1000); // 转换为毫米 } // ------------------ 定时器回调函数(修复窗口更新) ------------------ void CALLBACK TimerCallback(UINT uTimerID, UINT uMsg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2) { static uint32_t start_time = 0; static uint32_t last_time = 0; static LARGE_INTEGER start_counter; static LARGE_INTEGER last_counter; HWND hwnd = (HWND)dwUser; // 初始化计时器 if (start_time == 0) { start_time = timeGetTime(); QueryPerformanceCounter(&start_counter); last_counter = start_counter; last_time = 0; } // 获取当前时间(毫秒) uint32_t current_time = timeGetTime() - start_time; // 使用高精度计数器计算实际间隔 LARGE_INTEGER current_counter; QueryPerformanceCounter(&current_counter); uint32_t actual_interval = (uint32_t)((current_counter.QuadPart - last_counter.QuadPart) * 1000 / frequency.QuadPart); last_counter = current_counter; // 更新车辆状态(使用实际间隔时间) UpdateVehicleState(current_time, actual_interval); // 缓冲日志(简化版) BufferLog(current_time, current_vehicle_speed, actual_interval); // 实时更新UI // 计算总距离(米),四舍五入 uint64_t total_distance_m = (total_distance_mm + 500) / 1000; wchar_t buffer[256]; swprintf_s(buffer, 256, L"速度: %d km/h\n距离: %llu m", current_vehicle_speed, total_distance_m); // 直接更新UI(使用SendMessage确保立即更新) SendMessageW(hStatic, WM_SETTEXT, 0, (LPARAM)buffer); } // ------------------ 窗口处理函数 ------------------ LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { static UINT timerResolution = 0; // 保存定时器分辨率 switch (uMsg) { case WM_CREATE: { // 初始化日志临界区 InitializeCriticalSection(&log_cs); // 创建事件对象 hExitEvent = CreateEvent(NULL, TRUE, FALSE, NULL); hLogEvent = CreateEvent(NULL, FALSE, FALSE, NULL); ClearLogFile(LOG_FILE); // 创建按钮控件 CreateWindowW(L"BUTTON", L"Pause", WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, 20, 20, 120, 40, hwnd, (HMENU)1, NULL, NULL); // 创建静态文本控件 hStatic = CreateWindowW(L"STATIC", L"速度: 0 km/h\n距离: 0 m", WS_VISIBLE | WS_CHILD | SS_LEFT | SS_NOTIFY, 20, 80, 350, 100, hwnd, (HMENU)2, NULL, NULL); // 确保静态文本控件创建成功 if (!hStatic) { MessageBoxW(hwnd, L"无法创建静态文本控件", L"错误", MB_ICONERROR); } QueryPerformanceFrequency(&frequency); GenerateCANMessage(0, can_data); srand((unsigned int)time(NULL)); // 创建日志线程 hLogThread = CreateThread( NULL, 0, LogThread, NULL, CREATE_SUSPENDED, // 先挂起线程 NULL ); // 设置日志线程优先级 SetThreadPriority(hLogThread, THREAD_PRIORITY_BELOW_NORMAL); ResumeThread(hLogThread); // 设置系统定时器精度 TIMECAPS tc; timeGetDevCaps(&tc, sizeof(tc)); timerResolution = std::min(std::max(tc.wPeriodMin, 1), tc.wPeriodMax); timeBeginPeriod(timerResolution); // 提升进程优先级 SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS); // 创建多媒体定时器 hTimerID = timeSetEvent( TARGET_INTERVAL, timerResolution, TimerCallback, (DWORD_PTR)hwnd, TIME_PERIODIC | TIME_CALLBACK_FUNCTION ); if (!hTimerID) { MessageBoxW(hwnd, L"无法创建定时器", L"错误", MB_ICONERROR); } break; } case WM_COMMAND: { if (LOWORD(wParam) == 1) { is_paused = !is_paused; SetWindowTextW(GetDlgItem(hwnd, 1), is_paused ? L"Resume" : L"Pause"); } break; } case WM_DESTROY: { // 通知线程退出 SetEvent(hExitEvent); SetEvent(hLogEvent); // 等待日志线程退出 WaitForSingleObject(hLogThread, 1000); // 关闭句柄 CloseHandle(hLogThread); CloseHandle(hExitEvent); CloseHandle(hLogEvent); // 清理日志临界区 DeleteCriticalSection(&log_cs); // 停止定时器 if (hTimerID) { timeKillEvent(hTimerID); hTimerID = 0; } // 恢复系统定时器精度 timeEndPeriod(timerResolution); PostQuitMessage(0); break; } default: return DefWindowProcW(hwnd, uMsg, wParam, lParam); } return 0; } // ------------------ 主程序 ------------------ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow) { // 确保正确注册窗口类 WNDCLASSW wc = {0}; wc.lpfnWndProc = WindowProc; wc.hInstance = hInstance; wc.lpszClassName = L"VehicleLogger"; wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.style = CS_HREDRAW | CS_VREDRAW; if (!RegisterClassW(&wc)) { MessageBoxW(NULL, L"窗口类注册失败!", L"错误", MB_ICONERROR); return 0; } HWND hwnd = CreateWindowExW( 0, wc.lpszClassName, L"CAN信号记录器", WS_OVERLAPPEDWINDOW | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 400, 300, NULL, NULL, hInstance, NULL ); if (!hwnd) { MessageBoxW(NULL, L"窗口创建失败!", L"错误", MB_ICONERROR); return 0; } ShowWindow(hwnd, nCmdShow); UpdateWindow(hwnd); MSG msg; while (GetMessageW(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessageW(&msg); } return (int)msg.wParam; } 修改上述代码的错误,以C语言输出
最新发布
08-08
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值