65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 .NET/Blazor 与 Raspberry Pi I2C 传感器交互

starIconstarIconstarIconstarIconstarIcon

5.00/5 (11投票s)

2021 年 1 月 6 日

CPOL

12分钟阅读

viewsIcon

14966

downloadIcon

211

使用运行在 Raspberry Pi 上的 Blazor Server,显示来自 MCP9808 I2C 传感器的数据

引言

尽管我找到了关于在 Pi 上运行 .NET 和 Blazor 的文章,但我没有找到任何关于使用它们为 I2C 总线(集成电路间通信,通常显示为 I2C)传感器创建仪表板的内容。我希望能够在 Pi 上创建可以通过网络上的浏览器访问的 GUI 应用程序。我的第一个尝试是通过在 Windows 系统上创建一个 syslog 服务器,并让 Pi 向其写入。这并不是我想要的。我认为使用更新的 .NET/Blazor 技术在 Pi 上构建一个服务器,既具有教育意义,又实用。随着较新的 Pi4 拥有高达 8GB 的内存,有许多选项可以提供 GUI。

互联网上两位博主的帖子帮助我入门:Jeremy Lindsay (在 Wordpress 上) 和 Bradley Wells (在他自己的网站上)。像大多数搜索一样,需要根据自己的独特情况进行添加和修改。这是修改的结果。

背景

一位朋友想在办公楼里替换 1-Wire 总线温度传感器时,出现了这个需求。由于这些传感器共享总线,因此难以排除故障。本文使用的传感器是 I2C 连接的。对于多个传感器,可以使用多路复用器进行隔离(外部可用,不在 Pi 中)。

Using the Code

注意:Linux 区分大小写。

硬件

  • Raspberry Pi (我使用的是 4 版本)
  • 电源
  • 传感器 MCP9808 温度模块
  • 小型面包板
  • 跳线公对母和公对公各 4 根 (如果您使用 T-Cobbler 分线器之一,则不需要母对公)

软件

最新版本的 Raspian (基于 Debian 构建)。从 https://www.raspberrypi.org/software/ 下载。目前,我运行的是 32 位版本。我在尝试在 64 位版本上运行 .NET 时(大部分是 BETA 版本)没有取得太多成功。如果您之前没有为 Pi 配置过操作系统,同一网站上有详细的步骤说明。

配置 Pi 时,请启用 SSH、VNC 和 I2C。首次启动时应该会提供此选项,否则请使用“首选项”。如果您希望能够从其他系统进行 FTP,请安装 vsftpd。

在 Pi 上编程

我更喜欢使用 Visual Studio Code 编写 .NET 代码,并从我的 Linux 主机远程连接。您也可以使用 Windows 系统上的 Visual Studio,然后将文件复制到 Pi,再从那里发布。当您通过 VS Code 远程连接时,会收到一条有关调试的提示,以及一个指向相关 GitHub 文章的链接。我在这里不包含该内容。这两个应用程序都相当简单。

基本操作,启动 VS Code 并通过 SSH 远程连接到 Pi:按 Ctrl-Shift-P,然后向下滚动到“Remote-SSH Connect to host”。输入 pi@<IP 地址> (例如:pi@10.0.2.29)。这假设您使用的是默认用户“pi”。我的 Pi 的地址是 10.0.2.29。打开终端 (Terminal/new terminal)。我们可以在此终端中运行以下所有命令。

安装适用于 ARM 的 .NET Core

来源:https://dotnet.microsoft.com/download/dotnet

目前,5.0.101 是最新版本。SDK 在左侧列中,您需要 32 位版本。我下载 tarball 并手动安装效果最好。您可以通过多种方式将其传输到 Pi。

  1. 下载到 Pi。
  2. 下载到您的主机并通过 FTP 传输到 Pi (您需要安装 vsftpd)。
  3. Sneakernet(通过 U 盘下载到主机并传输)。
  4. 如果主机是 Linux,将 SD 卡插入主机并复制到其中。在您的 Pi 上

将 tarball 放在 Downloads 目录中。请记住,Linux 区分大小写。Linux 使用“/”作为目录结构,而不是“\”。

安装

