我已经构建了一个适配器DS9097E并连接到它DS18B20数字温度计。在互联网上,您可以在Delphi和C中找到从该设备读取温度的应用示例。我正在尝试用C#编写它。一开始我依赖.NET但它没有用。我遇到了RESET和PRESENCE PULSES的问题,所以我尝试使用kernel32.dll。昨天我找到了这个库:OpenNETCF。不幸的是没有它的文档。与此同时,我试着写自己的库:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Activities;
using Microsoft.Win32.SafeHandles;
using System.IO;
using System.Collections.Specialized;
using System.IO.Ports;
namespace COMAPI
{
public class COMutils
{
private int hCOM = -1;
private DCB dcb = new DCB();
private COMMTIMEOUTS commtime = new COMMTIMEOUTS();
private int bufferSize = 128;
private byte[] ReceiveBytes;
#region STALE
private const int PURGE_TXABORT = 0x01;
private const int PURGE_RXABORT = 0x02;
private const int PURGE_TXCLEAR = 0x04;
private const int PURGE_RXCLEAR = 0x08;
private const int INVALID_HANDLE_VALUE = -1;
private const uint GENERIC_READ = 0x80000000;
private const uint GENERIC_WRITE = 0x40000000;
#endregion
#region KERNEL32
[DllImport("kernel32.dll")]
static extern bool PurgeComm(int hFile, int dwFlags);
[DllImport("kernel32.dll", SetLastError=true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool CloseHandle(int hObject);
[DllImport("kernel32.dll")]
static extern bool FlushFileBuffers(int hFile);
[DllImport("kernel32.dll")]
static extern bool TransmitCommChar(int hFile, char cChar);
[DllImport("kernel32.dll")]
static extern bool WriteFile(int hFile, byte [] lpBuffer, int nNumberOfBytesToWrite, ref int lpNumberOfBytesWritten, int lpOverlapped);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool ReadFile(int hFile, [Out] byte[] lpBuffer, int nNumberOfBytesToRead, ref int lpNumberOfBytesRead, int lpOverlapped);
[DllImport("kernel32.dll")]
static extern bool GetCommState(int hFile, ref DCB lpDCB);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool GetCommTimeouts(int hFile, ref COMMTIMEOUTS lpCommTimeouts);
[DllImport("kernel32.dll")]
static extern bool SetCommState(int hFile, [In] ref DCB lpDCB);
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern int CreateFile(
string lpFileName,
[MarshalAs(UnmanagedType.U4)] uint dwDesiredAccess,
[MarshalAs(UnmanagedType.U4)] int dwShareMode,
int lpSecurityAttributes,
[MarshalAs(UnmanagedType.U4)] int dwCreationDisposition,
[MarshalAs(UnmanagedType.U4)] int dwFlagsAndAttributes,
int hTemplateFile);
[DllImport("kernel32.dll")]
static extern int GetTickCount();
#endregion
#region DCB
[StructLayout(LayoutKind.Sequential)]
internal struct DCB
{
internal uint DCBLength;
internal uint BaudRate;
private BitVector32 Flags;
private ushort wReserved; // not currently used
internal ushort XonLim; // transmit XON threshold
internal ushort XoffLim; // transmit XOFF threshold
internal byte ByteSize;
internal Parity Parity;
internal StopBits StopBits;
internal sbyte XonChar; // Tx and Rx XON character
internal sbyte XoffChar; // Tx and Rx XOFF character
internal sbyte ErrorChar; // error replacement character
internal sbyte EofChar; // end of input character
internal sbyte EvtChar; // received event character
private ushort wReserved1; // reserved; do not use
private static readonly int fBinary;
private static readonly int fParity;
private static readonly int fOutxCtsFlow;
private static readonly int fOutxDsrFlow;
private static readonly BitVector32.Section fDtrControl;
private static readonly int fDsrSensitivity;
private static readonly int fTXContinueOnXoff;
private static readonly int fOutX;
private static readonly int fInX;
private static readonly int fErrorChar;
private static readonly int fNull;
private static readonly BitVector32.Section fRtsControl;
private static readonly int fAbortOnError;
static DCB()
{
// Create Boolean Mask
int previousMask;
fBinary = BitVector32.CreateMask();
fParity = BitVector32.CreateMask(fBinary);
fOutxCtsFlow = BitVector32.CreateMask(fParity);
fOutxDsrFlow = BitVector32.CreateMask(fOutxCtsFlow);
previousMask = BitVector32.CreateMask(fOutxDsrFlow);
previousMask = BitVector32.CreateMask(previousMask);
fDsrSensitivity = BitVector32.CreateMask(previousMask);
fTXContinueOnXoff = BitVector32.CreateMask(fDsrSensitivity);
fOutX = BitVector32.CreateMask(fTXContinueOnXoff);
fInX = BitVector32.CreateMask(fOutX);
fErrorChar = BitVector32.CreateMask(fInX);
fNull = BitVector32.CreateMask(fErrorChar);
previousMask = BitVector32.CreateMask(fNull);
previousMask = BitVector32.CreateMask(previousMask);
fAbortOnError = BitVector32.CreateMask(previousMask);
}
}
#endregion
#region COMMTIMEOUTS
struct COMMTIMEOUTS
{
public UInt32 ReadIntervalTimeout;
public UInt32 ReadTotalTimeoutMultiplier;
public UInt32 ReadTotalTimeoutConstant;
public UInt32 WriteTotalTimeoutMultiplier;
public UInt32 WriteTotalTimeoutConstant;
}
#endregion
#region METODY
public bool openCOM(int numer)
{
hCOM = CreateFile("COM" + numer, GENERIC_READ | GENERIC_WRITE, 0, 0, 3, 0, 0);
if (hCOM == INVALID_HANDLE_VALUE)
return false;
if (!GetCommState(hCOM, ref dcb))
return false;
if (!GetCommTimeouts(hCOM, ref commtime))
return false;
return true;
}
public bool closeCOM()
{
return CloseHandle(hCOM);
}
public bool setCOM(int baud, byte bsize, Parity par, StopBits sbits)
{
dcb.BaudRate = (uint)baud;
dcb.ByteSize = bsize;
dcb.Parity = par;
dcb.StopBits = sbits;
return SetCommState(hCOM, ref dcb);
}
public bool cleanCOM()
{
return PurgeComm(hCOM, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR);
}
public bool flushCOM()
{
return FlushFileBuffers(hCOM);
}
public bool TxByteCOM(byte dane)
{
return TransmitCommChar(hCOM, (char)dane);
}
public bool TxDataCOM(byte[] daneW)
{
int byteZap = 0;
return WriteFile(hCOM, daneW, daneW.Length, ref byteZap, 0);
}
public byte[] RxDataCOM(byte[] odebraneBytes, int ilosc, int odczytane)
{
if(ilosc == 0)
ilosc = bufferSize;
if(hCOM != INVALID_HANDLE_VALUE)
{
odczytane = 0;
bool stanOdczytu = true;
odebraneBytes = new byte[ilosc];
stanOdczytu = ReadFile (hCOM, odebraneBytes, ilosc, ref odczytane, 0);
if(stanOdczytu == false)
{
throw new ApplicationException("Błąd odczytu");
}
else
{
return odebraneBytes;
}
}
else
{
throw new ApplicationException ("Port nie został otwarty");
}
}
public int returnTime()
{
return GetTickCount();
}
private bool IsOdd(int value)
{
return value % 2 != 0;
}
public int sendByte(int X)
{
int D = 0;
int czas, temp;
byte[] B = new byte[1];
temp = X;
setCOM(115200, 8, Parity.None, StopBits.One);
cleanCOM();
czas = returnTime() + 50;
for (int n = 1; n <= 8; n++)
{
if (IsOdd(temp)) TxByteCOM(0xFF);
else TxByteCOM(0x00);
temp = temp << 1;
do
{
RxDataCOM(B, 1, D);
} while ((D > 1) | (czas < returnTime()));
if (D != 1) break;
if (IsOdd(B[0])) temp = (temp | 0x80);
}
return temp;
}
public bool sendCOM(byte[] WrByt)
{
int BytesWritten = 0;
bool writeState = false;
if (hCOM != INVALID_HANDLE_VALUE)
{
PurgeComm(hCOM, PURGE_RXCLEAR | PURGE_TXCLEAR);
writeState = WriteFile(hCOM, WrByt, WrByt.Length, ref BytesWritten, 0);
if (writeState == false)
{
throw new ApplicationException("Błąd zapisu do portu ");
}
}
else
{
throw new ApplicationException("Port nie został otwarty");
}
return writeState;
}
public byte[] receiveCOM (int NumBytes)
{
if(NumBytes == 0)
NumBytes = bufferSize;
if (hCOM != INVALID_HANDLE_VALUE)
{
int BytesRead = 0;
bool readState = true;
ReceiveBytes = new byte[NumBytes];
readState = ReadFile(hCOM, ReceiveBytes, NumBytes, ref BytesRead, 0);
if (readState == false)
{
throw new ApplicationException("Błąd odczytu");
}
else
{
return ReceiveBytes;
}
}
else
{
throw new ApplicationException("Port nie został otwarty");
}
}
public bool resetCOM()
{
int czasOd;
int D = 0;
byte[] baju = new byte[1];
byte[] lista = new byte[1];
setCOM(9600, 8, Parity.None, StopBits.One);
cleanCOM();
lista[0] = 0xF0;
sendCOM(lista);
czasOd = returnTime() + 50;
do
{
RxDataCOM(baju, 1, D);
}
while ((D == 1) | czasOd < returnTime());
if (D == 1)
return (baju[0] != 0xF0);
return true;
}
#endregion
}
}
这是我的申请代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using COMAPI;
namespace temp_3
{
class Program
{
static private COMutils util = new COMutils();
static void Main(string[] args)
{
int TH,TL;
int TEMP_READ;
double TEMP;
util.openCOM(1);
byte[] lista = new byte[1];
bool czy = util.resetCOM();
lista[0] = 0xCC;
czy = util.sendCOM(lista);
lista[0] = 0x44;
czy = util.sendCOM(lista);
Thread.Sleep(750);
czy = util.resetCOM();
lista[0] = 0xCC;
czy = util.sendCOM(lista);
lista[0] = 0xBE;
czy = util.sendCOM(lista);
TL = util.sendByte(0xFF);
Console.WriteLine(TL);
TH = util.sendByte(0xFF);
Console.WriteLine(TH);
czy = util.resetCOM();
Console.WriteLine(czy);
TEMP_READ = TL + 256 * TH;
TEMP = TEMP_READ / 16.0;
Console.WriteLine(TEMP);
Console.WriteLine(czy);
Console.ReadKey();
}
}
}
不幸的是,基于此代码,它读取的温度超过8000摄氏度。有人能指出错误在哪里吗?任何提示将不胜感激。以下是在Delphi中编写的函数:
function Reset_COM:boolean;
var B:Byte;
D,time:DWord;
begin
Result := False;
//ustawienie portu RS232
Ustaw_COM(9600,8,NOPARITY,ONESTOPBIT);
//czyszczenie RS232
Result := Czysc_COM;
TransmitCommChar(hCom,Chr($F0));
time:=GetTickCount+50;
repeat
ReadFile(hCom,B,1,D,nil)
until (D=1) or (time<GetTickCount);
if D=1 then
Result:=(B<>$F0);
end;
function send_Bajt(X:Byte):Byte;
var
n:Integer;
B:Byte;
D,time:DWord;
begin
Result:=$FF;
Ustaw_Com(115200,8,NOPARITY,ONESTOPBIT);
Czysc_COM;
time:=GetTickCount+50;
for n:=1 to 8 do
begin
if Odd(X) then TransmitCommChar(hCom,Chr($FF)) else TransmitCommChar(hCom,Chr($00));
X:=X shr 1;
repeat ReadFile(hCom,B,1,D,nil)
until (D=1) or (time<GetTickCount);
if D<>1 then exit;
if Odd(B) then X:=X or $80;
if Odd(B xor CRC)
then CRC:=((CRC xor $18) shr 1) or $80
else CRC:=CRC shr 1;
end;
Result:=X;
end;
function Odczytaj_TEMP:real;
var TH,TL:Byte;
TEMP_READ: Smallint;
Temp: double;
begin
Resetuj_COM;
send_Bajt($CC); //Skip ROM
send_Bajt($44); //Start T Convert
Sleep(750);
Resetuj_COM;
send_Bajt($CC); //Skip ROM
send_Bajt($BE); //Read Scratchpad
TL:=send_Bajt($FF);
TH:=send_Bajt($FF);
Resetuj_COM;
TEMP_READ := TL + 256 * TH;
Temp := TEMP_READ / 16.0;
Result := Temp;
end;