CMD历史最大显示行数

使用for循环,创建约3.9万行代码,对比输出结果。1809次4行循环之前被循环覆盖掉。改变字符数量发现,cmd窗口限制了输出行数,未限制每行数量,触及极限字符串长度应该到内存上限,尚未尝试。

命令行限制为32767行。

查阅windows文档发现

#include "main.h" #include "RS485.h" #include <string.h> #include <stdio.h> #include "OLED.h" #include "tjc_usart_hmi.h" #include "read_param.h" #define FRAME_LENGTH 7 // 显示控制结构体 typedef struct { uint8_t line_count; uint32_t last_update; uint32_t last_history_update; volatile char lines[MAX_LINES][LINE_BUF_SIZE]; volatile char latest_line[LINE_BUF_SIZE]; uint8_t update_flag; uint8_t history_updated; char last_alarm_text[LINE_BUF_SIZE]; // 上次报警文本 uint32_t last_alarm_time; // 上次报警时间 uint8_t history_changed; // 历史记录内容变化 } DisplayCtrl; volatile DisplayCtrl disp_ctrl = {0}; volatile AlarmState temp_alarm = {.trigger_delay = 3000}; // 温度报警状态 volatile uint8_t g_alarm_flag = 50; volatile float outlet_water_temperature =50; volatile float inlet_water_upper =50; volatile float inlet_water_lower =50; volatile float outlet_water_upper =50; volatile float outlet_water_lower =50; volatile float flow_difference =50; volatile float alarm_delay =50; // 初始化显示系统 void Display_Init(void) { memset((void*)&disp_ctrl, 0, sizeof(DisplayCtrl)); disp_ctrl.line_count = 0; disp_ctrl.last_update = HAL_GetTick(); disp_ctrl.last_history_update = HAL_GetTick(); disp_ctrl.update_flag = 0; disp_ctrl.last_alarm_text[0] = '\0'; // 清空上次报警文本 disp_ctrl.last_alarm_time = 0; // 初始化所有为空字符串 for (int i = 0; i < MAX_LINES; i++) { disp_ctrl.lines[i][0] = '\0'; } disp_ctrl.latest_line[0] = '\0'; // 清空屏幕 const char* clear_cmd = "lishishuju.slt0.txt=\"\"" CMD_END; HAL_UART_Transmit(&TJC_UART, (uint8_t*)clear_cmd, strlen(clear_cmd), 100); // 初始化报警状态 memset(&temp_alarm, 0, sizeof(temp_alarm)); disp_ctrl.update_flag = 1; } // 检查参数是否有效 uint8_t IsParamValid(float value) { // 温度有效范围:-20℃ 到 150℃ if(value < -20.0f || value > 150.0f) { return 0; } return 1; } // 检查多个参数是否有效 uint8_t AreParamsValid(void) { return IsParamValid(outlet_water_temperature) && IsParamValid(inlet_water_upper) && IsParamValid(inlet_water_lower) && IsParamValid(outlet_water_upper) && IsParamValid(outlet_water_lower); } // 安全字符串操作函数 void safe_strcpy(volatile char *dest, const char *src) { char tmp[LINE_BUF_SIZE]; strncpy(tmp, src, LINE_BUF_SIZE - 1); tmp[LINE_BUF_SIZE - 1] = '\0'; for(int i = 0; i < LINE_BUF_SIZE && tmp[i] != '\0'; i++) { dest[i] = tmp[i]; } dest[LINE_BUF_SIZE - 1] = '\0'; } void safe_strcat(volatile char *dest, const char *src) { char tmp[LINE_BUF_SIZE]; int i = 0; // 复制源到临时缓冲区 while(i < LINE_BUF_SIZE - 1 && src[i] != '\0') { tmp[i] = src[i]; i++; } tmp[i] = '\0'; // 找到目标字符串结束位置 i = 0; while(i < LINE_BUF_SIZE && dest[i] != '\0') i++; // 追加内容 int j = 0; while(i < LINE_BUF_SIZE - 1 && tmp[j] != '\0') { dest[i++] = tmp[j++]; } dest[LINE_BUF_SIZE - 1] = '\0'; } size_t safe_strlen(volatile const char *s) { size_t len = 0; while(len < LINE_BUF_SIZE && s[len] != '\0') len++; return len; } // 安全添加新 void SafeAddNewLine(const char *newText,float current_value, float limit_value,AlarmState* state) { char alarm_buf[LINE_BUF_SIZE]; uint32_t now = HAL_GetTick(); // 在系统稳定前不记录报警 if(!sys_state.system_stable) { return; } snprintf(alarm_buf, sizeof(alarm_buf), "%d-%d-%d-%d:%d:%d-%s %0.1f℃ > %0.1f℃", param_values[7], param_values[8], param_values[9], param_values[10],param_values[11], param_values[12],newText,current_value,limit_value); // 检查是否需要添加新 int add_new_line = 0; if (!state->active) { // 新报警激活 add_new_line = 1; state->active = 1; state->recorded = 0; // 重置记录标志 } else if (strcmp(alarm_buf, state->display_text) != 0) { // 报警内容变化 add_new_line = 1; state->recorded = 1; // 标记已记录 } else if ((now - state->last_display) > 5000) { // 5秒更新一次显示值 state->last_display = now; } else { // 内容相同且在5秒内,只更新显示不添加新 strncpy(state->display_text, alarm_buf, sizeof(state->display_text)); disp_ctrl.update_flag = 1; return; } // 保存当前报警文本 strncpy(state->display_text, alarm_buf, sizeof(state->display_text)); // 更新最新一(只显示当前活动报警) if(add_new_line) { // 缓冲区满时删除最旧 if (disp_ctrl.line_count >= MAX_LINES) { for (int i = MAX_LINES - 1; i > 0; i--) { safe_strcpy((char*)disp_ctrl.lines[i], (const char*)disp_ctrl.lines[i-1]); } } else { // 下移所有 for (int i = disp_ctrl.line_count; i > 0; i--) { safe_strcpy((char*)disp_ctrl.lines[i], (const char*)disp_ctrl.lines[i-1]); } disp_ctrl.line_count++; } // 添加新到顶部 safe_strcpy((char*)disp_ctrl.lines[0], alarm_buf); // 标记历史记录内容已变化 disp_ctrl.history_changed = 1; } // 更新最新一 safe_strcpy((char*)disp_ctrl.latest_line, alarm_buf); // strncpy((char*)disp_ctrl.latest_line, alarm_buf, LINE_BUF_SIZE); // disp_ctrl.latest_line[LINE_BUF_SIZE-1] = '\0'; // 强制终止 // 标记需要更新显示 disp_ctrl.update_flag = 1; state->last_trigger = now; state->last_display = now; } // 安全更新显示 void SafeUpdateDisplay(void) { uint32_t now = HAL_GetTick(); // // // 检查更新间隔 // if (now - disp_ctrl.last_update < DISP_UPDATE_INTERVAL) { // return; // } // // // 避开参数读取关键期 // if (com_ctrl.retry_count != 0 || (now - com_ctrl.last_send_time) < 50) { // return; // } // 1. 更新滚动文本显示 if(disp_ctrl.update_flag ) { static char g0_cmd[CMD_BUF_SIZE]; static char display_text[LINE_BUF_SIZE] ={0}; // 检查是否有激活的报警 if (temp_alarm.active) { strncpy(display_text, temp_alarm.display_text, sizeof(display_text)); display_text[sizeof(display_text)-1] = '\0'; // 确保以null结尾 } else if (disp_ctrl.latest_line[0] != '\0') { // 2. 非报警状态的最新信息 strncpy(display_text, (const char*)disp_ctrl.latest_line, sizeof(display_text)-1); } // 显示空 else { // 无活动报警时清空 display_text[0] = '\0'; } // 清理非法字符(保留中文字符) for(char *p = display_text; *p; p++) { if((uint8_t)*p < 32) { *p = ' '; // 只替换控制字符 } } // 确保字符串以null结尾 display_text[sizeof(display_text)-1] = '\0'; snprintf(g0_cmd, sizeof(g0_cmd), "main.g0.txt=\"%s\"" CMD_END, display_text); if(HAL_UART_Transmit(&TJC_UART, (uint8_t*)g0_cmd, strlen(g0_cmd), 100) == HAL_OK) { disp_ctrl.update_flag = 0; } } // 2. 更新历史记录 if(disp_ctrl.history_changed) { // 清空历史记录控件 // const char* clear_cmd = "lishishuju.slt0.txt=\"\"" CMD_END; // HAL_UART_Transmit(&TJC_UART, (uint8_t*)clear_cmd, strlen(clear_cmd), 100); // HAL_Delay(50); // 等待清空完成 for(int i = 0;i<disp_ctrl.line_count ; i++) { // 跳过空 if(disp_ctrl.lines[i][0] == '\0') continue; char clean_line[LINE_BUF_SIZE]; strncpy(clean_line, (const char*)disp_ctrl.lines[i], sizeof(clean_line)-1); clean_line[sizeof(clean_line)-1] = '\0'; // 确保以null结尾 // 清理非法字符 for(char *p = clean_line; *p; p++) { if((uint8_t)*p < 32) { *p = ' '; } } char line_cmd[256]; // 第一使用 ="" 语法,后续使用 +="" if(i == disp_ctrl.line_count-1) { snprintf(line_cmd, sizeof(line_cmd), "lishishuju.slt0.txt=\"%s\\r\"" CMD_END, clean_line); } else { snprintf(line_cmd, sizeof(line_cmd), "lishishuju.slt0.txt+=\"%s\\r\"" CMD_END, clean_line); } // 发送命令 HAL_UART_Transmit(&TJC_UART, (uint8_t*)line_cmd, strlen(line_cmd), 100); HAL_Delay(10); // 间延时 } disp_ctrl.history_updated = 1; disp_ctrl.history_changed = 0; // 清除变化标志 } } void alarm_tip(void) { if(!IsSystemStable() || !AreParamsValid()) { return; // 系统不稳定或参数无效,跳过报警检测 } uint16_t hex = 100; outlet_water_temperature = param_values[4]/hex; inlet_water_upper = param_values[0]/hex; inlet_water_lower = param_values[1]/hex; outlet_water_upper = param_values[2]/hex; outlet_water_lower = param_values[3]/hex; flow_difference = param_values[5]/hex; alarm_delay = param_values[6]/hex; static uint32_t last_temp_alarm_time = 0; uint32_t now = HAL_GetTick(); // 特别处理:避免"30℃>0℃"误报警 if(outlet_water_temperature < 1.0f) { return; // 跳过本次检测 } // 温度报警检测 if(temp1 > outlet_water_temperature) { // if(!temp_alarm.active) { // 首次检测到报警条件 if(temp_alarm.condition_start == 0) { temp_alarm.condition_start = now; } else if(now - temp_alarm.condition_start > alarm_delay) { SafeAddNewLine("出水温度超过上限", temp1, outlet_water_temperature, &temp_alarm); HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET); temp_alarm.active = 1; } // } } else { // 报警条件不再满足 temp_alarm.condition_start = 0; // if(temp_alarm.active) { temp_alarm.active = 0; HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET); temp_alarm.display_text[0] = '\0'; // 清空报警文本 // 添加以下代码:清除滚动文本 disp_ctrl.latest_line[0] = '\0'; // 清空最新 disp_ctrl.update_flag = 1; // 触发显示更新 // } } } 以上程序可以在报警时只显示,但每次报警就只显示第一,我想把之前的数据也显示在屏幕上,即当我第一次报警时,显示在最上面,报警结束后,当遇到第二次报警后,该显示在第二上,第一为第二次报警的信息,我该如何修改这端程序
08-08
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值