一旦文件位于 Pi 上的@HOME/Downloads 目录中,在线即可找到详细说明,但步骤如下

  1. 通过 SSH 登录到 Pi,或在 VS Code 中打开 Pi 的远程会话(我使用的就是这种方式),您也可以直接在 Pi 本身打开终端。我推荐使用 VS Code,请参阅上面的说明。请注意,您也可以从 Windows 上的 WSL 使用远程 SSH。
  2. 在终端会话中,执行以下命令
    cd $HOME/Downloads
    mkdir -p $HOME/dotnet
    tar zxf dotnet-sdk-5.0.101-linux-arm.tar.gz -C $HOME/dotnet

    请确保使用您下载的版本,我的是 5.0.101。

  3. tar 命令可能需要几秒钟。完成后,使用终端中的以下命令添加 2 个环境变量
    export DOTNET_ROOT=$HOME/dotnet
    export PATH=$PATH:$HOME/dotnet
  4. 要使这两个环境变量在重启后仍然生效,请将它们添加到您的$HOME/.bashrc文件的末尾。请注意文件名中的“.”。您应该可以在 VS Code 中完成此操作,或者可以使用
    nano $HOME/.bashrc (nano is a rather basic editor, no mouse). 

    要测试安装,请在终端中执行

    dotnet --version
    5.0.101

创建一个控制台应用程序来测试我们的设备和 .NET

cd ~
mkdir TempConsole
cd TempConsole
dotnet new console
The template "Console Application" was created successfully.
Processing post-creation actions...
Running 'dotnet restore' on /home/pi/TempConsole/TempConsole.csproj...
  Determining projects to restore...
  Restored /home/pi/TempConsole/TempConsole.csproj (in 75 ms).
Restore succeeded.

dotnet run
Hello World

请注意,您可能会收到关于 Linux ARM 调试器不起作用的提示,并提供一个解决方法。我尚未在 Pi 上进行测试。如果我进行大量 Blazor 工作,我更喜欢在 Visual Studio 中调试非 GPIO 部分,然后将文件复制到 Pi 以完成。您会在最终版本中看到,我在传感器部分使用了 try/catch,这允许在 Windows 系统上运行。

所以,我们有一个 .NET 控制台程序,带有标准的 Hello World。

接线

