SerialPort串口编程

从Microsoft .Net 2.0版本以后,就默认提供了System.IO.Ports.SerialPort类,用户可以非常简单地编写少量代码就完成串口的信息收发程序。 串口端口号搜索 string[] portList = System.IO.Ports.SerialPort.GetPortNames(); for (int i = 0; i < portList.Length; i++) { string name = portList[i]; comboBox.Items.Add(name); } 串口属性参数设置 SerialPort mySerialPort = new SerialPort("COM2");//端口 mySerialPort.BaudRate = 9600;//波特率 mySerialPort.Parity = Parity.None;//校验位 mySerialPort.StopBits = StopBits.One;//停止位 mySerialPort.DataBits = 8;//数据位 mySerialPort.Handshake = Handshake.Non; mySerialPort.ReadTimeout = 1500; mySerialPort.DtrEnable = true;//启用数据终端就绪信息 mySerialPort.Encoding = Encoding.UTF8; mySerialPort.ReceivedBytesThreshold = 1;//DataReceived触发前内部输入缓冲器的字节数 mySerialPort.DataReceived += new SerialDataReceivedEvenHandler(DataReceive_Method); mySerialPort.Open(); 串口发送信息 // Write a string port.Write("Hello World"); // Write a set of bytes port.Write(new byte[] { 0x0A, 0xE2, 0xFF }, 0, 3); // Close the port port.Close(); 串口接收信息 string serialReadString; private void port_DataReceived(object sender, SerialDataReceivedEventArgs e) { serialReadString = port.ReadExisting()); this.txt1.Invoke( new MethodInvoker(delegate { this.txt1.AppendText(serialReadString); })); } 循环接收数据 void com_DataReceived(object sender, SerialDataReceivedEventArgs e) { // Use either the binary OR the string technique (but not both) // Buffer and process binary data while (com.BytesToRead > 0) bBuffer.Add((byte)com.ReadByte()); ProcessBuffer(bBuffer); // Buffer string data sBuffer += com.ReadExisting(); ProcessBuffer(sBuffer); } private void ProcessBuffer(string sBuffer) { // Look in the string for useful information // then remove the useful data from the buffer } private void ProcessBuffer(List<byte> bBuffer) { // Look in the byte array for useful information // then remove the useful data from the buffer }

2025年7月22日 · 1 分钟 · 196 字

STAThread

