I have built an adapter DS9097E and connected to it DS18B20 digital thermometer. On the internet you can find examples of applications in Delphi and C that reads the temperature from this device. I'm trying to write it in C#. At the beginning I was relying on .NET but it didn't work. I had problems with RESET AND PRESENCE PULSES, so I tried with kernel32.dll. Yesterday I found this library: OpenNETCF. Unfortunately there is no documentation for it. In the meantime, I tried to write my own library:
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
}
}
This is code of my application:
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();
}
}
}
Unfortunately, based on this code, it reads the temperature of over 8000 degrees Celsius. Could someone point out where is the mistake? Any hint will be appreciated. Here are functions wrote in 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;