接线很简单。引脚布局并不简单。引脚编号与 GPIO 编号不匹配。对于这个设备来说,这也不是什么大问题,我将引用引脚编号(而不是 GPIO)。我们需要从 Pi 到设备的 4 根跳线,Vcc (3.3 伏,引脚 #1),Ground (引脚 #6),I2C 数据 (SDA,引脚 #3) 和 I2C 时钟 (CLK,引脚 #5)。Raspberrypi.org 网站上有引脚布局图。我的 Pi 套件中包含了一个。

修改我们刚刚创建的简单控制台应用程序,以从温度模块获取数据
该模块的数据手册可在制造商网站上找到。

我们需要一个 I2C 库来简化从温度模块获取数据的工作。如今,C# 库并不存在。嗯,即使存在,我也没找到。所以,我们将使用 Linux C 库函数与 interopServices。例如

[DllImport("libc.so.6", EntryPoint = "open")]
 public static extern int Open(string fileName, int mode);

对于 open 函数。

请注意,libc.so.6 是指向当前最新版本库的符号链接,在我的 Pi 上是libc-2.28.so。总而言之,我们需要 4 个函数:open、ioctl、read 和 write。我认为 MCP9808 有点独特,因为它需要一个 write 函数来告诉我们要读取哪个寄存器。

在 Linux 中,我们在/dev 文件夹中与设备通信。I2C 总线也在这里。我们使用 open 函数打开第一个 I2C 设备

Open("/dev/i2c-1", OPEN_READ_WRITE);

这将返回一个句柄 (int)。我们使用句柄进行 Ioctl 函数,该函数挂载我们的设备。我们将客户端设置为 0x0703。我们设备的默认总线设备地址是 0x1A,还有地址引脚允许连接多个设备,您可以将它们跳接高。我们只需要默认的。write 命令告诉设备我们要从寄存器 0x05 读取。然后我们将 2 个字节读入 deviceData 字节数组。这得到了高低字节温度数据。设备数据手册给出了计算摄氏度温度的公式。一些高中物理告诉我们如何获得华氏度值。为简洁起见,我忽略了返回值,您应该检查它们,它们返回 -1 表示错误。

在您的 VS Code 编辑器中,转到 tempconsole 文件夹并打开Program.cs 文件。在Program.cs 文件中,将所有内容替换为

using System;
using System.Runtime.InteropServices;
namespace TempConsole
{
    class Program
    {
        // constants for i2c
        private static int OPEN_READ_WRITE = 2;
        private static int I2C_CLIENT = 0x0703;

       // externals for the i2c libraries
        [DllImport("libc.so.6", EntryPoint = "open")]
        private static extern int Open(string fileName, int mode);
        [DllImport("libc.so.6", EntryPoint = "ioctl", SetLastError = true)]
        private static extern int Ioctl(int fd, int request, int data);
        [DllImport("libc.so.6", EntryPoint = "read", SetLastError = true)]
        private static extern int Read(int handle, byte[] data, int length);
        [DllImport("libc.so.6", EntryPoint = "write", SetLastError = true)]
        private static extern int Write(int handle, byte[] data, int length);

        static void Main(string[] args)
        {
            // read from I2C device bus 1
            int i2cHandle = Open("/dev/i2c-1", OPEN_READ_WRITE);
            // mount the device at address 0x1A for communication
            int registerAddress = 0x1A;
            int deviceReturnCode = Ioctl(i2cHandle, I2C_CLIENT, registerAddress);
            Console.WriteLine(deviceReturnCode.ToString());
            //set byte arrays for specifying  the register and reading the data
            byte[] deviceData = new byte[2];
            byte[] reg=new byte[1];
            //we have to tell it what register to read 0x05
            reg[0]=0x05;
            deviceReturnCode= Write(i2cHandle,reg,1);
            //now we can read 2 bytes
            deviceReturnCode= Read(i2cHandle, deviceData, deviceData.Length);
            int msb=deviceData[0];  //most significant byte
            int lsb=deviceData[1];  //least significant byte
            //calculate according to the datasheet
            msb=msb & 0x1F;
            double tempc = (msb * 256) + lsb;
            if (tempc > 4095)//positive
                tempc -= 8192;//remove sign bit
            tempc *= .0625;
            //and a little high school physics for F
            double tempf=32+tempc*9/5;
            Console.WriteLine(tempc.ToString("N1")+(char)176+"C");
            Console.WriteLine(tempf.ToString("N1")+(char)176+"F");     
        }
    }
}

现在,执行程序。在终端中运行

dotnet run
24.0°C
75.2°F

这表明我们的模块以及 .NET 本身都在工作。您将获得自己的温度读数。

Blazor

现在,我们将使用 VS Code 终端中的远程 VS Code 连接,让 Blazor 参与进来

cd ~
mkdir tempserver
cd tempserver
dotnet new server

与我们的控制台程序类似,这应该会创建一个 Blazor 服务器应用程序,并最终显示“Restore succeeded”。我们的首要任务是让服务器可供 LAN 上的其他系统访问,默认 URL 仅限于 localhost。打开Program.cs 文件。在IHostBuilder方法中,有一行“webBuilder.UseStartup<Startup>():”,在其下方添加一行:WebBuilder.UseUrls("Http://*:5000"); 您的方法现在应包含

.ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();
                    webBuilder.UseUrls("Http://*:5000");
                });

保存文件并运行

dotnet run
Building...
info: Microsoft.Hosting.Lifetime[0]
      Now listening on: http://[::]:5000
info: Microsoft.Hosting.Lifetime[0]
      Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
      Hosting environment: Development
info: Microsoft.Hosting.Lifetime[0]
      Content root path: /home/pi/tempserver

我们不再看到文本输出,而是有一个运行在 5000 端口的 Blazor 服务器。VS Code 通常会询问您是否要在主机浏览器中打开它。在我的 Pi 上,这将是http://10.0.2.29:5000。我们没有设置 https,因为我们没有证书。如果您为一个端口(例如 5001)设置 https,您的浏览器会尝试通过 https 连接,有些浏览器会拒绝打开。只需使用 http 即可。

另一个 Hello World。这对于从 Pi 开始来说已经取得了很大的进展。要退出程序,请在终端中按 Ctrl-c。让我们将控制台温度程序移到 Blazor 应用程序中,并在其中显示温度。我们将使用相同的代码来读取传感器,但将其放入一个名为GetTheTemp的函数中。首先,我们需要添加一点(非常基本的)HTML 来显示读数。一个基本的 HTML 仪表将添加一些相当粗糙的 GUI。正如我之前所说,有很多仪表可供使用,我使用了一个供应商的免费版本。为了避免使用第三方内容,我只使用了这里的基本仪表。