[STAThread] STAThread:Single Thread Apartment Thread.(单一线程单元线程) []是用来表示Attributes; [STAThread] 是一种线程模型,用在程序的入口方法上(在C#和VB.NET里是Main()方法),来指定当前线程的ApartmentState 是STA。用在其他方法上不产生影响。在aspx页面上可以使用AspCompat = “true” 来达到同样的效果。这个属性只在 Com Interop 有用,如果全部是 managed code 则无用。简单的说法:[STAThread]指示应用程序的默认线程模型是单线程单元 (STA)。启动线程模型可设置为单线程单元或多线程单元。如果未对其进行设置,则该线程不被初始化。也就是说如果你用的.NET Framework,并且没有使用COM Interop,一般不需要这个Attribute。其它的还有MTA(多线程套间)、Free Thread(自由线程)。 [STAThread] attribute指示应用程序的 COM 线程模型是单线程单元。 而于此对应的多线程单元则是 [MTAThread] (多线程单元线程) COM 线程模型只适用于使用 COM interop 的应用程序。如果将此属性应用到不使用 COM interop 的应用程序,将没有任何效果。 COM 线程模型可设置为单线程单元或多线程单元。如果应用程序线程实际调用了 COM 组件,则仅为 COM interop 初始化该线程。如果没有使用 COM interop,则不初始化该线程。

2025年7月22日 · 1 分钟 · 46 字

如何对搜索结果同时选中并编辑

使用快捷键:CTRL+SHIFT+L 示例:我们有下面多条链接,现在我们需要将链接中的181、182…数字找出来,并替换成110; 第一步:按下CTRL+F 并在右上角启用正则表达式 输入匹配规则(这一步在解决本文的问题中,并不重要,重要的是第二步) 第二步:点击界面空白处(这一步是为了不让光标还在搜索框中),按下CTRL+SHIFT+L 快捷键 当我们要批量操作目标字符串时:在完成了查找这个过程后,如何全部选中目标是我们最关心的,(CTRL+SHIFT+L帮我们解决了这个问题),至于选中后我们是"复制(CTRL+C)“还是直接批量修改便不是问题了。

2025年7月22日 · 1 分钟 · 8 字

.ctor&.cctor&对象的构造过程

.ctor 构造函数,在类被实例化时,它会被自动调用。 .cctor 类型初始化器,是一个静态方法,无参数无返回值,不能直接调用,最多只有一个 在继承中对象构造过程,看下面这段程序: public class A { public int x = 1; public A() { m1(); } public void m1() { } } public class B : A { public int y = 2; public static string sb = "B"; public B() { m2(); } public void m2() { } } public class C : B { public int z = 3; public static string sc = "C"; public C() { m3(); } public void m3() { } } 可以看到三者都有一个.ctor,B、C中有.cctor,而A没有,打开B,C的.cctor,可以看到它们都负责初始化自己的静态字段,现在主要来看它们的.ctor。 总结 .ctor是构造方法; .cctor是类型初始化器,在C#中也就是静态构造函数; 当类C实例化时,会先对声明时就进行赋值的字段赋值,然后调用基类的构造函数,基类再以同样的方法构造自己,一直到顶层的System.Object,然后再回来执行C的显式构造方法中的代码,就是这么一个递归的过程。

2025年7月22日 · 1 分钟 · 86 字

CS0006未能找到元数据文件

在不同的解决方案中把一个项目搬来搬去,终于出现了传说的CSC : error CS0006。 编译的时候总是提示一个引用中不存在的项找不到元数据文件。 无论怎样删除项目,删除引用都没法通过生成。 解决方案 找到自己的xxx.csproj项目文件 以文本的方式打开改文件 找到包含出问题的引用项所在的项,整个删除此项。

2025年7月22日 · 1 分钟 · 10 字

csharp中的析构函数

析构函数 析构函数(destructor) 与构造函数相反,当对象脱离其作用域时(例如对象所在的函数已调用完毕),系统自动执行析构函数。析构函数往往用来做“清理善后” 的工作(例如在建立对象时用new开辟了一片内存空间,应在退出前在析构函数中用delete释放)。 以C++语言为例,析构函数名也应与类名相同,只是在函数名前面加一个波浪符~,例如~stud( ),以区别于构造函数。它不能带任何参数,也没有返回值(包括void类型)。只能有一个析构函数,不能重载。如果用户没有编写析构函数,编译系统会自动生成一个缺省的析构函数,它也不进行任何操作。所以许多简单的类中没有用显式的析构函数。 解构器 我们知道,‘解构器’被用来清除类的事例。当我们在C#中使用解构器是,我们必须记住以下几点: 一个类只能有一个解构器。 解构器不能被继承或重载。 解构器不能被调用。他们是自动被(编译器)调用的。 解构器不能带修饰或参数。 下面是类MyClass解构器的一个声明: ~ Class() { //Cleaning up code goes here } 程序员不能控制解构器何时将被执行因为这是由垃圾收集器决定的。垃圾收集器检查不在被应用程序使用的对象。它认为这些条件是符合清楚的并且收回它们的内存。解构器也在程序退出时被调用。当解构器执行时其背后所发生的那一幕是解构器隐式调用对象基类的Object.Finalize方法。因此上述解构器代码被隐含转化成: protected override void Finalize() { try { //Cleaning up. } finally { base.Finalize(); } } 使用完对象你就想调用解构器,该怎么做?有两个方法: 调用垃圾搜集器来清理GC.Collect(); 。 实现IDisposable的Dispose方法。 尽管如此我们花费一些时间实现IDisposable接口,如果不能合适地调用它们会怎样?为此C#有一个酷的解决方案。‘using’代码块。它看起来像这样: using (MyClass objCls =new MyClass()) { } https://www.cnblogs.com/paper/archive/2009/07/31/1535998.html

2025年7月22日 · 1 分钟 · 51 字

csharp互操作

Platform Invoke(P/Invoke),即平台调用,主要用于调用C库函数和Windows API using System; // 使用平台调用技术进行互操作性之前,首先需要添加这个命名空间 using System.Runtime.InteropServices; namespace 平台调用Demo { class Program { // 在托管代码中对非托管函数进行声明,并且附加平台调用所需要属性 // 在默认情况下,CharSet为CharSet.Ansi // 指定调用哪个版本的方法有两种——通过DllImport属性的CharSet字段和通过EntryPoint字段指定 // 在托管函数中声明注意一定要加上 static 和extern 这两个关键字 [DllImport("user32.dll")] public static extern int MessageBox1(IntPtr hWnd, String text, String caption, uint type); // 在默认情况下,CharSet为CharSet.Ansi [DllImport("user32.dll")] public static extern int MessageBoxA(IntPtr hWnd, String text, String caption, uint type); // 在默认情况下,CharSet为CharSet.Ansi [DllImport("user32.dll")] public static extern int MessageBox(IntPtr hWnd, String text, String caption, uint type); // 第一种指定方式,通过CharSet字段指定 [DllImport("user32.dll", CharSet = CharSet.Unicode)] public static extern int MessageBox2(IntPtr hWnd, String text, String caption, uint type); // 通过EntryPoint字段指定 [DllImport("user32.dll", EntryPoint="MessageBoxA")] public static extern int MessageBox3(IntPtr hWnd, String text, String caption, uint type); [DllImport("user32.dll", EntryPoint = "MessageBoxW")] public static extern int MessageBox4(IntPtr hWnd, String text, String caption, uint type); static void Main(string[] args) { // 在托管代码中直接调用声明的托管函数 // 使用CharSet字段指定的方式,要求在托管代码中声明的函数名必须与非托管函数名一样 // 否则就会出现找不到入口点的运行时错误 //MessageBox1(new IntPtr(0), "Learning Hard", "欢迎", 0); // 下面的调用都可以运行正确 //MessageBoxA(new IntPtr(0), "Learning Hard", "欢迎", 0); //MessageBox(new IntPtr(0), "Learning Hard", "欢迎", 0); // 使用指定函数入口点的方式调用 //MessageBox3(new IntPtr(0), "Learning Hard", "欢迎", 0); // 调用Unicode版本的会出现乱码 MessageBox4(new IntPtr(0), "Learning Hard", "欢迎", 0); } } } C++ Introp, 主要用于Managed C++(托管C++)中调用C++类库 第二部分主要向大家介绍了第一种互操作性技术,然后我们也可以使用C++ Interop技术来实现与非托管代码进行交互。 然而C++ Interop 方式有一个与平台调用不一样的地方,就是C++ Interop 允许托管代码和非托管代码存在于一个程序集中,甚至同一个文件中。 C++ Interop 是在源代码上直接链接和编译非托管代码来实现与非托管代码进行互操作的,而平台调用是加载编译后生成的非托管DLL并查找函数的入口地址来实现与非托管函数进行互操作的。 C++ Interop使用托管C++来包装非托管C++代码,然后编译生成程序集,然后再托管代码中引用该程序集,从而来实现与非托管代码的互操作。 ...

2025年7月22日 · 2 分钟 · 261 字

不能在控制元件上呼叫Invoke

在Window窗體程式開發的時候,如果使用多執行緒程式設計,在子執行緒中訪問主執行緒窗體內的控制元件,就需要使用控制元件的Control.Invoke方法或者BeginInvoke方法。但是有時候因為Window執行速度太快,尤其是你寫程式碼的時候在InitializeComponent();完成之前起了一個執行緒去執行某些操作,涉及到窗體控制元件的,當你在呼叫Control.Invoke的時候,就可能出現 “在建立視窗控制代碼之前,不能在控制元件上呼叫 Invoke 或 BeginInvoke 解決的辦法就是讓執行緒等待,直到視窗控制代碼建立完畢: while (!this.IsHandleCreated) { ; } this.BeginInvoke(new ProListIndexChangedDelegate(GetProLyric)); //根據不同情況也可以: if (this.IsHandleCreated) BeginInvoke(new ProListIndexChangedDelegate(GetProLyric)); 有一個更巧妙的方法,只要在BeginInvoke方法的呼叫語句前再加一句:IntPtr i = this.Handle;就OK了,這比死迴圈配合this.IsHandleCreated的判斷方法更簡潔,因為this.Handle這個屬性本身就對應一個方法,取不到控制代碼,程式就不會向下進行。

2025年7月22日 · 1 分钟 · 22 字

tesseract使用

怎么开始使用? Q:这个开源库要怎么开始使用?https://github.com/tesseract-ocr/tesseract A:要开始使用Tesseract OCR开源库,您需要经过以下几个步骤: 下载与安装Tesseract 访问Tesseract的GitHub页面: https://github.com/tesseract-ocr/tesseract 根据您的操作系统选择合适的安装方法。对于Windows用户,您可以直接下载预编译的可执行文件,通常推荐从UB Mannheim的发布页面下载稳定版本:Tesseract Releases 设置环境变量 添加Tesseract可执行文件的路径到系统的PATH环境变量中,以便在命令行任何位置调用tesseract命令。 同样,需要设置TESSDATA_PREFIX环境变量指向包含tessdata文件夹的路径,该文件夹内存储了语言数据包 安装语言数据包 Tesseract需要相应的语言数据包才能进行识别。您可以从这里下载所需的语言包(.traineddata文件)。 将下载的.traineddata文件放置到<TESSDATA_PREFIX>/tessdata目录下。例如,对于英文识别,您需要eng.traineddata。 测试安装 打开命令提示符或终端,输入 tesseract –version 来确认Tesseract已成功安装及其版本信息。 运行 tesseract –list-langs 来查看已安装的语言包列表。 使用Tesseract进行识别 基本命令格式为:tesseract <input_image> <output_text> [-l ] <input_image> 是您要识别的图片文件路径。 <output_text> 是输出文本文件的名称。 -l 是指定识别的语言,默认为英文。 在C#项目中集成Tesseract 要在C#项目中使用Tesseract,您可以使用第三方封装库,如Tesseract.SPI或Tesseract。首先,在Visual Studio中打开您的项目,然后通过NuGet包管理器安装这些库之一。 Install-Package Tesseract -Version 4.1.1 接着,按照前面提到的C#示例代码来调用Tesseract进行OCR识别。 通过以上步骤,您就可以开始在您的项目中使用Tesseract OCR进行文字识别了。记得根据实际需求调整配置以优化识别效果。 test D:\Tesseract-OCR>tesseract.exe --version tesseract v5.4.0.20240606 leptonica-1.84.1 libgif 5.2.1 : libjpeg 8d (libjpeg-turbo 3.0.1) : libpng 1.6.43 : libtiff 4.6.0 : zlib 1.3 : libwebp 1.4.0 : libopenjp2 2.5.2 Found AVX512BW Found AVX512F Found AVX512VNNI Found AVX2 Found AVX Found FMA Found SSE4.1 Found libarchive 3.7.4 zlib/1.3.1 liblzma/5.6.1 bz2lib/1.0.8 liblz4/1.9.4 libzstd/1.5.6 D:\Tesseract-OCR>tesseract --version tesseract v5.4.0.20240606 leptonica-1.84.1 libgif 5.2.1 : libjpeg 8d (libjpeg-turbo 3.0.1) : libpng 1.6.43 : libtiff 4.6.0 : zlib 1.3 : libwebp 1.4.0 : libopenjp2 2.5.2 Found AVX512BW Found AVX512F Found AVX512VNNI Found AVX2 Found AVX Found FMA Found SSE4.1 Found libarchive 3.7.4 zlib/1.3.1 liblzma/5.6.1 bz2lib/1.0.8 liblz4/1.9.4 libzstd/1.5.6 D:\Tesseract-OCR>tesseract --list-langs List of available languages in "D:\Tesseract-OCR/tessdata/" (7): chi_sim chi_sim_vert chi_tra chi_tra_vert eng enm osd D:\Tesseract-OCR>tesseract D:\Tesseract-OCR\input\test.png test.txt -l eng D:\Tesseract-OCR>tesseract D:\Tesseract-OCR\input\testforchs.png D:\Tesseract-OCR\output\testforchs -l chi_sim

2025年7月21日 · 1 分钟 · 172 字

使用CustomEvent polyfill来触发自定义事件

下面是一个完整的示例,展示了如何在ES5环境中使用CustomEvent polyfill来触发自定义事件: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Custom Event Example in ES5</title> </head> <body> <button id="myButton">Click me!</button> <script> if (!window.CustomEvent) { (function() { function CustomEvent(event, params) { params = params || { bubbles: false, cancelable: false, detail: undefined }; var evt = document.createEvent('CustomEvent'); evt.initCustomEvent(event, params.bubbles, params.cancelable, params.detail); return evt; } CustomEvent.prototype = window.Event.prototype; window.CustomEvent = CustomEvent; })(); } var button = document.getElementById('myButton'); // 创建并分发事件 button.addEventListener('click', function() { var myEvent = new CustomEvent('myCustomEvent', { detail: { message: 'Hello from the custom event!' }, bubbles: true, cancelable: true }); button.dispatchEvent(myEvent); }); // 注册事件监听器 button.addEventListener('myCustomEvent', function(event) { console.log('Custom event received'); console.log('Detail data:', event.detail); }); </script> </body> </html> 在这个示例中,当用户点击按钮时,会触发myCustomEvent事件,控制台将输出事件的详细信息。这种方法确保了在ES5环境下的广泛兼容性。

2025年7月21日 · 1 分钟 · 107 字