.Net Micro Framework研究—串口操作

.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;

        }

 

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

.Net Micro Framework研究—串口操作_第1张图片

(图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,  0 5   +  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,  0 5 );
                        }
                    }
                    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程序,测试如下: 

 .Net Micro Framework研究—串口操作_第2张图片

 (图MF10280002.JPG) 

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

 

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

 

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

 

你可能感兴趣的:(.Net Micro Framework研究—串口操作)