ardyPro 发表于 2011-10-10 09:41:52

C#与Arduino的对话

功能需求:
       PC机作为上位机,通过串口发送控制指令 F(ading) or B(link) 给Arduino,根据不同指令来实现LED闪烁或者渐明渐暗。

实现方式:
       单片机选用Arduino MEGA 1280,PWM10脚作为输出口,接220欧限流电阻至高亮LED,再与GND脚共地。
   


       上位机用C#作为编程语言,IDE选择VS2010,.Net版本选择了4.0,不过应该能够兼容其它版本的.net framework。之前上位机跟单片机通信时,传递的是字符串,方法是先将PWM值视为ASCII码,转换成对应的Char,然后将Char再转换成String类型。由于ANSI ASCII码表只支持128个字符,所以128-255之间的数在传递的时候就遇到难题,通过串口监视发现,超过127的ASCII发给arduino之后,都被修改为63,导致传输失效。

       现在的方法改为直接传递byte类型的无符号数,解决了这个问题。

       运行界面如下:



       上位机源代码: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 intFillSerialPorts()
    {
      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)
    {
      txtRead.Clear();
      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)
      {
          if (rbFading.Checked)
          {
            serialPort1.Write("F");
            byte[] bytesToSend = new byte ;
            bytesToSend =Convert.ToByte ( trkPWM.Value *2.55 ); //疑问:当Value=100,ToByte=255,但是((int)(trkPWM.Value * 2.55)).ToString()却是254?
            serialPort1.Write(bytesToSend, 0, 1);

            //serialPort1.Write( ((Char ) ((int) trkPWM.Value *2.55 )).ToString () ); //这个方法不能传递高于127的数
            //tsMessage.Text = ((int)(trkPWM.Value * 2.55)).ToString();
          }
          else
          {
            serialPort1.Write("B");
            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)
    {
      if (chkReceive.Checked)
      {
      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);
      }
    }
    private void frmMain_FormClosing(object sender, FormClosingEventArgs e)
    {
      if (serialPort1.IsOpen)
      serialPort1.Close();
    }
    private void 清空ToolStripMenuItem1_Click(object sender, EventArgs e)
    {
      txtRead.Clear();
    }
}
}

ardyPro 发表于 2011-10-10 09:49:10

Arduino程序源代码://COPYRIGHT DECLARATION
//THIS APPLICATION IS A DEMOSTRATION APPLICATON FOR EDUCATION PURPOSE ONLY. YOU CAN USE OR
//REDISTRIBUTE IT FREELY ON CONDITION THAT YOU WOULD NOT MAKE MONEY OF IT.

//THE DESKTOP APPLICATON WHICH IS PROGRAMMED IN C# WOULD SEND CONTROL CODE AND PARAMETERS, IF ANY,
//TO THE ARDUINO, THE MICROCONTROLLER WOULD MAKE THE LED FADING OR BLINKING IN ACCORDANCE
//WITH THE CONTROL CODE, THEN.
//SINCE THIS IS MY FIRST APPLICATION IN EITHER C# AND ARDUINO, THERE MIGHT BE SOME BUGS IN IT,
//IF YOU RUN INTO ANY EXCEPTIONS, PLEASE REPORT THEM TO ME AT [email protected].

//HISTORY
//VER 0.101 1:32 2011-7-31
//Add Fade function to the application
//VER 0.100 16:45 2011-7-30
//Add blink function to the application

char CMD;         //command
int pwmValue;       //PWM value
int PinOUT=10;      //output pin
int Interval = 10;

