• 正文
  • 相关推荐
申请入驻 产业图谱

手机也能看离散光谱?小装置+APP秒变光谱分析仪

2025/11/15
941
加入交流群
扫码加入
获取工程师必备礼包
参与热点资讯讨论

前几天我们介绍到利用ESP32驱动AS7341离散光谱传感器利用串口和串口示波器实现了离散光谱测量。

本期我们介绍利用.NET MAUI制作一块配套的手机APP,实现在手机上接受离散光谱测量结果,实现便携式离散光谱测量。

1、程序架构

ESP32部分开启AP模式,让手机可以直连ESP32的Wifi,接着初始化AS7341并开始读取数据,读取到数据后利用UDP广播到子网所有地址上。

同时手机APP连接到ESP32的Wifi后开启监听自身端口,由于UDP在进行广播,并不需要额外的地址对应环节。

2、NET MAUi代码

        <VerticalStackLayout            Padding="30,0"            Spacing="25">
            <Label Text="光谱数据"                   FontSize="24"                   FontAttributes="Bold"                   HorizontalOptions="Center" />
            <Frame BackgroundColor="LightBlue" Padding="15" HorizontalOptions="Fill">                <HorizontalStackLayout Spacing="10" HorizontalOptions="Center">                    <Button x:Name="connectButton"                            Text="开始监听"                            Clicked="OnConnectClicked"                            WidthRequest="120" />                    <Button x:Name="disconnectButton"                            Text="停止监听"                            Clicked="OnDisconnectClicked"                            IsEnabled="False"                            WidthRequest="120" />                </HorizontalStackLayout>            </Frame>
            <!-- 光谱图画布 -->            <Frame BackgroundColor="LightGray"                   Padding="10"                   HorizontalOptions="Fill"                   VerticalOptions="Start">                <skia:SKCanvasView x:Name="spectrumCanvas"                                  HeightRequest="300"                                  HorizontalOptions="Fill"                                  PaintSurface="OnSpectrumCanvasPaintSurface" />            </Frame>
            <Frame BackgroundColor="White"                   Padding="15"                   HorizontalOptions="Fill">                <VerticalStackLayout Spacing="10">                    <Label Text="实时数据:" FontAttributes="Bold" />                    <Label x:Name="dataLabel" Text="等待数据..." LineBreakMode="WordWrap" />                </VerticalStackLayout>            </Frame>
        </VerticalStackLayout>

.xaml文件构建界面布局,总体分为:状态显示标签,画布以及实时数据文本,通过按钮控制UDP监听状态。

privatevoidProcessReceivedData(string data){       try       {       // 解析数据格式: "A:123,456,789,123,456,789,123,456"            if (data.StartsWith("A:"))            {                var numberPart = data.Substring(2);                var numbers = numberPart.Split(',');                if (numbers.Length >= 8)                {                 for (int i = 0; i < 8 && i < numbers.Length; i++)                 {                    if (int.TryParse(numbers[i], out int value))                        {                            spectrumData[i] = value;                        }                  }                     UpdateDataDisplay();             }         }      }      catch (Exception ex)      {           System.Diagnostics.Debug.WriteLine($"数据处理错误: {ex.Message}");      }}

后台线程接收到ESP32发送上来的指定格式数据后:A:ch1,ch2,ch3,ch4,ch5,ch6,ch7,ch8rn之后解析8个通道的数据。

        privatevoidDrawSpectrumChart(SKCanvas canvas, float x, float y, float width, float height){            if (spectrumData.Length == 0 || spectrumData.All(val => val == 0))            {                // 如果没有数据,显示提示信息                using var waitTextPaint = new SKPaint                {                    Color = SKColors.Gray,                    TextSize = 24,                     IsAntialias = true,                    TextAlign = SKTextAlign.Center,                    Typeface = SKTypeface.FromFamilyName("Arial", SKFontStyleWeight.Bold, SKFontStyleWidth.Normal, SKFontStyleSlant.Upright)                };                canvas.DrawText("等待数据...", width / 2, height / 2, waitTextPaint);                return;            }            int maxValue = spectrumData.Max();            if (maxValue == 0) maxValue = 1;            float barSpacing = 10;            float availableWidth = width - (spectrumData.Length - 1) * barSpacing;            float barWidth = availableWidth / spectrumData.Length;            using var axisPaint = new SKPaint            {                Color = SKColors.Black,                StrokeWidth = 3,                 IsAntialias = true            };            canvas.DrawLine(x, y + height, x + width, y + height, axisPaint);            canvas.DrawLine(x, y, x, y + height, axisPaint);            using var axisTextPaint = new SKPaint            {                Color = SKColors.Black,                TextSize = 16, // 增大字体                IsAntialias = true,                TextAlign = SKTextAlign.Center,                Typeface = SKTypeface.FromFamilyName("Arial", SKFontStyleWeight.Normal, SKFontStyleWidth.Normal, SKFontStyleSlant.Upright)            };            using var labelTextPaint = new SKPaint            {                Color = SKColors.Black,                TextSize = 18,                 IsAntialias = true,                TextAlign = SKTextAlign.Center,                Typeface = SKTypeface.FromFamilyName("Arial", SKFontStyleWeight.Bold, SKFontStyleWidth.Normal, SKFontStyleSlant.Upright)            };            // 绘制Y轴刻度            for (int i = 0; i <= 5; i++)            {                float yPos = y + height - (i * height / 5);                float value = i * maxValue / 5;                canvas.DrawLine(x - 5, yPos, x, yPos, axisPaint);                canvas.DrawText(value.ToString("F0"), x - 15, yPos + 6, axisTextPaint);            }            for (int i = 0; i < spectrumData.Length; i++)            {                float barHeight = (spectrumData[i] / (float)maxValue) * height;                float barX = x + i * (barWidth + barSpacing);                float barY = y + height - barHeight;                using var barPaint = new SKPaint                {                    Color = channelColors[i],                    Style = SKPaintStyle.Fill,                    IsAntialias = true                };                canvas.DrawRect(barX, barY, barWidth, barHeight, barPaint);                // 绘制通道名称                canvas.DrawText(channelNames[i], barX + barWidth / 2, y + height + 20, labelTextPaint);                // 绘制数值标签                if (barHeight > 25)                {                    canvas.DrawText(spectrumData[i].ToString(), barX + barWidth / 2, barY - 8, axisTextPaint);                }            }            // 添加标题            canvas.DrawText("AS7341 光谱分析", width / 2, y - 10, labelTextPaint);        }

接着我们再根据光谱数据利用光谱的实际颜色在光谱图中绘制柱状图。

 

虽然是利用一张光谱图,但是由于显示屏的底层显示原理,并不是特别的准确。

相关推荐