設計單片機日誌系統

設計單片機日誌系統


本文博客鏈接:http://blog.csdn.net/jdh99,作者:jdh,轉載請註明.

 

環境:

主機:WIN10

開發環境:MDK5.12

MCU: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 [email protected]
* @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\r\n",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\r\n",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,"*******************************************\r\n");
	console_tx((uint8_t *)log_out,strlen(log_out));
	strcpy(log_out,"             UWB基站日誌幫助界面            \r\n");
	console_tx((uint8_t *)log_out,strlen(log_out));
	sprintf(log_out,"硬件版本:%d 軟件版本:%d\r\n",VERSION_HARD,VERSION_SOFT);
	console_tx((uint8_t *)log_out,strlen(log_out));
	sprintf(log_out,"總線通信協議版本:%s\r\n",VERSION_NAME_BUS);
	console_tx((uint8_t *)log_out,strlen(log_out));
	sprintf(log_out,"空口通信協議版本:%s\r\n",VERSION_NAME_UWB);
	console_tx((uint8_t *)log_out,strlen(log_out));
	sprintf(log_out,"CSSN:0x%06x ID:0x%04x\r\n",para_manage_read_cssn(), para_manage_read_id());
	console_tx((uint8_t *)log_out,strlen(log_out));
	strcpy(log_out,"快捷鍵I(INFO)輸出本地日誌\r\n");
	console_tx((uint8_t *)log_out,strlen(log_out));
	strcpy(log_out,"快捷鍵C(CLEAR)清除本地日誌\r\n");
	console_tx((uint8_t *)log_out,strlen(log_out));
	strcpy(log_out,"快捷鍵P(PAUSE)暫停輸出\r\n");
	console_tx((uint8_t *)log_out,strlen(log_out));
	strcpy(log_out,"快捷鍵S(START)開始輸出\r\n");
	console_tx((uint8_t *)log_out,strlen(log_out));
	strcpy(log_out,"快捷鍵A(ACTION)動作\r\n");
	console_tx((uint8_t *)log_out,strlen(log_out));
	strcpy(log_out,"A1:讀取1號dw1000狀態寄存器\r\n");
	console_tx((uint8_t *)log_out,strlen(log_out));
	strcpy(log_out,"A2:清除1號dw1000狀態寄存器\r\n");
	console_tx((uint8_t *)log_out,strlen(log_out));
	strcpy(log_out,"A3:打開1號dw1000接收\r\n");
	console_tx((uint8_t *)log_out,strlen(log_out));
	strcpy(log_out,"快捷鍵H(HELP)打開幫助\r\n");
	console_tx((uint8_t *)log_out,strlen(log_out));
	strcpy(log_out,"快捷鍵F(FILTER)過濾輸出\r\n");
	console_tx((uint8_t *)log_out,strlen(log_out));
	strcpy(log_out,"例:過濾1號模塊:F1\r\n");
	console_tx((uint8_t *)log_out,strlen(log_out));
	strcpy(log_out,"例:全部過濾:F\r\n");
	console_tx((uint8_t *)log_out,strlen(log_out));
	strcpy(log_out,"快捷鍵O(OPEN)打開模塊\r\n");
	console_tx((uint8_t *)log_out,strlen(log_out));
	strcpy(log_out,"例:打開1號模塊:O1\r\n");
	console_tx((uint8_t *)log_out,strlen(log_out));
	strcpy(log_out,"例:全部打開:O\r\n");
	console_tx((uint8_t *)log_out,strlen(log_out));
	strcpy(log_out,"包含的模塊:\r\n");
	console_tx((uint8_t *)log_out,strlen(log_out));
	sprintf(log_out,"TEST:%d 過濾:%d \r\n",LOG_TEST,Filter[LOG_TEST]);
	console_tx((uint8_t *)log_out,strlen(log_out));
	sprintf(log_out,"CLOCK:%d 過濾:%d \r\n",LOG_CLOCK,Filter[LOG_CLOCK]);
	console_tx((uint8_t *)log_out,strlen(log_out));
	sprintf(log_out,"DW1000:%d 過濾:%d \r\n",LOG_DW1000,Filter[LOG_DW1000]);
	console_tx((uint8_t *)log_out,strlen(log_out));
	sprintf(log_out,"DW1000_STATUS:%d 過濾:%d \r\n",LOG_DW1000_STATUS,Filter[LOG_DW1000_STATUS]);
	console_tx((uint8_t *)log_out,strlen(log_out));
	sprintf(log_out,"DW1000_DEAL_BUS:%d 過濾:%d \r\n",LOG_DEAL_BUS,Filter[LOG_DEAL_BUS]);
	console_tx((uint8_t *)log_out,strlen(log_out));
	strcpy(log_out,"*******************************************\r\n");
	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,"本地日誌輸出:\r\n");
	console_tx((uint8_t *)log_out,strlen(log_out));
	sprintf(log_out,"收到移動點數據次數:%d\r\n", Log.num_rf_rx);
	console_tx((uint8_t *)log_out,strlen(log_out));
	sprintf(log_out,"發送超時被刪除點數:%d\r\n", Log.num_time_out_delete);
	console_tx((uint8_t *)log_out,strlen(log_out));
	sprintf(log_out,"RF發送次數:%d\r\n", Log.num_rf_tx);
	console_tx((uint8_t *)log_out,strlen(log_out));
	sprintf(log_out,"RF校時或分配事件次數:%d\r\n", Log.num_rf_time);
	console_tx((uint8_t *)log_out,strlen(log_out));
	sprintf(log_out,"RF隨機信道發送次數:%d\r\n", Log.num_rf_random_tx);
	console_tx((uint8_t *)log_out,strlen(log_out));
	sprintf(log_out,"復位次數:%d\r\n", Log.num_reset);
	console_tx((uint8_t *)log_out,strlen(log_out));
	sprintf(log_out,"運行時間:%d\r\n", Log.time_run);
	console_tx((uint8_t *)log_out,strlen(log_out));
	sprintf(log_out,"收到同步脈衝計數:%d\r\n", Log.num_sync_pulse);
	console_tx((uint8_t *)log_out,strlen(log_out));
	sprintf(log_out,"收到422輪詢/事件幀次數:%d\r\n", Log.num_bus_poll);
	console_tx((uint8_t *)log_out,strlen(log_out));
	sprintf(log_out,"收到422事務命令次數:%d\r\n", Log.num_bus_down_cmd);
	console_tx((uint8_t *)log_out,strlen(log_out));
	sprintf(log_out,"收到422事務命令中事件個數:%d\r\n", Log.num_bus_down_cmd_dot);
	console_tx((uint8_t *)log_out,strlen(log_out));
	sprintf(log_out,"收到有效的422幀次數:%d\r\n", Log.num_valid_bus);
	console_tx((uint8_t *)log_out,strlen(log_out));
	sprintf(log_out,"收到無效的422幀次數:%d\r\n", Log.num_invalid_bus);
	console_tx((uint8_t *)log_out,strlen(log_out));
	sprintf(log_out,"校時時間錯誤次數:%d\r\n", 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\r\n", 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\r\n", i, Log.num_dw1000_time_error[i]);
		console_tx((uint8_t *)log_out,strlen(log_out));
	}
	sprintf(log_out,"輪詢超時被刪除點數:%d\r\n", 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\r\n", 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\r\n", 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\r\n", 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;
		}
	}
}





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章