View previous topic :: View next topic |
Author |
Message |
sonicfire
Joined: 11 Feb 2007 Posts: 19 Location: Cedar Rapids
|
tachometer issues |
Posted: Thu Apr 12, 2007 2:49 pm |
|
|
I've been working on building a tachometer for a dc motor. The motor's axel has a gear with 24 teeth (24 teeth per revolution). The teeth go in between a photodiode and sensor. This creates a square wave. I wrote a program for a PIC 16F877 that counts the number of low to high signals that occur in one second. This count is then divided by 4 to give the RPM (in powers of 10) and then display the output. Here's the code:
Code: | #include <16F877.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=10000000)
#define TIMER_SET 65535-25000 //holds the initial condition of timer
int8 hundredths;
int8 tenths;
int8 seconds;
int last_value;
int current_value;
unsigned int8 rpm = 0;
unsigned int8 teeth = 0;
unsigned int8 huns;
unsigned int8 tens;
unsigned int8 ones;
//int overflow;
void main() {
setup_timer_1(T1_INTERNAL); //1Mhz/8 gives us 125000Hz because it originally is
// divided by 4 automatically
hundredths = 0;
tenths = 0;
seconds = 0;
set_timer1(TIMER_SET);
enable_interrupts(INT_TIMER1);
enable_interrupts(GLOBAL);
last_value = input(PIN_C0);
//only counts
while( TRUE ) {
current_value = input(PIN_C0);
if(last_value == 0) {
if(current_value == 1) {
teeth = teeth + 1;
last_value = 1;
}
}
else { //last_value = 1
if(current_value == 0) {
last_value = 0;
}
}
}
}
//interupt
#INT_TIMER1
void time_increment_isr()
{
set_timer1(TIMER_SET + get_timer1() + 26);
hundredths ++;
if (hundredths == 10)
{
hundredths = 0;
tenths++;
}
if (tenths == 10)
{
tenths = 0;
seconds++;
}
if (seconds == 1)
{
//fancy output time...
//teeth/4 comes from (teeth)(1Rev/24teeth)(60seconds/min)(divided by 10). Value is RPMx10
//divide by 4 will be done by right shifting the digits to the right by two spaces, no need to do this math, just output what is desired
rpm = (teeth/4);
//NEED TO CONVERT THE RPM INT INTO DECIMAL BINARY EQUIVALENT FOR 7 SEGMENT DISPLAYS...
huns = rpm/100;
tens = (rpm - (huns*100) )/10;
ones = rpm - ((huns*100)+(tens*10));
//convert the huns
switch (huns) {
case 0:
output_low(PIN_B7);
output_low(PIN_B6);
output_low(PIN_B5);
output_low(PIN_B4);
break;
case 1:
output_low(PIN_B7);
output_low(PIN_B6);
output_low(PIN_B5);
output_high(PIN_B4);
break;
case 2:
output_low(PIN_B7);
output_low(PIN_B6);
output_high(PIN_B5);
output_low(PIN_B4);
break;
case 3:
output_low(PIN_B7);
output_low(PIN_B6);
output_high(PIN_B5);
output_high(PIN_B4);
break;
case 4:
output_low(PIN_B7);
output_high(PIN_B6);
output_low(PIN_B5);
output_low(PIN_B4);
break;
case 5:
output_low(PIN_B7);
output_high(PIN_B6);
output_low(PIN_B5);
output_high(PIN_B4);
break;
case 6:
output_low(PIN_B7);
output_high(PIN_B6);
output_high(PIN_B5);
output_low(PIN_B4);
break;
case 7:
output_low(PIN_B7);
output_high(PIN_B6);
output_high(PIN_B5);
output_high(PIN_B4);
break;
case 8:
output_high(PIN_B7);
output_low(PIN_B6);
output_low(PIN_B5);
output_low(PIN_B4);
break;
case 9:
output_high(PIN_B7);
output_low(PIN_B6);
output_low(PIN_B5);
output_high(PIN_B4);
break;
default:
output_high(PIN_B7);
output_high(PIN_B6);
output_high(PIN_B5);
output_high(PIN_B4);
break;
}
//convert the tens
switch (tens) {
case 0:
output_low(PIN_B3);
output_low(PIN_B2);
output_low(PIN_B1);
output_low(PIN_B0);
break;
case 1:
output_low(PIN_B3);
output_low(PIN_B2);
output_low(PIN_B1);
output_high(PIN_B0);
break;
case 2:
output_low(PIN_B3);
output_low(PIN_B2);
output_high(PIN_B1);
output_low(PIN_B0);
break;
case 3:
output_low(PIN_B3);
output_low(PIN_B2);
output_high(PIN_B1);
output_high(PIN_B0);
break;
case 4:
output_low(PIN_B3);
output_high(PIN_B2);
output_low(PIN_B1);
output_low(PIN_B0);
break;
case 5:
output_low(PIN_B3);
output_high(PIN_B2);
output_low(PIN_B1);
output_high(PIN_B0);
break;
case 6:
output_low(PIN_B3);
output_high(PIN_B2);
output_high(PIN_B1);
output_low(PIN_B0);
break;
case 7:
output_low(PIN_B3);
output_high(PIN_B2);
output_high(PIN_B1);
output_high(PIN_B0);
break;
case 8:
output_high(PIN_B3);
output_low(PIN_B2);
output_low(PIN_B1);
output_low(PIN_B0);
break;
case 9:
output_high(PIN_B3);
output_low(PIN_B2);
output_low(PIN_B1);
output_high(PIN_B0);
break;
default:
output_high(PIN_B3);
output_high(PIN_B2);
output_high(PIN_B1);
output_high(PIN_B0);
break;
}
//convert the ones
switch (ones) {
case 0:
output_low(PIN_D7);
output_low(PIN_D6);
output_low(PIN_D5);
output_low(PIN_D4);
break;
case 1:
output_low(PIN_D7);
output_low(PIN_D6);
output_low(PIN_D5);
output_high(PIN_D4);
break;
case 2:
output_low(PIN_D7);
output_low(PIN_D6);
output_high(PIN_D5);
output_low(PIN_D4);
break;
case 3:
output_low(PIN_D7);
output_low(PIN_D6);
output_high(PIN_D5);
output_high(PIN_D4);
break;
case 4:
output_low(PIN_D7);
output_high(PIN_D6);
output_low(PIN_D5);
output_low(PIN_D4);
break;
case 5:
output_low(PIN_D7);
output_high(PIN_D6);
output_low(PIN_D5);
output_high(PIN_D4);
break;
case 6:
output_low(PIN_D7);
output_high(PIN_D6);
output_high(PIN_D5);
output_low(PIN_D4);
break;
case 7:
output_low(PIN_D7);
output_high(PIN_D6);
output_high(PIN_D5);
output_high(PIN_D4);
break;
case 8:
output_high(PIN_D7);
output_low(PIN_D6);
output_low(PIN_D5);
output_low(PIN_D4);
break;
case 9:
output_high(PIN_D7);
output_low(PIN_D6);
output_low(PIN_D5);
output_high(PIN_D4);
break;
default:
output_high(PIN_D7);
output_high(PIN_D6);
output_high(PIN_D5);
output_high(PIN_D4);
break;
}
//make sure everthing is reset before resuming the count
teeth = 0;
hundredths = 0;
tenths = 0;
seconds = 0;
}
} |
Thanks! |
|
|
Ttelmah Guest
|
|
Posted: Thu Apr 12, 2007 3:32 pm |
|
|
You don't say what your 'issues' are. However there are some glaring things. Your #use delay statement, is for a 10MHz clock, not a 1Mhz clock. This would also make sense of the 'HS' fuse. Then your timer setup, gives a rate of 2.5MHz (if this is right), or 250KHz, if the source is 1MHz.The clock is being divided by four. For /8, you need T1_INTERNAL | T1_DIV_BY_2
Then you are doing vastly too much in the interrupt handler.
Best Wishes |
|
|
rnielsen
Joined: 23 Sep 2003 Posts: 852 Location: Utah
|
|
Posted: Thu Apr 12, 2007 4:24 pm |
|
|
Like Ttelmah said, there is WAY too much going on in the ISR. Keep it as short as possible. Set a few things and then bail out. Let the main() section take care of the calculation stuff. The ISR is going to take so much time that it's likely that your input(PIN_C0) statement could miss a few pulses.
Quote: | set_timer1(TIMER_SET + get_timer1() + 26); |
Even though this is being done as the first instruction of the ISR you'll be half way down the block by the time it's done and will cause inaccuracies.
Ronald |
|
|
sonicfire
Joined: 11 Feb 2007 Posts: 19 Location: Cedar Rapids
|
|
Posted: Fri Apr 13, 2007 12:15 pm |
|
|
The PIC is being run off of a 10 MHz oscillator. The problem is simply that it is giving me bogus values. The values it gives are proportional to changes in speed, but are nothing resembling the RPMs. I realize that I am putting a lot of command requirements on the PIC. Is there a way to reduce this? Also, could there be a problem in the way the PIC handles math that would cause errors? |
|
|
|