Tuesday, August 5

MCP2200 with Visual C# 2010 express

        ในบางครั้ง เรามีความจำเป็นต้องทำปุ่มกดพิเศษขึ้นมานอกเหนือจากการใช้แป้นจากคีย์บอร์ดคอมพิวเตอร์ปกติ เพื่อให้โปรแกรมที่เราเขียนขึ้นมาเองทำงานฟังก์ชั่นพิเศษ หรือในบางงานเราอาจจะไม่สะดวกที่จะให้ User ทำการกดบนแป้นคีย์บอร์ด แต่ อยากให้มีปุ่มที่ทำงานเฉพาะเพื่อรับค่าการกดปุ่ม แล้วนำไปประมวลผลต่อในโปรแกรม

       วันนี้ ผมมีตัวอย่างง่ายๆ ด้วยการรับค่าจากปุ่มกด Push button แบบกดติดปล่อยดับ โดยต่อเข้ากับอินพุตพอร์ตของไอซี MCP2200 ของทางบริษัทไมโครชิพ แล้วให้โปรแกรมที่เขียนด้วย C# มาอ่านค่าจากพอร์ต GPIO ของ MCP2200 และแสดงค่าบนหน้าต่างโปรแกรมของเรา

      ไม่ขอกล่าวถึงรายละเอียดของ MCP2200 มากนัก ซึ่งเราสามารถหาอ่านรายละเอียดได้จากเว็บ www.microchip.com ได้เลย เพียงแต่จะบอกรายละเอียดย่อๆ ไว้  แท้จริงแล้ว MCP2200 นั้นก็คือ ไมโครคอนโทรลเลอร์เบอร์ 18F14K50 ที่ได้บรรจุ firmware ที่ทำหน้าที่เป็น USB to Serial converter ไว้แล้ว นอกจากนี้ ยังมี GPIO เหลือให้ใช้อีก จำนวนหนึ่ง (ไม่เกิน 8 pin) และยังสามารถเรียกใช้หน่วยความจำ EEPROM ให้ใช้ได้อีก 256 byte  แต่ในตัวอย่างที่ผมจะทดสอบให้ดูวันนี้ เป็นแค่การเรียกใช้ GPIO2 - GPIO5 ของมันเท่านั้น

ทำการต่อวงจรตามรูป

MCP2200 with Visual C# 2010

เสร็จแล้วทดลองจ่ายไฟเข้าบอร์ดผ่านทางสาย USB ถ้าวงจรที่เราทำนั้นทำงานได้ปกติ ตัว Windows เองจะพยายามทำการติดตั้ง Driver ให้เราทำการโหลด Driver จากเว็บแล้วติดตั้งลงไป ตรงนี้ไม่ขออธิบายมากนัก ก็เหมือนๆ กับการติดตั้ง Driver ทั่วๆไป
http://www.microchip.com/wwwproducts/devices.aspx?dDocName=en546923

เสร็จแล้ว ลองทดสอบด้วยการเปิดโปรแกรม MCP2200 Configuration Utility v1.3.1 โหลดได้จากที่นี่ เหมือนกัน

http://www.microchip.com/wwwproducts/devices.aspx?dDocName=en546923

หากสามารถเชื่อมต่อไป โปรแกรมจะแสดงคำว่า Connected ที่ด้านล่าง ตามรูป

MCP2200 with Visual C# 2010

ปิดโปรแกรมไป ทีนี้ เราจะมาสร้าง Windows application เพื่ออ่านค่าจาก push button ที่เราต่อไว้กับ GPIO2, GPIO3, GPIO4, GPIO5 ของ MCP2200 เพื่ออ่านค่าสถานะ push button แล้วแสดงค่าบนฟอร์มที่เราออกแบบไว้บน Visual C# 2010 express

หน้าต่างโปรแกรม ครับ

MCP2200 with Visual C# 2010

ทำการ add reference ไฟล์ SimpleIO-M.dll ซึ่งต้องไปดาวน์โหลดที่

