//Counter Driver for the 8254 chip #include #include #include #include #include //Base Address passed is actually base the offset for the address of the //counter unsigned read_status(unsigned BaseAddress) { unsigned status; outp(BaseAddress + 3, 0xE4); // 1110 0100 ReadBack for ctr1 status = inp(BaseAddress + 1); // ctr1 output status = status >> 7; return(status); } unsigned get_count(unsigned BaseAddress) { unsigned counted=0, LSB=0, MSB=0, x; outp(BaseAddress + 3, 0xD2); // 1101 0010 LSB = inp(BaseAddress); // LSB of ctr0 MSB = inp(BaseAddress); // MSB of ctr0 counted = (MSB << 8) + LSB; // values at ctr1 = 0 return(counted); } long frequency_measure(unsigned BaseAddress) { unsigned secondcount=0; double frequency; long returnval; unsigned long timeout = 655350L; outp(BaseAddress + 3, 0x76); // 0111 0110 ctr1 mode3, LSB/MSB outp(BaseAddress + 1, 0xFE); // load LSB and MSB values into outp(BaseAddress + 1, 0xFF); // ctr1 to make slow input to gate 0 while (read_status(BaseAddress) && timeout--); // out ctr1 = 1 timeout = 655350L; outp(BaseAddress + 3, 0x34); // 0011 0100 ctr0 mode 2 L/M outp(BaseAddress, 0xFF); outp(BaseAddress, 0xFF); // load 65535 into ctr 0 while (!(read_status(BaseAddress)) && timeout--); // ctr1 still 0 timeout = 655350L; while (read_status(BaseAddress) && timeout--); // ctr1 = 1 timeout = 655350L; secondcount = get_count(BaseAddress); // read value of counter frequency = (65535 - secondcount)/0.032767; // convert from counts to f returnval = frequency; // convert from double to int return(returnval); } void init_counter(unsigned BaseAddress) { outp(BaseAddress + 3, 0x30); // 0011 0000 ctr0 LSB/MSB mode 0 outp(BaseAddress, 0xFF); outp(BaseAddress, 0xFF); // load 65535 into ctr0 } unsigned read_counter(unsigned BaseAddress) { int countval; outp(BaseAddress + 3, 0xD2); // 1101 0010 RB ctr0 latch countval = inp(BaseAddress); // LSB countval += (inp(BaseAddress) << 8); // MSB return (countval); } unsigned event_counter(unsigned BaseAddress, int feature) { 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 static unsigned previousmeasure = 0; unsigned currentmeasure, returnval; int flag = 0; if (INITIALIZE & feature) // 1 { init_counter(BaseAddress); // init counter0 to count in mode 0 } if (START & feature) // 2 { outp(BaseAddress + 3, 0x74); // 0111 0010 ctr1 LSB/MSB mode 1 // to hold gate of ctr0 high } if (SINCESTART & feature) // 4 { if (!flag) // counts down from 65535 { currentmeasure = 65535 - read_counter(BaseAddress); flag = 1; // flag read counter } returnval = currentmeasure; // set value to return } if (SINCELAST & feature) // 8 { if (!flag) { // calculate counts currentmeasure = 65535 - read_counter(BaseAddress); flag = 1; } // calculate since last returnval = currentmeasure - previousmeasure; } if (STOP & feature) // 16 { outp(BaseAddress + 3, 0x70); // 0111 0000 ctr1 mode0 out=0 } if (RESET & feature) // 32 { init_counter(BaseAddress); // init counter to 65535 previousmeasure = 0; // no previous counts } if (flag) // set previous measure if counter read previousmeasure = currentmeasure; if (flag) return(returnval); // if counter read return value else return (0); // return 0 if counter not read } long round(float number) // round off the floats { float compareval; long returnval; compareval = (long)(number); // convert to long if (number > (compareval + 0.5)) // round up for > 0.5 returnval = compareval + 1; else returnval = compareval; // round down for <= 0.5 return (returnval); // return long } void generatefrequency(unsigned BaseAddress, unsigned long frequency) { unsigned int countsA, countsB; long temp; float trash = 0; unsigned int x = 2; // return if freq is too low/high if ((frequency > 250000) || (frequency < 1)) return; trash = (float)(frequency); // convert to float for division trash = 1000000/trash; // calculate the number of counts temp = round(trash); // round to the nearest count do { // try to divide the counts countsA = x; // evenly between the two counters x++; } // exit if counts too high while ((temp % countsA) && (countsA < temp) && (countsA < 65535)); if ((countsA >= temp) && (temp < 131070)) { // went 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 } outp(BaseAddress + 3, 0xBE); // 1011 1110 ctr2 mode3 temp = countsA & 0x00FF; outp(BaseAddress + 2, temp); // write the low byte temp = countsA >> 8; temp &= 0x00FF; outp(BaseAddress + 2, temp); // write the high byte outp(BaseAddress + 3, 0x74); // 0111 0100 ctr1 mode2 temp = countsB & 0x00FF; outp(BaseAddress + 1, temp); // write the low byte temp = countsB >> 8; temp &= 0x00FF; outp(BaseAddress + 1, temp); // write the high byte } unsigned total_count(unsigned BaseAddress) { unsigned LSB, MSB; outp(BaseAddress + 3, 0xD4); // 1101 0100 Read Back counts ctr1 LSB = inp(BaseAddress + 1); // ctr1 counts LSB MSB = inp(BaseAddress + 1); // ctr1 counts MSB return (MSB << 8) + LSB; } unsigned count2(unsigned BaseAddress) { unsigned LSB, MSB; outp(BaseAddress + 3, 0xD8); // 1101 1000 Read Back counts ctr1 LSB = inp(BaseAddress + 2); // ctr1 counts LSB MSB = inp(BaseAddress + 2); // ctr1 counts MSB return (MSB << 8) + LSB; } double pulse_measure(unsigned BaseAddress) { #define TIMEOUTVAL 150000 unsigned firstcount = 0; unsigned secondcount = 0; unsigned previouscount = 0; unsigned time = 0; unsigned long timeout; unsigned one, two; outp(BaseAddress + 3, 0xB4); // 1011 0100 ctr2 mode2 outp(BaseAddress + 2, 0xFF); // write 65535 to counters outp(BaseAddress + 2, 0xFF); outp(BaseAddress + 3, 0x72); // 0111 0010 ctr1 mode2 delay(1); outp(BaseAddress + 3, 0x70); // 0111 0000 ctr1 mode2 delay(1); outp(BaseAddress + 3, 0x74); // 0111 0100 ctr1 mode2 outp(BaseAddress + 1, 0xFF); // write 65535 to counters outp(BaseAddress + 1, 0xFF); firstcount = total_count(BaseAddress); // read the counter timeout = 0; do { previouscount = firstcount; firstcount = total_count(BaseAddress); timeout++; } while ((firstcount != previouscount) && (timeout < TIMEOUTVAL)); // check to see if the counts are changing one = count2(BaseAddress); if (timeout < TIMEOUTVAL) timeout = 0; do { secondcount = total_count(BaseAddress); timeout++; } while ((firstcount == secondcount) && (timeout < TIMEOUTVAL)); // check to see if counts are stable if (timeout < TIMEOUTVAL) timeout = 0; do { previouscount = secondcount; delay(1); secondcount = total_count(BaseAddress); timeout++; } while ((secondcount != previouscount) && (timeout < TIMEOUTVAL)); // check to see if counts are changing two = count2(BaseAddress); if (timeout < TIMEOUTVAL) { time = firstcount - secondcount; return(time); // return the counts for the pulse } else return 0; } void syncronize(unsigned BaseAddress) { unsigned secondcount = 0; unsigned previouscount = 0; unsigned timeout = 500; secondcount = total_count(BaseAddress); do { previouscount = secondcount; delay(1); secondcount = total_count(BaseAddress); } while ((secondcount != previouscount) && timeout--); } double pulse_width(unsigned BaseAddress) { unsigned temp = 0; syncronize(BaseAddress); temp = pulse_measure(BaseAddress); return(temp); }