Source file: /~heha/hs/sht11.zip/win3x/SHT11.C

/* Ansteuerung des Temperatur- und Feuchte-Sensor-Schaltkreises
 * SHT11 mit dem PC am Parallelport
 * h#s 12/03
 */
#ifdef WIN32
# pragma comment(linker,"/OPT:nowin98")
# pragma comment(linker,"/LARGEADDRESSAWARE /RELEASE")
#endif

#ifdef _Windows
# define STRICT
# include <windows.h>
# include <ddeml.h>
# include <string.h>
#endif

#include <stdio.h>
#include <stdlib.h>	//exit
#ifndef TEXT
# define TEXT(x) x
# define TCHAR char
#endif
#ifdef WIN32
# ifdef UNICODE
#  define _UNICODE
# endif
# include <tchar.h>
#else
# include <dos.h>
typedef TCHAR *PTSTR, NEAR*NPTSTR, FAR*LPTSTR;
# define GetDlgItemTextA GetDlgItemText
# define _tcschr strchr
# define _stprintf sprintf
# define CP_WINNEUTRAL CP_WINANSI
#endif
typedef const TCHAR *PCTSTR, NEAR*NPCTSTR, FAR*LPCTSTR;
typedef enum {false,true} bool;
typedef unsigned char byte;
typedef unsigned word;
#define elemof(x) (sizeof(x)/sizeof((x)[0]))
#define T(x) TEXT(x)
word lpt;

#ifdef WIN32
#include <winioctl.h>
#include "PortTalk_IOCTL.h"
HANDLE hPortTalk;

void outportb(word a, byte b) {
#if 1
 DWORD bret;
 ((byte*)&a)[2]=b;
 DeviceIoControl(hPortTalk,IOCTL_WRITE_PORT_UCHAR,&a,3,NULL,0,&bret,NULL);
#else
 _asm{	mov	edx,[a]
	mov	eax,dword ptr [b]
	out	dx,al
 }
#endif
}

byte inportb(word a) {
#if 1
 DWORD bret;
 DeviceIoControl(hPortTalk,IOCTL_READ_PORT_UCHAR,&a,2,&a,1,&bret,NULL);
 return ((byte*)&a)[0];
#else
 _asm{	mov	edx,[a]
	in	al,dx
 }
#endif
}
#endif

void TransmissionStart(void) {
 outportb(lpt,0xE0);	// SCLK=1
 outportb(lpt,0x60);	// DATA=0
 outportb(lpt,0x20);	// SCLK=0
 outportb(lpt,0x60);	// SCLK=1
 outportb(lpt,0xE0);	// DATA=1
 outportb(lpt,0xA0);	// SCLK=0
}

void ConnectionReset(void) {
 int i;
 for (i=0;i<9;i++) {	// Startsequenz
  outportb(lpt,0xE0);	// SCLK=1
  outportb(lpt,0xA0);	// SCLK=0
 }
 TransmissionStart();
}

bool SendByte(byte x) {
 int i;
 bool b;
 for (i=0;i<8;i++) {
  outportb(lpt,(x&0x80)|0x20);	// Datenbit, MSB zuerst, SCLK=0
  outportb(lpt,(x&0x80)|0x60);	// SCLK=1
  x<<=1;
 }
 outportb(lpt,0xA0);	// SCLK=0, DATA=1 (hochohmig)
 outportb(lpt,0xE0);	// SCLK=1
 b=inportb(lpt+1)&0x40?false:true;	// true wenn DATA=0
 outportb(lpt,0xA0);	// Ruhezustand
 return b;
}

byte RecvByte(bool more) {
 int i;
 byte b=0,b2=0x20;
 for (i=0;i<8;i++) {
  outportb(lpt,0xE0);	// SCLK=1
  b=(b<<1)|(inportb(lpt+1)&0x40?1:0);
  outportb(lpt,0xA0);
 }
 if (!more) b2=0xA0;	// Je nach "end of transmission"
 outportb(lpt,b2);	// DATA=0 (oder 1 wenn letztes Byte)
 outportb(lpt,b2|0x40);	// SCLK=1
 outportb(lpt,0xA0);	// SCLK=0, DATA=1
 return b;
}

