#include "main.h"
/*----------------------------------------------------------------------------------------------------------*/
// 添加全局变量
ConfigData g_config;
uint8_t x_left_running = 0; //手动控制变量
uint8_t x_right_running = 0; //手动控制变量
uint8_t z_up_running = 0; //手动控制变量
uint8_t z_down_running = 0; //手动控制变量
uint8_t levelState; // 液面传感器状态(0:正常 1:异常)
// 静态变量保存历史值,用于判断是否变化(仅初始化一次)
static int32_t last_temp = 0; // 初始化为极小值,确保首次能触发更新
static int32_t last_temp2 = 0; // 初始化为极小值,确保首次能触发更新
static uint8_t last_level = 0; // 初始化为极大值,确保首次能触发更新
/*----------------------------------------------------------------------------------------------------------*/
// 初始化SD卡文件
FIL step_file;
FRESULT fr;
FIL log_file;
FIL config_file;
/*----------------------------------------------------------------------------------------------------------*/
extern volatile uint8_t x_right_limit_triggered;
extern volatile uint8_t z_up_limit_triggered;
/*----------------------------------------------------------------------------------------------------------*/
// 全局变量:记录当前状态、延时开始时间、目标延时
StainState g_stain_state = STAIN_IDLE; // 当前染色状态
uint32_t g_delay_start_tick = 0; // 延时开始的时间戳(毫秒)
uint32_t g_current_delay_s = 0; // 当前步骤的目标延时时长(毫秒)
/*----------------------------------------------------------------------------------------------------------*/
// 从SD卡读取配置参数(扩展支持新参数)
uint8_t read_config_from_sd(ConfigData *config) {
FIL config_file;
FRESULT fr;
char line[4096];
fr = f_open(&config_file, "0:config.txt", FA_READ);
delay_ms(5);
if (fr != FR_OK) {
printf("config2.t0.txt=\"配置文件打开失败\"\xff\xff\xff");
config->x_pos1 = 160000;
config->x_pos2 = 510000;
config->x_pos3 = 960000;
config->x_pos4 = 1370000;
config->x_pos5 = 1750000;
config->x_pos6 = 2080000;
config->x_pos7 = 2400000;
config->x_pos8 = 2710000;
config->x_pos9 = 3020000;
config->x_pos10 = 80000;
config->x_offset = 0;
config->z_soak = 230000;
config->z_lift = 480000;
config->z_lift1 = 0;
config->t_fix = 60; // 30min
config->t_rinse = 10; // 30s
config->t_acid = 60; // 30min
config->t_stain = 60; // 45min
config->t_dehy1 = 60; // 10min
config->t_dehy2 = 60;
config->t_dehy3 = 60;
config->t_dehy4 = 60;
config->t_dry = 10; // 20min
write_config_to_sd(config);
return 1;
}
delay_ms(5);
while (f_gets(line, sizeof(line), &config_file)) {
if (strstr(line, "X_POS1:")) sscanf(line, "X_POS1:%ld", &config->x_pos1);
else if (strstr(line, "X_POS2:")) sscanf(line, "X_POS2:%ld", &config->x_pos2);
else if (strstr(line, "X_POS3:")) sscanf(line, "X_POS3:%ld", &config->x_pos3);
else if (strstr(line, "X_POS4:")) sscanf(line, "X_POS4:%ld", &config->x_pos4);
else if (strstr(line, "X_POS5:")) sscanf(line, "X_POS5:%ld", &config->x_pos5);
else if (strstr(line, "X_POS6:")) sscanf(line, "X_POS6:%ld", &config->x_pos6);
else if (strstr(line, "X_POS7:")) sscanf(line, "X_POS7:%ld", &config->x_pos7);
else if (strstr(line, "X_POS8:")) sscanf(line, "X_POS8:%ld", &config->x_pos8);
else if (strstr(line, "X_POS9:")) sscanf(line, "X_POS9:%ld", &config->x_pos9);
else if (strstr(line, "X_POS10:")) sscanf(line, "X_POS10:%ld", &config->x_pos10);
else if (strstr(line, "X_OFFSET:")) sscanf(line, "X_OFFSET:%ld", &config->x_offset);
else if (strstr(line, "Z_SOAK:")) sscanf(line, "Z_SOAK:%ld", &config->z_soak);
else if (strstr(line, "Z_LIFT:")) sscanf(line, "Z_LIFT:%ld", &config->z_lift);
else if (strstr(line, "Z_LIFT1:")) sscanf(line, "Z_LIFT1:%ld", &config->z_lift1);
else if (strstr(line, "T_FIX:")) sscanf(line, "T_FIX:%lu", &config->t_fix);
else if (strstr(line, "T_RINSE:")) sscanf(line, "T_RINSE:%lu", &config->t_rinse);
else if (strstr(line, "T_ACID:")) sscanf(line, "T_ACID:%lu", &config->t_acid);
else if (strstr(line, "T_STAIN:")) sscanf(line, "T_STAIN:%lu", &config->t_stain);
else if (strstr(line, "T_DEHY1:")) sscanf(line, "T_DEHY1:%lu", &config->t_dehy1);
else if (strstr(line, "T_DEHY2:")) sscanf(line, "T_DEHY2:%lu", &config->t_dehy2);
else if (strstr(line, "T_DEHY3:")) sscanf(line, "T_DEHY3:%lu", &config->t_dehy3);
else if (strstr(line, "T_DEHY4:")) sscanf(line, "T_DEHY4:%lu", &config->t_dehy4);
else if (strstr(line, "T_DRY:")) sscanf(line, "T_DRY:%lu", &config->t_dry);
}
f_close(&config_file);
return 0;
}
/*----------------------------------------------------------------------------------------------------------*/
// 写入配置参数到SD卡
void write_config_to_sd(ConfigData *config) {
FIL config_file;
FRESULT fr;
UINT bw;
char line[2048];
fr = f_open(&config_file, "0:config.txt", FA_WRITE | FA_CREATE_ALWAYS);
if (fr != FR_OK) {
printf("config2.b3.txt=\"配置文件打开失败\"\xff\xff\xff");
return;
}else if(fr == FR_OK) {
f_lseek(&config_file, 0); // 移至文件开头,准备覆盖写入
}
sprintf(line, "X_POS1:%ld\r\n", config->x_pos1); f_write(&config_file, line, strlen(line), &bw);
sprintf(line, "X_POS2:%ld\r\n", config->x_pos2); f_write(&config_file, line, strlen(line), &bw);
sprintf(line, "X_POS3:%ld\r\n", config->x_pos3); f_write(&config_file, line, strlen(line), &bw);
sprintf(line, "X_POS4:%ld\r\n", config->x_pos4); f_write(&config_file, line, strlen(line), &bw);
sprintf(line, "X_POS5:%ld\r\n", config->x_pos5); f_write(&config_file, line, strlen(line), &bw);
sprintf(line, "X_POS6:%ld\r\n", config->x_pos6); f_write(&config_file, line, strlen(line), &bw);
sprintf(line, "X_POS7:%ld\r\n", config->x_pos7); f_write(&config_file, line, strlen(line), &bw);
sprintf(line, "X_POS8:%ld\r\n", config->x_pos8); f_write(&config_file, line, strlen(line), &bw);
sprintf(line, "X_POS9:%ld\r\n", config->x_pos9); f_write(&config_file, line, strlen(line), &bw);
sprintf(line, "X_POS10:%ld\r\n", config->x_pos10); f_write(&config_file, line, strlen(line), &bw);
sprintf(line, "X_OFFSET:%ld\r\n", config->x_offset); f_write(&config_file, line, strlen(line), &bw);
sprintf(line, "Z_SOAK:%ld\r\n", config->z_soak); f_write(&config_file, line, strlen(line), &bw);
sprintf(line, "Z_LIFT:%ld\r\n", config->z_lift); f_write(&config_file, line, strlen(line), &bw);
sprintf(line, "Z_LIFT1:%ld\r\n", config->z_lift1); f_write(&config_file, line, strlen(line), &bw);
sprintf(line, "T_FIX:%lu\r\n", config->t_fix); f_write(&config_file, line, strlen(line), &bw);
sprintf(line, "T_RINSE:%lu\r\n", config->t_rinse); f_write(&config_file, line, strlen(line), &bw);
sprintf(line, "T_ACID:%lu\r\n", config->t_acid); f_write(&config_file, line, strlen(line), &bw);
sprintf(line, "T_STAIN:%lu\r\n", config->t_stain); f_write(&config_file, line, strlen(line), &bw);
sprintf(line, "T_DEHY1:%lu\r\n", config->t_dehy1); f_write(&config_file, line, strlen(line), &bw);
sprintf(line, "T_DEHY2:%lu\r\n", config->t_dehy2); f_write(&config_file, line, strlen(line), &bw);
sprintf(line, "T_DEHY3:%lu\r\n", config->t_dehy3); f_write(&config_file, line, strlen(line), &bw);
sprintf(line, "T_DEHY4:%lu\r\n", config->t_dehy4); f_write(&config_file, line, strlen(line), &bw);
sprintf(line, "T_DRY:%lu\r\n", config->t_dry); f_write(&config_file, line, strlen(line), &bw);
f_sync(&config_file);
f_close(&config_file);
delay_ms(10);
printf("config2.b3.txt=\"配置成功\"\xff\xff\xff");
printf("config2.tm1.en=1\xff\xff\xff");
USART_ClearBuffer();
}
void write_log(int32_t x, int32_t z) {
FRESULT fr;
UINT bw;
char log_line[512];
char time_str[64]; // 存储时间字符串 "YYYY-MM-DD HH:MM:SS"
// 1. 通过RTC获取当前时间
RTC_Get();
// 2. 格式化时间字符串
sprintf(time_str, "%04d-%02d-%02d %02d:%02d:%02d",
calendar.w_year,
calendar.w_month,
calendar.w_date,
calendar.hour,
calendar.min,
calendar.sec);
// 3. 打开日志文件(追加模式)
fr = f_open(&log_file, "0:log.txt", FA_WRITE | FA_OPEN_ALWAYS);
if (fr != FR_OK) {
OLED_ShowString(1, 1, "Log Open Err");
printf("config3.t0.txt=\"追踪文件打开失败\"\xff\xff\xff");
printf("config3.tm3.en=1\xff\xff\xff");
return;
}
// 4. 移动到文件末尾(准备追加内容)
f_lseek(&log_file, f_size(&log_file));
// 5. 格式化日志内容(末尾仅添加一次 \r\n 换行)
sprintf(log_line, "[%s] X_位置:%ld\r, Z_位置:%ld\r\n", time_str,x,z); // 关键修改
// 6. 写入文件并同步
f_write(&log_file, log_line, strlen(log_line), &bw);
f_sync(&log_file); // 确保数据写入SD卡
f_close(&log_file);
}
/*----------------------------------------------------------------------------------------------------------*/
//查看配置参数
void usmart_view_config(void) {
FIL file;
FRESULT fr;
char buffer[2048]; // 缓冲区,根据配置文件可能的大小调整
UINT br;
DWORD pos = 0;
// 打开文件
fr = f_open(&file, "0:config.txt", FA_READ);
if (fr != FR_OK) {
printf("config2.va1.txt=\"Open config.txt failed! Error: %d\r\n\"\xff\xff\xff", fr);
USART_ClearBuffer();
return;
}
// 确定读取位置(配置文件通常需全量显示,从开头读取)
pos = 0;
f_lseek(&file, pos);
// 读取文件内容到缓冲区(最多读取缓冲区大小)
f_read(&file, buffer, sizeof(buffer) - 1, &br); // 留1字节给结束符
buffer[br] = '\0'; // 添加字符串结束符
// 打印配置文件内容
printf("config2.va1.txt=\"设备配置参数:\r\n%s\r\n\"\xff\xff\xff", buffer);
delay_ms(5);
// 关闭文件
f_close(&file);
USART_ClearBuffer();
}
// 参数: 配置项名称(字符串)、新值(整数)
void setParam(const char* param_name, int32_t value) {
if (strcmp(param_name, "T_FIX") == 0) g_config.t_fix = value;
else if (strcmp(param_name, "T_RINSE") == 0) g_config.t_rinse = value;
else if (strcmp(param_name, "T_ACID") == 0) g_config.t_acid = value;
else if (strcmp(param_name, "T_STAIN") == 0) g_config.t_stain = value;
else if (strcmp(param_name, "T_DEHY1") == 0) g_config.t_dehy1 = value;
else if (strcmp(param_name, "T_DEHY2") == 0) g_config.t_dehy2 = value;
else if (strcmp(param_name, "T_DEHY3") == 0) g_config.t_dehy3 = value;
else if (strcmp(param_name, "T_DEHY4") == 0) g_config.t_dehy4 = value;
else if (strcmp(param_name, "T_DRY") == 0) g_config.t_dry = value;
else if (strcmp(param_name, "X_POS1") == 0) g_config.x_pos1 = value;
else if (strcmp(param_name, "X_POS2") == 0) g_config.x_pos2 = value;
else if (strcmp(param_name, "X_POS3") == 0) g_config.x_pos3 = value;
else if (strcmp(param_name, "X_POS4") == 0) g_config.x_pos4 = value;
else if (strcmp(param_name, "X_POS5") == 0) g_config.x_pos5 = value;
else if (strcmp(param_name, "X_POS6") == 0) g_config.x_pos6 = value;
else if (strcmp(param_name, "X_POS7") == 0) g_config.x_pos7 = value;
else if (strcmp(param_name, "X_POS8") == 0) g_config.x_pos8 = value;
else if (strcmp(param_name, "X_POS9") == 0) g_config.x_pos9 = value;
else if (strcmp(param_name, "X_POS10") == 0) g_config.x_pos10 = value;
else if (strcmp(param_name, "Z_LIFT") == 0) g_config.z_lift = value;
else if (strcmp(param_name, "Z_LIFT1") == 0) g_config.z_lift1 = value;
else if (strcmp(param_name, "Z_SOAK") == 0) g_config.z_soak = value;
else if (strcmp(param_name, "X_OFFSET") == 0)
{
delay_ms(10);
g_config.x_offset = value;
g_config.x_pos2 = g_config.x_pos2+value;
g_config.x_pos3 = g_config.x_pos3+value;
g_config.x_pos4 = g_config.x_pos4+value;
g_config.x_pos5 = g_config.x_pos5+value;
g_config.x_pos6 = g_config.x_pos6+value;
g_config.x_pos7 = g_config.x_pos7+value;
g_config.x_pos8 = g_config.x_pos8+value;
g_config.x_pos9 = g_config.x_pos9+value;
g_config.x_pos10 = g_config.x_pos10+value;
delay_ms(10);
}
// 其他参数...
else {
printf("config2.t0.txt=\"请检查参数,输入无效\"\xff\xff\xff");
USART_ClearBuffer();
return;
}
write_config_to_sd(&g_config);
}
//////查看log文件后10行
void usmart_view_log(void) {
FIL file;
FRESULT fr;
char buffer[2048];
UINT br;
DWORD file_size, pos;
int line_count = 0;
fr = f_open(&file, "0:log.txt", FA_READ);
if (fr != FR_OK) {
printf("config3.va0.txt=\"Open log.txt failed! Error: %d\r\n\"\xff\xff\xff", fr);
USART_ClearBuffer();
return;
}
file_size = f_size(&file);
// 从文件末尾向前查找10行
pos = file_size < sizeof(buffer) ? 0 : file_size - sizeof(buffer);
f_lseek(&file, pos);
f_read(&file, buffer, sizeof(buffer), &br);
buffer[br] = '\0';
// 从后往前统计行数
for (int i = br - 1; i >= 0; i--) {
if (buffer[i] == '\n') {
line_count++;
if (line_count >= 30) {
pos = i + 1;
break;
}
}
}
// 打印找到的内容
if (line_count < 20) pos = 0; // 如果不足10行则从头开始
printf("config3.va0.txt=\"\r\n%s\r\n\"\xff\xff\xff",buffer + pos);
USART_ClearBuffer();
f_close(&file);
}
//删除log文件
void delete_log(void)
{
delay_ms(50);
u8 ret = mf_unlink("log.txt");
if (ret == FR_OK) {
printf("config3.t0.txt=\"日志删除成功\r\n日志删除成功\r\n\"\xff\xff\xff");
} else {
printf("config3.t0.txt=\"日志删除失败\r\n日志删除失败\r\n\"\xff\xff\xff");
}
}
/*----------------------------------------------------------------------------------------------------------*/
void moveX(int32_t steps)
{
moveAxisCommon(AXIS_X,steps);
}
void moveZ(int32_t steps)
{
moveAxisCommon(AXIS_Z,steps);
}
/*----------------------------------------------------------------------------------------------------------*/
// 移动到指定染缸(1-9)
void moveToTank(uint8_t tank_num) {
if (tank_num < 1 || tank_num > 9) {
OLED_ShowString(4,1,"Invalid Tank");
return;
}
// 获取目标缸X坐标
int32_t target_x = 0;
switch(tank_num) {
case 1: target_x = g_config.x_pos1; break;
case 2: target_x = g_config.x_pos2; break;
case 3: target_x = g_config.x_pos3; break;
case 4: target_x = g_config.x_pos4; break;
case 5: target_x = g_config.x_pos5; break;
case 6: target_x = g_config.x_pos6; break;
case 7: target_x = g_config.x_pos7; break;
case 8: target_x = g_config.x_pos8; break;
case 9: target_x = g_config.x_pos9; break;
}
// X轴移动到目标位置
int32_t x_steps = target_x - x_current_position;
delay_ms(10);
moveAxisCommon(AXIS_X, x_steps);//1
// Z轴下降()
moveAxisCommon(AXIS_Z, g_config.z_lift);//2
}
/*----------------------------------------------------------------------------------------------------------*/
// 染色流程状态机处理函数(在主循环中调用,非阻塞)
void process_auto_stain(void) {
if (g_stain_state == STAIN_IDLE) return; // 空闲状态不处理
get_sys_time_s();
uint32_t elapsed_ms = sys_time_s - g_delay_start_tick; // 已过去的时间
switch (g_stain_state) {
// -------------------------- 步骤1:等待放入染架 --------------------------
case STAIN_STEP1_WAIT_LOAD_INIT:
printf("move.t0.txt=\"请放入染架到固定缸\"\xff\xff\xff");
g_delay_start_tick = sys_time_s; // 记录开始时间
g_current_delay_s = 3; // 等待
g_stain_state = STAIN_STEP1_WAIT_LOAD_DELAY; // 进入延时状态
break;
case STAIN_STEP1_WAIT_LOAD_DELAY:
if (elapsed_ms >= g_current_delay_s) {
// 等待结束,进入固定缸初始化
g_stain_state = STAIN_STEP1_FIX_INIT;
}
break;
// -------------------------- 步骤1:固定缸(1#) --------------------------
case STAIN_STEP1_FIX_INIT:
printf("move.t2.bco=1024\xff\xff\xff");
g_delay_start_tick = sys_time_s; // 记录开始时间
g_current_delay_s = g_config.t_fix; // 目标延时(用户配置)
g_stain_state = STAIN_STEP1_FIX_DELAY; // 进入延时状态
printf("move.t0.txt=\"固定剩余时间:\"\xff\xff\xff");
printf("move.tm1.en=1\xff\xff\xff");
printf("move.t25.aph=127\xff\xff\xff");
printf("move.t26.aph=127\xff\xff\xff");
break;
case STAIN_STEP1_FIX_DELAY:
if (elapsed_ms >= g_current_delay_s) {
printf("move.t25.txt=\"0\"\xff\xff\xff");
printf("move.tm1.en=0\xff\xff\xff");
printf("move.t25.aph=0\xff\xff\xff");
printf("move.t26.aph=0\xff\xff\xff");
g_stain_state = STAIN_STEP1_FIX_DONE;
}
break;
case STAIN_STEP1_FIX_DONE:
// 执行移动操作(非阻塞,假设moveAxisCommon内部已处理等待)
printf("move.t0.txt=\"移动到冲洗缸\"\xff\xff\xff");
moveAxisCommon(AXIS_X, g_config.x_pos1);
moveAxisCommon(AXIS_Z, g_config.z_lift);
Xmove_right2(); //右移小距离,抓住染架
Zmove_up();
g_stain_state = STAIN_STEP2_RINSE_INIT; // 进入下一步
break;
// -------------------------- 步骤2:冲洗缸(4#) --------------------------
case STAIN_STEP2_RINSE_INIT:
printf("move.t8.bco=1024\xff\xff\xff");
moveToTank(4); // 移动到冲洗缸
up_down(); // 执行上下动作
g_delay_start_tick = sys_time_s; //这里不是current_tick,是因为运动会阻塞函数,无法运行 uint32_t current_tick = sys_time_s;获取当前时间
g_current_delay_s = g_config.t_rinse; // 冲洗延时
g_stain_state = STAIN_STEP2_RINSE_DELAY;
printf("move.t0.txt=\"冲洗剩余时间:\"\xff\xff\xff");
printf("move.t25.aph=127\xff\xff\xff");
printf("move.t26.aph=127\xff\xff\xff");
printf("move.tm2.en=1\xff\xff\xff");
break;
case STAIN_STEP2_RINSE_DELAY:
if (elapsed_ms >= g_current_delay_s) {
printf("move.t25.txt=\"0\"\xff\xff\xff");
printf("move.tm2.en=0\xff\xff\xff");
printf("move.t25.aph=0\xff\xff\xff");
printf("move.t26.aph=0\xff\xff\xff");
g_stain_state = STAIN_STEP2_RINSE_DONE;
}
break;
case STAIN_STEP2_RINSE_DONE:
printf("move.t0.txt=\"移动到酸化缸\"\xff\xff\xff");
Zmove_up();
g_stain_state = STAIN_STEP3_ACID_INIT; // 进入酸化缸
break;
// -------------------------- 步骤3:酸化缸(2#) --------------------------
case STAIN_STEP3_ACID_INIT:
printf("move.t4.bco=1024\xff\xff\xff");
moveToTank(2); // 移动到酸化缸
g_delay_start_tick = sys_time_s;
g_current_delay_s = g_config.t_acid; // 酸化延时
g_stain_state = STAIN_STEP3_ACID_DELAY;
printf("move.t0.txt=\"酸化剩余时间:\"\xff\xff\xff");
printf("move.t25.aph=127\xff\xff\xff");
printf("move.t26.aph=127\xff\xff\xff");
printf("move.tm3.en=1\xff\xff\xff");
break;
case STAIN_STEP3_ACID_DELAY:
if (elapsed_ms >= g_current_delay_s) {
printf("move.t25.txt=\"0\"\xff\xff\xff");
printf("move.t25.aph=0\xff\xff\xff");
printf("move.t26.aph=0\xff\xff\xff");
printf("move.tm3.en=0\xff\xff\xff");
g_stain_state = STAIN_STEP3_ACID_DONE;
}
break;
case STAIN_STEP3_ACID_DONE:
printf("move.t0.txt=\"移动到冲洗缸\"\xff\xff\xff");
Zmove_up();
g_stain_state = STAIN_STEP4_RINSE_INIT; // 进入冲洗缸
break;
// -------------------------- 步骤4:冲洗缸(4#) --------------------------
case STAIN_STEP4_RINSE_INIT:
printf("move.t8.bco=1024\xff\xff\xff");
moveToTank(4); // 移动到冲洗缸
up_down();
g_delay_start_tick = sys_time_s;
g_current_delay_s = g_config.t_rinse; // 冲洗延时
g_stain_state = STAIN_STEP4_RINSE_DELAY;
printf("move.t0.txt=\"冲洗剩余时间:\"\xff\xff\xff");
printf("move.t25.aph=127\xff\xff\xff");
printf("move.t26.aph=127\xff\xff\xff");
printf("move.va3.val=%d\xff\xff\xff",g_config.t_rinse);
printf("move.tm2.en=1\xff\xff\xff");
break;
case STAIN_STEP4_RINSE_DELAY:
if (elapsed_ms >= g_current_delay_s) {
printf("move.t25.txt=\"0\"\xff\xff\xff");
printf("move.tm2.en=0\xff\xff\xff");
printf("move.t25.aph=0\xff\xff\xff");
printf("move.t26.aph=0\xff\xff\xff");
g_stain_state = STAIN_STEP4_RINSE_DONE;
}
break;
case STAIN_STEP4_RINSE_DONE:
printf("move.t0.txt=\"移动到染色缸\"\xff\xff\xff");
Zmove_up();
g_stain_state = STAIN_STEP5_STAIN_INIT; // 进入染色缸
break;
// -------------------------- 步骤5:染色缸(3#) --------------------------
case STAIN_STEP5_STAIN_INIT:
printf("move.t6.bco=1024\xff\xff\xff");
moveToTank(3); // 移动到染色缸
g_delay_start_tick = sys_time_s;
g_current_delay_s = g_config.t_stain; // 染色延时
g_stain_state = STAIN_STEP5_STAIN_DELAY;
printf("move.t0.txt=\"染色剩余时间:\"\xff\xff\xff");
printf("move.t25.aph=127\xff\xff\xff");
printf("move.t26.aph=127\xff\xff\xff");
printf("move.tm4.en=1\xff\xff\xff");
break;
case STAIN_STEP5_STAIN_DELAY:
if (elapsed_ms >= g_current_delay_s) {
printf("move.t25.txt=\"0\"\xff\xff\xff");
printf("move.tm4.en=0\xff\xff\xff");
printf("move.t25.aph=0\xff\xff\xff");
printf("move.t26.aph=0\xff\xff\xff");
g_stain_state = STAIN_STEP5_STAIN_DONE;
}
break;
case STAIN_STEP5_STAIN_DONE:
printf("move.t0.txt=\"移动到冲洗缸\"\xff\xff\xff");
Zmove_up();
g_stain_state = STAIN_STEP6_RINSE_INIT; // 进入冲洗缸
break;
// -------------------------- 步骤6:冲洗缸(4#) --------------------------
case STAIN_STEP6_RINSE_INIT:
printf("move.t8.bco=1024\xff\xff\xff");
moveToTank(4); // 移动到冲洗缸
up_down();
g_delay_start_tick = sys_time_s;
g_current_delay_s = g_config.t_rinse; // 冲洗延时
g_stain_state = STAIN_STEP6_RINSE_DELAY;
printf("move.va3.val=%d\xff\xff\xff",g_config.t_rinse);
printf("move.t0.txt=\"冲洗剩余时间:\"\xff\xff\xff");
printf("move.t25.aph=127\xff\xff\xff");
printf("move.t26.aph=127\xff\xff\xff");
printf("move.tm2.en=1\xff\xff\xff");
break;
case STAIN_STEP6_RINSE_DELAY:
if (elapsed_ms >= g_current_delay_s) {
printf("move.t25.txt=\"0\"\xff\xff\xff");
printf("move.tm2.en=0\xff\xff\xff");
printf("move.t25.aph=0\xff\xff\xff");
printf("move.t26.aph=0\xff\xff\xff");
g_stain_state = STAIN_STEP6_RINSE_DONE;
}
break;
case STAIN_STEP6_RINSE_DONE:
printf("move.t0.txt=\"移动到梯度脱水1缸\"\xff\xff\xff");
Zmove_up();
g_stain_state = STAIN_STEP7_DEHY1_INIT; // 进入脱水1
break;
// -------------------------- 步骤7:梯度脱水1(5#) --------------------------
case STAIN_STEP7_DEHY1_INIT:
printf("move.t10.bco=1024\xff\xff\xff");
moveToTank(5); // 移动到脱水1缸
g_delay_start_tick = sys_time_s;
g_current_delay_s = g_config.t_dehy1; // 脱水1延时
g_stain_state = STAIN_STEP7_DEHY1_DELAY;
printf("move.t0.txt=\"梯度脱水1剩余时间:\"\xff\xff\xff");
printf("move.t25.aph=127\xff\xff\xff");
printf("move.t26.aph=127\xff\xff\xff");
printf("move.tm5.en=1\xff\xff\xff");
break;
case STAIN_STEP7_DEHY1_DELAY:
if (elapsed_ms >= g_current_delay_s) {
printf("move.t25.txt=\"0\"\xff\xff\xff");
printf("move.tm5.en=0\xff\xff\xff");
printf("move.t25.aph=0\xff\xff\xff");
printf("move.t26.aph=0\xff\xff\xff");
g_stain_state = STAIN_STEP7_DEHY1_DONE;
}
break;
case STAIN_STEP7_DEHY1_DONE:
printf("move.t0.txt=\"移动到梯度脱水2缸\"\xff\xff\xff");
Zmove_up();
g_stain_state = STAIN_STEP8_DEHY2_INIT; // 进入脱水2
break;
// -------------------------- 步骤8:梯度脱水2(6#) --------------------------
case STAIN_STEP8_DEHY2_INIT:
printf("move.t12.bco=1024\xff\xff\xff");
moveToTank(6); // 移动到脱水2缸
g_delay_start_tick = sys_time_s;
g_current_delay_s = g_config.t_dehy2; // 脱水2延时
g_stain_state = STAIN_STEP8_DEHY2_DELAY;
printf("move.t0.txt=\"梯度脱水2剩余时间:\"\xff\xff\xff");
printf("move.t25.aph=127\xff\xff\xff");
printf("move.t26.aph=127\xff\xff\xff");
printf("move.tm6.en=1\xff\xff\xff");
break;
case STAIN_STEP8_DEHY2_DELAY:
if (elapsed_ms >= g_current_delay_s) {
printf("move.t25.txt=\"0\"\xff\xff\xff");
printf("move.tm6.en=0\xff\xff\xff");
printf("move.t25.aph=0\xff\xff\xff");
printf("move.t26.aph=0\xff\xff\xff");
g_stain_state = STAIN_STEP8_DEHY2_DONE;
}
break;
case STAIN_STEP8_DEHY2_DONE:
printf("move.t0.txt=\"移动到梯度脱水3缸\"\xff\xff\xff");
Zmove_up();
g_stain_state = STAIN_STEP9_DEHY3_INIT; // 进入脱水3
break;
// -------------------------- 步骤9:梯度脱水3(7#) --------------------------
case STAIN_STEP9_DEHY3_INIT:
printf("move.t14.bco=1024\xff\xff\xff");
moveToTank(7); // 移动到脱水3缸
g_delay_start_tick = sys_time_s;
g_current_delay_s = g_config.t_dehy3; // 脱水3延时
g_stain_state = STAIN_STEP9_DEHY3_DELAY;
printf("move.t0.txt=\"梯度脱水3剩余时间:\"\xff\xff\xff");
printf("move.t25.aph=127\xff\xff\xff");
printf("move.t26.aph=127\xff\xff\xff");
printf("move.tm7.en=1\xff\xff\xff");
break;
case STAIN_STEP9_DEHY3_DELAY:
if (elapsed_ms >= g_current_delay_s) {
printf("move.t25.txt=\"0\"\xff\xff\xff");
printf("move.tm7.en=0\xff\xff\xff");
printf("move.t25.aph=0\xff\xff\xff");
printf("move.t26.aph=0\xff\xff\xff");
g_stain_state = STAIN_STEP9_DEHY3_DONE;
}
break;
case STAIN_STEP9_DEHY3_DONE:
printf("move.t0.txt=\"移动到梯度脱水4缸\"\xff\xff\xff");
Zmove_up();
g_stain_state = STAIN_STEP10_DEHY4_INIT; // 进入脱水4
break;
// -------------------------- 步骤10:梯度脱水4(8#) --------------------------
case STAIN_STEP10_DEHY4_INIT:
printf("move.t16.bco=1024\xff\xff\xff");
moveToTank(8); // 移动到脱水4缸
g_delay_start_tick = sys_time_s;
g_current_delay_s = g_config.t_dehy4; // 脱水4延时
g_stain_state = STAIN_STEP10_DEHY4_DELAY;
printf("move.t0.txt=\"梯度脱水4剩余时间:\"\xff\xff\xff");
printf("move.t25.aph=127\xff\xff\xff");
printf("move.t26.aph=127\xff\xff\xff");
printf("move.tm8.en=1\xff\xff\xff");
break;
case STAIN_STEP10_DEHY4_DELAY:
if (elapsed_ms >= g_current_delay_s) {
printf("move.t25.txt=\"0\"\xff\xff\xff");
printf("move.tm8.en=0\xff\xff\xff");
printf("move.t25.aph=0\xff\xff\xff");
printf("move.t26.aph=0\xff\xff\xff");
g_stain_state = STAIN_STEP10_DEHY4_DONE;
}
break;
case STAIN_STEP10_DEHY4_DONE:
printf("move.t0.txt=\"移动到梯度晾片缸\"\xff\xff\xff");
Zmove_up();
g_stain_state = STAIN_STEP11_DRY_INIT; // 进入晾片缸
break;
// -------------------------- 步骤11:晾片缸(9#) --------------------------
case STAIN_STEP11_DRY_INIT:
printf("move.t18.bco=1024\xff\xff\xff");
printf("move.t0.txt=\"晾片\"\xff\xff\xff");
moveToTank(9); // 移动到晾片缸
printf("move.tm11.en=1\xff\xff\xff");
g_delay_start_tick = sys_time_s;
g_current_delay_s = g_config.t_dry; // 晾片延时
g_stain_state = STAIN_STEP11_DRY_DELAY;
break;
case STAIN_STEP11_DRY_DELAY:
if (elapsed_ms >= g_current_delay_s) {
printf("move.t25.txt=\"0\"\xff\xff\xff");
printf("move.tm11.en=0\xff\xff\xff");
printf("move.t25.aph=0\xff\xff\xff");
printf("move.t26.aph=0\xff\xff\xff");
g_stain_state = STAIN_STEP11_DRY_DONE;
}
break;
case STAIN_STEP11_DRY_DONE:
Xmove_left(); // 脱离晾片缸
g_stain_state = STAIN_FINISH; // 流程结束
break;
// -------------------------- 流程结束 --------------------------
case STAIN_FINISH:
printf("move.t0.txt=\"染色完成,请移走染架\"\xff\xff\xff");
g_stain_state = STAIN_IDLE; // 重置为空闲状态
break;
default:
g_stain_state = STAIN_IDLE; // 异常状态重置
break;
}
}
/*----------------------------------------------------------------------------------------------------------*/
// 优化后的X轴移动函数
void Xmove_left(void) {
delay_ms(10);
moveAxisCommon(AXIS_X,g_config.x_pos1);//最后一次移动距离,脱离晾片缸
}
void Xmove_right(void) {
delay_ms(10);
moveAxisCommon(AXIS_X,-g_config.x_pos1);
}
void Xmove_right2(void) {
delay_ms(10);
moveAxisCommon(AXIS_X,-g_config.x_pos10);//距离是需要右移或者左移抓染架的距离
}
void Xmove_left2(void) {
delay_ms(10);
moveAxisCommon(AXIS_X,g_config.x_pos10);//距离是需要右移或者左移抓染架的距离
}
// 优化后的Z轴移动函数
void Zmove_down(void) {
delay_ms(10);
moveAxisCommon(AXIS_Z,g_config.z_lift);
}
void Zmove_down_2(void) {
delay_ms(10);
moveAxisCommon(AXIS_Z,g_config.z_soak);
}
void Zmove_up(void) {
delay_ms(10);
moveAxisCommon(AXIS_Z,-g_config.z_lift);
}
void Zmove_up_2(void) {
delay_ms(10);
moveAxisCommon(AXIS_Z,-g_config.z_soak);
}
void up_down(void)
{
delay_ms(10);
Zmove_up_2();
delay_ms(100);
Zmove_down_2();
Zmove_up_2();
delay_ms(100);
Zmove_down_2();
}
/*----------------------------------------------------------------------------------------------------------*/
//一直移动函数GUI界面函数
// 处理触摸屏指令
void touch_command_process(uint8_t cmd) {
switch(cmd) {
case TOUCH_X_LEFT_PRESS:
x_left_running = 1;
x_right_running = 0;
break;
case TOUCH_X_LEFT_RELEASE:
if(x_left_running) {
motor_stop(AXIS_X);
x_left_running = 0;
}
break;
case TOUCH_X_RIGHT_PRESS:
x_right_running = 1;
x_left_running = 0;
break;
case TOUCH_X_RIGHT_RELEASE:
if(x_right_running) {
motor_stop(AXIS_X);
x_right_running = 0;
}
break;
case TOUCH_Z_UP_PRESS:
z_up_running = 1;
z_down_running = 0;
break;
case TOUCH_Z_UP_RELEASE:
if(z_up_running) {
motor_stop(AXIS_Z);
z_up_running = 0;
}
break;
case TOUCH_Z_DOWN_PRESS:
z_down_running = 1;
z_up_running = 0;
break;
case TOUCH_Z_DOWN_RELEASE:
if(z_down_running) {
motor_stop(AXIS_Z);
z_down_running = 0;
}
break;
case STAIN_STEP1_WAIT_LOAD_INIT_USART:
if (g_stain_state == STAIN_IDLE)
{
g_stain_state = STAIN_STEP1_WAIT_LOAD_INIT; // 从第一步开始
}
break;
case STAIN_IDLE_USART:
GPIO_SetBits(X_ENA_PORT, X_ENA_PIN); // 高电平禁用
GPIO_SetBits(Z_ENA_PORT, Z_ENA_PIN);
reinitialize_system();
break;
}
}
// 电机连续移动函数
void motor_continuous_move(AxisType axis, int32_t direction) {
if(axis == AXIS_X) {
if(!x_motor_running) {
// 设置一个较大的目标步数实现连续移动
moveAxisCommon(AXIS_X, direction * 10000000);
}
} else if(axis == AXIS_Z) {
if(!z_motor_running) {
moveAxisCommon(AXIS_Z, direction * 10000000);
}
}
}
// 电机停止函数
void motor_stop(AxisType axis) {
if(axis == AXIS_X) {
x_motor_running = 0;
disableMotor(AXIS_X);
} else if(axis == AXIS_Z) {
z_motor_running = 0;
disableMotor(AXIS_Z);
}
}
/*----------------------------------------------------------------------------------------------------------*/
void X_home(void)
{
Home_Motor(AXIS_X);
}
void Z_home(void)
{
Home_Motor(AXIS_Z);
}
/*----------------------------------------------------------------------------------------------------------*/
//初始化SD配置文件
void SD_config_init(void)
{
fr = f_open(&config_file, "0:config.txt", FA_READ);
if (fr == FR_OK) {
read_config_from_sd(&g_config);
delay_ms(10);
f_close(&config_file);
} else {
printf("not find config");
delay_ms(10);
}
fr = f_open(&log_file, "0:log.txt", FA_READ | FA_OPEN_ALWAYS);
f_close(&log_file);
}
/*----------------------------------------------------------------------------------------------------------*/
/**
* 读取温度状态并更新(仅在状态变化时执行操作)
*/
void prin_temp(void)
{
// 读取温度(已转为整数)
int32_t current_temp = (int32_t)(SMBus_ReadTemp());
// 仅当当前温度与历史值不同时,才执行更新(避免无效操作)
if (current_temp != last_temp)
{
if(current_temp < 150 && current_temp > -10)
{
// 调用公共函数更新显示和发送数据
printf("home.va0.val=%d\xff\xff\xff", current_temp);
OLED_ShowNum(3,4, current_temp, 2); // 显示温度(占3位,适应更大数值)
OLED_ShowString(3,6,"C");
OLED_ShowString(3,1,"T1:");
last_temp = current_temp; // 更新历史值
USART_ClearBuffer();
}
}
}
/**
* 读取温度状态并更新(仅在状态变化时执行操作)
*/
void prin_temp2(void)
{
// 读取温度(已转为整数)
int32_t current_temp2 = (int32_t)DS18B20_Get_Temp()/ 10.0f;
// 仅当当前温度与历史值不同时,才执行更新(避免无效操作)
if (current_temp2 != last_temp2)
{
if(current_temp2 < 150 && last_temp2 > -10){
// 调用公共函数更新显示和发送数据
printf("home.va1.val=%d\xff\xff\xff", current_temp2);
OLED_ShowNum(3,12, current_temp2, 2); // 显示温度(占3位,适应更大数值)
OLED_ShowString(3,14,"C");
OLED_ShowString(3,9,"T2:");
last_temp2 = current_temp2; // 更新历史值
USART_ClearBuffer();
}
}
}
/**
* 读取液位状态并更新(仅在状态变化时执行操作)
*/
void print_level(void)
{
// 读取液位状态
uint8_t current_level = LevelSensor_GetState();
if(current_level==1)//出水,模式
{
close_rinse_input();
open_rinse_output();
}
if(current_level==0)//进水,判断,水满信号位置1
{
open_rinse_input();
close_rinse_output();
}
// 仅当当前状态与历史值不同时,才执行更新
if (current_level != last_level)
{
// 调用公共函数更新显示和发送数据
printf("move.va1.val=%d\xff\xff\xff", current_level);
OLED_ShowString(1,1,"water_leve:");
OLED_ShowNum(1,14,current_level, 2); // 显示液位状态
last_level = current_level; // 更新历史值
USART_ClearBuffer();
}
}
/*----------------------------------------------------------------------------------------------------------*/
void moveAxisCommon(AxisType axis, int32_t target_steps) {
delay_ms(10);
// 启动带加速度的运动(假设此函数仅启动运动,不阻塞)
moveStepsWithAccel(axis, target_steps);
// 立即更新OLED显示(运动开始时的位置)
OLED_ShowNum(2, 9, x_current_position, 7);
OLED_ShowNum(4, 9, z_current_position, 7);
while ((axis == AXIS_X && x_motor_running) || (axis == AXIS_Z && z_motor_running)) {
delay_ms(1); // 短延迟,降低CPU占用
}
delay_ms(10); // 稳定延迟
// 5. 写日志与显示
write_log(x_current_position, z_current_position);
}
/*--------------------------------------------------------------------------------------------------------------------------------*/
// 安全清理函数:释放资源,停止外设
void safe_cleanup(void) {
// 1. 停止电机运动
motor_stop(AXIS_X);
motor_stop(AXIS_Z);
x_left_running = 0;
x_right_running = 0;
z_up_running = 0;
z_down_running = 0;
// 2. 关闭文件系统相关资源
f_close(&step_file);
f_close(&log_file);
f_close(&config_file);
f_mount(NULL, "0:", 1); // 卸载SD卡
f_mount(NULL, "1:", 1); // 卸载FLASH
// 3. 重置状态机和全局变量
g_stain_state = STAIN_IDLE;
g_delay_start_tick = 0;
g_current_delay_s = 0;
// 4. 清空OLED显示
OLED_Clear();
delay_ms(500);
}
// 重新初始化函数(复用main中的初始化逻辑)
void reinitialize_system(void) {
safe_cleanup(); // 先清理资源
// 重新执行初始化(完全复用main中的初始化步骤)
delay_init(72);
delay_ms(10);
OLED_Init();
OLED_Clear();
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
StepMotor_GPIO_Init(AXIS_X);
StepMotor_GPIO_Init(AXIS_Z);
StepMotor_TIM_Init(AXIS_X);
StepMotor_TIM_Init(AXIS_Z);
delay_ms(10);
my_mem_init(SRAMIN);
delay_ms(10);
SMBus_Init();
delay_ms(10);
LevelSensor_Init();
delay_ms(10);
DS18B20_Init();
delay_ms(10);
// 重新初始化SD卡(带重试)
while(SD_Init()) {
OLED_ShowString(2, 1, "SD Error, Retry...");
delay_ms(1000);
}
delay_ms(10);
// 重新初始化文件系统
while(exfuns_init()) {
OLED_ShowString(2, 1, "FS Error, Retry...");
delay_ms(1000);
}
f_mount(fs[0], "0:", 1);
f_mount(fs[1], "1:", 1);
delay_ms(10);
// 重新初始化串口和USMART
USART1_Init(115200);
delay_ms(10);
usmart_dev.init(72);
delay_ms(10);
// 重新初始化RTC
RTC_Init();
delay_ms(10);
// 重新加载配置
SD_config_init();
delay_ms(10);
// 重新初始化限位开关
LimitSwitch_Init();
CheckLimitSwitches();
delay_ms(10);
/*************************开机初始化将配置参数传到move页面***************************************/
printf("move.va2.val=%d\xff\xff\xff",g_config.t_fix);
printf("move.va3.val=%d\xff\xff\xff",g_config.t_rinse);
printf("move.va4.val=%d\xff\xff\xff",g_config.t_acid);
printf("move.va5.val=%d\xff\xff\xff",g_config.t_stain);
printf("move.va6.val=%d\xff\xff\xff",g_config.t_dehy1);
printf("move.va7.val=%d\xff\xff\xff",g_config.t_dehy2);
printf("move.va8.val=%d\xff\xff\xff",g_config.t_dehy3);
printf("move.va9.val=%d\xff\xff\xff",g_config.t_dehy4);
printf("move.va10.val=%d\xff\xff\xff",g_config.t_dry);
/***********************************************************************************************/
OLED_Clear();
printf("系统重新初始化完成\xFF\xFF\xFF");
delay_ms(1000);
OLED_Clear();
}
/*--------------------------------------------------------------------------------------------------------------------------------*/
int main(void)
{
int a=0; //温度循环值初始,1秒检测一次
g_stain_state = STAIN_IDLE; //初始化为空闲状态,状态机
delay_init(72);
delay_ms(1000);
OLED_Init();
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置中断优先级分组为组0
StepMotor_GPIO_Init(AXIS_X);
StepMotor_GPIO_Init(AXIS_Z);
StepMotor_TIM_Init(AXIS_X);
StepMotor_TIM_Init(AXIS_Z);
delay_ms(10);
my_mem_init(SRAMIN); //初始化内部内存池
delay_ms(10);
SMBus_Init(); // 初始化SMBus总线(用于MLX90614通信)
delay_ms(10);
LevelSensor_Init(); // 初始化液面传感器
delay_ms(10);
DS18B20_Init(); // 初始化DS18B20温度传感器
delay_ms(10);
while(SD_Init()) //检测不到SD卡,SDIO初始化
{
OLED_ShowString(1,1,"SD Card Error!");
printf("SD Card Error!");
delay_ms(100);
OLED_ShowString(1,1,"Please Check! ");
delay_ms(100);
}
delay_ms(10);
while(exfuns_init()) //FAFTS文件系统是否挂载失败
{
OLED_ShowString(1,1," exfuns_init Error!");
printf("exfuns_init Error!");
delay_ms(1000);
}
f_mount(fs[0],"0:",1); //挂载SD卡
f_mount(fs[1],"1:",1); //挂载FLASH.
/*************************初始化USMART通信********************************************************/
delay_ms(10);
USART1_Init(115200); //串口初始化为115200
delay_ms(10);
usmart_dev.init(72); //串口通信初始化
delay_ms(10);
/*************************初始化RTC初始化********************************************************/
RTC_Init(); //RTC初始化
delay_ms(10);
SD_config_init(); //初始化,将config文件的参数一次性更新到程序里
delay_ms(10);
LimitSwitch_Init(); //运动限位最后初始化。
CheckLimitSwitches(); //检查限位,复位限位
OLED_Clear(); //oled显示屏幕清空
// Home_Motor(AXIS_Z); //初始化Z轴,Z轴回零
// Home_Motor(AXIS_X); //初始化X轴,X轴回零
OLED_Clear(); //清空屏幕
/*************************开机初始化将配置参数传到move页面***************************************/
printf("move.va2.val=%d\xff\xff\xff",g_config.t_fix);
printf("move.va3.val=%d\xff\xff\xff",g_config.t_rinse);
printf("move.va4.val=%d\xff\xff\xff",g_config.t_acid);
printf("move.va5.val=%d\xff\xff\xff",g_config.t_stain);
printf("move.va6.val=%d\xff\xff\xff",g_config.t_dehy1);
printf("move.va7.val=%d\xff\xff\xff",g_config.t_dehy2);
printf("move.va8.val=%d\xff\xff\xff",g_config.t_dehy3);
printf("move.va9.val=%d\xff\xff\xff",g_config.t_dehy4);
printf("move.va10.val=%d\xff\xff\xff",g_config.t_dry);
/***********************************************************************************************/
while (1) {
process_auto_stain();
if(x_left_running) {
motor_continuous_move(AXIS_X, 1); // X轴左移
}
if(x_right_running) {
motor_continuous_move(AXIS_X, -1); // X轴右移
}
if(z_up_running) {
motor_continuous_move(AXIS_Z, -1); // Z轴上移
}
if(z_down_running) {
motor_continuous_move(AXIS_Z, 1); // Z轴下移
}
a++; //累加计数
if(a==800){
prin_temp();
prin_temp2();
a=0;
}
print_level();
delay_ms(2); // 主循环基础延时(保持不变)
}
}
为什么初始化SD卡时容易失败
最新发布