【YFIOs】用C#开发硬件之串口通信

YFIOs文档源链接:https://docs.yfios.net/docs/sdk/yfesp32s3-sdk/serial-communication

概述

串口通信是嵌入式系统中最常用的数据传输方式之一。YF3300-ESP32S3 开发板提供了 2 个串口:RS232 和 RS485,用于与外部设备进行数据通信。本章节将介绍如何使用 nanoFramework 进行串口编程。

所需 NuGet 包

在 nanoFramework 项目中使用串口需要引用以下包:

包名 说明
nanoFramework.CoreLibrary 基础类库(通常自动包含)
nanoFramework.System.IO.Ports 串口操作核心库
nanoFramework.Hardware.Esp32 ESP32 硬件配置库(用于引脚映射)

注意 :串口通信不需要 引用 nanoFramework.System.Device.Gpio 库。引脚映射通过 nanoFramework.Hardware.Esp32.Configuration.SetPinFunction() 完成,而非 GPIO 控制器。

核心概念

SerialPort 类

SerialPort 是 nanoFramework 中串口操作的核心类,主要属性和方法:

硬件连接说明

YF3300-ESP32S3 开发板提供 2 个串口

串口类型 端口名 TX 引脚 RX 引脚 默认波特率
RS232 COM2 GPIO11 GPIO12 9600
RS485 COM1 GPIO9 GPIO10 9600

串口使用示例

YF3300_ESP32S3.cs

csharp 复制代码
using System;

namespace YFSoft.Hardware.YF3300_ESP32S3
{
    public static class CPU
    {
        public static class Pins
        {
            public const int GPIO9 = 9;
            public const int GPIO10 = 10;
            public const int GPIO11 = 11;
            public const int GPIO12 = 12;
        }
    }

    public static class Mainboard
    {
        // RS485 串口定义
        public static class RS485
        {
            public const string PortName = "COM1";
            public const int DefaultBaudRate = 9600;
            public const int TxPin = CPU.Pins.GPIO9;        // UART1 TX (电路图: TX1=IO9)
            public const int RxPin = CPU.Pins.GPIO10;       // UART1 RX (电路图: RX1=IO10)
        }

        // RS232 串口定义
        public static class RS232
        {
            public const string PortName = "COM2";
            public const int DefaultBaudRate = 9600;
            public const int TxPin = CPU.Pins.GPIO11;       // UART2 TX (电路图: TX2=IO11)
            public const int RxPin = CPU.Pins.GPIO12;       // UART2 RX (电路图: RX2=IO12)
        }
    }
}

Program.cs

csharp 复制代码
using System;
using System.Diagnostics;
using System.Text;
using System.Threading;
using System.IO.Ports;
using YFSoft.Hardware.YF3300_ESP32S3;
using nanoFramework.Hardware.Esp32;

namespace SerialPortTest
{
    public class Program
    {
        // 串口实例
        private static SerialPort _rs232Port;
        private static SerialPort _rs485Port;

        public static void Main()
        {
            Debug.WriteLine("YF3300-ESP32S3 串口测试程序启动");

            try
            {
                // 初始化 RS232
                InitializeRS232();

                // 初始化 RS485
                InitializeRS485();

                // 发送打招呼消息
                SendGreeting();

                // 启动回显线程
                StartEchoLoop();

            }
            catch (Exception ex)
            {
                Debug.WriteLine($"初始化失败: {ex.Message}");
            }

            Thread.Sleep(Timeout.Infinite);
        }

        // 初始化 RS232 串口
        private static void InitializeRS232()
        {
            Debug.WriteLine($"配置 RS232 引脚: Tx={Mainboard.RS232.TxPin}, Rx={Mainboard.RS232.RxPin}");
            
            // 配置 RS232 串口引脚映射 (COM2)
            // 在创建 SerialPort 实例之前配置引脚
            Configuration.SetPinFunction(Mainboard.RS232.TxPin, DeviceFunction.COM2_TX);
            Configuration.SetPinFunction(Mainboard.RS232.RxPin, DeviceFunction.COM2_RX);

            Debug.WriteLine("创建 RS232 SerialPort 实例...");
            _rs232Port = new SerialPort(
                Mainboard.RS232.PortName,
                Mainboard.RS232.DefaultBaudRate,
                Parity.None,
                8,
                StopBits.One);

            Debug.WriteLine("打开 RS232 串口...");
            _rs232Port.Open();
            Debug.WriteLine($"RS232 已初始化: {Mainboard.RS232.PortName} @ {Mainboard.RS232.DefaultBaudRate}");
        }

