2011年7月29日星期五

PC 机与Arduino通信--故障

这是我写的第一个像模像样的C#上位机程序,以前除了写过Hello World之外,没有写过超过20行的C#程序,呵呵,Arduino的程序也是。所以出现bug是很正常的。

接线图



上位机的问题就是,当单击停止按钮关闭COMPort之后,整个窗体处于假死状态,不知道是不是跟.Net的读串口需要另开线程有关,由于是新学,这个问题存疑。

Arduino端的程序问题是,通过串口返回给上位机的信息,i+“ | ”+ Value这个木有返回,更严重的是,返回的东西每隔一段时间就会有乱码。

上位机程序代码:

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 System.IO.Ports;
using System.Threading;

namespace WindowsFormsApplication1
{
  
    public partial class frmMain : Form
       {
        int FlashTimes;
        int FlashCounts;
        Label FlashingLED;
        string TextRead;
        public frmMain()
        {
            InitializeComponent();
        }
        private int  FillSerialPorts()
        {
            int PortCount;
            PortCount = 0;
            //加载串口列表
            SerialPort _tempPort;
            String[] Portname = SerialPort.GetPortNames();
            foreach (string str in Portname)
            {
                try
                {
                    _tempPort = new SerialPort(str);
                    _tempPort.Open();
                    if (_tempPort.IsOpen)
                    {
                        cboCOMPorts.Items.Add(str);
                        _tempPort.Close();
                        PortCount++;
                    }
                }
                catch (Exception ex)
                {
                    tsMessage.Text = ex.ToString();
                }

            }
            if (!(PortCount ==0))
                cboCOMPorts.SelectedIndex =0;
            tsCOMPort.Text = cboCOMPorts.Text;
            return PortCount;
        }
        private void trkPWM_ValueChanged(object sender, EventArgs e)
        {
            lblPWM.Text = trkPWM.Value.ToString ();
        }
        private void button1_Click(object sender, EventArgs e)
        {
            //if serialPort1.
            if (cboCOMPorts.Text == "")
            {
                tsMessage.Text = "尚未选择串口!";
            }
            else
            {
                if (!serialPort1.IsOpen)
                {
                    serialPort1.PortName = cboCOMPorts.Text;
                    serialPort1.Open();
                    try
                    {
                        tsCOMPort.Text = cboCOMPorts.Text;
                        tsCOMState.Text = "开启";
                    }
                    catch (Exception ex)
                    {
                        tsMessage.Text = ex.ToString(); // "串口打开过程中遇到错误,串口不存在或者已经被占用!";
                        tsCOMPort.Text = "";
                        tsCOMState.Text = "已断开";
                    }
                }
                if (serialPort1.IsOpen)
                {
                    serialPort1.Write("P");
                    serialPort1.Write(Convert.ToChar(Convert.ToInt16(trkPWM.Value)).ToString());
                    FlashLED(lblRX, 10);
                }
            }
        }
        private void Form1_Load(object sender, EventArgs e)
        {
            FillSerialPorts();
            trkPWM.Value = 80;
        }
        private void FlashLED(Label LED, int Count)
        {
            FlashingLED = LED;
            FlashCounts = Count;
            timer1.Enabled = true;
        }
        private void DisplayText(object sender, EventArgs e)
        {
            txtRead.AppendText(TextRead);
        }
        private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            TextRead  = serialPort1.ReadExisting();
            this.Invoke (new EventHandler ( DisplayText));
            FlashLED(lblRX,10);
        }
        private void timer1_Tick(object sender, EventArgs e)
        {
            //add flash times
            if (FlashTimes <= FlashCounts)
            {
                FlashingLED.Visible = !FlashingLED.Visible;
                FlashTimes++;
            }
            else
            {
                timer1.Enabled = false;
                FlashCounts = 0;
                FlashTimes = 0;
                FlashingLED.Visible = true;
            }
        }

