.Net Micro Framework研究—串列埠操作

weixin_34377065發表於2007-10-28

.Net Micro Framework研究—串列埠操作

試驗平臺:Digi MF開發板

Digi提供的示例中包含了串列埠的示例程式,主要程式碼如下:


 

  1. public bool EchoByte()  
  2.  
  3.         {  
  4.  
  5.             SerialPort serial;  
  6.  
  7.             bool exceptionRaised = false;  
  8.  
  9.             bool testResult = true;  
  10.  
  11.             string message = " This is an echo test.  Enter the character to echo, or ESC to exit. ";  
  12.  
  13.             byte[] encodedMessage = c_encoding.GetBytes(message);  
  14.  
  15.             byte[] buffer = new byte[1];  
  16.  
  17.             try 
  18.  
  19.             {  
  20.  
  21.                 serial = new SerialPort(new SerialPort.Configuration(Cpu.Serial.COM1, Cpu.BaudRate.Baud115200, false));  
  22.  
  23.    
  24.  
  25.                 serial.Write(encodedMessage, 0, message.Length);  
  26.  
  27.    
  28.  
  29.                 while (buffer[0] != 0x1b)  
  30.  
  31.                 {  
  32.  
  33.                     serial.Read(buffer, 0, buffer.Length, Timeout.Infinite);  
  34.  
  35.                     serial.Write(buffer, 0, buffer.Length);  
  36.  
  37.                 }  
  38.  
  39.    
  40.  
  41.                 serial.Dispose();  
  42.  
  43.             }  
  44.  
  45.             catch 
  46.  
  47.             {  
  48.  
  49.                 exceptionRaised = true;  
  50.  
  51.             }  
  52.  
  53.             if (exceptionRaised == true)  
  54.  
  55.                 testResult = false;  
  56.  
  57.             return testResult;  
  58.  
  59.         }  
  60.  
  61.  
  62.  

 

部署執行後,你可以用超級終端進行測試,測試圖如下:

 


