设计单片机日志系统

2019-04-15 17:28发布

设计单片机日志系统
本文博客链接:http://blog.csdn.net/jdh99,作者:jdh,转载请注明.
 环境:主机:WIN10开发环境:MDK5.12MCU:STM32F407
说明:为单片机设计了一套简单的日志系统,通过日志系统提供的接口可以查看设备状态,并进行一些基本的调试。日志系统通过串口输出,所以单片机需要准备一个串口供日志系统使用。注意串口发送不能用DMA发送(避免在在中断中打印日志造成的中断竞争),接收可以用DMA接收。
功能:
  • 打开/关闭各个模块的调试输出
  • 输入动作指令,让设备进行一些动作
  • 打印系统运行日志
指令:
  • H:帮助
  • O:调试输出全开
  • O1:打开1号模块,打开其他模块指令类似
  • F:调试输出全关
  • F1:关闭1号模块
  • I:输出系统日志
  • C:清除系统日志
  • A1:执行1号动作,执行其他动作指令类似
源代码:log.h:/** * Copyright (c), 2015-2025 * @file log.h * @brief 日志模块主文件 * @author jdh * @date 2015/5/7 * @update 2015/6/19 * @update 2015/6/23 * @update 2015/6/30 * @update 2015/7/8 * @update 2015/7/13 * @update 2015/8/12 * @update 2015/8/18 * @update 2016/5/17 * @update 2016/6/30 * @update 2016/7/22 * @update 2016/8/11 * @update 2016/8/24 * @update 2016/9/2 * @update 2016/9/5 * @update 2016/9/7 * @update 2016/9/9 */ #ifndef _LOG_H_ #define _LOG_H_ /********************************************************************* * 头文件 **********************************************************************/ #include "world.h" #include "console.h" /********************************************************************* * 宏定义 **********************************************************************/ /** * @brief 日志模块数量 */ #define NUM_LOG 5 /** * @brief 模块编号 */ #define LOG_TEST 0 #define LOG_CLOCK 1 #define LOG_DW1000 2 #define LOG_DW1000_STATUS 3 #define LOG_DEAL_BUS 4 /********************************************************************* * 数据结构 **********************************************************************/ /** * @brief 日志 */ struct _Log { //公有日志 //收到移动点数据次数 uint32_t num_rf_rx; //发送超时被删除点数 uint32_t num_time_out_delete; //RF发送次数 uint32_t num_rf_tx; //RF校时或分配事件次数 uint32_t num_rf_time; //RF随机信道发送次数 uint32_t num_rf_random_tx; //复位次数 uint32_t num_reset; //运行时间,分度为0.5s uint32_t time_run; //收到同步脉冲计数 uint32_t num_sync_pulse; //收到422轮询/事件帧次数 uint32_t num_bus_poll; //收到422事务命令次数 uint32_t num_bus_down_cmd; //收到422事务命令中事件个数 uint32_t num_bus_down_cmd_dot; //收到有效的422帧次数 uint32_t num_valid_bus; //收到无效的422帧次数 uint32_t num_invalid_bus; //接收时间错误 uint32_t num_time_error; //私有日志 //dw1000芯片错误次数 uint32_t num_dw1000_error[NUM_DW1000]; //接收时间错误 uint32_t num_dw1000_time_error[NUM_DW1000]; //轮询超时被删除点数 uint32_t num_poll_time_out_delete; //接收超时复位 uint32_t num_dw1000_time_out_reset[NUM_DW1000]; //dw1000芯片状态错误次数 uint32_t num_dw1000_status_error[NUM_DW1000]; }; /********************************************************************* * 函数 **********************************************************************/ /** * @brief 模块加载 */ void log_load(void); /** * @brief 读取日志 * @retval 日志 */ struct _Log log_read(void); /** * @brief 清除日志 */ void log_clear(void); /** * @brief 收到移动点数据次数 */ void log_write_num_rf_rx(void); /** * @brief 发送超时被删除点数 */ void log_write_num_time_out_delete(void); /** * @brief RF发送次数 */ void log_write_num_rf_tx(void); /** * @brief RF校时或分配事件次数 */ void log_write_num_rf_time(void); /** * @brief RF随机信道发送次数 */ void log_write_num_rf_random_tx(void); /** * @brief 复位次数 */ void log_write_num_reset(void); /** * @brief 运行时间 * @param add_time:增加的时间.单位:0.5s */ void log_write_time_run(uint32_t add_time); /** * @brief 收到同步脉冲计数 */ void log_write_num_sync_pulse(void); /** * @brief 收到422轮询/事件帧次数 */ void log_write_num_bus_poll(void); /** * @brief 收到422事务命令次数 */ void log_write_num_bus_down_cmd(void); /** * @brief 收到422事务命令中事件个数 */ void log_write_num_bus_down_cmd_dot(void); /** * @brief 收到有效的422帧次数 */ void log_write_num_valid_bus(void); /** * @brief 收到无效的422帧次数 */ void log_write_num_invalid_bus(void); /** * @brief 收到时间错误 */ void log_write_num_time_error(void); /** * @brief dw1000芯片错误次数 * @param index:模块序号,从0开始 */ void log_write_num_dw1000_error(uint8_t index); /** * @brief dw1000芯片接收时间错误次数 * @param index:模块序号,从0开始 */ void log_write_num_dw1000_time_error(uint8_t index); /** * @brief 轮询超时被删除点数 */ void log_write_num_poll_time_out_delete(void); /** * @brief dw1000芯片接收超时复位次数 * @param index:模块序号,从0开始 */ void log_write_num_dw1000_time_out_reset(uint8_t index); /** * @brief dw1000芯片状态错误次数 * @param index:模块序号,从0开始 */ void log_write_num_dw1000_status_error(uint8_t index); /** * @brief 控制台打印 * @param index:模块编号 * @param info:打印的信息 */ void log_print(uint8_t index,char *info); /** * @brief 控制台强制打印 * @param info:打印的信息 */ void log_print_force(char *info); /** * @brief 接收处理 * @param rx:接收数据 */ void log_deal_rx(struct _Console_Rx rx); #endif log.c:/** * Copyright (c), 2015-2025 * @file log.c * @brief 日志模块主文件 * @author jdh * @email jdh821@163.com * @date 2015/5/7 * @update 2015/6/19 * @update 2015/6/30 * @update 2015/7/8 * @update 2015/7/13 * @update 2015/7/15 * @update 2015/8/12 * @update 2015/8/13 * @update 2015/11/11 * @update 2016/5/17 * @update 2016/6/30 * @update 2016/7/22 * @update 2016/8/11 * @update 2016/8/18 * @update 2016/8/22 * @update 2016/8/24 * @update 2016/9/2 * @update 2016/9/5 * @update 2016/9/7 * @update 2016/9/9 * @update 2016/9/12 */ /********************************************************************* * 头文件 **********************************************************************/ #include "log.h" #include "protocol_bus.h" #include "protocol_uwb.h" #include "para_manage.h" /********************************************************************* * 静态变量 **********************************************************************/ /** * @brief 运行日志 */ static struct _Log Log __attribute__((section("NO_INIT"),zero_init)); /** * @brief 日志过滤标志数组,0:未过滤,1:过滤 */ static uint8_t Filter[NUM_LOG] = {1, 1, 1, 1, 1}; /** * @brief 暂停输出标志,0:未暂停输出,1:暂停输出 */ static uint8_t Flag_Pause = 0; /********************************************************************* * 静态函数 **********************************************************************/ /** * @brief 帮助界面 */ static void help(void); /** * @brief 输出本地日志 */ static void print_log(void); /** * @brief 处理动作 * @param index:动作编号 */ static void deal_action(uint8_t index); /********************************************************************* * 函数 **********************************************************************/ /** * @brief 模块加载 */ void log_load(void) { //检查是否上电 if (RCC_GetFlagStatus(RCC_FLAG_PORRST) == SET) { //清除标志位 RCC_ClearFlag(); //清除日志 memset(&Log, 0, sizeof(Log)); } else { //日志:复位次数 Log.num_reset++; } } /** * @brief 清除日志 */ void log_clear(void) { memset(&Log, 0, sizeof(Log)); } /** * @brief 读取日志 * @retval 日志 */ struct _Log log_read(void) { return Log; } /** * @brief 收到移动点数据次数 */ void log_write_num_rf_rx(void) { Log.num_rf_rx++; } /** * @brief 发送超时被删除点数 */ void log_write_num_time_out_delete(void) { Log.num_time_out_delete++; } /** * @brief RF发送次数 */ void log_write_num_rf_tx(void) { Log.num_rf_tx++; } /** * @brief RF校时或分配事件次数 */ void log_write_num_rf_time(void) { Log.num_rf_time++; } /** * @brief RF随机信道发送次数 */ void log_write_num_rf_random_tx(void) { Log.num_rf_random_tx++; } /** * @brief 复位次数 */ void log_write_num_reset(void) { Log.num_reset++; } /** * @brief 运行时间 * @param add_time:增加的时间.单位:0.5s */ void log_write_time_run(uint32_t add_time) { Log.time_run += add_time; } /** * @brief 收到同步脉冲计数 */ void log_write_num_sync_pulse(void) { Log.num_sync_pulse++; } /** * @brief 收到422轮询/事件帧次数 */ void log_write_num_bus_poll(void) { Log.num_bus_poll++; } /** * @brief 收到422事务命令次数 */ void log_write_num_bus_down_cmd(void) { Log.num_bus_down_cmd++; } /** * @brief 收到422事务命令中事件个数 */ void log_write_num_bus_down_cmd_dot(void) { Log.num_bus_down_cmd_dot++; } /** * @brief 收到有效的422帧次数 */ void log_write_num_valid_bus(void) { Log.num_valid_bus++; } /** * @brief 收到无效的422帧次数 */ void log_write_num_invalid_bus(void) { Log.num_invalid_bus++; } /** * @brief 收到时间错误 */ void log_write_num_time_error(void) { Log.num_time_error++; } /** * @brief dw1000芯片错误次数 * @param index:模块序号,从0开始 */ void log_write_num_dw1000_error(uint8_t index) { Log.num_dw1000_error[index]++; } /** * @brief dw1000芯片接收时间错误次数 * @param index:模块序号,从0开始 */ void log_write_num_dw1000_time_error(uint8_t index) { Log.num_dw1000_time_error[index]++; } /** * @brief 轮询超时被删除点数 */ void log_write_num_poll_time_out_delete(void) { Log.num_poll_time_out_delete++; } /** * @brief dw1000芯片接收超时复位次数 * @param index:模块序号,从0开始 */ void log_write_num_dw1000_time_out_reset(uint8_t index) { Log.num_dw1000_time_out_reset[index]++; } /** * @brief dw1000芯片状态错误次数 * @param index:模块序号,从0开始 */ void log_write_num_dw1000_status_error(uint8_t index) { Log.num_dw1000_status_error[index]++; } /** * @brief 控制台打印 * @param index:模块编号 * @param info:打印的信息 */ void log_print(uint8_t index,char *info) { T_Time time; char log_out[256] = {0}; //判断是否是暂停输出 if (Flag_Pause) { return; } //判断是否被过滤输出 if (Filter[index]) { return; } time = get_time(); sprintf(log_out,"%05d:%03d:%03d %s ",time.s,time.ms,time.us,info); console_tx((uint8_t *)log_out,strlen(log_out)); } /** * @brief 控制台强制打印 * @param info:打印的信息 */ void log_print_force(char *info) { T_Time time; char log_out[256] = {0}; time = get_time(); sprintf(log_out,"%05d:%03d:%03d %s ",time.s,time.ms,time.us,info); console_tx((uint8_t *)log_out,strlen(log_out)); } /** * @brief 接收处理 * @param rx:接收数据 */ void log_deal_rx(struct _Console_Rx rx) { uint8_t i = 0; int num = 0; char str_temp[5] = {0}; //判断是否是输出本地日志 if (rx.len == 1 && rx.buf[0] == 'I') { print_log(); return; } //判断是否是输出本地日志 if (rx.len == 1 && rx.buf[0] == 'C') { log_clear(); return; } //判断是否是暂停输出 if (rx.len == 1 && rx.buf[0] == 'P') { Flag_Pause = 1; return; } //判断是否是打开输出 if (rx.len == 1 && rx.buf[0] == 'S') { Flag_Pause = 0; return; } //判断是否是帮助 if (rx.len == 1 && rx.buf[0] == 'H') { help(); return; } //判断是否是过滤规则 if (rx.len <= 3 && rx.buf[0] == 'F') { if (rx.len == 1) { //全部过滤 for (i = 0;i < NUM_LOG;i++) { Filter[i] = 1; } return; } memset(str_temp,sizeof(str_temp),0); memcpy(str_temp,rx.buf,rx.len); sscanf(str_temp,"F%d",&num); Filter[num] = 1; return; } //判断是否是打开模块 if (rx.len <= 3 && rx.buf[0] == 'O') { if (rx.len == 1) { //清除过滤规则 for (i = 0;i < NUM_LOG;i++) { Filter[i] = 0; } return; } memset(str_temp,sizeof(str_temp),0); memcpy(str_temp,rx.buf,rx.len); sscanf(str_temp,"O%d",&num); Filter[num] = 0; return; } //判断是否是打开模块 if (rx.len > 1 && rx.len <= 3 && rx.buf[0] == 'A') { memset(str_temp,sizeof(str_temp),0); memcpy(str_temp,rx.buf,rx.len); sscanf(str_temp,"A%d",&num); deal_action(num); return; } } /** * @brief 帮助界面 */ static void help(void) { char log_out[100] = {0}; strcpy(log_out,"******************************************* "); console_tx((uint8_t *)log_out,strlen(log_out)); strcpy(log_out," UWB基站日志帮助界面 "); console_tx((uint8_t *)log_out,strlen(log_out)); sprintf(log_out,"硬件版本:%d 软件版本:%d ",VERSION_HARD,VERSION_SOFT); console_tx((uint8_t *)log_out,strlen(log_out)); sprintf(log_out,"总线通信协议版本:%s ",VERSION_NAME_BUS); console_tx((uint8_t *)log_out,strlen(log_out)); sprintf(log_out,"空口通信协议版本:%s ",VERSION_NAME_UWB); console_tx((uint8_t *)log_out,strlen(log_out)); sprintf(log_out,"CSSN:0x%06x ID:0x%04x ",para_manage_read_cssn(), para_manage_read_id()); console_tx((uint8_t *)log_out,strlen(log_out)); strcpy(log_out,"快捷键I(INFO)输出本地日志 "); console_tx((uint8_t *)log_out,strlen(log_out)); strcpy(log_out,"快捷键C(CLEAR)清除本地日志 "); console_tx((uint8_t *)log_out,strlen(log_out)); strcpy(log_out,"快捷键P(PAUSE)暂停输出 "); console_tx((uint8_t *)log_out,strlen(log_out)); strcpy(log_out,"快捷键S(START)开始输出 "); console_tx((uint8_t *)log_out,strlen(log_out)); strcpy(log_out,"快捷键A(ACTION)动作 "); console_tx((uint8_t *)log_out,strlen(log_out)); strcpy(log_out,"A1:读取1号dw1000状态寄存器 "); console_tx((uint8_t *)log_out,strlen(log_out)); strcpy(log_out,"A2:清除1号dw1000状态寄存器 "); console_tx((uint8_t *)log_out,strlen(log_out)); strcpy(log_out,"A3:打开1号dw1000接收 "); console_tx((uint8_t *)log_out,strlen(log_out)); strcpy(log_out,"快捷键H(HELP)打开帮助 "); console_tx((uint8_t *)log_out,strlen(log_out)); strcpy(log_out,"快捷键F(FILTER)过滤输出 "); console_tx((uint8_t *)log_out,strlen(log_out)); strcpy(log_out,"例:过滤1号模块:F1 "); console_tx((uint8_t *)log_out,strlen(log_out)); strcpy(log_out,"例:全部过滤:F "); console_tx((uint8_t *)log_out,strlen(log_out)); strcpy(log_out,"快捷键O(OPEN)打开模块 "); console_tx((uint8_t *)log_out,strlen(log_out)); strcpy(log_out,"例:打开1号模块:O1 "); console_tx((uint8_t *)log_out,strlen(log_out)); strcpy(log_out,"例:全部打开:O "); console_tx((uint8_t *)log_out,strlen(log_out)); strcpy(log_out,"包含的模块: "); console_tx((uint8_t *)log_out,strlen(log_out)); sprintf(log_out,"TEST:%d 过滤:%d ",LOG_TEST,Filter[LOG_TEST]); console_tx((uint8_t *)log_out,strlen(log_out)); sprintf(log_out,"CLOCK:%d 过滤:%d ",LOG_CLOCK,Filter[LOG_CLOCK]); console_tx((uint8_t *)log_out,strlen(log_out)); sprintf(log_out,"DW1000:%d 过滤:%d ",LOG_DW1000,Filter[LOG_DW1000]); console_tx((uint8_t *)log_out,strlen(log_out)); sprintf(log_out,"DW1000_STATUS:%d 过滤:%d ",LOG_DW1000_STATUS,Filter[LOG_DW1000_STATUS]); console_tx((uint8_t *)log_out,strlen(log_out)); sprintf(log_out,"DW1000_DEAL_BUS:%d 过滤:%d ",LOG_DEAL_BUS,Filter[LOG_DEAL_BUS]); console_tx((uint8_t *)log_out,strlen(log_out)); strcpy(log_out,"******************************************* "); console_tx((uint8_t *)log_out,strlen(log_out)); } /** * @brief 输出本地日志 */ static void print_log(void) { char log_out[100] = {0}; uint8_t i = 0; strcpy(log_out,"本地日志输出: "); console_tx((uint8_t *)log_out,strlen(log_out)); sprintf(log_out,"收到移动点数据次数:%d ", Log.num_rf_rx); console_tx((uint8_t *)log_out,strlen(log_out)); sprintf(log_out,"发送超时被删除点数:%d ", Log.num_time_out_delete); console_tx((uint8_t *)log_out,strlen(log_out)); sprintf(log_out,"RF发送次数:%d ", Log.num_rf_tx); console_tx((uint8_t *)log_out,strlen(log_out)); sprintf(log_out,"RF校时或分配事件次数:%d ", Log.num_rf_time); console_tx((uint8_t *)log_out,strlen(log_out)); sprintf(log_out,"RF随机信道发送次数:%d ", Log.num_rf_random_tx); console_tx((uint8_t *)log_out,strlen(log_out)); sprintf(log_out,"复位次数:%d ", Log.num_reset); console_tx((uint8_t *)log_out,strlen(log_out)); sprintf(log_out,"运行时间:%d ", Log.time_run); console_tx((uint8_t *)log_out,strlen(log_out)); sprintf(log_out,"收到同步脉冲计数:%d ", Log.num_sync_pulse); console_tx((uint8_t *)log_out,strlen(log_out)); sprintf(log_out,"收到422轮询/事件帧次数:%d ", Log.num_bus_poll); console_tx((uint8_t *)log_out,strlen(log_out)); sprintf(log_out,"收到422事务命令次数:%d ", Log.num_bus_down_cmd); console_tx((uint8_t *)log_out,strlen(log_out)); sprintf(log_out,"收到422事务命令中事件个数:%d ", Log.num_bus_down_cmd_dot); console_tx((uint8_t *)log_out,strlen(log_out)); sprintf(log_out,"收到有效的422帧次数:%d ", Log.num_valid_bus); console_tx((uint8_t *)log_out,strlen(log_out)); sprintf(log_out,"收到无效的422帧次数:%d ", Log.num_invalid_bus); console_tx((uint8_t *)log_out,strlen(log_out)); sprintf(log_out,"校时时间错误次数:%d ", Log.num_time_error); console_tx((uint8_t *)log_out,strlen(log_out)); for (i = 0; i < NUM_DW1000; i++) { sprintf(log_out,"%d号dw1000模块错误次数:%d ", i, Log.num_dw1000_error[i]); console_tx((uint8_t *)log_out,strlen(log_out)); } for (i = 0; i < NUM_DW1000; i++) { sprintf(log_out,"%d号dw1000模块时间错误次数:%d ", i, Log.num_dw1000_time_error[i]); console_tx((uint8_t *)log_out,strlen(log_out)); } sprintf(log_out,"轮询超时被删除点数:%d ", Log.num_poll_time_out_delete); console_tx((uint8_t *)log_out,strlen(log_out)); for (i = 0; i < NUM_DW1000; i++) { sprintf(log_out,"%d号dw1000模块接收时间超时复位次数:%d ", i, Log.num_dw1000_time_out_reset[i]); console_tx((uint8_t *)log_out,strlen(log_out)); } for (i = 0; i < NUM_DW1000; i++) { sprintf(log_out,"%d号dw1000模块状态错误次数:%d ", i, Log.num_dw1000_status_error[i]); console_tx((uint8_t *)log_out,strlen(log_out)); } } /** * @brief 处理动作 * @param index:动作编号 */ static void deal_action(uint8_t index) { uint32_t status = 0; char log_out[100] = {0}; switch (index) { //读取1号dw1000状态寄存器 case 1: { status = dwt_read32bitreg(0, SYS_STATUS_ID); sprintf(log_out,"1号dw1000状态:0x%08x ", status); console_tx((uint8_t *)log_out,strlen(log_out)); break; } //清除1号dw1000状态寄存器 case 2: { status = dwt_read32bitreg(0, SYS_STATUS_ID); dwt_write32bitreg(0, SYS_STATUS_ID, status); break; } //打开1号dw1000接收 case 3: { dwt_rxenable(0, 0); break; } } }