#define TIMEOUT 400	// Millisekunden
#ifdef _Windows
HWND MainWnd;		// Hauptfenster

bool ShortYield(void) {	// true wenn OK zum Fortsetzen
 MSG msg;
 if (!PeekMessage(&msg,0,0,0,PM_REMOVE)) return true;
 if (msg.hwnd==MainWnd && msg.message==WM_CLOSE) {
  PostMessage(msg.hwnd,msg.message,msg.wParam,msg.lParam);	// zurück
  return false;
 }
 TranslateMessage(&msg);
 DispatchMessage(&msg);
 return true;
}

bool WaitReady(void) {
 unsigned t=(unsigned)GetTickCount();
 while (inportb(lpt+1)&0x40) {	// warten solange High
  if ((unsigned)GetTickCount()-t>TIMEOUT) return false;
  if (!ShortYield()) return false;
 }return true;
}
#else
bool WaitReady(void) {
 unsigned t=*(unsigned*)MK_FP(0x40,0x6C);
 while (inportb(lpt+1)&0x40) {	// warten solange High
  if (*(unsigned*)MK_FP(0x40,0x6C)-t>TIMEOUT/55) return false;
 }return true;
}
#endif
#undef TIMEOUT

byte crc_start=0;
byte crc;

void cs_put(byte x) {	// Prüfsummen-Maschinerie
#ifdef _WIN32
 int i;
 for (i=0; i<8; i++) {
  crc=(crc>>1)^(((signed char)(x^(crc<<7))>>7)&0x8C);
  x<<=1;
 }
#else
 asm{	mov	ah,8
 }l1: asm{
	rol	x,1	// Bit 7 nach CY
	adc	al,al	// CY nach Bit 0 von AL
	xor	al,crc	// Bit 0 mit CRC Bit 0 verXORen
	shr	al,1	// das XOR-Ergebnis wieder nach CY
	sbb	al,al	// je nach CY 00 oder FF daraus machen
	and	al,0x8C	// daraus (sprungfrei!) 00 oder 8C machen
	shr	crc,1	// Bit 7 der CRC frei machen
	xor	crc,al	// neue CRC machen
	dec	ah	// Schleife
	jnz	l1
 }
#endif
}

word GetVal(byte code, bool twobyte) {
 word w;
 byte b;
 crc=crc_start;
 if (!SendByte(code)) {
#ifdef _Windows
  SetDlgItemText(MainWnd,111,T("▄bertragungsfehler!"));
  return 0;
#else
  printf(T("Übertragungsfehler!\n"));
  exit(2);
#endif
 }
 cs_put(code);
 if (!WaitReady()) {
#ifdef _Windows
  SetDlgItemText(MainWnd,111,T("Zeitⁿberschreitung!"));
  return 0;
#else
  printf(T("Zeitüberschreitung!\n"));
  exit(2);
#endif
 }
 w=b=RecvByte(true);
 cs_put(b);
 if (twobyte) {
  b=RecvByte(true);
  cs_put(b);
  w=(w<<8)|b;
 }
 b=RecvByte(false);
 if (crc!=b) {
#ifdef _Windows
  TCHAR s[64];
  wsprintf(s,T("Prⁿfsumme, %02X!=%02X!"),crc,b);
  SetDlgItemText(MainWnd,111,s);
#else
  printf(T("Prüfsumme falsch, crc=%02X, recv=%02X!\n"),crc,b);
  exit(2);
#endif
 }
 return w;
}