        // 初始化 RS485 串口
        private static void InitializeRS485()
        {
            Debug.WriteLine($"配置 RS485 引脚: Tx={Mainboard.RS485.TxPin}, Rx={Mainboard.RS485.RxPin}");
            
            // 配置 RS485 串口引脚映射 (COM1)
            // 在创建 SerialPort 实例之前配置引脚
            Configuration.SetPinFunction(Mainboard.RS485.TxPin, DeviceFunction.COM1_TX);
            Configuration.SetPinFunction(Mainboard.RS485.RxPin, DeviceFunction.COM1_RX);

            Debug.WriteLine("创建 RS485 SerialPort 实例...");
            _rs485Port = new SerialPort(
                Mainboard.RS485.PortName,
                Mainboard.RS485.DefaultBaudRate,
                Parity.None,
                8,
                StopBits.One);

            Debug.WriteLine("打开 RS485 串口...");
            _rs485Port.Open();
            Debug.WriteLine($"RS485 已初始化: {Mainboard.RS485.PortName} @ {Mainboard.RS485.DefaultBaudRate}");
        }

        // 发送打招呼消息
        private static void SendGreeting()
        {
            string greeting = "Hello from YF3300-ESP32S3!\r\n";
            byte[] data = Encoding.UTF8.GetBytes(greeting);

            // RS232 发送
            _rs232Port.Write(data, 0, data.Length);
            Debug.WriteLine("RS232 打招呼消息已发送");

            // RS485 发送
            _rs485Port.Write(data, 0, data.Length);
            Debug.WriteLine("RS485 打招呼消息已发送");
        }


        // 启动回显循环
        private static void StartEchoLoop()
        {
            Debug.WriteLine("进入回显模式...");
            Debug.WriteLine("RS232 和 RS485 会回显收到的所有数据");

            // 启动 RS232 回显线程
            new Thread(RS232EchoLoop).Start();

            // 启动 RS485 回显线程
            new Thread(RS485EchoLoop).Start();
        }

        // RS232 回显循环
        private static void RS232EchoLoop()
        {
            byte[] buffer = new byte[256];
            Debug.WriteLine("RS232 回显线程已启动");

            while (true)
            {
                try
                {
                    int bytesAvailable = _rs232Port.BytesToRead;
                    
                    if (bytesAvailable > 0)
                    {
                        Debug.WriteLine($"RS232 有 {bytesAvailable} 字节待读取");
                        int bytesRead = _rs232Port.Read(buffer, 0, bytesAvailable);

                        if (bytesRead > 0)
                        {
                            // 回显数据
                            _rs232Port.Write(buffer, 0, bytesRead);

                            // 输出调试信息
                           string received = Encoding.UTF8.GetString(buffer, 0, bytesRead);
                           Debug.WriteLine($"RS232 收到 {bytesRead} 字节: {received}");
                        }
                    }

                    Thread.Sleep(10);
                }
                catch (Exception ex)
                {
                    Debug.WriteLine($"RS232 回显错误: {ex.Message}");
                }
            }
        }

        // RS485 回显循环
        private static void RS485EchoLoop()
        {
            byte[] buffer = new byte[256];
            Debug.WriteLine("RS485 回显线程已启动");

            while (true)
            {
                try
                {
                    int bytesAvailable = _rs485Port.BytesToRead;
                    
                    if (bytesAvailable > 0)
                    {
                        Debug.WriteLine($"RS485 有 {bytesAvailable} 字节待读取");
                        int bytesRead = _rs485Port.Read(buffer, 0, bytesAvailable);

                        if (bytesRead > 0)
                        {
                            // 回显数据(自动流向控制,无需手动切换)
                            _rs485Port.Write(buffer, 0, bytesRead);

                            // 输出调试信息
                           string received = Encoding.UTF8.GetString(buffer, 0, bytesRead);
                            Debug.WriteLine($"RS485 收到 {bytesRead} 字节: {received}");
                        }
                    }

                    Thread.Sleep(10);
                }
                catch (Exception ex)
                {
                    Debug.WriteLine($"RS485 回显错误: {ex.Message}");
                }
            }
        }
    }
}
相关推荐
于先生吖2 小时前
同城物流创业项目,Java源码搭建多车型搬家拉货、就近配货预约小程序
java·开发语言·小程序
码不停蹄的玄黓2 小时前
Java 异常分类
java·开发语言
牛油果子哥q2 小时前
【C++前置声明与头文件】C++前置声明与头文件深度精讲:重复包含、循环依赖、重复定义报错、工程编译架构与实战解决方案
开发语言·c++
-凌凌漆-2 小时前
Qt QML应用层框架
开发语言·qt
少司府2 小时前
C++进阶:map和set的使用
开发语言·数据结构·c++·容器·stl·set·map
江湖中的阿龙2 小时前
23种设计模式
java·开发语言·设计模式
xiaoshuaishuai82 小时前
C# Avaloniaui ListBox样式及用法
开发语言·c#
天才程序YUAN2 小时前
Windows 11 C 盘扩容完整教程:恢复分区拦路、页面文件锁盘、WinRE 重建全记录
c语言·开发语言·windows
川冰ICE2 小时前
JavaScript进阶③|Map_Set_WeakMap_WeakSet,新型数据结构
开发语言·javascript·数据结构