void setup()
{
Serial.begin(9600);
pinMode(PinOUT, OUTPUT);    //set the pin 10 as output pin
CMD = 'F';
pwmValue = 50;
}
void loop()
{
if (Serial.available())
{
    char PrevCMD;
    PrevCMD = CMD;
    CMD = Serial.read();
    switch(CMD)
    {
    case 'B':   //Blink
      //read PWM value in readPWMValue routine
      pwmValue = readPWMValue();
      break ;
      //any other CASE statement
    case 'F':   //Fading
      pwmValue = readPWMValue();
      break;
    default :
      CMD = PrevCMD; //当没有按键或者控制指令无效时,继续执行原来的指令
      break;
    }
}

//if there is no chars income, then execute the last command
switch(CMD)
{
case 'B':
    setPWM(pwmValue);
    break;
case 'F':
    ledFading(pwmValue);
    break;

default:
    break;
}
}
int readPWMValue()
{
int Value;
while (!Serial.available())
{
    //wait for another incoming char
}
Value=Serial.read();

Serial.print("Parameters received: ");
Serial.println(Value);

return Value;
}
void setPWM(int Value)
{
int i;

Serial.println(Value);

for (i=0; i<=100; i++)
{
    //debug
    Serial.print(i);
    Serial.print(" / ");
    if (i<= Value)
    {
      digitalWrite(PinOUT,HIGH);

      //Debug
      Serial.println("HIGH");
    }
    else
    {
      digitalWrite(PinOUT,LOW);

      //DEBUG
      Serial.println("LOW");
    }
    delay(Interval);
}
}
void ledFading(int Value)
{
Serial.print("Fading Value: ");
Serial.println(Value);
int i;
/*
    if (Value>=255)
   Value = 255;
   else
   if (Value<=0);
   Value =0;
   */

//fade in
for (i=0; i<=Value; i++)
{
    analogWrite(PinOUT, i);
    Serial.println(i);
    delay(Interval);
}

delay(500);

//fade out
for (i=Value; i>=0; i--)
{
    analogWrite(PinOUT,i);
    Serial.println(i);
    delay(Interval);
}

delay(500);

}

davidce 发表于 2011-12-12 22:10:29

赞一个{:soso_e100:}

プ汏坏疍 发表于 2011-12-13 00:12:03

大神级人物,向您致敬!:P

infowalker 发表于 2011-12-13 23:54:12

这个很给力呀。。。直接输入pwm了

h784533 发表于 2012-2-27 11:20:12

C#可以直接开发么?求详细资料

h784533 发表于 2012-2-27 11:25:48

仔细看了下代码,明白c#只是用来串口通信。呵呵,支持楼主

ardyPro 发表于 2012-2-28 02:53:10

h784533 发表于 2012-2-27 11:20 static/image/common/back.gif
C#可以直接开发么?求详细资料

Netduino是用C#开发的,支持调试,弱点就是库比arduino的少

SS15 发表于 2012-2-28 10:26:20

ardyPro 发表于 2012-2-28 02:53 static/image/common/back.gif
Netduino是用C#开发的,支持调试,弱点就是库比arduino的少

Netduino的致命弱点:速度慢
相同处理器条件下

ardyPro 发表于 2012-2-29 00:04:11

SS15 发表于 2012-2-28 10:26 static/image/common/back.gif
Netduino的致命弱点:速度慢
相同处理器条件下

是吗?我没用过,对我来讲,相同功能,netduino贵多了,不划算。:lol

难道是因为.net CF的原因?今天看到一篇文章介绍,奇瑞汽车自主研发的机械臂,执行用实时系统,但是数据运算就是在WinCE平台上做的,WinCE上面也带的有一坨.net CF呢 ;P

SS15 发表于 2012-2-29 12:35:04

ardyPro 发表于 2012-2-29 00:04 static/image/common/back.gif
是吗?我没用过,对我来讲,相同功能,netduino贵多了,不划算。

难道是因为.net CF的原因?今天看 ...

.net 平台的中间代码在翻译成机器代码过程中必然消耗资源,占用时间。

.net 只是WinCE的一个组件,应用程序快慢和.net这个组件没关系,而是与是否运行于这个组件上有关。

一般的机械臂实时性要求不太高,WinCE拿来做两三百公里的无人机飞控运算都基本够用了。速度再高,就得RTOS了。

自由创客 发表于 2012-5-9 13:44:13

上位机是以后开发的重要支撑,不管是电脑还是手机的上位机,求基础学习资料

xushu 发表于 2012-7-5 11:50:16

呵呵!不错啊!

Dream 发表于 2012-12-14 23:43:45

if (serialPort1.IsOpen)
      {
          if (rbFading.Checked)
          // 第二个if 是干嘛的?没看懂

ttyp 发表于 2012-12-15 09:44:32

Dream 发表于 2012-12-14 23:43 static/image/common/back.gif
if (serialPort1.IsOpen)
      {
          if (rbFading.Checked)


是否显示内容打勾的意思
页: [1] 2 3
查看完整版本: C#与Arduino的对话