#ifdef _Windows
int CmdShow;
HFONT LargeFont;
HBRUSH BlueBrush;
HBRUSH YellowBrush;	// für DDE-Advise-Variablen
ATOM AtomBack;
DWORD DdeInst;
HSZ hszService,hszItem[2];
#define hszTopic hszService
#define WM_CONTINUEINIT (WM_USER+100)

HSZ CreateStringHandle(PCTSTR Str) {
 return DdeCreateStringHandle(DdeInst,Str,CP_WINNEUTRAL);
}

void FreeStringHandle(HSZ hsz) {
 if (hsz) DdeFreeStringHandle(DdeInst,hsz);
}

int CheckHsz(HSZ hsz) {
// liefert Fenster-ID für zu holenden String, 0 bei Fehler
 if (!DdeCmpStringHandles(hsz,hszItem[0])) return 108;
 if (!DdeCmpStringHandles(hsz,hszItem[1])) return 110;
 return 0;			// alles andere ist Fehler
}

#pragma argsused
HDDEDATA CALLBACK DdeCallback(UINT type, UINT fmt, HCONV conv,
 HSZ hsz1, HSZ hsz2, HDDEDATA data, DWORD data1, DWORD data2) {
 switch (type) {
  case XTYP_CONNECT: {
   if (hsz1==hszTopic) {
    SetDlgItemText(MainWnd,111,T("DDE-Verbindung gestartet"));
    return (HDDEDATA)TRUE;
   }
  }break;
  case XTYP_DISCONNECT: {
   SetDlgItemText(MainWnd,111,T("DDE-Verbindung beendet"));
  }break;
  case XTYP_REQUEST:
  case XTYP_ADVREQ: {
   int id=CheckHsz(hsz2);
   char s[16];
   if (fmt!=CF_TEXT) break;
   if (!id) break;
   return DdeCreateDataHandle(DdeInst,s,
     GetDlgItemTextA(MainWnd,id,s,elemof(s))+1,
     0,hsz2,fmt,0);
  }
  case XTYP_ADVSTART:
  case XTYP_ADVSTOP: {
   int id=CheckHsz(hsz2);
   HWND w;
   if (!id) break;
   w=GetDlgItem(MainWnd,id);
   id=(int)GetProp(w,(LPTSTR)AtomBack);
   id+=type==XTYP_ADVSTART?+1:-1;
   if (id) SetProp(w,(LPTSTR)AtomBack,(HANDLE)id);
   else RemoveProp(w,(LPTSTR)AtomBack);
   InvalidateRect(w,NULL,TRUE);
   return (HDDEDATA)TRUE;
  }
 }
 return (HDDEDATA)FALSE;
}

void DdeStart(void) {
 DdeInitialize(&DdeInst,DdeCallback,
   CBF_FAIL_POKES|CBF_FAIL_EXECUTES|
   CBF_SKIP_REGISTRATIONS|CBF_SKIP_UNREGISTRATIONS,0);
 hszService=CreateStringHandle(T("SHT11"));
 hszItem[0]=CreateStringHandle(T("T"));
 hszItem[1]=CreateStringHandle(T("F"));	// deutsch gedacht!
 AtomBack=AddAtom(T("DdeAdvises"));
 YellowBrush=CreateSolidBrush(0xC0FFFFL);
 DdeNameService(DdeInst,hszService,0,DNS_REGISTER);
}

void DdeStop(void) {
 DdeUninitialize(DdeInst);
 DeleteObject(YellowBrush);
}

