/* 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); // zurck
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) { // Prfsummen-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("Zeitberschreitung!\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("Prfsumme falsch, crc=%02X, recv=%02X!\n"),crc,b);
exit(2);
#endif
}
return w;
}
#ifdef _Windows
int CmdShow;
HFONT LargeFont;
HBRUSH BlueBrush;
HBRUSH YellowBrush; // fr 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 fr 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 Mh' 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 Prfsumme
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: UTF-8 | 0
|