#include #include #include #include #include unsigned BASE=0x300; unsigned done=0; // Generic 8254 (Counter/Timer) control routines. void CtrMode(unsigned addr, char cntr, char mode) { int ctrl; ctrl = (cntr << 6) | 0x30 | (mode << 1); outportb(addr+3,ctrl); } void CtrLoad(unsigned addr ,int c,int val) { outportb(addr+c,val & 0x00FF); outportb(addr+c,(val>>8) & 0x00FF); } unsigned CtrRead(unsigned addr , int c) { outportb(addr+3,c<<6); return inportb (addr+c) + (inportb(addr+c) << 8); } unsigned AskFor(char *Prompt,unsigned int OldOne) { char msg[8]; unsigned int NewOne = 0, Success = 0, Dummy; int AddrInputPosX, AddrInputPosY; printf("\nPlease enter the %s (in hex) ",Prompt); printf("or press ENTER for %X.\n>",OldOne); AddrInputPosX = wherex(); AddrInputPosY = wherey(); do { gotoxy(AddrInputPosX, AddrInputPosY); clreol(); msg[0] = 5; msg[1] = 0; cgets(msg); sscanf(msg + 2, "%x", &NewOne); Success = 1; Dummy = NewOne; if (msg[1] == 0) { gotoxy(AddrInputPosX, AddrInputPosY); printf("%X", OldOne); Success = 1; Dummy = OldOne; } } while(!Success); return (Dummy); } /* end of AskForBaseAddress */ double long AskForDouble(char *Prompt,double OldOne) { char msg[28]; unsigned int Success = 0; double Dummy,NewOne; int AddrInputPosX, AddrInputPosY; printf("\nPlease enter the %s or press ENTER for %6.2lf.\n>",Prompt,OldOne); AddrInputPosX = wherex(); AddrInputPosY = wherey(); do { gotoxy(AddrInputPosX, AddrInputPosY); clreol(); msg[0] = 8; msg[1] = 0; cgets(msg); sscanf(msg + 2, "%lf", &NewOne); Success = 1; Dummy = NewOne; if (msg[1] == 0) { gotoxy(AddrInputPosX, AddrInputPosY); printf("%6.4lf", OldOne); Success = 1; Dummy = OldOne; } } while(!Success); return (Dummy); } /* end of AskForDouble */ /* SetHz */ // This function determines the "best-fit" divisors for any given target sample rate (Hz), and returns "achievable" sample rate // "ActualHz". It also sets two global variables Div1 and Div2, just in case someone wants to look at them, and configures the // two counters for the selected rate. unsigned long Div1,Div2; double SetHz(double Hz) { #define SourceHz 10000000.0 //Ctr1 Source is 10MHz double TargetDiv,Err,MinErr,ActualHz=0.0,L ; if (Hz*4.0 >= SourceHz) { Div1=2;Div2=2; } else { TargetDiv = SourceHz / Hz; L = sqrt(TargetDiv); Div1 = TargetDiv / L; Div2 = L; MinErr = abs(Hz - (SourceHz / (Div1 * L))); for(L=ceil(L);L>=2;L--) { Div1 = TargetDiv / L; if (Div1 > 0xFFFF) break; //Limited to 16 bits, so this and all further L are invalid. Err = abs(Hz - (SourceHz / (Div1 * L))); if (Err == 0) { Div2 = L; break; } if (Err < MinErr) { Div2 = L; MinErr = Err; } } Div1 = TargetDiv / Div2; } ActualHz = SourceHz / (Div1 * Div2); CtrMode(BASE+0x8,1,2); CtrMode(BASE+0x8,2,2); CtrLoad(BASE+0x8,1,Div1); CtrLoad(BASE+0x8,2,Div2); return ActualHz; } void main(void) { int i=0,sch=0,ech=0x0F,oversample=0,gaincode=0; double Hz=1.0; clrscr(); puts( "A/D Sample program - slow. DOS ONLY (Will not work in NT4 or later)\n" "This program demonstrates SIMPLE operation of many features of the A/D\n" "You will be prompted to enter the address of the card. If you are using\n" "a PCI card, please run PCIFind to determine this address. Non-PCI cards\n" "use the address set by the jumpers/switches.\n" "\n" "It is recommended that you choose the defaults the first time you run\n" "this program (other than the base address.)\n" "\n" ); /*gather information from the user*/ BASE=AskFor("Base Address",BASE); sch=AskFor("Start Channel (0-F)",sch); ech=AskFor("End Channel (0-F)",ech); gaincode=AskFor("Gain Code (0,1,2,3)",gaincode); // oversample=AskFor("Oversample (0-FF)",oversample); //note, oversample is commented out because the program isn't designed to //display more than 16 points onscreen. It gets really ugly and a little //confusing if you set oversample * number of channels to more than 16 in //this little sample. But, we left the code here so you can see how you //*would* use oversample. /* Ask for scan rate */ //This sample is only capable of fairly slow acquisition due to a number //of factors, such as using "printf()", as well as using FIFO Empty to //perform formatting. The cascaded 8254 counter timers used to time A/D //scan starts are very good at selecting slow frequencies, but available //rates decline as you get faster. The function SetHz calculates the //divisors for the counters, which can only be integers, and reports the //actual frequency you'll achieve. Hz = AskForDouble("Start SCAN Freq in Hz",10.0); printf("\nA/D SCAN Starts Desired at %4.4lf.\n\n",Hz); Hz = SetHz(Hz); printf("\nActual A/D SCAN Starts at %4.4lf.\n\n",Hz); puts( "The program now has enough information to begin.\n" "Please note, this program has not modified the digital calibration \n" "circuitry, so the data is probably uncalibrated. Please run the \n" "calibration program, or cal utility, to ensure calibration is valid if\n" "you experience problems.\n" "Press any key to run the acquistion. During the run press any key to exit.\n" ); getch(); clrscr(); /* set up the hardware as per user instruction */ outportb(BASE+0x1B,0x07); //perform a complete board reset outportb(BASE+0x06,(ech<<4)|sch);//write high and low channel numbers outportb(BASE+7,oversample); //configure the oversample regsiter outport(BASE+2,gaincode*0x5555); //we write the same gain code to every... outport(BASE+4,gaincode*0x5555); //channel - you can be more flexible outportb(BASE+0x11,0x05); //Configure Scan (0x04) with Timer (0x01) A/D Start Conversion Mode for(i=sch;i <= ech;i++) printf("%3d ",i); //print channel numbers puts(""); do{ while(((inportb(BASE+0x12) & 0x20) == 0x00) && (!kbhit()));//wait for not empty while (inportb(BASE+0x12) & 0x20) //drain until empty printf("%04X ",inport(BASE + 0x00));//print the data puts("");//newline on fifo empty }while (!kbhit()&&(!done)); outportb(BASE+0x11,0);//Disable start conversions (other than software) getch(); puts("program done."); }