#pragma argsused
BOOL CALLBACK MainDlgProc(HWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam){
 static TCHAR DefaultTitle[64];
 static TCHAR sDecimal[2];
 switch (Msg) {
  case WM_INITDIALOG: {
   MainWnd=Wnd;
   GetWindowText(Wnd,DefaultTitle,elemof(DefaultTitle));
   LargeFont=CreateFont(40,0,0,0,700,0,0,0,0,0,0,0,0,T("Times"));
   BlueBrush=CreateSolidBrush(0xFFC0C0L);
   if (LargeFont) {
    SendDlgItemMessage(Wnd,108,WM_SETFONT,(WPARAM)LargeFont,0);
    SendDlgItemMessage(Wnd,110,WM_SETFONT,(WPARAM)LargeFont,0);
   }
   DdeStart();
   SetTimer(Wnd,1,1000,NULL);
   SendMessage(Wnd,WM_WININICHANGE,0,0);
   PostMessage(Wnd,WM_CONTINUEINIT,0,0);
  }return TRUE;

  case WM_CONTINUEINIT: {
   ShowWindow(Wnd,CmdShow);
  }break;

  case WM_WININICHANGE: {
   GetProfileString(T("intl"),T("sDecimal"),T("."),sDecimal,elemof(sDecimal));
  }break;

  case WM_TIMER: {
   static int Fehler;
   word w;
   float t,f;
   TCHAR s[16];
   SetDlgItemText(Wnd,111,NULL);	// Statuszeile leeren
   ConnectionReset();		// Das ist erforderlich, sonst kommt nichts!
   w=GetVal(0x07,false);		// Statusregister
   crc_start=w&0x0F;			// idiotisch!!
   wsprintf(s,T("%02X"),w); SetDlgItemText(Wnd,102,s);
   CheckDlgButton(Wnd,103,(w>>6)&1);
   CheckDlgButton(Wnd,104,(w>>2)&1);
   CheckDlgButton(Wnd,105,(w>>1)&1);
   CheckDlgButton(Wnd,106,w&1);
   ConnectionReset();		// Das ist erforderlich, sonst kommt nichts!
   w=GetVal(0x03,true);			// Temperatur
   wsprintf(s,T("%04X"),w); SetDlgItemText(Wnd,107,s);
   if (w) {
    PTSTR p;
    t=-40.0+0.01*w;
    _stprintf(s,T("%.2f ░C"),t);
    p=_tcschr(s,T('.'));
    if (p) *p=sDecimal[0];
    SetDlgItemText(Wnd,108,s);
    DdePostAdvise(DdeInst,hszTopic,hszItem[0]);
    Fehler=0;
   }else{
    Fehler++;		// Ab 10 Fehler Fenstertext löschen!
    if (Fehler>10) SetDlgItemText(Wnd,108,T("--"));
   }
   ConnectionReset();		// Das ist erforderlich, sonst kommt nichts!
   w=GetVal(0x05,true);
   wsprintf(s,T("%04X"),w); SetDlgItemText(Wnd,109,s);
   if (w) {
    PTSTR p;
    f=-4+0.0405*w-2.8E-6*w*w;
    f+=(t-25)*(0.01+0.00008*w);
    _stprintf(s,T("%.2f %%"),f);
    p=_tcschr(s,T('.'));
    if (p) *p=sDecimal[0];
    SetDlgItemText(Wnd,110,s);
    DdePostAdvise(DdeInst,hszTopic,hszItem[1]);
    Fehler=0;
   }else{
    Fehler++;
    if (Fehler>10) SetDlgItemText(Wnd,110,T("--"));
   }
   if (IsIconic(Wnd)) goto settitle;
  }break;
  case WM_SIZE: if (wParam==SIZEICONIC) {
   TCHAR buf[32];
settitle:
   GetDlgItemText(Wnd,108,buf,16);
   lstrcat(buf,T("; "));
   GetDlgItemText(Wnd,110,buf+lstrlen(buf),16);
   SetWindowText(Wnd,buf);
  }break;
  case WM_QUERYOPEN: {
   SetWindowText(Wnd,DefaultTitle);
  }break;
#ifdef _WIN32
  case WM_CTLCOLORSTATIC: {
#else
  case WM_CTLCOLOR: {
#endif
   if ((HWND)lParam==GetDlgItem(Wnd,108)
   ||  (HWND)lParam==GetDlgItem(Wnd,110)) {
    SetBkMode((HDC)wParam,TRANSPARENT);
    if (GetProp((HWND)lParam,(LPTSTR)AtomBack)) return (BOOL)YellowBrush;
    return (BOOL)BlueBrush;
   }
  }break;

  case WM_COMMAND: switch (LOWORD(wParam)){
   case 101: {
    ConnectionReset();
    if (SendByte(0x06) && SendByte(IsDlgButtonChecked(Wnd,101)<<2));
    else SetDlgItemText(Wnd,111,T("Schreibversuch"));
   }break;
   case 1:
   case 2:
   EndDialog(Wnd,wParam);
  }break;

  case WM_DESTROY: {
   DdeStop();
   DeleteObject(LargeFont);
   DeleteObject(BlueBrush);
  }break;
 }
 return FALSE;
}

#pragma argsused
int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
  LPSTR lpCmdLine, int nCmdShow) {
 static WNDCLASS wc={
  CS_DBLCLKS,
  DefDlgProc,
  0,
  DLGWINDOWEXTRA,
  0,0,0,
  (HBRUSH)(COLOR_BACKGROUND+1),
  NULL,
  T("SHT11")};
 if (!hPrevInstance) {
  wc.hInstance=hInstance;
  wc.hIcon=LoadIcon(hInstance,MAKEINTRESOURCE(100));
  wc.hCursor=LoadCursor(0,IDC_ARROW);
  RegisterClass(&wc);
 }
#ifdef WIN32
 lpt=0x378;
 hPortTalk=CreateFile("\\\\.\\PortTalk",GENERIC_READ,0,NULL,OPEN_EXISTING,
   FILE_ATTRIBUTE_NORMAL,NULL);
 if (hPortTalk==INVALID_HANDLE_VALUE)
   MessageBox(0,T("PortTalk (www.beyondlogic.org/porttalk/) "
   "muss installiert und gestartet (net start PortTalk) sein!"),T("SHT11"),0);
#else
 lpt=*(unsigned far*)MK_FP(0x40,0x08);	// LPT1
 if (!lpt) {
  MessageBox(0,T("Kein LPT1 vorhanden!\n"),T("SHT11"),0);
  return IDCANCEL;
 }
#endif
 outportb(lpt,0xA0);	// Betriebsspannung anlegen, SCLK=0, DATA=1
 if (nCmdShow==SW_SHOWMAXIMIZED) nCmdShow=SW_SHOWNORMAL;
 CmdShow=nCmdShow;	// Diese Müh' wird von Win32 nicht belohnt!
 return DialogBox(hInstance,MAKEINTRESOURCE(100),0,MainDlgProc);
}

