1.写日志/写json
main.c
cpp
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include "log.h"
#include "common_config.h"
#define INFO_PRINT(fmt, ...) \
do { \
fprintf(stderr, "[INFO] " fmt "\n", ##__VA_ARGS__); \
log_write(LOG_LEVEL_INFO, fmt "\n", ##__VA_ARGS__); \
} while (0)
#define APP_VERSION "V132.1.01"
// __DATE__ 和 __TIME__ 是编译器预定义宏,会在编译时自动替换为当前日期和时间
#define APP_VERSION_BUILD APP_VERSION "(built " __DATE__ " " __TIME__ ")"
// 全局标志位,用于控制程序退出
volatile int keep_running = 1;
// 2. 模拟信号处理函数
void signal_handler(int sig) {
printf("\n[Signal Handler] Received signal %d. Exiting gracefully...\n", sig);
keep_running = 0; // 修改标志位,让主循环退出
}
int main() {
// 3. 注册信号处理 (对应 main.c 中的 signal 调用)
signal(SIGINT, signal_handler); // Ctrl+C
signal(SIGTERM, signal_handler); // kill 命令
//初始化日志系统
if(ecu_log_init()<0)
{
printf("ERROR: Failed to initialize log system!\n");
return -1;
}
pid_t pid = getpid(); // 获取当前进程的PID
printf("我的进程号是: %d\n", pid);
//本地系统参数配置
if(local_system_init()<0)
return -1;
// 4. 打印版本信息 (对应 main.c 中的 INFO_PRINT)
printf("========================================\n");
INFO_PRINT("Application version: %s\n", APP_VERSION_BUILD);
printf("========================================\n");
printf("Program is running. Press Ctrl+C to stop.\n");
// 5. 模拟主循环
while (keep_running) {
// 休眠 1 秒,避免占用过多 CPU,同时等待信号
sleep(1);
printf(".");
fflush(stdout); // 确保立即输出
}
printf("\nMain exited cleanly.\n");
return 0;
}
实验现象:

1 写日志:
路径/home/aurio/logs/ecu_log
2 写json
路径/home/aurio/config.json
makefile
cpp
# Makefile for ECU Project
# Compiler settings
CC = gcc
CFLAGS = -Wall -Wextra -O2 -I. -std=c99 -D_POSIX_C_SOURCE=200809L -DG_DEBUG_ENABLE=1
LDFLAGS = -lpthread -lm -lrt
# Source files
SRCS = cJSON.c common_config.c main.c log.c
OBJS = $(SRCS:.c=.o)
TARGET = ecu_program
# Default target
all: $(TARGET)
# Link executable
$(TARGET): $(OBJS)
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
@echo "Build completed: $(TARGET)"
# Compile .c files to .o files
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $@
# Clean build files
clean:
rm -f $(OBJS) $(TARGET)
@echo "Clean completed."
.PHONY: all clean
分析makefile
Makefile 文档分析
概述
这是一个用于构建 ECU(Electronic Control Unit,电子控制单元)项目的 Makefile 文件。它定义了编译规则、源文件、目标文件和构建流程,用于自动化构建名为 ecu_program的可执行程序。
文件结构分析
1. 编译器设置
CC = gcc
CFLAGS = -Wall -Wextra -O2 -I. -std=c99 -D_POSIX_C_SOURCE=200809L -DG_DEBUG_ENABLE=1
LDFLAGS = -lpthread -lm -lrt
| 变量 | 值 | 说明 |
|---|---|---|
CC |
gcc |
指定使用 GCC 编译器 |
CFLAGS |
-Wall -Wextra -O2 -I. -std=c99 -D_POSIX_C_SOURCE=200809L -DG_DEBUG_ENABLE=1 |
编译选项: • -Wall -Wextra:启用所有警告和额外警告 • -O2:启用优化级别 2 • -I.:包含当前目录作为头文件搜索路径 • -std=c99:使用 C99 标准 • -D_POSIX_C_SOURCE=200809L:定义 POSIX 特性测试宏 • -DG_DEBUG_ENABLE=1:启用调试输出宏 |
LDFLAGS |
-lpthread -lm -lrt |
链接选项: • -lpthread:链接 POSIX 线程库 • -lm:链接数学库 • -lrt:链接实时库(用于 clock_gettime等函数) |
2. 源文件和目标文件定义
SRCS = cJSON.c common_config.c main.c log.c
OBJS = $(SRCS:.c=.o)
TARGET = ecu_program
| 变量 | 值 | 说明 |
|---|---|---|
SRCS |
cJSON.c common_config.c main.c log.c |
源文件列表,包含 4 个 C 源文件 |
OBJS |
$(SRCS:.c=.o) |
目标文件列表,将 .c后缀替换为 .o |
TARGET |
ecu_program |
最终生成的可执行文件名 |
3. 默认目标
all: $(TARGET)
-
默认目标是
all,依赖于$(TARGET) -
执行
make或make all时,会构建ecu_program可执行文件
4. 链接可执行文件规则
$(TARGET): $(OBJS)
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
@echo "Build completed: $(TARGET)"
| 元素 | 说明 |
|---|---|
| 目标 | $(TARGET)(即 ecu_program) |
| 依赖 | $(OBJS)(即所有 .o文件) |
| 命令 | 1. 使用 gcc将所有 .o文件链接成可执行文件 2. 输出构建完成信息 |
5. 编译规则
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $@
| 元素 | 说明 |
|---|---|
| 目标 | %.o(任意 .o文件) |
| 依赖 | %.c(对应的同名 .c文件) |
| 命令 | 编译单个 .c文件为 .o文件 |
6. 清理规则
clean:
rm -f $(OBJS) $(TARGET)
@echo "Clean completed."
| 元素 | 说明 |
|---|---|
| 目标 | clean |
| 依赖 | 无 |
| 命令 | 1. 删除所有 .o文件和可执行文件 2. 输出清理完成信息 |
7. 伪目标声明
.PHONY: all clean
-
声明
all和clean为伪目标,表示它们不是实际的文件 -
确保即使存在同名文件,
make也会执行这些目标的命令
构建流程
-
执行
make时,首先查找默认目标all -
all
依赖于$(TARGET)(即ecu_program`) -
ecu_program依赖于所有.o文件 -
通过模式规则
%.o: %.c编译每个.c文件为对应的.o文件 -
将所有
.o文件链接为最终的可执行文件
项目结构
基于 Makefile 中的源文件列表,可以推断项目包含以下模块:
| 文件 | 描述 |
|---|---|
cJSON.c |
cJSON 库实现,用于 JSON 解析 |
common_config.c |
通用配置管理模块 |
main.c |
主程序入口 |
log.c |
日志系统模块 |
注意事项
-
依赖关系:此 Makefile 使用简单的模式规则,没有自动处理头文件依赖
-
并行构建 :此 Makefile 支持并行构建(通过
make -j) -
可移植性:使用 POSIX 标准,适合 Linux/Unix 系统
-
调试支持 :通过
DG_DEBUG_ENABLE=1启用了调试输出
3.定时器触发
在makefile里面 加入 mytime.c

main.c
cpp
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include "log.h"
#include "common_config.h"
#include "mytimer.h" // 包含新的定时器头文件
#define INFO_PRINT(fmt, ...) \
do { \
fprintf(stderr, "[INFO] " fmt "\n", ##__VA_ARGS__); \
log_write(LOG_LEVEL_INFO, fmt "\n", ##__VA_ARGS__); \
} while (0)
#define APP_VERSION "V132.1.01"
#define APP_VERSION_BUILD APP_VERSION "(built " __DATE__ " " __TIME__ ")"
// 全局标志位,用于控制程序退出
volatile int keep_running = 1;
// 信号处理函数 - 处理 Ctrl+C 和 kill 命令
void signal_handler(int sig) {
printf("\n[Signal Handler] Received signal %d. Exiting gracefully...\n", sig);
log_write(LOG_LEVEL_INFO, "Received signal %d. Exiting gracefully...\n", sig);
// 停止定时器
if (sig == SIGINT || sig == SIGTERM) {
stop_timer();
}
keep_running = 0; // 修改标志位,让主循环退出
}
int main() {
pid_t pid = getpid(); // 获取当前进程的PID
// 注册信号处理函数
signal(SIGINT, signal_handler); // Ctrl+C
signal(SIGTERM, signal_handler); // kill 命令
// 初始化日志系统
if (ecu_log_init() < 0) {
printf("ERROR: Failed to initialize log system!\n");
return -1;
}
printf("我的进程号是: %d\n", pid);
log_write(LOG_LEVEL_INFO, "Process started with PID: %d\n", pid);
// 本地系统参数配置 json文件
if (local_system_init() < 0) {
return -1;
}
// 初始化定时器信号处理
if (init_timer_signal() < 0) {
printf("ERROR: Failed to initialize timer signal handler!\n");
log_write(LOG_LEVEL_ERROR, "Failed to initialize timer signal handler\n");
return -1;
}
#if 0
// 设置定时器:3秒后触发 就触发一次
if (setup_timer(3, 0) < 0) {
printf("ERROR: Failed to setup timer!\n");
log_write(LOG_LEVEL_ERROR, "Failed to setup timer\n");
return -1;
}
#endif
// 设置周期定时器:3秒后触发
if (setup_periodic_timer(3, 0) < 0) {
printf("ERROR: Failed to setup timer!\n");
log_write(LOG_LEVEL_ERROR, "Failed to setup timer\n");
return -1;
}
// 打印版本信息
printf("========================================\n");
INFO_PRINT("Application version: %s\n", APP_VERSION_BUILD);
printf("========================================\n");
printf("Program is running. Timer will expire in 3 seconds. Press Ctrl+C to stop.\n");
// 主循环
int loop_count = 0;
while (keep_running) {
// 模拟业务逻辑处理
usleep(500 * 1000); // 每次循环休眠 500ms
loop_count++;
printf("Working... loop count: %d\n", loop_count);
// 检查定时器是否触发
if (is_timer_triggered()) {
// 重置标志位
reset_timer_flag();
printf("\n[EVENT] Timer Expired! SIGALRM received.\n");
// 这里可以添加具体的业务逻辑
// 例如:execute_shutdown_command();
// 注意:这里不退出循环,程序继续运行直到用户按下 Ctrl+C
// 可选:设置新的定时器
//setup_timer(5, 0); // 5秒后再次触发
}
}
// 清理工作
stop_timer(); // 停止定时器
printf("\nMain exited cleanly.\n");
log_write(LOG_LEVEL_INFO, "Program exited cleanly.\n");
return 0;
}
实验现象 现在是3s定时器触发;周期性的