<p>-50<meter id="temp" value=@theTempC min="-50" max="100" ></meter>100 </p>

其中 temp 将在变量theTempC(摄氏度)中。一个获取读数的按钮(我们稍后会添加一个计时器)。

button class="btn btn-primary" @onclick="startRead">Start Temp Reading</button>

显示摄氏度和华氏度读数的文本。

<p>Temp is: @theTempC &#176C @theTempF &#176F </p>

显示错误信息的文本。

<p>Error: @errorMessage</p>

在 Pages 文件夹中,打开Index.razor文件。保留顶行 @page "/" 将其他所有内容替换为

@using System;
@using System.Runtime.InteropServices;
<h1>Current Temperature</h1>
<p>-50<meter id="temp" 
value=@theTempC min="-50" max="100" ></meter>100 </p>
<button class="btn btn-primary" @onclick="GetTheTemp">Start Temp reading</button>
<p>Temp is: @theTempC &#176C @theTempF &#176F </p><p>Error: @errorMessage</p>
@code 
{    
    public double currentTemp = 0.0;   
    public string theTempC = string.Empty;    
    public string theTempF = string.Empty;    
    int OPEN_READ_WRITE = 2;    
    string errorMessage = string.Empty;   
    [DllImport("libc.so.6", EntryPoint = "open")]
            private static extern int Open(string fileName, int mode);
            [DllImport("libc.so.6", EntryPoint = "ioctl", SetLastError = true)]
            private static extern int Ioctl(int fd, int request, int data);
            [DllImport("libc.so.6", EntryPoint = "read", SetLastError = true)]
            private static extern int Read(int handle, byte[] data, int length);
            [DllImport("libc.so.6", EntryPoint = "write", SetLastError = true)]
            private static extern int Write(int handle, byte[] data, int length);
    public  void GetTheTemp()   
    {        
        try        
        {                       
        int I2C_CLIENT = 0x0703; // read from I2C device bus 1            
        int i2cHandle = Open("/dev/i2c-1", OPEN_READ_WRITE);            
        // open the device at address 0x1A for communication            
        int registerAddress = 0x1A;            
        int deviceReturnCode = Ioctl(i2cHandle, I2C_CLIENT, registerAddress); //set byte 
                                 // arrays for specifying  the register and reading the data
        byte[] deviceData = new byte[2];            
        byte[] reg = new byte[1];            
        //we have to tell it to read register 0x05            
        reg[0] = 0x05;            
        deviceReturnCode = Write(i2cHandle, reg, 1);            
        //now we can read 2 bytes            
        deviceReturnCode = Read(i2cHandle, deviceData, deviceData.Length);            
        int msb = deviceData[0];  //most significant byte            
        int lsb = deviceData[1];  //least significant byte            
        //calculate according to the datasheet            
        msb = msb & 0x1F;            
        double tempc = (msb * 256) + lsb;            
        if (tempc > 4095)         //positive                
        tempc -= 8192;            //remove sign bit            
        tempc *= .0625;            
        //and a little high school physics for F            
        double tempf = 32 + tempc * 9 / 5;           
        currentTemp = tempc;            
        theTempC =     Convert.ToInt32(tempc).ToString();            
        theTempF = Convert.ToInt32(tempf).ToString();        
    }        
    catch (Exception e)        
    {                        
    errorMessage = e.ToString();  
    }    
  }    
}

再次运行 dotnet run,点击按钮后,您应该能在主页上看到我们的温度。

这样不错,但我们有一个默认服务器模板的修改版本,并且当多个系统访问 Blazor 服务器时,我的经验好坏参半。所以我决定做一些更改,并将函数替换为一个服务。

  1. 创建一个定时器服务来刷新读数。
  2. GetTheTemp函数转换为服务。
  3. 自定义以删除模板中我们不需要/不想要的内容。
  4. 发布(类似于链接)解决方案,以便不每次运行时都让 .NET 进行生成。

删除Data文件夹。

Pages文件夹中,删除Counter.razorFetchData.razor

编辑以下文件

Startup.cs中,删除以下行

using tempserver.Data;

services.AddSingleton<WeatherForecastService>();

