//--------------------------------------------------------------------------- #include #pragma hdrstop #include #include "f8254Unit.h" #include "ACCES32.h" //--------------------------------------------------------------------------- #pragma package(smart_init) #pragma resource "*.dfm" Tf8254Form *f8254Form; unsigned BaseAddress; const INITIALIZE = 1; // initialize the counter const START = 2; // start counting const SINCESTART = 4; // how many since starting const SINCELAST = 8; // how many since last check const STOP = 16; // stop counting const RESET = 32; // reset counter to 65535 //--------------------------------------------------------------------------- __fastcall Tf8254Form::Tf8254Form(TComponent* Owner) : TForm(Owner) { } //--------------------------------------------------------------------------- void CtrMode(unsigned long addr, byte cntr, byte mode) { int ctrl; ctrl = ((cntr << 6) | 0x30 | (mode << 1)); OutPortB(addr + 3, ctrl); }; // end CtrMode void CtrLoad(unsigned long addr, unsigned c, unsigned val) { OutPortB(addr + c, val & 0x00FF); OutPortB(addr + c, (val >> 8) & 0x00FF); }; // end CtrLoad // NOTE: CtrRead isn't actually used in this sample, but it is here for reference unsigned long CtrRead(unsigned long addr, unsigned c) { OutPortB(addr + 3, c << 6); return InPortB(addr + c) + (InPortB(addr + c) << 8); }; // end CtrRead unsigned ReadStatus(unsigned int Base) { OutPortB(Base + 3, 0xE4); // 1110 0100 ReadBack for ctr1 return InPortB(Base + 1) >> 7; // ctr1 output } void InitCounter(unsigned int Base) { CtrMode(Base, 0, 0); // 0011 0000 ctr0 LSB/MSB mode 0 CtrLoad(Base, 0, 0xFFFF); // load 65535 into ctr0 } unsigned ReadCounter0(unsigned int Base) { unsigned LSB, MSB; OutPortB(Base + 3, 0xD2); // 1101 0010 RB ctr0 latch LSB = InPortB(Base); // LSB of ctr0 MSB = InPortB(Base); // MSB of ctr0 return (MSB << 8) + LSB; // values at ctr1 = 0 } unsigned long ReadCounter1(unsigned int Base) { unsigned LSB, MSB; OutPortB(Base + 3, 0xD4); // 1101 0100 Read Back counts ctr1 LSB = InPortB(Base + 1); // ctr1 counts LSB MSB = InPortB(Base + 1); // ctr1 counts MSB return (MSB << 8) + LSB; } unsigned long ReadCounter2(unsigned int Base) { unsigned LSB, MSB; OutPortB(Base + 3, 0xD8); // 1101 1000 Read Back counts ctr2 LSB = InPortB(Base + 2); // ctr1 counts LSB MSB = InPortB(Base + 2); // ctr1 counts MSB return (MSB << 8) + LSB; } void __fastcall Tf8254Form::FeatureGroupClick(TObject *Sender) { StartButton->Enabled = true; FreqInTimer->Enabled = false; PulseWidthTimer->Enabled = false; switch (FeatureGroup->ItemIndex) { case 0: StartButton->Caption = "Start Input"; FreqInPanel->Visible = true; FreqOutPanel->Visible = false; EventCountPanel->Visible = false; PulseWidthPanel->Visible = false; Instructions->SelStart = 161; Instructions->SelLength = 1000; Instructions->SelText = "Frequency Measurement requires CTR0 Gate controlled by CTR1 Output and a 1MHz clock input to CTR1. Bring the the frequency you want to measure into Counter 0 input."; Instructions->Lines->Add("Click the ""Start Measure"" button to demonstrate the frequency measuring feature. The measured frequency will be displayed in the text box."); break; case 1: StartButton->Caption = "Start Output"; FreqInPanel->Visible = false; FreqOutPanel->Visible = true; EventCountPanel->Visible = false; PulseWidthPanel->Visible = false; Instructions->SelStart = 161; Instructions->SelLength = 1000; Instructions->SelText = "Frequency Generation requires a 1MHz input to CTR1, and CTR1 Output connected to CTR2 Clock, as well as both CTR1 & CTR2 Gates enabled. The frequency will be generated from Counter 2 output."; Instructions->Lines->Add("To demonstrate the frequency output feature, enter the desired output frequency in the text box (between 1Hz and 250000Hz), then click the ""Start Output"" button."); Instructions->Lines->Add("The actual output frequency will be also be displayed."); break; case 2: StartButton->Caption = "Start Counts"; FreqInPanel->Visible = false; FreqOutPanel->Visible = false; EventCountPanel->Visible = true; PulseWidthPanel->Visible = false; Instructions->SelStart = 161; Instructions->SelLength = 1000; Instructions->SelText = "Event Counting requires CTR0 Gate enabled, or connected to CTR1. Bring your pulse train in on Counter 0 input."; Instructions->Lines->Add("Click the ""Start Counting"" button to demonstrate the event counting feature. Use the ""Since First"" and ""Since Last"" buttons to display the event counts since starting the demo, and since the last reading, respectively."); Instructions->Lines->Add("Use the ""Stop & Reset"" button to stop the demo, and reset the count."); break; case 3: StartButton->Caption = "Start Measure"; FreqInPanel->Visible = false; FreqOutPanel->Visible = false; EventCountPanel->Visible = false; PulseWidthPanel->Visible = true; Instructions->SelStart = 161; Instructions->SelLength = 1000; Instructions->SelText = "Pulse Width Measurement requires a 1MHz input to CTR1. Bring the the signal you want to measure into Gate 1."; Instructions->Lines->Add("Click the ""Start Measure"" button to demonstrate the pulse width measuring feature. The measured pulse width will be displayed in the text box."); break; } // end switch } //--------------------------------------------------------------------------- void __fastcall Tf8254Form::FreqInTimerTimer(TObject *Sender) { unsigned secondcount; unsigned long timeout; timeout = 65535; CtrMode(BaseAddress, 1, 3); // 0111 0110 ctr1 mode3, LSB/MSB CtrLoad(BaseAddress, 1, 0xFFFE); // load LSB and MSB values into // ctr1 to make slow input to gate 0 while ((ReadStatus(BaseAddress) == 1) && (timeout != 0)) timeout--; // out ctr1 = 1 timeout = 65535; CtrMode(BaseAddress, 0, 2); // 0011 0100 ctr0 mode 2 L/M CtrLoad(BaseAddress, 0, 0xFFFF); // load 65535 into ctr 0 while ((ReadStatus(BaseAddress) == 0) && (timeout != 0)) timeout--; // ctr1 still 0 timeout = 65535; while ((ReadStatus(BaseAddress) == 1) && (timeout != 0)) timeout--; // ctr1 = 1 secondcount = ReadCounter0(BaseAddress); // read value of counter FreqInEdit->Text = IntToStr((int)((65535 - secondcount)/0.032767)); // convert from counts to f } //--------------------------------------------------------------------------- float FreqOutTest(unsigned Base, unsigned long frequency) { unsigned long countsA, countsB; unsigned long temp, x; double trash; x = 2; //Result := 0; if ((frequency > 250000) || (frequency < 1)) return 0; // return if freq is too low/high trash = frequency; // convert to float for division trash = 1000000 / trash; // calculate the number of counts temp = (int)(trash); // round to the nearest count do { // try to divide the counts countsA = x; // evenly between the two counters x++; } while (((temp % countsA) != 0) && (countsA < temp) && (countsA < 65535)); // exit if counts too high if ((countsA >= temp) && (temp < 131070)) { // gone through all vals countsA = 2; // counter can only hold 65535 countsB = temp / 2; } else { if (temp >= 131070) { // counts too high to fit in counter countsA = 20; // divide to make fit countsB = temp / 20; } else countsB = temp / countsA; // if found divisor use it } // end if/else CtrMode(Base, 2, 3); // 1011 1110 ctr2 mode3 CtrLoad(Base, 2, countsA); CtrMode(Base, 1, 2); // 0111 0100 ctr1 mode2 CtrLoad(Base, 1, countsB); return 1000000 / (countsA * countsB); } // end FreqOutTest unsigned EventCountTest(unsigned Base, int feature) { static unsigned previousmeasure = 0; unsigned currentmeasure, returnvalue; bool flag; flag = false; returnvalue = 0; currentmeasure = 0; if ((INITIALIZE & feature) != 0) // 1 InitCounter(Base); // init counter0 to count in mode 0 if ((START & feature) != 0) // 2 CtrMode(Base, 1, 1); // 0111 0010 ctr1 LSB/MSB mode 1 // to hold gate of ctr0 high if ((SINCESTART & feature) != 0) { // 4 if (!flag) { // counts down from 65535 currentmeasure = 65535 - ReadCounter0(Base); flag = true; // flag read counter } returnvalue = currentmeasure; // set value to return } if ((SINCELAST & feature) != 0) { // 8 if (!flag) { // calculate counts currentmeasure = 65535 - ReadCounter0(Base); flag = true; } // calculate since last returnvalue = currentmeasure - previousmeasure; } if ((STOP & feature) != 0) // 16 CtrMode(Base, 1, 0); // 0111 0000 ctr1 mode0 out=0 if ((RESET & feature) != 0) { // 32 InitCounter(Base); // init counter to 65535 previousmeasure = 0; // no previous counts } if (flag) { // set previous measure if counter read previousmeasure = currentmeasure; return returnvalue; // if counter read return value } else return 0; // return 0 if counter not read } // end EventCountTest void __fastcall Tf8254Form::SinceFirstButtonClick(TObject *Sender) { EventCountEdit->Text = IntToStr(EventCountTest(BaseAddress, SINCESTART)); } //--------------------------------------------------------------------------- void __fastcall Tf8254Form::SinceLastButtonClick(TObject *Sender) { EventCountEdit->Text = IntToStr(EventCountTest(BaseAddress, SINCELAST)); } //--------------------------------------------------------------------------- void __fastcall Tf8254Form::EventTestButtonClick(TObject *Sender) { EventCountTest(BaseAddress, STOP + RESET); FeatureGroup->Enabled = true; } //--------------------------------------------------------------------------- void __fastcall Tf8254Form::PulseWidthTimerTimer(TObject *Sender) { const TIMEOUTVAL = 150000; unsigned long temp, secondcount, previouscount; unsigned long timeout; unsigned long one, two; CtrMode(BaseAddress, 2, 2); // ctr2 mode2 CtrLoad(BaseAddress, 2, 0xFFFF); // write 65535 to counter 2 CtrMode(BaseAddress, 1, 2); // ctr1 mode2 CtrLoad(BaseAddress, 1, 0xFFFF); // write 65535 to counter 1 temp = ReadCounter1(BaseAddress); // read the counter timeout = 0; //the following two repeat-until loops ensure a high transition has happened //(a high on gate input reloads the counter) do { previouscount = temp; temp = ReadCounter1(BaseAddress); timeout++; } while (!((temp == previouscount) || (timeout >= TIMEOUTVAL))); one = ReadCounter2(BaseAddress); if (timeout < TIMEOUTVAL) timeout = 0; do { secondcount = ReadCounter1(BaseAddress); timeout++; } while (!((temp != secondcount) || (timeout >= TIMEOUTVAL))); if (timeout < TIMEOUTVAL) timeout = 0; // wait until the counts stop (low on the gate again) do { previouscount = secondcount; secondcount = ReadCounter1(BaseAddress); timeout++; } while (!((secondcount == previouscount) || (timeout >= TIMEOUTVAL))); two = ReadCounter2(BaseAddress); if (timeout < TIMEOUTVAL) // return the counts for the pulse PulseEdit->Text = IntToStr((one - two) * 65536 + (65535 - secondcount)); else PulseEdit->Text = '0'; } // end PulseWidthTimerTimer //--------------------------------------------------------------------------- void __fastcall Tf8254Form::StartButtonClick(TObject *Sender) { unsigned long frequency; BaseAddress = StrToInt("0x" + BaseEdit->Text); switch (FeatureGroup->ItemIndex) { case 0: if (FreqInTimer->Enabled == false) { FreqInTimer->Tag = BaseAddress; StartButton->Caption = "Stop Measure"; FreqInTimer->Enabled = true; } else { StartButton->Caption = "Start Measure"; FreqInTimer->Enabled = false; } case 1: frequency = StrToInt(FreqOutEdit->Text); RealEdit->Text = FloatToStr(FreqOutTest(BaseAddress, frequency)); case 2: EventCountTest(BaseAddress, INITIALIZE + START); case 3: if (PulseWidthTimer->Enabled == false) { PulseWidthTimer->Tag = BaseAddress; StartButton->Caption = "Stop Measure"; PulseWidthTimer->Enabled = true; } else { StartButton->Caption = "Start Measure"; PulseWidthTimer->Enabled = false; } } // end swtich } //--------------------------------------------------------------------------- void __fastcall Tf8254Form::ExitButtonClick(TObject *Sender) { Close(); } //--------------------------------------------------------------------------- void __fastcall Tf8254Form::FormClose(TObject *Sender, TCloseAction &Action) { EventCountTest(BaseAddress, STOP + RESET); FreqInTimer->Enabled = false; PulseWidthTimer->Enabled = false; } //--------------------------------------------------------------------------- void __fastcall Tf8254Form::FormCreate(TObject *Sender) { if (InPortB(0x61) == 0xAA55) { Application->MessageBox("ACCESNT.SYS not detected. Please copy ACCESNT.SYS into [NT]/system32/drivers and re-run this sample.", "Warning", IDOK); } } //---------------------------------------------------------------------------