现在的位置: 首页 > 综合 > 正文

.Net Micro Framework研究—串口操作

2014年01月24日 ⁄ 综合 ⁄ 共 9276字 ⁄ 字号 评论关闭

.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开发嵌入式系统还是非常有前景的,至少使产品的开发周期大大缩短,并且代码升级维护方便。

 

【上篇】
【下篇】

抱歉!评论已关闭.