Shared/NavMenu.razor文件中,删除counterfetchdata的列表项

    <li class="nav-item px-3">
      <NavLink class="nav-link" href="counter">
        <span class="oi oi-plus" aria-hidden="true"></span> Counter
      </NavLink>
    </li>
    <li class="nav-item px-3">
      <NavLink class="nav-link" href="fetchdata">
        <span class="oi oi-list-rich" aria-hidden="true"></span> Fetch data
      </NavLink>
    </li>

我还将“Home”改为了Temperature

Shared/MainLayout.razor中,我删除了About链接。<a href="https://docs.microsoft.com/aspnet/" target="_blank">About</a>

如果您想添加自己的About链接,请编辑它而不是删除它。

再次运行 .NET 并访问服务器,以确保我们没有破坏任何东西。您应该看到我们的修改。

现在,我们需要删除“Start temp”按钮,而应使用计时器来更新读数,而不是点击按钮。我们将把计时器创建一个服务,并将GetTheTemp方法转换为一个服务。

tempserver文件夹中,添加一个名为Services的文件夹。打开Services文件夹并添加一个名为TempTimer.cs的文件和一个名为GetTemp.cs的文件。

我的文件夹结构现在看起来像

打开TempTime.cs并添加以下内容

using System;
using System.Timers;
namespace tempserver.Services
{
    public class TempTimer
    {
        private Timer aTimer;
        public void SetTimer(double interval)
        {
            aTimer = new Timer(interval);
            aTimer.Elapsed += TimedOut;
            aTimer.Enabled = true;
        }
        public event Action OnTimeout;
        private void TimedOut(Object source, ElapsedEventArgs e)
        {
            OnTimeout();
        }
    }
}

保存文件。

编辑GetTemp.cs文件,添加以下内容

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
namespace tempserver.Services
{
    public class GetTemp
    {
        public string theTempC = string.Empty;
        public string theTempF = string.Empty;
        int OPEN_READ_WRITE = 2;
        public string errorMessage = "OK";
        [DllImport("libc.so.6", EntryPoint = "open")]
        private static extern int Open(string fileName, int mode);
        [DllImport("libc.so.6", EntryPoint = "ioctl", SetLastError = true)]
        private static extern int Ioctl(int fd, int request, int data);
        [DllImport("libc.so.6", EntryPoint = "read", SetLastError = true)]
        private static extern int Read(int handle, byte[] data, int length);
        [DllImport("libc.so.6", EntryPoint = "write", SetLastError = true)]
        private static extern int Write(int handle, byte[] data, int length);
        public void GetTheTemp()
        {
            try
            {
                int I2C_CLIENT = 0x0703;            // read from I2C device bus 1
                int i2cHandle = Open("/dev/i2c-1", OPEN_READ_WRITE);
                // open the device at address 0x1A for communication
                int registerAddress = 0x1A;
                int deviceReturnCode = Ioctl(i2cHandle, I2C_CLIENT, registerAddress);            
                //set byte arrays for specifying  the register and reading the data
                byte[] deviceData = new byte[2];
                byte[] reg = new byte[1];
                //we have to tell it to read register 0x05
                reg[0] = 0x05;
                deviceReturnCode = Write(i2cHandle, reg, 1);
                //now we can read 2 bytes
                deviceReturnCode = Read(i2cHandle, deviceData, deviceData.Length);
                int msb = deviceData[0];  //most significant byte
                int lsb = deviceData[1];  //least significant byte 
                //calculate according to the datasheet
                msb = msb & 0x1F;
                double tempc = (msb * 256) + lsb;
                if (tempc > 4095)         //positive
                    tempc -= 8192;        //remove sign bit
                tempc *= .0625;
                //and a little high school physics for F
                double tempf = 32 + tempc * 9 / 5;
                theTempC = Convert.ToInt32(tempc).ToString();
                theTempF = Convert.ToInt32(tempf).ToString();
            }
            catch (Exception e)
            {
                errorMessage = e.ToString();
                  //so we can see the exception
            }
        }
    }
}

大部分内容是我们方法的复制。保存文件。我们需要将这两个类注册为服务。打开Startup.cs文件,并在ConfigureServices方法中添加

services.AddTransient<Services.TempTimer>();

services.AddSingleton<Services.GetTemp>();

该方法应如下所示

public void ConfigureServices(IServiceCollection services)

        {
            services.AddRazorPages();
            services.AddServerSideBlazor();
            services.AddTransient<Services.TempTimer>();
            services.AddSingleton<Services.GetTemp>();           
        }