http://ww1.microchip.com/downloads/en/DeviceDoc/MCP2200_DLL_2013-01-28.zip

จากนั้นแตกไฟล์ออก ไฟล์จะอยู่ที่โฟวเดอร์ Managed\ เนื่องจากเราพัฒนาโปรแกรมด้วย Visual C# ซึ่งมองว่าเป็นแบบ Managed code แล้ว add reference ไปใส่ในโปรเจค C# ของเรา และในโฟวเดอร์เดียวกันนี้ เขาจะมีไฟล์ SimpleIO DLL (Managed) User Manual.pdf ให้เรา เพื่ออธิบายการทำงานแต่ละ method ศึกษาเพิ่มเติมได้จากนี่แหละครับ

ทำการ using SimpleIO; เพื่อเรียกใช้ class ใน namespace  แล้วทำการเขียนโค๊ด

อธิบายการทำงานของโปรแกรม
ทำการ Initial constructor ของ SimpleIOClass ด้วยการกำหนดค่า VID, PID ที่ได้จากการตั้งค่าจากโปรแกรม MCP2200 Configuration Utility v1.3.1
Timer1 ทำหน้าอ่านค่าสถานะของ push button ที่ต่ออยู่กับ GPIO ทุกๆ 200ms
ทำการอ่านค่า Port ด้วยเมธอด SimpleIOClass.ReadPort ซึ่งจากให้ค่าเป็นแบบ One-at-a-time มีลักษณะเปลี่ยนแปลงแบบครั้งเดียว ไม่คงค่าไว้ ดังนั้นเราจึงต้องใช้ Timer1 ช่วยในการ sampling ตลอดเวลา

================= โค๊ด==========================

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using SimpleIO;

namespace SimpleMCP2200
{   
    public partial class Form1 : Form
    {
        const uint mcp2200_VID = 0x04D8;
        const uint mcp2200_PID = 0x00DF;
        bool isConnected = false;
        public Form1()
        {
            InitializeComponent();
            SimpleIOClass.InitMCP2200(mcp2200_VID, mcp2200_PID);
            timer1.Interval = 200;
            timer1.Stop();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            isConnected = SimpleIOClass.IsConnected();
            if (isConnected)
            {
                connectedLabel.Text = "The device is connected";
                connectedLabel.ForeColor = Color.Green;
                if (SimpleIOClass.ConfigureIO(0xFF))
                {
                    configLabel.Text = "Success";
                    configLabel.ForeColor = Color.Green;
                    timer1.Start();
                }
                else
                {
                    configLabel.Text = "Invalid command";
                    configLabel.ForeColor = Color.Red;
                }

            }
            else
            {
                connectedLabel.Text = "The device is NOT connected";
                connectedLabel.ForeColor = Color.Red;
                errorReadPortLabel.Text = "Read port Fail";
                errorReadPortLabel.ForeColor = Color.Red;
                configLabel.Text = "Not config";
                configLabel.ForeColor = Color.Red;
            }
        }

        private void timer1_Tick(object sender, EventArgs e)
        {          
            unsafe
            {
                uint add = 0x00;
                uint* returnValue = &add;
                if (SimpleIOClass.ReadPort(returnValue))
                {
                    int ret = SimpleIOClass.ReadPortValue();
                    if (ret != 0x8000)
                    {
                        errorReadPortLabel.Text = "Read port Success";
                        errorReadPortLabel.ForeColor = Color.Green;
                        readPortValueTextBox.Text = String.Format("{0:x2}", ret);
                        readPortValueTextBox.Text = String.Concat("0x",readPortValueTextBox.Text.ToUpper());
                        switch(ret)
                        {
                            case 0x00FB:
                                gpio2Label.Text = "ON";
                                break;
                            case 0x00F7:
                                gpio3Label.Text = "ON";
                                break;
                            case 0x00EF:
                                gpio4Label.Text = "ON";
                                break;
                            case 0x00DF:
                                gpio5Label.Text = "ON";
                                break;
                            default:
                                gpio5Label.Text = "OFF";
                                gpio4Label.Text = "OFF";       
                                gpio3Label.Text = "OFF";
                                gpio2Label.Text = "OFF";
                                break;
                        }
                       
                    }
                    else
                    {
                        errorReadPortLabel.Text = "Read port Fail";
                        errorReadPortLabel.ForeColor = Color.Red;
                    }
                }               
            }
           
        }

