前几天我们介绍到利用ESP32驱动AS7341离散光谱传感器利用串口和串口示波器实现了离散光谱测量。
本期我们介绍利用.NET MAUI制作一块配套的手机APP,实现在手机上接受离散光谱测量结果,实现便携式离散光谱测量。
1、程序架构
ESP32部分开启AP模式,让手机可以直连ESP32的Wifi,接着初始化AS7341并开始读取数据,读取到数据后利用UDP广播到子网所有地址上。
同时手机APP连接到ESP32的Wifi后开启监听自身端口,由于UDP在进行广播,并不需要额外的地址对应环节。
2、NET MAUi代码
<VerticalStackLayoutPadding="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);}
接着我们再根据光谱数据利用光谱的实际颜色在光谱图中绘制柱状图。
虽然是利用一张光谱图,但是由于显示屏的底层显示原理,并不是特别的准确。
阅读全文
941