打开Index.razor。我们将删除按钮、GetTheTemp方法,并注入我们的类。所以,只需将所有内容替换为

@inject Services.TempTimer aTimer
@inject Services.GetTemp gTemp
@page "/"
@using System;
@using System.Runtime.InteropServices;

<h1>Current Temperature</h1>
<p>-50<meter id="temp" 
value=@gTemp.theTempC min="-32" max="100" ></meter>100 </p>
<p>Temperature: @gTemp.theTempC &#176C @gTemp.theTempF &#176F </p>
<p>Status: @gTemp.errorMessage</p>
@code 
{    
    protected override void OnInitialized()
    {
        gTemp.GetTheTemp();
                InvokeAsync(() => base.StateHasChanged());
           StartTimer();
    }
    void StartTimer()
    {
        InvokeAsync(() => base.StateHasChanged());
        aTimer.SetTimer(2000);
        // 2 seconds
        aTimer.OnTimeout += TimedOut;  
    }    

    void TimedOut()
    {
        gTemp.GetTheTemp();
        InvokeAsync(() => base.StateHasChanged());
        // refreshes the GUI
     }
}

请注意,sTimergTemp是我们用于访问类的对象名称,我只是随意命名的(我不太擅长命名)。保存文件并再次运行 .NET。这是我们最终的版本,姑且这么说。

在接触模块前,先释放静电,然后将手指放在温度模块上,您应该会看到温度每 2 秒上升一次。您可以根据需要更改计时器。为避免每次都进行构建,我们将发布我们的程序。在终端中,运行

dotnet publish -r linux-arm -c Release -o /home/pi/tempserver/publish -p:PublishSingleFile=true
(after a minute or so)
Copyright (C) Microsoft Corporation. All rights reserved.

  Determining projects to restore...
  Restored /home/pi/tempserver/tempserver.csproj (in 378 ms).
  tempserver -> /home/pi/tempserver/bin/Release/net5.0/linux-arm/tempserver.dll
  tempserver -> /home/pi/tempserver/bin/Release/net5.0/linux-arm/tempserver.Views.dll
  tempserver -> /home/pi/tempserver/publish/

这将创建一个名为tempserver的可执行文件,位于publish目录中。该目录包含

-rw-r--r--  1 pi pi  195 Dec 25 11:00 appsettings.Development.json
-rw-r--r--  1 pi pi  192 Dec 25 11:00 appsettings.json
-rwxr-xr-x  1 pi pi  78M Jan  2 17:48 tempserver
-rw-r--r--  1 pi pi  22K Jan  2 17:48 tempserver.pdb
-rw-r--r--  1 pi pi  20K Jan  2 17:48 tempserver.Views.pdb
drwxr-xr-x  3 pi pi 4.0K Jan  2 17:48 wwwroot

请注意tempserver可执行文件的大小。78 兆。它包含 DLL 等。

可执行文件位于publish文件夹中(默认),您可以在publish命令中指定其他文件夹。

要运行它,我们

cd ./publish
./tempserver 
info: Microsoft.Hosting.Lifetime[0]
      Now listening on: http://[::]:5000
info: Microsoft.Hosting.Lifetime[0]
      Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
      Hosting environment: Production
info: Microsoft.Hosting.Lifetime[0]
      Content root path: /home/pi/tempserver/publish

再次

现在您可以从 LAN 上的任何设备访问它,无需 VS Code,只需 SSH 登录到 Pi 启动,或者将其添加到启动程序中。

我的 CS 教授过去常说:“作为学生的练习”,添加一个文本框,允许用户选择数据刷新延迟时间。我为了测试将其设置为 2 秒。请自行尝试。

结论

在我们的 Pi 上安装 .NET 后,我们就可以使用 Blazor 和 C# 创建 Web 服务器了。Pi 的资源有限,但我发现性能是可以接受的。

关于 I2C 的一些注意事项。总线对电容敏感,比对电阻更敏感。这导致了距离和可连接设备数量的限制。您可以尝试通过改变上拉电阻来解决其中一些问题,但我更喜欢使用一个通过 Cat 5 (或以上) 电缆连接的 I2C 扩展器。对于较短的距离,您也可以使用多路复用器来增加地址并分离数据和时钟线。

© . All rights reserved.