        private void linkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            System.Diagnostics.Process.Start("
http://visual-studio-express-project.blogspot.com/");
        }

    }
}

ทดสอบกด push button แล้วดูการเปลี่ยนแปลงที่หน้าโปรแกรมที่เราสร้างขึ้นมาครับ

MCP2200 with Visual C# 2010

 

หมายเหตุ : Dll ไฟล์นี้ ใช้ได้กับ .NET Framework 3.5  ไม่เกินนี้  ตอน Build project จำเป็นต้องเช็คบ๊อกซ์ Allow unsafe code ด้วย เพราะมีการเรียกใช้ pointer ในโค๊ด

MCP2200 with Visual C# 2010

MCP2200 with Visual C# 2010

โหลดไฟล์โปรเจคของผมไปศึกษากันดูครับ

https://dl.dropboxusercontent.com/u/65353188/SimpleMCP2200.zip

อ่านเพิ่มเติม...

Tuesday, January 28

Emgu.CV.CvInvoke invoke OpenCV function

cvInvoke simple tutorial

    เนื่องด้วยข้อเสียของ Emgu คือ เรื่องเอกสาร Tutorial หาอ่านยากมากๆ (ไม่นับรวม api class referrence) ในเว็บ wiki ของเขาเอง ก็ใช่ว่าจะมีตัวอย่างครบ นั่นอาจจะเป็นเพราะว่า Emgu เอง มันเองเป็น wrapper function ที่ครอบอยู่บน OpenCV อยู่ เลยทำให้ Developer เอง ไม่อยากจะทำ Tutorial ออกมา คงเข้าใจว่า ผู้นำ Emgu ไปใช้ คงมีความรู้พื้นฐานอยู่บ้าง และหากสงสัยใน Class ไหน ก็ให้หาอ่านเอาในเอกสารของ OpenCV หล่ะมั้ง (อันนี้ ผมคิดไปเองนะครับ)

ในเมื่อไม่มีทางเลือกที่จะต้องเรียกใช้ OpenCV Function ตรงๆ ใน .NET แล้ว ทาง Emgu ก็มี CvInvoke ที่จะทำให้เราสามารถเรียกใช้ OpenCV ได้โดยตรง และเมื่อเรียกใช้โดยตรงแล้ว ก็ให้อ้างอิงเอกสารของ OpenCV ได้เลย (ซึ่งมีตัวอย่างการใช้งาน และอื่นๆ ค่อนข้างครบ) เอาหล่ะ เรามาลองเขียน Emgu application โดยใช้ความสามารถของ CvInvoke กันดูครับ

สร้าง win application ขึ้นมา โดยทำตามขั้นตอนแรกๆ Getting started Emgu with Visual C# 2010 Express จากนั้นบนหน้าฟอร์มเปล่าๆ ก็สร้าง button ขึ้นมา 1 อัน แล้วก็เขียนไปบน Event double click ของมัน โดยดับเบิลคลิกที่ปุ่มบนฟอร์ม แล้วเขียนโค๊ดเหล่านี้ลงไป

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

using Emgu.CV;
using Emgu.Util;
using Emgu.CV.Structure;

namespace Emgu_cvInvoke
{
    public partial class Form1 : Form
    {
        MCvScalar color_text = new MCvScalar(255, 255, 255);
        MCvFont font = new MCvFont(Emgu.CV.CvEnum.FONT.CV_FONT_HERSHEY_SIMPLEX, 0.5, 0.5);
        IntPtr img = CvInvoke.cvCreateImage(new Size(200, 200), Emgu.CV.CvEnum.IPL_DEPTH.IPL_DEPTH_8U, 1);

        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            CvInvoke.cvPutText(img, "Hello Emgu", new Point(50, 50), ref font, color_text);
            CvInvoke.cvShowImage("Simple Emgu application", img);
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            CvInvoke.cvDestroyWindow("Simple Emgu application");
            CvInvoke.cvReleaseImage(ref img);
        }
    }
}