(圖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程式碼

 

  1. using System;  
  2. using Microsoft.SPOT;  
  3. using System.Threading;  
  4. using Microsoft.SPOT.Hardware;  
  5.  
  6. namespace MFModbus  
  7. {  
  8.     public class ModbusRtu  
  9.     {  
  10.         private Thread m_worker;  
  11.         private bool m_RunFlag;  
  12.  
  13.         private byte bytRtuDataFlag=0;  
  14.         private byte bytRtuDataIdx;  
  15.         private byte[] bytRtuData = new byte[8];  
  16.  
  17.         //裝置地址,預設為1      
  18.         private byte ModbusAddr = 1;  
  19.         //資料區(注意,Modbus讀寫是以字(雙位元組)為單位的)  
  20.         private byte[] DataBuff = new byte[128];  
  21.  
  22.         SerialPort serial = null;  
  23.  
  24.         InputPort[] input = new InputPort[5];  
  25.         Cpu.Pin[] pin = new Cpu.Pin[5] { (Cpu.Pin)0, (Cpu.Pin)1, (Cpu.Pin)2, (Cpu.Pin)5, (Cpu.Pin)6 };  
  26.  
  27.         public ModbusRtu(byte mModbusAddr)  
  28.         {  
  29.             ModbusAddr=mModbusAddr;  
  30.             for (int i = 0; i < 5; i++)  
  31.             {  
  32.                 input[i] = new InputPort(pin[i], false, Port.ResistorMode.PullUp);  
  33.             }  
  34.         }  
  35.  
  36.         ~ModbusRtu()  
  37.         {  
  38.             Stop();  
  39.         }  
  40.  
  41.         //CRC16校驗  
  42.         private UInt16 GetCheckCode(byte[] buf, int nEnd)  
  43.         {  
  44.             UInt16 crc = (UInt16)0xffff;  
  45.             int i, j;  
  46.             for (i = 0; i < nEnd; i++)  
  47.             {  
  48.                 crc ^= (UInt16)buf[i];  
  49.                 for (j = 0; j < 8; j++)  
  50.                 {  
  51.                     if ((crc & 1) != 0)  
  52.                     {  
  53.                         crc >>= 1;  
  54.                         crc ^= 0xA001;  
  55.                     }  
  56.                     else 
  57.                         crc >>= 1;  
  58.                 }  
  59.             }  
  60.             return crc;  
  61.         }  
  62.  
  63.         //啟動Modbus服務  
  64.         public void Run()  
  65.         {  
  66.             try 
  67.             {  
  68.                 //僅有波特率選項,竟然沒有奇偶校驗控制  
  69.                 serial = new SerialPort(new SerialPort.Configuration(Serial.COM1, BaudRate.Baud9600, false));  
  70.                 Debug.Print("Open Serial OK");  
  71.                 m_worker = new Thread(new ThreadStart(this.ModbusThreadProc));  
  72.                 m_RunFlag = true;  
  73.                 m_worker.Start();  
  74.             }  
  75.             catch 
  76.             {  
  77.                 Debug.Print("Serial Error");  
  78.             }             
  79.         }  
  80.  
  81.         //停止Modbus服務  
  82.         public void Stop()  
  83.         {  
  84.             m_RunFlag = false;  
  85.             if (serial != null)  
  86.                 serial.Dispose();  
  87.         }  
  88.  
  89.         //Modbus Slave服務  
  90.         private void ModbusThreadProc()  
  91.         {  
  92.             Debug.Print("Start Modbus Slave");  
  93.             byte[] bytData=new byte[1];  
  94.             while (m_RunFlag)  
  95.             {  
  96.                 serial.Read(bytData, 0, bytData.Length, Timeout.Infinite);  
  97.                 RtuSlave(bytData[0]);  
  98.             }  
  99.         }  
  100.         //串列埠資料處理  
  101.         private void RtuSlave(byte bytData)  
  102.         {  
  103.             //Debug.Print(bytRtuDataIdx.ToString() + " - " + bytData.ToString());  
  104.             if (bytRtuDataFlag == 0)  
  105.             {  
  106.                 //如果資料為首地址  
  107.                 if (bytData == ModbusAddr)  
  108.                 {  
  109.                     bytRtuDataFlag = 1;  
  110.                     bytRtuDataIdx = 0;  
  111.                     bytRtuData[bytRtuDataIdx++] = bytData;  
  112.                 }  
  113.             }  
  114.             else 
  115.             {  
  116.                 bytRtuData[bytRtuDataIdx++] = bytData;  
  117.                 if (bytRtuDataIdx >= 8)  
  118.                 {  
  119.                     //資訊處理  
  120.                     UInt16 intCRC16 = GetCheckCode(bytRtuData, 8 - 2);  
  121.  
  122.                     //Debug.Print("CRC:" + bytRtuData[8 - 2].ToString() + " " + ((byte)(intCRC16 & 0xFF)).ToString() +"|" + bytRtuData[8 - 1].ToString() + " " + ((byte)((intCRC16 >> 8) & 0xff)).ToString());  
  123.                     //CRC16校驗檢驗  
  124.                     if (bytRtuData[8 - 2] == (intCRC16 & 0xFF) && bytRtuData[8 - 1] == ((intCRC16 >> 8) & 0xff))  
  125.                     {  
  126.                         byte[] bytSendData = new byte[255];  
  127.                         byte bytErrorFlag = 0;  
  128.                         byte bytErrorNo = 1;  
  129.  
  130.                         //Debug.Print("CRC OK");  
  131.                         //讀資料  
  132.                         if (bytRtuData[1] == 3)  
  133.                         {  
  134.                             UInt16 lngDataAddr = bytRtuData[2];  
  135.                             lngDataAddr = (UInt16)((lngDataAddr << 8) + bytRtuData[3]);  //地址  
  136.                             UInt16 lngDataNum = bytRtuData[4];  
  137.                             lngDataNum = (UInt16)((lngDataNum << 8) + bytRtuData[5]);    //數量  
  138.  
  139.                             if (lngDataAddr * 2 + lngDataNum * 2 > 1024 || lngDataNum > 120)  
  140.                             {  
  141.                                 bytErrorNo = 2;  
  142.                                 bytErrorFlag = 0;  
  143.                             }  
  144.                             else 
  145.                             {  
  146.                                 bytSendData[0] = bytRtuData[0];  
  147.                                 bytSendData[1] = bytRtuData[1];  
  148.                                 bytSendData[2] = (byte)(lngDataNum * 2);  
  149.  
  150.                                 //讀GPIO訊號  
  151.                                 DataBuff[0] = 0;  
  152.                                 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));  
  153.                                   
  154.                                 for (int i = 0; i < bytSendData[2]; i++)  
  155.                                 {  
  156.                                     bytSendData[3 + i] = DataBuff[lngDataAddr * 2 + i];  
  157.                                 }  
  158.                                 intCRC16 = GetCheckCode(bytSendData, 3 + lngDataNum * 2);  
  159.                                 bytSendData[3 + lngDataNum * 2] = (byte)(intCRC16 & 0xFF);                    //CRC校驗低位  
  160.                                 bytSendData[4 + lngDataNum * 2] = (byte)((intCRC16 >> 8) & 0xff);             //CRC校驗高位                    
  161.  
  162.                                 //傳送資料  
  163.                                 int intRet=serial.Write(bytSendData, 0, 5 + lngDataNum * 2);  
  164.  
  165.                                 //Debug.Print("SendData OK " + intRet.ToString() );  
  166.                                 bytErrorFlag = 1;  
  167.                             }  
  168.                         }  
  169.  
  170.                         if (bytErrorFlag == 0)  
  171.                         {  
  172.                             //協議不支援  
  173.                             bytSendData[0] = bytRtuData[0];  
  174.                             bytSendData[1] = (byte)(bytRtuData[1] | 0x80);  
  175.                             bytSendData[2] = bytErrorNo;  
  176.  
  177.                             intCRC16 = GetCheckCode(bytSendData, 3);  
  178.                             bytSendData[3] = (byte)(intCRC16 & 0xFF);                       //CRC校驗低位  
  179.                             bytSendData[4] = (byte)((intCRC16 >> 8) & 0xff);                //CRC校驗高位  
  180.  
  181.                             //傳送資料  
  182.                             serial.Write(bytSendData, 0, 5);  
  183.                         }  
  184.                     }  
  185.                     bytRtuDataFlag = 0;  
  186.                 }  
  187.             }  
  188.             return;  
  189.         }  
  190.  
  191.         //串列埠號  
  192.         public static class Serial  
  193.         {  
  194.             public const SerialPort.Serial COM1 = (SerialPort.Serial)0;  
  195.             public const SerialPort.Serial COM2 = (SerialPort.Serial)1;  
  196.         }  
  197.  
  198.         //串列埠波特率  
  199.         public static class BaudRate  
  200.         {  
  201.             public const SerialPort.BaudRate Baud4800 = (SerialPort.BaudRate)4800;  
  202.             public const SerialPort.BaudRate Baud9600 = (SerialPort.BaudRate)9600;  
  203.             public const SerialPort.BaudRate Baud19200 = (SerialPort.BaudRate)19200;  
  204.             public const SerialPort.BaudRate Baud38400 = (SerialPort.BaudRate)38400;  
  205.             public const SerialPort.BaudRate Baud57600 = (SerialPort.BaudRate)57600;  
  206.             public const SerialPort.BaudRate Baud115200 = (SerialPort.BaudRate)115200;  
  207.             public const SerialPort.BaudRate Baud230400 = (SerialPort.BaudRate)230400;  
  208.         }  
  209.     }  
  210. }  
  211.  

 

程式部署執行後,直接用標準的Modbus Rtu客戶端程式測試即可,我用的是我以前編寫的Modbus Rtu Client程式,測試如下:

 

 (圖MF10280002.JPG)


這時候,你直接操作SW2的撥碼,該數字就會發生變化(前提SW1的撥碼都撥到右邊)。

 

缺點:很奇怪的是串列埠的引數僅能配置波特率,奇偶校驗,資料位卻無法配置。

 

總的印象:用MF開發嵌入式系統還是非常有前景的,至少使產品的開發週期大大縮短,並且程式碼升級維護方便。

 

 

相關文章