        private void frmMain_Activated(object sender, EventArgs e)
        {
            if (cboCOMPorts.Items.Count ==0 )
                FillSerialPorts ();
        }
        private void button2_Click(object sender, EventArgs e)
        {
            serialPort1.Close();
            timer1.Enabled = false;
        }
        private void pictureBox1_Paint(object sender, PaintEventArgs e)
        {
            pictureBox1.Invalidate();
            int yOffset=100;
            int yBase = 40;
            int xOffset = 40;
            int i ;
            int x=0;
            Pen p = new Pen(Color.Yellow ,1);
            Graphics g = e.Graphics;
            if (trkPWM.Value ==100)
                g.DrawLine(p, pictureBox1.Left , pictureBox1.Height - yOffset , pictureBox1.Left + 10 , pictureBox1.Height - yOffset ); // __
            else
                g.DrawLine(p, pictureBox1.Left , pictureBox1.Height - yBase, pictureBox1.Left + 10 , pictureBox1.Height - yBase); // __
            for (i = 0; i <= 5; i++)
            {
                x = 100 * i;
                if (!((trkPWM.Value ==0 )||(trkPWM.Value ==100)))
                    g.DrawLine(p, pictureBox1.Left + 10 + x, pictureBox1.Height - yBase, pictureBox1.Left + 10 + x, pictureBox1.Height - yOffset); // |
                //p.Color = Color.Blue ;
                xOffset = trkPWM.Value;
                g.DrawLine(p, pictureBox1.Left + 10 + x, pictureBox1.Height - yOffset, pictureBox1.Left + 10 + xOffset + x, pictureBox1.Height - yOffset);//--
                if (!((trkPWM.Value == 0) || (trkPWM.Value == 100)))
                    g.DrawLine(p, pictureBox1.Left + 10 + xOffset + x, pictureBox1.Height - yOffset, pictureBox1.Left + 10 + xOffset + x, pictureBox1.Height - yBase);//|
                g.DrawLine(p,pictureBox1.Left + 10 + xOffset + x, pictureBox1.Height - yBase, pictureBox1.Left + 10 + xOffset + x + 100 -trkPWM.Value , pictureBox1.Height - yBase);//__
                e.Graphics.DrawString(trkPWM.Value.ToString () + "%", panel1.Font , new SolidBrush(Color.White ), panel1.Left +  120 , 5, StringFormat.GenericDefault);
            }
        }
    }
}
原图中没有LED显示方式,借用新图



Arduino端程序与串口监视工具界面:
char CMD;      //Command included in the chars received from PC
char* Str;     //strings received
int PWMValue;  //PWM value received from PC
int PinOUT=10;
void setup()
{
    Serial.begin(9600);
    pinMode(PinOUT, OUTPUT);
}
int ReadPWM()
{
  int Result=255;
  while (!Serial.available())
  {
    //等到有输入再退出等待
  }
  Result = Serial.read();
  Serial.flush();
  return Result;
}
void loop()
{
   int i=0;
   if (Serial.available())
   {
      CMD = Serial.read();
      Serial.flush();
      switch(CMD)                          //根据不同的控制命令,来决定是否需要接收参数
      {
         case 'P':
           PWMValue = ReadPWM();
           //PWMWave(PWMValue);            //取消
           Serial.println(PWMValue);
           break;
      }
   }
                                          //根据不同的控制命令,实现对应的功能
   switch(CMD)
   {
      case 'P':
       
        //Debug
        Serial.println("");
        Serial.println("command P");
        Serial.println("");
       
        PWMWave(PWMValue);
        break;
   }
}
void PWMWave(int Value)
{
    int i;
    for (i=0; i<=100; i++)
      {
        
        //debug
        Serial.println(i+" | "+ Value);
       
        if (i<= Value)
        {
          digitalWrite(PinOUT,HIGH);
         
          //Debug
          Serial.println("HIGH");
         
         // delay(10);
        }
        else
        {
           digitalWrite(PinOUT,LOW);
          
           //DEBUG
           Serial.println("LOW");
          
        }
        delay(10);
      }
}

另外从上位机发PWM值,有时候arduino似乎只循环一次,之后LED灯熄灭,但是从串口监视工具发指令,似乎又正常。

先把代码贴出来,错误有待慢慢去修改。

1 条评论:

  1. 源代码中存在一些错误,修改后的代码见另外一篇博客
    http://ardypro.blogspot.com/2011/07/carduino.html

    主要问题为:

    C#代码:
    Serial.Write(),原来是传递Char,但是ANSI ASCII码表只支持128个,其余的传递给Arduino之后,会变成ASCII码63,现在改为传递byte类型的无符号数。

    Arduino部分:
    在switch(CMD)代码块中,增加了default块,当控制指令无效时,可以执行原来的过程而不至于停止。

    回复删除