จริงๆ แล้ว ตัวอย่างนี้ เราใช้่ cvCreatImage (Creates an image header and allocates the image data ) เป็นแค่การจองหน่วยความจำสำหรับเก็บข้อมูลรูปภาพ แล้วก็ใส่ตัวอักษร ด้วย cvPutText ไปบนพื้นที่ว่างบนรูปภาพ (คือพื้นสีดำว่างๆ นั่นแหละ) โดยกำหนดตำแหน่งข้อความและขนาดและสีของตัวอักษรเท่านั้นเอง 

ซึ่งหากจะเปรียบเทียบรูปแบบฟังก์ชั่นของ cvCreatImage และ cvPutText กับ cvShowImage แล้วจะพบว่า รูปแบบของการใส่ Parameter เข้าไปในฟังก์ชั่นก็ยังเหมือนเดิมในเอกสารของ OpenCV ถึงแม้ว่าเรากำลังเขียนอยู่บน Emgu Framework ก็ตาม เพีิยงแค่เรียก cvInvoke แล้วก็ตามด้วยฟังก์ชั่นบน OpenCV จากนั้นก็เติมพารามิเตอร์ให้ครบตามเอกสาร เท่านี้ เราก็เรียกใช้ OpenCV function ได้แล้วครับ

Emgu.CV.CvInvoke invoke OpenCV function

cvCreateImage

cvPutText

cvShowImage

แล้วทดสอบรันโปรแกรมดูครับ

image

งาน Image Processing บางอย่างเราอาจจะเจอวิธีแก้ไข ด้วย OpenCV Function ซึ่งถ้าหากเราต้องการนำมาใส่ใน Emgu Application ของเรา ก็เพียงเรียกใช้ cvInvoke เข้ามา แล้วก็ปรับแก้นิดหน่อยให้เป็นไปตาม .NET syntax เราก็อาจจะจบงานของเราได้เหมือนกัน ลองเอาไปประยุกต์ดูครับ

แล้วสนุกกับ Emgu นะครับ

ปล. และหากต้องการนำข้อมูลรูปภาพที่อยู่ใน pointer img กลับไปใส่ใน picturebox control ก็สามารถทำได้ ด้วยการใช้ CvInvoke.cvCopy Method โดยปลายทางของข้อมูล อาจจะเป็น bitmap แต่ size และ channel ต้องเท่ากันกับภาพต้นฉบับ และใช้ pointer properties ของตัวแปรปลายทางด้วย

private void button1_Click(object sender, EventArgs e)
{
      Image<Gray, byte> img2 = new Image<Gray, byte>(200,200);
      CvInvoke.cvPutText(img, "Hello Emgu", new Point(50, 50), ref font, color_text);           
      CvInvoke.cvShowImage("Simple Emgu application", img);
      CvInvoke.cvCopy(img, img2.Ptr, IntPtr.Zero);
      pictureBox1.Image = img2.ToBitmap();
   
}

how to create bitmap from image pointer IplImage

how to create bitmap from image pointer IplImage

อ่านเพิ่มเติม...

Passing Values Between Windows Forms

ตัวอย่างการส่งข้อมูลข้ามไปมา ระหว่างฟอร์ม ใน C# วันนี้จะนำเสนอ 3 รูปแบบ อย่างง่ายๆ จริงๆ อาจจะมีรูปแบบมากกว่านี้ แต่ ผมว่า 3 รูปแบบนี้ ก็ใช้งานดีครับ หรือถ้าใครมีรูปแบบอื่นๆ นำเสนอ ก็โพสมาได้เลยครับ

