--[[ @module tsb_wavein_page @summary 波形输入页面 @version 1.0 @date 2026.03.18 @author 李一玮 @usage 本文件是波形输入页面,展示波形数据和控制功能。 ]] local tsb_wavein_page = {} -- 页面UI元素 local main_container = nil local scroll_container = nil local chart_timer = nil -- 数据推送定时器ID local page_active = false -- 页面是否活跃,用于定时器安全 local common_ui = require("tsb_common_page") local chart = nil -- 图表对象 local freq_label = nil -- 频率显示标签 local vmax_label = nil -- 电压最大值标签 local vmin_label = nil -- 电压最小值标签 local trigger_threshold_input = nil -- 触发阈值输入框 local visible_btn = nil -- 按钮可见性按钮 local set_btn = nil -- 设置按钮 local reset_btn = nil -- 重置按钮 local label_btn = nil -- 标签按钮 local trigger_type_btn = nil -- 触发类型按钮 local trigger_mode_btn = nil -- 触发方式按钮 local pulse_width_input = nil -- 脉宽触发输入框 local time_scale_dropdown = nil -- 时间档位下拉框 local run_control_btn = nil -- 运行控制按钮 -- 控制参数 local time_scale = "2ms" -- 时间档位 local vertical_scale = "5V" -- 垂直档位 local trigger_threshold = "0" -- 触发阈值 local trigger_type = "上升沿" -- 触发类型:上升沿、下降沿、双边沿、脉宽触发 local trigger_mode = "自动" -- 触发方式:自动、普通、单次 local show_menu = false local vertical_scale_dropdown = nil local is_running = true -- 运行状态 local last_x_offset = 0 -- 上一次的水平偏移值 local last_t_offset = 0 -- 上一次的触发位置 local label_x_offset = nil -- 水平偏移标签 local tp_touch_subid = nil -- 触摸事件订阅ID -- 示波器可移动标签相关参数 local show_labels = false -- 是否显示标签 local step_size = 1 -- 标签移动步长 local choose_step_btn = nil -- 步长选择按钮 local trigger_line = nil -- 触发位置竖线 local trigger_label = nil -- 触发位置标签"T" local trigger_line_color = 0xA8A8A8 -- 灰色 local label_overlay = nil -- 标签覆盖层 -- 更新触发位置竖线 local function update_trigger_line(x_offset) -- 500个数据点映射到440像素宽度 -- x_offset范围: 0-500,默认250(中间位置) -- 计算屏幕X坐标 local screen_x = x_offset / 500 * 440 -- 销毁旧的触发线 if trigger_line then trigger_line:destroy() trigger_line = nil end -- 创建新的触发线(红色竖线) trigger_line = airui.shape({ parent = chart, x = 0, y = 0, w = 430, h = 220, items = { { type = "line", x1 = screen_x, y1 = 0, x2 = screen_x, y2 = 230, color = trigger_line_color, width = 2, opacity = 80 } } }) -- 销毁旧的标签"T" if trigger_label then trigger_label:destroy() trigger_label = nil end -- 创建标签"T" trigger_label = airui.label({ parent = main_container, text = "T", x = 10 + screen_x + 7, -- 居中显示 y = 35, w = 14, h = 16, color = trigger_line_color, font_size = 14, }) log.info("chart", "触发位置更新", "x_offset:", x_offset, "screen_x:", screen_x) end local label_msg_container = nil -- 标签消息容器 local label_btn_container = nil -- 标签操作按钮容器 local label_a_title = nil -- 标签A标题 local label_b_title = nil -- 标签B标题 local label_a_x = nil -- 标签A位置 local label_b_x = nil -- 标签B位置 local label_a_msg = nil -- 标签A消息 local label_b_msg = nil -- 标签B消息 local label_ab_msg = nil -- 标签AB消息 local label_btn_a_left = nil -- 标签A左移按钮 local label_btn_a_right = nil -- 标签A右移按钮 local label_btn_b_left = nil -- 标签B左移按钮 local label_btn_b_right = nil -- 标签B右移按钮 local label_c_title = nil -- 标签C标题 local label_d_title = nil -- 标签D标题 local label_c_y = nil -- 标签C位置 local label_d_y = nil -- 标签D位置 local label_c_msg = nil -- 标签C消息 local label_d_msg = nil -- 标签D消息 local label_cd_msg = nil -- 标签CD消息 local label_btn_c_up = nil -- 标签C上移按钮 local label_btn_c_down = nil -- 标签C下移按钮 local label_btn_d_up = nil -- 标签D上移按钮 local label_btn_d_down = nil -- 标签D下移按钮 local label_a_color = 0xD32F2F -- 复古红 local label_b_color = 0x0277BD -- 湖蓝 local label_c_color = 0x2E7D32 -- 墨绿 local label_d_color = 0x7B1FA2 -- 深紫 -- 引入uart1_msg模块 local uart_send = require("uart1_msg") -- 发送ADC配置指令 local function send_adc_config() -- 收集参数 local config = {} -- 垂直档位(单位:mV) local vertical_gear_map = { ["1.5V"] = 15000, ["1V"] = 10000, ["500mV"] = 5000, ["200mV"] = 2000, ["100mV"] = 1000, ["50mv"] = 500, ["20mv"] = 200 } config.vertical_gear = vertical_gear_map[vertical_scale] or 5000 -- 时间档位(单位:us) local time_gear_map = { ["1s"] = 1000000, ["500ms"] = 500000, ["200ms"] = 200000, ["100ms"] = 100000, ["50ms"] = 50000, ["20ms"] = 20000, ["10ms"] = 10000, ["5ms"] = 5000, ["2ms"] = 2000, ["1ms"] = 1000, ["500us"] = 500, ["200us"] = 200, ["100us"] = 100, ["50us"] = 50 } config.time_gear = time_gear_map[time_scale] or 1000 -- 水平偏移 if _G.x_offset == 0 then config.x_offset = 0 -- 回归原始 elseif _G.x_offset > last_x_offset then config.x_offset = 2 -- 右移 elseif _G.x_offset < last_x_offset then config.x_offset = 1 -- 左移 else config.x_offset = 0 end -- 更新上一次的x_offset值 last_x_offset = _G.x_offset -- 垂直偏移 config.y_offset = _G.y_offset -- 触发阈值(单位:mV) local threshold = tonumber(trigger_threshold_input:get_text()) or 2 config.trigger_threshold = threshold * 1000 -- 触发类型 local trigger_type_map = { ["上升沿"] = 0, ["下降沿"] = 1, ["双边沿"] = 2, ["脉宽触发"] = 3 } config.trigger_type = trigger_type_map[trigger_type] or 0 -- 触发脉宽(单位:us) local pulse_width = tonumber(pulse_width_input:get_text()) or 200 config.trigger_width = pulse_width -- 触发方式 local trigger_method_map = { ["自动"] = 0, ["普通"] = 1, ["单次"] = 2 } config.trigger_method = trigger_method_map[trigger_mode] or 0 -- 运行控制 config.run_control = is_running and 1 or 0 -- 复位 config.reset = 0 -- 发送指令 uart_send.send_adc_config(config) end -- 发送ADC动态操作指令 local function send_adc_operate() -- 收集参数 local config = {} -- 触发方式 local trigger_method_map = { ["自动"] = 0, ["普通"] = 1, ["单次"] = 2 } config.trigger_method = trigger_method_map[trigger_mode] or 0 -- 运行控制 config.run_control = is_running and 1 or 0 -- 复位 config.reset = 0 -- 发送指令 uart_send.send_adc_operate(config) end -- 更新水平偏移标签显示 local function update_x_offset_label() local offset_value = _G.x_offset or 0 local percent = math.abs(offset_value) * 10 -- 将 -10~10 转换为 0~100% local text if offset_value == 0 then text = "偏移 0%" elseif offset_value < 0 then text = string.format("左移 %d%%", percent) else text = string.format("右移 %d%%", percent) end if label_x_offset then label_x_offset:set_text(text) end end local function update_vertical_scale_dropdown() if not vertical_scale_dropdown then return end -- 反向映射:Y_FULL_SCALE 值到档位选项 local scale_map = { [15] = 0, -- "15V" [10] = 1, -- "10V" [5] = 2, -- "5V" [2] = 3, -- "2V" [1] = 4, -- "1V" [0.5] = 5, -- "500mv" [0.2] = 6 -- "200mv" } local index = scale_map[_G.Y_FULL_SCALE] or 2 -- 默认5V vertical_scale_dropdown:set_selected(index) -- 同时更新 vertical_scale 变量 local options = {"1.5V","1V", "500mV", "200mV", "100mV", "50mv", "20mv"} vertical_scale = options[index + 1] end local function update_time_scale_dropdown() if not time_scale_dropdown then return end -- 设置时间档位为2ms(索引8) local default_index = 8 -- 2ms time_scale_dropdown:set_selected(default_index) -- 同时更新 time_scale 变量 local options = {"1s", "500ms", "200ms", "100ms", "50ms", "20ms", "10ms", "5ms", "2ms", "1ms", "500us", "200us", "100us", "50us"} time_scale = options[default_index + 1] end local function reset_all_settings() -- 重置全局变量 _G.x_offset = 0 _G.y_offset = 0 _G.Y_FULL_SCALE = 5 -- 重置垂直档位 update_vertical_scale_dropdown() -- 重置时间档位 update_time_scale_dropdown() -- 初始化时更新标签显示 update_x_offset_label() -- 重置触发阈值输入框 if trigger_threshold_input then trigger_threshold_input:set_text("2") end -- 重置脉宽触发输入框 if pulse_width_input then pulse_width_input:set_text("200") end -- 重置触发类型 trigger_type = "上升沿" if trigger_type_btn then trigger_type_btn:set_text("上升沿") end -- 重置触发方式 trigger_mode = "自动" if trigger_mode_btn then trigger_mode_btn:set_text("自动") end -- 重置运行状态 is_running = true if run_control_btn then run_control_btn:set_text("暂停") end -- 发送配置指令 send_adc_config() send_adc_operate() end -- 创建UI function tsb_wavein_page.create_ui() main_container = airui.container({ x = 0, y = 0, w = 480, h = 320, color = 0xFFFFFF }) --------------------- 标题栏 ------------------------ local title_bar = airui.container({ parent = main_container, x = 0, y = 0, w = 480, h = 30, color = 0xFFD93D }) airui.label({ parent = title_bar, text = "波形输入", x = 200, y = 8, w = 80, h = 20, font_size = 16, color = 0xFFFFFF, }) -- 标题栏公共信息展示 common_ui.add_battery_display(title_bar) common_ui.create_back_button(title_bar, tsb_wavein_page.cleanup) --------------------------------------------------- local keyboard1 = airui.keyboard({ x = 0, y = 0, w = 480, h = 160, -- x, y, 键盘默认打开ALIGN_BOTTOM_MID,位置从中下方开始计算 mode = "numeric", -- 键盘模式,可选 "text"/"upper"/"lower"/"numeric" auto_hide = true, -- 自动隐藏键盘 preview = true, preview_height = 35, bg_color = 0xf1f1f1, -- 键盘背景颜色为灰色,可选,不设置则透明 on_commit = function() -- 确认事件回调,只有在按下确认键时才会触发 log.info("keyboard", "commit") send_adc_config() end }) chart = airui.chart({ parent = main_container, x = 10, y = 40, w = 460, h = 250, y_min = 0, y_max = 100, point_count = 500, update_mode = "shift", line_color = 0x00b4ff, line_width = 2, hdiv = 11, vdiv = 11, bg_opa = 0 }) -- 控制区域(右侧) local control_container = airui.container({ parent = main_container, x = 210, y = 40, w = 210, h = 250, color = 0xFFFFFF, radius = 5, border_width = 1, border_color = 0xDDDDDD, color_opacity = 255 }) control_container:hide() -- 订阅触摸事件,点击左侧区域关闭设置面板 tp_touch_subid = sys.subscribe("TP_TOUCH", function(x, y) -- 只响应按下事件,避免重复触发 if x >= 20 and x <= 200 and y >= 30 and y <= 280 then if show_menu then control_container:hide() show_menu = false log.info("chart", "点击左侧区域关闭设置面板") end end end) -- 隐藏/显示按钮(放在最顶层) visible_btn = airui.button({ parent = main_container, text = "隐藏", x = 420, y = 40, w = 50, h = 30, style = {bg_opa = 0}, on_click = function(self) if self:get_text() == "隐藏" then self:set_text("显示") scroll_container:hide() else self:set_text("隐藏") scroll_container:open() end end }) -- 按钮容器(放在chart之后,确保在chart之上) scroll_container = airui.container({ parent = main_container, x = 410, y = 70, w = 65, h = 190, color = 0xFFFFFFF, color_opacity =0 }) set_btn = airui.button({ parent = scroll_container, text = "设置", x = 10, y = 5, w = 50, h = 30, --style = {bg_opa = 0}, on_click = function() if show_menu then control_container:hide() show_menu = false else control_container:open() show_menu = true end end }) reset_btn = airui.button({ parent = scroll_container, text = "复位", x = 10, y = 40, w = 50, h = 30, --style = {bg_opa = 0}, on_click = function() reset_all_settings() end }) trigger_mode_btn = airui.button({ parent = scroll_container, text = "自动", x = 10, y = 75, w = 50, h = 30, font_size = 14, --style = {bg_opa = 0}, on_click = function(self) if trigger_mode == "自动" then trigger_mode = "普通" elseif trigger_mode == "普通" then trigger_mode = "单次" else trigger_mode = "自动" end self:set_text(trigger_mode) log.info("chart", "触发方式: " .. trigger_mode) send_adc_operate() end }) -- 开始/暂停按钮 run_control_btn = airui.button({ parent = scroll_container, text = "暂停", x = 10, y = 110, w = 50, h = 30, font_size = 14, --style = {bg_opa = 0}, on_click = function(self) if is_running then self:set_text("开始") is_running = false log.info("chart", "暂停") else self:set_text("暂停") is_running = true log.info("chart", "开始") end send_adc_operate() end }) label_msg_container = airui.container({ parent = main_container, x = 180, y = 40, w = 240, h = 80, color = 0xFFFFFF, radius = 8, border_width = 0, color_opacity = 0 }) label_a_msg = airui.label({ parent = label_msg_container, text = "Xa: ms", x = 5, y = 10, w = 120, h = 20, font_size = 13, color = 0x000000, }) label_b_msg = airui.label({ parent = label_msg_container, text = "Xb: ms", x = 5, y = 30, w = 120, h = 20, font_size = 13, color = 0x000000, }) label_ab_msg = airui.label({ parent = label_msg_container, text = "Xab: ms", x = 5, y = 50, w = 120, h = 20, font_size = 13, color = 0x000000, }) label_c_msg = airui.label({ parent = label_msg_container, text = "Yc: mV", x = 130, y = 10, w = 110, h = 20, font_size = 13, color = 0x000000, }) label_d_msg = airui.label({ parent = label_msg_container, text = "Yd: mV", x = 130, y = 30, w = 110, h = 20, font_size = 13, color = 0x000000, }) label_cd_msg = airui.label({ parent = label_msg_container, text = "Ycd: mV", x = 130, y = 50, w = 110, h = 20, font_size = 13, color = 0x000000, }) label_msg_container:hide() label_btn_container = airui.container({ parent = main_container, x = 10, y = 130, w = 210, h = 150, color = 0xF111FF, radius = 8, border_width = 0, color_opacity = 0 }) -- 时间档位映射(单位:ms) local time_gear_map = { ["1s"] = 1000, ["500ms"] = 500, ["200ms"] = 200, ["100ms"] = 100, ["50ms"] = 50, ["20ms"] = 20, ["10ms"] = 10, ["5ms"] = 5, ["2ms"] = 2, ["1ms"] = 1, ["500us"] = 0.5, ["200us"] = 0.2, ["100us"] = 0.1, ["50us"] = 0.05 } -- 垂直档位映射(单位:V) local vertical_gear_map = { ["50V"] = 50, ["20V"] = 20, ["10V"] = 10, ["5V"] = 5, ["2V"] = 2, ["1V"] = 1, ["500mV"] = 0.5, ["200mV"] = 0.2, ["100mV"] = 0.1, ["50mV"] = 0.05, ["20mV"] = 0.02, ["10mV"] = 0.01, ["5mV"] = 0.005 } -- 更新标签位置函数 local function update_label_positions() if not label_overlay then return end -- 销毁旧的overlay并重建 label_overlay:destroy() -- 创建新的overlay label_overlay = airui.shape({ parent = chart, x = 0, y = 0, w = 430, h = 220, items = { -- 标签A竖线 { type = "line", x1 = label_a_x, y1 = 0, x2 = label_a_x, y2 = 250, color = label_a_color, width = 2, opacity = 255, dash_width = 2, dash_gap = 2, }, -- 标签B竖线 { type = "line", x1 = label_b_x, y1 = 0, x2 = label_b_x, y2 = 250, color = label_b_color, width = 2, opacity = 255, dash_width = 2, dash_gap = 2, }, -- 标签C竖线 { type = "line", x1 = 0, y1 = label_c_y, x2 = 430, y2 = label_c_y, color = label_c_color, width = 2, opacity = 255, dash_width = 2, dash_gap = 2, }, -- 标签D竖线 { type = "line", x1 = 0, y1 = label_d_y, x2 = 430, y2 = label_d_y, color = label_d_color, width = 2, opacity = 255, dash_width = 2, dash_gap = 2, } } }) -- 更新标签A文字位置 if label_a_title then label_a_title:destroy() end label_a_title = airui.label({ parent = main_container, text = "A", x = 10 + label_a_x + 6, y = 30, w = 14, h = 16, color = label_a_color, font_size = 14, }) -- 更新标签B文字位置 if label_b_title then label_b_title:destroy() end label_b_title = airui.label({ parent = main_container, text = "B", x = 10 + label_b_x + 6, y = 30, w = 14, h = 16, color = label_b_color, font_size = 14, }) -- 更新标签C文字位置 if label_c_title then label_c_title:destroy() end label_c_title = airui.label({ parent = main_container, text = "C", x = 5, y = 40 + label_c_y, w = 14, h = 16, color = label_c_color, font_size = 14, }) -- 更新标签D文字位置 if label_d_title then label_d_title:destroy() end label_d_title = airui.label({ parent = main_container, text = "D", x = 5, y = 40 + label_d_y, w = 14, h = 16, color = label_d_color, font_size = 14, }) -- 计算并更新时间显示(标签A和B) local div_time = time_gear_map[time_scale] or 2 -- 每格时间(ms) local px_per_div_x = 44 -- 横向每格像素数 local px_per_ms = px_per_div_x / div_time -- 每ms对应的像素数 -- 计算Xa(以最左边为起点) local xa_ms = label_a_x / px_per_ms -- 计算Xb(以最左边为起点) local xb_ms = label_b_x / px_per_ms -- 计算Xab local xab_ms = math.abs(xb_ms - xa_ms) -- 获取最大绝对值用于确定统一单位 local max_val_x = math.max(math.abs(xa_ms), math.abs(xb_ms), xab_ms) -- 根据最大值确定统一单位 local unit_x if max_val_x >= 1000 then unit_x = "s" xa_ms = xa_ms / 1000 xb_ms = xb_ms / 1000 xab_ms = xab_ms / 1000 elseif max_val_x >= 1 then unit_x = "ms" else unit_x = "us" xa_ms = xa_ms * 1000 xb_ms = xb_ms * 1000 xab_ms = xab_ms * 1000 end -- 更新时间标签显示 if unit_x == "s" then label_a_msg:set_text(string.format("Xa: %.3fs", xa_ms)) label_b_msg:set_text(string.format("Xb: %.3fs", xb_ms)) label_ab_msg:set_text(string.format("Xab: %.3fs", xab_ms)) elseif unit_x == "ms" then label_a_msg:set_text(string.format("Xa: %.3fms", xa_ms)) label_b_msg:set_text(string.format("Xb: %.3fms", xb_ms)) label_ab_msg:set_text(string.format("Xab: %.3fms", xab_ms)) else label_a_msg:set_text(string.format("Xa: %.0fus", xa_ms)) label_b_msg:set_text(string.format("Xb: %.0fus", xb_ms)) label_ab_msg:set_text(string.format("Xab: %.0fus", xab_ms)) end -- 计算并更新电压显示(标签C和D) local div_voltage = vertical_gear_map[vertical_scale] or 1 -- 每格电压(V) local px_per_div_y = 23 -- 纵向每格像素数 local px_per_v = px_per_div_y / div_voltage -- 每V对应的像素数 -- 计算Yc(以最上方为起点,y=0时为最大电压) local yc_v = (230 - label_c_y) / px_per_v -- 230为最大y位置(10格 × 23px/格) -- 计算Yd local yd_v = (230 - label_d_y) / px_per_v -- 计算Ycd local ycd_v = math.abs(yd_v - yc_v) -- 获取最大绝对值用于确定统一单位 local max_val_y = math.max(math.abs(yc_v), math.abs(yd_v), ycd_v) -- 根据最大值确定统一单位 local unit_y if max_val_y >= 1 then unit_y = "V" elseif max_val_y >= 0.001 then unit_y = "mV" yc_v = yc_v * 1000 yd_v = yd_v * 1000 ycd_v = ycd_v * 1000 else unit_y = "uV" yc_v = yc_v * 1000000 yd_v = yd_v * 1000000 ycd_v = ycd_v * 1000000 end -- 更新电压标签显示(保留2位小数) if unit_y == "V" then label_c_msg:set_text(string.format("Yc: %.2fV", yc_v)) label_d_msg:set_text(string.format("Yd: %.2fV", yd_v)) label_cd_msg:set_text(string.format("Ycd: %.2fV", ycd_v)) elseif unit_y == "mV" then label_c_msg:set_text(string.format("Yc: %.2fmV", yc_v)) label_d_msg:set_text(string.format("Yd: %.2fmV", yd_v)) label_cd_msg:set_text(string.format("Ycd: %.2fmV", ycd_v)) else label_c_msg:set_text(string.format("Yc: %.0fuV", yc_v)) label_d_msg:set_text(string.format("Yd: %.0fuV", yd_v)) label_cd_msg:set_text(string.format("Ycd: %.0fuV", ycd_v)) end end label_btn_a_left = airui.button({ parent = label_btn_container, text = "A左移", x = 5, y = 5, w = 60, h = 30, --style = {bg_opa = 0}, on_click = function() if label_a_x > 0 then label_a_x = label_a_x - step_size update_label_positions() log.info("chart", "标签A左移", "位置:", label_a_x) end end }) label_btn_a_right = airui.button({ parent = label_btn_container, text = "A右移", x = 70, y = 5, w = 60, h = 30, --style = {bg_opa = 0}, on_click = function() if label_a_x < 430 then label_a_x = label_a_x + step_size update_label_positions() log.info("chart", "标签A右移", "位置:", label_a_x) end end }) label_btn_b_left = airui.button({ parent = label_btn_container, text = "B左移", x = 5, y = 40, w = 60, h = 30, --style = {bg_opa = 0}, on_click = function() if label_b_x > 0 then label_b_x = label_b_x - step_size update_label_positions() log.info("chart", "标签B左移", "位置:", label_b_x) end end }) label_btn_b_right = airui.button({ parent = label_btn_container, text = "B右移", x = 70, y = 40, w = 60, h = 30, --style = {bg_opa = 0}, on_click = function() if label_b_x < 430 then label_b_x = label_b_x + step_size update_label_positions() log.info("chart", "标签B右移", "位置:", label_b_x) end end }) label_btn_c_up = airui.button({ parent = label_btn_container, text = "C上移", x = 5, y = 75, w = 60, h = 30, --style = {bg_opa = 0}, on_click = function() if label_c_y > 0 then label_c_y = label_c_y - step_size update_label_positions() log.info("chart", "标签C上移", "位置:", label_c_y) end end }) label_btn_c_down = airui.button({ parent = label_btn_container, text = "C下移", x = 70, y = 75, w = 60, h = 30, --style = {bg_opa = 0}, on_click = function() if label_c_y < 224 then label_c_y = label_c_y + step_size update_label_positions() log.info("chart", "标签C下移", "位置:", label_c_y) end end }) label_btn_d_up = airui.button({ parent = label_btn_container, text = "D上移", x = 5, y = 110, w = 60, h = 30, --style = {bg_opa = 0}, on_click = function() if label_d_y > 0 then label_d_y = label_d_y - step_size update_label_positions() log.info("chart", "标签D上移", "位置:", label_d_y) end end }) label_btn_d_down = airui.button({ parent = label_btn_container, text = "D下移", x = 70, y = 110, w = 60, h = 30, --style = {bg_opa = 0}, on_click = function() if label_d_y < 224 then label_d_y = label_d_y + step_size update_label_positions() log.info("chart", "标签D下移", "位置:", label_d_y) end end }) choose_step_btn = airui.button({ parent = label_btn_container, text = "步长:1", x = 135, y = 110, w = 70, h = 30, --style = {bg_opa = 0}, on_click = function(self) -- 步长档位列表 local step_sizes = {1, 5, 20, 50} -- 找到当前步长的索引 local current_index = 1 for i, size in ipairs(step_sizes) do if size == step_size then current_index = i break end end -- 切换到下一个步长(循环) local next_index = current_index % #step_sizes + 1 step_size = step_sizes[next_index] -- 更新按钮显示文字 self:set_text(string.format("步长:%d", step_size)) log.info("chart", "步长切换", "当前步长:", step_size) end }) label_btn_container:hide() label_btn = airui.button({ parent = scroll_container, text = "标签", x = 10, y = 145, w = 50, h = 30, --style = {bg_opa = 0}, on_click = function(self) if show_labels then self:set_text("标签") show_labels = false log.info("chart", "关闭标签") label_msg_container:hide() label_btn_container:hide() -- 销毁overlay if label_overlay then label_overlay:destroy() label_overlay = nil end -- 销毁标签文字 if label_a_title then label_a_title:destroy() label_a_title = nil end if label_b_title then label_b_title:destroy() label_b_title = nil end if label_c_title then label_c_title:destroy() label_c_title = nil end if label_d_title then label_d_title:destroy() label_d_title = nil end else self:set_text("关标") show_labels = true log.info("chart", "开启标签") label_msg_container:open() label_btn_container:open() -- 标签位置变量(可配置) label_a_x = 200 -- 标签A的X位置 label_b_x = 300 -- 标签B的X位置 label_c_y = 100 label_d_y = 150 -- 创建overlay,包含A、B两根竖线(父容器为chart,避免覆盖按钮) label_overlay = airui.shape({ parent = chart, x = 0, y = 0, w = 430, h = 220, items = { -- 标签A竖线 { type = "line", x1 = label_a_x, y1 = 0, x2 = label_a_x, y2 = 250, color = label_a_color, width = 2, opacity = 255, dash_width = 2, dash_gap = 2, }, -- 标签B竖线 { type = "line", x1 = label_b_x, y1 = 0, x2 = label_b_x, y2 = 250, color = label_b_color, width = 2, opacity = 255, dash_width = 2, dash_gap = 2, }, -- 标签C横线 { type = "line", x1 = 0, y1 = label_c_y, x2 = 430, y2 = label_c_y, color = label_c_color, width = 2, opacity = 255, dash_width = 2, dash_gap = 2, }, -- 标签D横线 { type = "line", x1 = 0, y1 = label_d_y, x2 = 430, y2 = label_d_y, color = label_d_color, width = 2, opacity = 255, dash_width = 2, dash_gap = 2, } } }) -- 创建标签A文字 label_a_title = airui.label({ parent = main_container, text = "A", x = 10 + label_a_x + 6, y = 35, w = 14, h = 16, color = label_a_color, font_size = 14, }) -- 创建标签B文字 label_b_title = airui.label({ parent = main_container, text = "B", x = 10 + label_b_x + 6, y = 35, w = 14, h = 16, color = label_b_color, font_size = 14, }) -- 创建标签C文字 label_c_title = airui.label({ parent = main_container, text = "C", x = 10, y = label_c_y + 40, w = 14, h = 16, color = label_c_color, font_size = 14, }) -- 创建标签D文字 label_d_title = airui.label({ parent = main_container, text = "D", x = 10, y = label_d_y + 40, w = 14, h = 16, color = label_d_color, font_size = 14, }) end end }) -- 添加选项卡 local tabview = airui.tabview({ parent = control_container, x = 2, y = 2, w = 205, h = 245, tabs = {"基础设置", "触发设置"}, active = 0, page_style = { tabbar_size = 40, pad = { method = airui.TABVIEW_PAD_ALL, value = 0 }, bg_opa = 255, }, }) -- 第一页:基础设置 local tab1 = tabview:get_content(0) local control_y1 = 10 -- 时间档位 airui.label({ parent = tab1, text = "时间档位", x = 10, y = control_y1 + 5, w = 70, h = 20, font_size = 12, color = 0x000000, }) time_scale_dropdown = airui.dropdown({ parent = tab1, x = 80, y = control_y1, w = 110, h = 25, options = {"1s", "500ms", "200ms", "100ms", "50ms", "20ms", "10ms", "5ms", "2ms", "1ms", "500us", "200us", "100us", "50us"}, default_index = 8, -- 默认2ms on_change = function(self, idx) local options = {"1s", "500ms", "200ms", "100ms", "50ms", "20ms", "10ms", "5ms", "2ms", "1ms", "500us", "200us", "100us", "50us"} time_scale = options[idx + 1] log.info("chart", "时间档位: " .. time_scale) send_adc_config() end }) control_y1 = control_y1 + 40 -- 垂直档位 airui.label({ parent = tab1, text = "垂直档位", x = 10, y = control_y1 + 5, w = 90, h = 20, font_size = 12, color = 0x000000, }) vertical_scale_dropdown = airui.dropdown({ parent = tab1, x = 80, y = control_y1, w = 110, h = 25, options = {"1.5V","1V", "500mV", "200mV", "100mV", "50mv", "20mv"}, default_index = 2, -- 默认5V on_change = function(self, idx) local options = {"1.5V","1V","500mV", "200mV", "100mV", "50mv", "20mv"} vertical_scale = options[idx + 1] -- 根据选择的档位更新全局变量 local scale_map = { ["1.5V"] = 15, ["1V"] = 10, ["500mV"] = 5, ["200mV"] = 2, ["100mV"] = 1, ["50mv"] = 0.5, ["20mv"] = 0.2 } _G.Y_FULL_SCALE = scale_map[vertical_scale] or 5 log.info("chart", "垂直档位: " .. vertical_scale, "Y_FULL_SCALE: " .. _G.Y_FULL_SCALE) send_adc_config() end }) control_y1 = control_y1 + 40 -- 水平偏移 airui.label({ parent = tab1, text = "水平偏移", x = 10, y = control_y1, w = 110, h = 20, font_size = 12, color = 0x000000, }) local x_offset_container = airui.container({ parent = tab1, x = 10, y = control_y1 + 20, w = 190, h = 30, color = 0xFFFFFF, radius = 4, }) airui.button({ parent = x_offset_container, text = "←", x = 10, y = 2, w = 75, h = 25, on_click = function() if _G.x_offset > -10 then _G.x_offset = _G.x_offset - 1 -- 左移 log.info("chart", "水平偏移左", "x_offset: " .. _G.x_offset) update_x_offset_label() -- 更新标签显示 send_adc_config() else log.info("chart", "水平偏移已达到左极限") end end }) airui.button({ parent = x_offset_container, text = "→", x = 110, y = 2, w = 75, h = 25, on_click = function() if _G.x_offset < 10 then _G.x_offset = _G.x_offset + 1 -- 右移 log.info("chart", "水平偏移右", "x_offset: " .. _G.x_offset) update_x_offset_label() -- 更新标签显示 send_adc_config() else log.info("chart", "水平偏移已达到右极限") end end }) label_x_offset = airui.label({ parent = tab1, text = "偏移 0%", x = 130, y = control_y1, w = 70, h = 20, font_size = 12, color = 0x000000, }) control_y1 = control_y1 + 60 -- 垂直偏移 airui.label({ parent = tab1, text = "垂直偏移", x = 10, y = control_y1, w = 110, h = 20, font_size = 12, color = 0x000000, }) local y_offset_container = airui.container({ parent = tab1, x = 10, y = control_y1 + 20, w = 190, h = 30, color = 0xFFFFFF, radius = 4, }) airui.button({ parent = y_offset_container, text = "↑", x = 10, y = 2, w = 75, h = 25, on_click = function() _G.y_offset = _G.y_offset + 5 -- 上移,值增大 log.info("chart", "垂直偏移上", "y_offset: " .. _G.y_offset) send_adc_config() end }) airui.button({ parent = y_offset_container, text = "↓", x = 110, y = 2, w = 75, h = 25, on_click = function() _G.y_offset = _G.y_offset - 5 -- 下移,值减小 log.info("chart", "垂直偏移下", "y_offset: " .. _G.y_offset) send_adc_config() end }) -- 第二页:触发设置 local tab2 = tabview:get_content(1) local control_y2 = 25 -- 触发阈值 airui.label({ parent = tab2, text = "触发阈值", x = 10, y = control_y2 + 10, w = 60, h = 20, font_size = 14, color = 0x000000, }) trigger_threshold_input = airui.textarea({ parent = tab2, x = 80, y = control_y2 + 5, w = 80, h = 25, text = "2", max_len = 5, keyboard = keyboard1, on_text_change = function(txt) log.info("text changed:", txt) end }) airui.label({ parent = tab2, text = "V", x = 165, y = control_y2 + 10, w = 30, h = 20, font_size = 14, color = 0x000000, }) control_y2 = control_y2 + 40 -- 触发类型 airui.label({ parent = tab2, text = "触发类型", x = 10, y = control_y2 + 30, w = 60, h = 20, font_size = 14, color = 0x000000, }) trigger_type_btn = airui.button({ parent = tab2, text = "上升沿", x = 80, y = control_y2 + 25, w = 80, h = 25, font_size = 14, on_click = function(self) if trigger_type == "上升沿" then trigger_type = "下降沿" elseif trigger_type == "下降沿" then trigger_type = "双边沿" elseif trigger_type == "双边沿" then trigger_type = "脉宽触发" elseif trigger_type == "脉宽触发" then trigger_type = "上升沿" end self:set_text(trigger_type) log.info("chart", "触发类型: " .. trigger_type) send_adc_config() end }) control_y2 = control_y2 + 80 -- 脉宽触发 airui.label({ parent = tab2, text = "脉宽触发", x = 10, y = control_y2 + 10, w = 60, h = 20, font_size = 14, color = 0x000000, }) pulse_width_input = airui.textarea({ parent = tab2, x = 80, y = control_y2 + 5, w = 80, h = 25, text = "200", max_len = 5, keyboard = keyboard1, }) airui.label({ parent = tab2, text = "us", x = 165, y = control_y2 + 10, w = 30, h = 20, font_size = 14, color = 0x000000, }) -- 信息显示区域(图表下方) local info_container = airui.container({ parent = main_container, x = 10, y = 40, w = 160, h = 80, color = 0xFFFFFF, radius = 8, border_width = 0, color_opacity = 0 }) airui.label({ parent = info_container, text = "频率:", x = 5, y = 10, w = 40, h = 20, font_size = 13, color = 0x000000, }) freq_label = airui.label({ parent = info_container, text = "0 Hz", x = 60, y = 10, w = 100, h = 20, font_size = 13, color = 0x000000, }) airui.label({ parent = info_container, text = "Vmax:", x = 5, y = 30, w = 60, h = 20, font_size = 13, color = 0x000000, }) vmax_label = airui.label({ parent = info_container, text = "0 mV", x = 60, y = 30, w = 65, h = 20, font_size = 13, color = 0x000000, }) airui.label({ parent = info_container, text = "Vmin:", x = 5, y = 50, w = 60, h = 20, font_size = 13, color = 0x000000, }) vmin_label = airui.label({ parent = info_container, text = "0 mV", x = 60, y = 50, w = 65, h = 20, font_size = 13, color = 0x000000, }) -- 底部信息 common_ui.create_status_bar(main_container) end local adc_wave_subid = nil local function subscribe_adc_wave() -- 先注销旧订阅,防止重复 if adc_wave_subid then sys.unsubscribe(adc_wave_subid) end -- 绑定订阅 adc_wave_subid = sys.subscribe("ADC_WAVE_DATA", function(wave_data) -- 只有页面激活 + 图表存在 才更新 if not page_active or not chart then return end -- 校验数据 if not wave_data or #wave_data ~= 500 then log.error("chart","波形长度错误!期望500,实际:", #wave_data) return end chart:set_values(1, wave_data) --log.info("chart","500点波形更新成功!") end) log.info("chart","ADC波形订阅已启动") end local adc_msg_subid = nil local function subscribe_adc_msg() -- 先注销旧订阅,防止重复 if adc_msg_subid then sys.unsubscribe(adc_msg_subid) end -- 绑定订阅 adc_msg_subid = sys.subscribe("ADC_DATA_UPDATE", function(data) if not data then return end -- 更新频率标签 if freq_label then local freq = data.frequency local freq_str, unit if freq >= 1000 then freq_str = string.format("%.2f", freq / 1000) unit = "kHz" else freq_str = tostring(freq) unit = "Hz" end freq_label:set_text(freq_str .. " " .. unit) end -- 更新电压最大值标签 if vmax_label then local max_vol = data.max_vol local vol_str, unit if max_vol >= 1000 then vol_str = string.format("%.2f", max_vol / 1000) unit = "V" else vol_str = tostring(max_vol) unit = "mV" end vmax_label:set_text(vol_str .. " " .. unit) end -- 更新电压最小值标签 if vmin_label then local min_vol = data.min_vol local vol_str, unit if min_vol >= 1000 then vol_str = string.format("%.2f", min_vol / 1000) unit = "V" else vol_str = tostring(min_vol) unit = "mV" end vmin_label:set_text(vol_str .. " " .. unit) end -- 更新触发位置竖线 if data.x_offset ~= nil and page_active and data.x_offset ~= last_t_offset then last_t_offset = data.x_offset update_trigger_line(data.x_offset) end end) end -- 初始化页面 function tsb_wavein_page.init(params) tsb_wavein_page.create_ui() page_active = true subscribe_adc_wave() -- 创建初始触发线(默认位置250,即中间位置) update_trigger_line(250) subscribe_adc_msg() -- 首次初始化时发送一次配置指令 -- 使用定时器延迟发送 sys.timerStart(function() -- 先发送一个同步字节,确保串口完全就绪 -- 短暂延时后发送实际配置 reset_all_settings() end, 100) end -- 清理页面 function tsb_wavein_page.cleanup() page_active = false -- 停止ADC运行 is_running = false send_adc_operate() -- 发送停止指令 log.info("chart", "ADC已停止运行") if chart_timer then sys.timerStop(chart_timer) chart_timer = nil end if adc_msg_subid then sys.unsubscribe(adc_msg_subid) adc_msg_subid = nil end if adc_wave_subid then sys.unsubscribe(adc_wave_subid) adc_wave_subid = nil end if tp_touch_subid then sys.unsubscribe(tp_touch_subid) tp_touch_subid = nil end if main_container then main_container:destroy() main_container = nil scroll_container = nil chart = nil freq_label = nil vmax_label = nil vmin_label = nil trigger_threshold_input = nil trigger_type_btn = nil trigger_mode_btn = nil end end return tsb_wavein_page