叶帆工作室

嵌入式开发爱好者(十年开发经验,精通C/C++/VC/VB/C#...)

刘洪峰ID:yefanqiu
504906次访问,排名80好友0人,关注者137
微软MVP / CSDN 2008十大MVB/MSDN中文技术论坛版主
yefanqiu的文章
原创 215 篇
翻译 0 篇
转载 3 篇
评论 1058 篇
叶帆的公告
本博客原创文章,作者保留一切权利,需经作者同意后方可转载,转载时 请注明[叶帆工作室]及文章链接。yefan@vip.sina.com
【简介】叶帆[微软MVP]
【文章】叶帆文章列表
【软件】叶帆共享软件列表
最近评论
lvpeng52:我在无串口的笔记本电脑中安装wince 6.0, 按照http://www.cnblogs.com/walzer/archive/2008/07/10/744729.html方式安装了所有软件。

1. 但是发现 项目->属性->Debugger选项中没有CE Dump File Reader和Sample Device Emulator EXDI 2 Dr……
yefanqiu:知道这个软件,不过更深层次知识我目前也不清楚。
吴为仁:请问你熟悉神奇的Reflector软件吗?用它可以得到.NET的源码。请问Reflector输出的源码与真正的源码有什么区别?要注意那些问题?您这个MVP写一点此方面的东西,可否?
yefanqiu:在C#上直接调用该控件吧。
yefanqiu:这是支持两种不同字符集的函数(ANSI/Unicode)
文章分类
收藏
    相册
    叶帆照片
    【叶帆软件】
    [01]VB源码之友(V2.1.548)
    [02]API浏览器.net(V5.0)
    [03]叶帆成语词典(V2.0.8)
    [04]叶帆密码库(V1.2.8)
    【叶帆资源】
    DAO 2.0引擎
    叶帆快速通道
    Windows Embedded 专题
    中文MSDN
    叶帆圈子--工业自动化
    叶帆工作室(博客园)
    叶帆工控--工业自动化
    叶帆群组--工业应用开发
    微软中文技术论坛
    瑞康社区论坛
    叶帆友情链接
    张欣
    枕善居
    莫依
    葛涵涛
    郑建
    陈辉
    马宁
    马骐
    魏涛序
    黎波
    存档
    订阅我的博客
    XML聚合  FeedSky
    订阅到鲜果
    订阅到Google
    订阅到抓虾
    订阅到BlogLines
    订阅到Yahoo
    订阅到GouGou
    订阅到飞鸽
    订阅到Rojo
    订阅到newsgator
    订阅到netvibes

    原创 .Net Micro Framework研究—串口操作收藏

    新一篇: .Net Micro Framework研究—TCP/IP通信 | 旧一篇: .Net Micro Framework研究—IO读写

    .Net Micro Framework研究串口操作

    试验平台:Digi MF开发板

    Digi提供的示例中包含了串口的示例程序,主要代码如下:

    public bool EchoByte()

            {

                SerialPort serial;

                
    bool exceptionRaised = false;

                
    bool testResult = true;

                
    string message = " This is an echo test.  Enter the character to echo, or ESC to exit. ";

                
    byte[] encodedMessage = c_encoding.GetBytes(message);

                
    byte[] buffer = new byte[1];

                
    try

                {

                    serial 
    = new SerialPort(new SerialPort.Configuration(Cpu.Serial.COM1, Cpu.BaudRate.Baud115200, false));

     

                    serial.Write(encodedMessage, 
    0, message.Length);

     

                    
    while (buffer[0!= 0x1b)

                    {

                        serial.Read(buffer, 
    0, buffer.Length, Timeout.Infinite);

                        serial.Write(buffer, 
    0, buffer.Length);

                    }

     

                    serial.Dispose();

                }

                
    catch

                {

                    exceptionRaised 
    = true;

                }

                
    if (exceptionRaised == true)

                    testResult 
    = false;

                
    return testResult;

            }

     

    部署运行后,你可以用超级终端进行测试,测试图如下:

    (图MF10280001.JPG

    注意:如果串口程序非正常退出,有可能导致开发板无法发送数据(接收倒是正常),重启开发板即可。

     

    用测试程序还是体现不出.Net Micro Framework的优势,我决定用MF实现Modbus Rtu Slave服务端(支持Modbus Rtu 3号命令),并且地址为0的数据存放了GPIO入的信息,这样在上位机就很方面的检测IO信号了。

     

    用了大约15分钟,就把我以前用C++开发的Modbus Rtu Slave程序移植到MF平台上来的,我想如果用单片来开发,虽然也有可能借用以前的代码,但很方便的把IO信号也非常快捷的集成进来,恐怕不容易。

     

    值得一提的是VS2005 的调试功能非常强大,很容易添加断点及监控当前变量的值,同时用debug.print()命令也非常好使,这样调试程序绝对比调试单片舒服。

     

    下面贴出我写的Modbus RtuSlave代码

     

    using System;
    using Microsoft.SPOT;
    using System.Threading;
    using Microsoft.SPOT.Hardware;

    namespace MFModbus
    {
        
    public class ModbusRtu
        {
            
    private Thread m_worker;
            
    private bool m_RunFlag;

            
    private byte bytRtuDataFlag=0;
            
    private byte bytRtuDataIdx;
            
    private byte[] bytRtuData = new byte[8];

            
    //设备地址,默认为1    
            private byte ModbusAddr = 1;
            
    //数据区(注意,Modbus读写是以字(双字节)为单位的)
            private byte[] DataBuff = new byte[128];

            SerialPort serial 
    = null;

            InputPort[] input 
    = new InputPort[5];
            Cpu.Pin[] pin 
    = new Cpu.Pin[5] { (Cpu.Pin)0, (Cpu.Pin)1, (Cpu.Pin)2, (Cpu.Pin)5, (Cpu.Pin)6 };

            
    public ModbusRtu(byte mModbusAddr)
            {
                ModbusAddr
    =mModbusAddr;
                
    for (int i = 0; i < 5; i++)
                {
                    input[i] 
    = new InputPort(pin[i], false, Port.ResistorMode.PullUp);
                }
            }

            
    ~ModbusRtu()
            {
                Stop();
            }

            
    //CRC16校验
            private UInt16 GetCheckCode(byte[] buf, int nEnd)
            {
                UInt16 crc 
    = (UInt16)0xffff;
                
    int i, j;
                
    for (i = 0; i < nEnd; i++)
                {
                    crc 
    ^= (UInt16)buf[i];
                    
    for (j = 0; j < 8; j++)
                    {
                        
    if ((crc & 1!= 0)
                        {
                            crc 
    >>= 1;
                            crc 
    ^= 0xA001;
                        }
                        
    else
                            crc 
    >>= 1;
                    }
                }
                
    return crc;
            }

            
    //启动Modbus服务
            public void Run()
            {
                
    try
                {
                    
    //仅有波特率选项,竟然没有奇偶校验控制
                    serial = new SerialPort(new SerialPort.Configuration(Serial.COM1, BaudRate.Baud9600, false));
                    Debug.Print(
    "Open Serial OK");
                    m_worker 
    = new Thread(new ThreadStart(this.ModbusThreadProc));
                    m_RunFlag 
    = true;
                    m_worker.Start();
                }
                
    catch
                {
                    Debug.Print(
    "Serial Error");
                }           
            }

            
    //停止Modbus服务
            public void Stop()
            {
                m_RunFlag 
    = false;
                
    if (serial != null)
                    serial.Dispose();
            }

            
    //Modbus Slave服务
            private void ModbusThreadProc()
            {
                Debug.Print(
    "Start Modbus Slave");
                
    byte[] bytData=new byte[1];
                
    while (m_RunFlag)
                {
                    serial.Read(bytData, 
    0, bytData.Length, Timeout.Infinite);
                    RtuSlave(bytData[
    0]);
                }
            }
            
    //串口数据处理
            private void RtuSlave(byte bytData)
            {
                
    //Debug.Print(bytRtuDataIdx.ToString() + " - " + bytData.ToString());
                if (bytRtuDataFlag == 0)
                {
                    
    //如果数据为首地址
                    if (bytData == ModbusAddr)
                    {
                        bytRtuDataFlag 
    = 1;
                        bytRtuDataIdx 
    = 0;
                        bytRtuData[bytRtuDataIdx
    ++= bytData;
                    }
                }
                
    else
                {
                    bytRtuData[bytRtuDataIdx
    ++= bytData;
                    
    if (bytRtuDataIdx >= 8)
                    {
                        
    //信息处理
                        UInt16 intCRC16 = GetCheckCode(bytRtuData, 8 - 2);

                        
    //Debug.Print("CRC:" + bytRtuData[8 - 2].ToString() + " " + ((byte)(intCRC16 & 0xFF)).ToString() +"|" + bytRtuData[8 - 1].ToString() + " " + ((byte)((intCRC16 >> 8) & 0xff)).ToString());
                        
    //CRC16校验检验
                        if (bytRtuData[8 - 2== (intCRC16 & 0xFF&& bytRtuData[8 - 1== ((intCRC16 >> 8& 0xff))
                        {
                            
    byte[] bytSendData = new byte[255];
                            
    byte bytErrorFlag = 0;
                            
    byte bytErrorNo = 1;

                            
    //Debug.Print("CRC OK");
                            
    //读数据
                            if (bytRtuData[1== 3)
                            {
                                UInt16 lngDataAddr 
    = bytRtuData[2];
                                lngDataAddr 
    = (UInt16)((lngDataAddr << 8+ bytRtuData[3]);  //地址
                                UInt16 lngDataNum = bytRtuData[4];
                                lngDataNum 
    = (UInt16)((lngDataNum << 8+ bytRtuData[5]);    //数量

                                
    if (lngDataAddr * 2 + lngDataNum * 2 > 1024 || lngDataNum > 120)
                                {
                                    bytErrorNo 
    = 2;
                                    bytErrorFlag 
    = 0;
                                }
                                
    else
                                {
                                    bytSendData[
    0= bytRtuData[0];
                                    bytSendData[
    1= bytRtuData[1];
                                    bytSendData[
    2= (byte)(lngDataNum * 2);

                                    
    //读GPIO信号
                                    DataBuff[0= 0;
                                    DataBuff[
    1= (byte)((input[0].Read() ? 1 : 0| (input[1].Read() ? 2 : 0| (input[2].Read() ? 4 : 0| (input[3].Read() ? 8 : 0| (input[4].Read() ? 16 : 0));
                                    
                                    
    for (int i = 0; i < bytSendData[2]; i++)
                                    {
                                        bytSendData[
    3 + i] = DataBuff[lngDataAddr * 2 + i];
                                    }
                                    intCRC16 
    = GetCheckCode(bytSendData, 3 + lngDataNum * 2);
                                    bytSendData[
    3 + lngDataNum * 2= (byte)(intCRC16 & 0xFF);                    //CRC校验低位
                                    bytSendData[4 + lngDataNum * 2= (byte)((intCRC16 >> 8& 0xff);             //CRC校验高位                  

                                    
    //发送数据
                                    int intRet=serial.Write(bytSendData, 05 + lngDataNum * 2);

                                    
    //Debug.Print("SendData OK " + intRet.ToString() );
                                    bytErrorFlag = 1;
                                }
                            }

                            
    if (bytErrorFlag == 0)
                            {
                                
    //协议不支持
                                bytSendData[0= bytRtuData[0];
                                bytSendData[
    1= (byte)(bytRtuData[1| 0x80);
                                bytSendData[
    2= bytErrorNo;

                                intCRC16 
    = GetCheckCode(bytSendData, 3);
                                bytSendData[
    3= (byte)(intCRC16 & 0xFF);                       //CRC校验低位
                                bytSendData[4= (byte)((intCRC16 >> 8& 0xff);                //CRC校验高位

                                
    //发送数据
                                serial.Write(bytSendData, 05);
                            }
                        }
                        bytRtuDataFlag 
    = 0;
                    }
                }
                
    return;
            }

            
    //串口号
            public static class Serial
            {
                
    public const SerialPort.Serial COM1 = (SerialPort.Serial)0;
                
    public const SerialPort.Serial COM2 = (SerialPort.Serial)1;
            }

            
    //串口波特率
            public static class BaudRate
            {
                
    public const SerialPort.BaudRate Baud4800 = (SerialPort.BaudRate)4800;
                
    public const SerialPort.BaudRate Baud9600 = (SerialPort.BaudRate)9600;
                
    public const SerialPort.BaudRate Baud19200 = (SerialPort.BaudRate)19200;
                
    public const SerialPort.BaudRate Baud38400 = (SerialPort.BaudRate)38400;
                
    public const SerialPort.BaudRate Baud57600 = (SerialPort.BaudRate)57600;
                
    public const SerialPort.BaudRate Baud115200 = (SerialPort.BaudRate)115200;
                
    public const SerialPort.BaudRate Baud230400 = (SerialPort.BaudRate)230400;
            }
        }
    }

     

    程序部署运行后,直接用标准的Modbus Rtu客户端程序测试即可,我用的是我以前编写的Modbus Rtu Client程序,测试如下: 

     

     (图MF10280002.JPG) 

    这时候,你直接操作SW2的拨码,该数字就会发生变化(前提SW1的拨码都拨到右边)。

     

    缺点:很奇怪的是串口的参数仅能配置波特率,奇偶校验,数据位却无法配置。

     

    总的印象:用MF开发嵌入式系统还是非常有前景的,至少使产品的开发周期大大缩短,并且代码升级维护方便。

     

    发表于 @ 2007年10月28日 17:41:00|评论(loading...)|编辑

    新一篇: .Net Micro Framework研究—TCP/IP通信 | 旧一篇: .Net Micro Framework研究—IO读写

    评论

    #Tom.Zhou 发表于2008-04-21 17:40:09  IP: 203.109.219.*
    请问下Modbus Rtu Client 这个电脑客户端程序能提供下载吗?
    #yefanqiu 发表于2008-04-21 19:02:36  IP: 221.221.67.*
    可以
    这是我工控blog上的文章,有相关下载连接
    http://blog.gkong.com/more.asp?name=yefanqiu&id=24545
    发表评论  


    登录
    Csdn Blog version 3.1a
    Copyright © 叶帆