รูปแบบการส่งข้อมูลจากฟอร์มหลัก ไปฟอร์มอื่นๆ 3 รูปแบบดังนี้

- การส่งข้อมูลด้วยวิธี Delegate Method
- Constructor Method
- Function Method

โดยเราจะสร้างรูปแบบการส่งข้อมูลจากฟอร์มหลักที่อยู่ในฟอร์ม 1 แล้วส่งไปหาฟอร์มที่ 2 ,3 และ 4 ในแต่ละรูปแบบ เริ่มจากวางคอมโพเนนต์บนฟอร์มต่างๆ ตามรูป

โค๊ด Form1.cs

Passing Values Between Windows Forms

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace Passing_Values_Between_Windows_Forms
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        // ส่งค่าระหว่างฟอร์ม ด้วยวิธี delegate
        public delegate void SendData(CheckedListBox chkList);
        private void delegateButton_Click(object sender, EventArgs e)
        {
            Form2 frm2 = new Form2();
            SendData send = new SendData(frm2.GetData);
            send(checkedListBox1);
            frm2.Show();
        }

        // ส่งค่าระหว่างฟอร์ม ด้วยวิธี constructor
        private void constructorButton_Click(object sender, EventArgs e)
        {
            Form3 frm3 = new Form3(textBox1.Text);
            frm3.Show();
        }

        // ส่งค่าระหว่างฟอร์ม ด้วยวิธี function
        private void button1_Click(object sender, EventArgs e)
        {
            Form4 frm4 = new Form4();
            frm4.GetData(SendValue());
            frm4.Show();
        }

        public string SendValue()
        {
            return textBox2.Text;
        }
       
        private void linkLabel1_LinkClicked_1(object sender, LinkLabelLinkClickedEventArgs e)
        {
            System.Diagnostics.Process.Start("http://visual-studio-express-project.blogspot.com/");
        }

    }
}

 

โค๊ด Form2.cs

Passing Values Between Windows Forms

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace Passing_Values_Between_Windows_Forms
{
    public partial class Form2 : Form
    {
        public Form2()
        {
            InitializeComponent();
            label1.Text = null;
        }

        public void GetData(CheckedListBox chkList)
        {
            System.Collections.IEnumerator i = chkList.CheckedItems.GetEnumerator();
            while (i.MoveNext())
            {
                label1.Text += i.Current.ToString() + "\n";
            }

        }
    }
}

 

โค๊ด Form3cs

Passing Values Between Windows Forms

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace Passing_Values_Between_Windows_Forms
{
    public partial class Form3 : Form
    {
        public Form3(string data)
        {
            InitializeComponent();
            label1.Text = null;
            label1.Text = data;
        }
    }
}

โค๊ด Form4.cs

Passing Values Between Windows Forms

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace Passing_Values_Between_Windows_Forms
{
    public partial class Form4 : Form
    {
        public Form4()
        {
            InitializeComponent();
        }

        public void GetData(string str)
        {
            label1.Text = str;
        }

        private void Form4_Load(object sender, EventArgs e)
        {

        }
    }
}

เป็นโค๊ดอย่างง่ายๆ ดูแล้วไม่น่างง งั้นผมไม่ขออธิบายนะครับ หุๆๆๆ

อ่านเพิ่มเติม...
 

แจกฟรี พื้นที่ฝากไฟล์ 2 GB

ads

ติดตามข่าวสารผ่าน Twitter

ติดตาม Blog นี้

About Me

My photo

สวัสดีครับ ชื่อเปิ้ลนะครับ ถ้ามีอะไรให้ช่วยเหลือได้ ก็จะช่วยครับ
ผมได้สร้างบล๊อกไว้ เพื่อเก็บรวบรวมความรู้ และประสบการณ์ในการทำงานครับ แวะไปเยี่ยมชมกันได้ครับ http://mechacity.blogspot.com และบล๊อก http://faker-programmer.blogspot.com ครับ

Blog อื่นๆของฉัน

จำนวนการเยี่ยมชมบล๊อก