#else

int _cdecl main(void) {
 word w;
 float t,f;

 lpt=*(unsigned far*)MK_FP(0x40,0x08);	// LPT1
 if (!lpt) {
  printf(T("Kein LPT1 vorhanden!\n"));
  return 1;
 }
 outportb(lpt,0xA0);	// Betriebsspannung anlegen, SCLK=0, DATA=1
 ConnectionReset();
 w=GetVal(0x07,false);	// Statusregister und Prüfsumme
 printf(T("w=%02X, Status: LowBat=%d, Heizer=%d, OTP?=%d, 8bit=%d\n"),
   w,w&(1<<14)?1:0,w&(1<<10)?1:0,w&(1<<9)?1:0,w&(1<<8)?1:0);

 ConnectionReset();
 w=GetVal(0x03,true);
 t=-40.0+0.01*w;
 printf(T("w=%04X, Temperatur = %.2f °C\n"),w,t);

 ConnectionReset();
 w=GetVal(0x05,true);
 f=-4+0.0405*w-2.8E-6*w*w;
 f+=(t-25)*(0.01+0.00008*w);
 printf(T("w=%04X, rel. Feuchte = %.2f %\n"),w,f);

 return 0;
}
#endif
Detected encoding: OEM (CP437)1
Wrong umlauts? - Assume file is ANSI (CP1252) encoded