RE: Input Capture for vehicle speed

Go To Last Post
18 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Reduce your code to the smallest representation that reproduces the problem. Then post your question, without any details disclosing your mental problems.

Then, if you're lucky, somebody will try to help you.

Sid

Life... is a state of mind

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I always have a hard time getting input capture to work. Its a range/resolution problem. It seems way easier to just poll the input looking for a rising edge, read the current tic counter into t1, wait for the input to go low, then wait for it to go hi again and read it a second time, save the current tics into t2. At this point you calc dt=t2-t1, and go crazy computing hz, rps, rpm, furlongs per fortnight etc etc. Doesnt need any interrupts othe than the overflow interrupt in the timer1 (gives a 24 bit count at 50ns per count). You need finer res than that?

Imagecraft compiler user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
Reduce your code to the smallest representation that reproduces the problem. Then post your question.

Here is the code,

#define F_CPU 1000000UL 
#include 
#include 
#include 
#include 
#include 
#include 
#include "EPAScontroller.h"

//---------------- Functions Prototypes --------------------
uint16_t readRPM(void);
void setValues(void);

//------------------ Global Variables ----------------------
volatile unsigned int in_timeout;
volatile uint16_t diff;
volatile uint16_t period; // Input capture time
volatile ADCtime = False;
float rollOut; // Tyre rolling distance in meters

void init_TIMER0(void)
{
	TCCR0B |= (1 << CS00)|(1 << CS01);  // 64 pre scaler 16.38 msec overflow
	TIMSK0 |= (1 << TOIE0);    // Enable Timer 0 interrupt on overflow
}

void init_Timer1(void)
{          
	TCCR1A = 0x00;      // normal mode
	TCCR1B = 0x43;     // (01000011) Rising edge trigger, Timer = CPU Clock/64 
	TCCR1C = 0x00;      // normal mode
	TIMSK1 = 0x20;     // (00100001) Input capture	
	TCNT1 = 0x00;       // start from 0
}

static void io_init(void)
{
	PORTD = (1<<PD7);
	DDRD = (1<<DDD7) | (1<<DDD4) | (1<<DDD3) | (1<<DDD1);
	
	ACSR = (1<<ACD);  // Analog Comparator Disabled
}

//////////////////////////////////  MAIN   /////////////////////////////////////////
int main(void)
{
   
   GetMapFromEEPROM();
   setValues();
   
   uint16_t rpm;
   io_init();
   init_TIMER0();
   init_Timer1();
   
   
   sei(); // Enable Global Interrupts
   
    while(1)
    {
        
       if (ADCtime == True) {
		  rpm = readRPM();  // wheel rpm
		  ecu.data.speed = (uint8_t)(((rollOut * rpm) / 1000.0) * 60);  // convert to Kph  
		  ADCtime = False;   
       } 	   
	  
    }
}

/////////////////////////////////////////////////////////////////////////////////////

//----------------------- Timer 0 Interrupt -----------------------
ISR (TIMER0_OVF_vect)
{
	static uint8_t cnt = 0;
	
	if (ADCtime == False) {
		cnt++;
		if (cnt > 2) {
			cnt = 0;
			ADCtime = True;
		}
	}
}


//---------------------- Timer1 Input Capture -----------------------------------
ISR(TIMER1_CAPT_vect)  // PULSE DETECTED
{
	static unsigned int recoded ,previous; 
	
		recoded = ICR1;
		
		diff = recoded  - previous;       //calc difference
		previous = recoded ;             //update previous value
		TCNT1 = 0;       // restart timer for next revolution  
		in_timeout = IN_RELOAD;       //reload input timeout 
		PORTD = PORTD^0x80;      // toggle PD7 pin
}



//----------------- Set Values -----------------------
void setValues(void)
{ 
	rollOut = (float)ecu.setup.speedCal / 1000;
}

//------------------------- Read RPM --------------------------
uint16_t readRPM(void)
{
	static unsigned long rpm_filter = 0;
	unsigned long l;
	unsigned int a,coeff;
	
	cli();
	a = period;       //read the current rpm period with interrupts disabled
	sei();
	//return(a);
	
	l = (unsigned long )a;
	if (l > 0) { //don't do div by zero!
	   l = ((F_CPU/TIMER1_PRESCALE) * 60L) / l;      //do reciprocal and scale. result = rpm/10 (sample freq *60 /10)
    } else {
	   l = 0;
    }

   if (in_timeout) {  // tacho timeout if no input pulses
      in_timeout--;
      a = (unsigned int)l;
   } else {
      a = 0;      //clear rpm value if timeout
   }
  
 // ecu.data.rpm2 = a;
//
//      'a' has the current rpm, now we filter it to slow down the jitters
//      if the coeff == 0 then there will be no filter action
//      if the coeff == 255 then the output will stay at the last input value
//      in between values will work between these two extremes! ie: increasing
//      the value increases the filter action (slows the response).
// 
  coeff = 128;
  coeff &=0x00ff;                // coeff must be between 0 and 255
  rpm_filter = ((rpm_filter * (256-coeff)) + (((unsigned long)a<<8) * coeff))>>8;
 // rpm_filter = rpm_filter / 2.0;
 
  return((rpm_filter>>8)); 
}

This the headder file code.

#define IN_RELOAD 20  //if no pulses for 50ms * 20 = 1second, rpm value is zeroed 
#define TIMER1_PRESCALE 64

struct Controller  {
	uint8_t startChar; // $ Start character
	uint8_t PacketHi;
	uint8_t PacketLo;
	uint8_t PacketID;

	struct RealTimeData {
		uint8_t startChar; // $ Start character
		uint8_t PacketHi;
		uint8_t PacketLo;
		uint8_t PacketID;
		uint8_t speed;
		uint16_t pot1;
		uint16_t pot2;
		uint8_t assist;
		uint16_t hz;
		uint32_t crcCnt;
	} data;

	struct SetupSettings {
		uint8_t startChar; // $ Start character
		uint8_t PacketHi;
		uint8_t PacketLo;
		uint8_t PacketID;
		uint8_t table[8];
		uint16_t speedCal;
		uint8_t selectedPot;
		uint32_t crcCnt;
	}setup;

	struct checkSum {
		uint32_t crcCnt;
	}crc;
}ecu;
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

rayhall wrote:

volatile ADCtime = False;


Where is the type in that declaration ?

rayhall wrote:
For some reason the ReadRPM(); function is not returning a value.

ReadRPM() always returns a value in the code you posted.

Sid

Life... is a state of mind

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
Where is the type in that declaration ?

I knew I would miss something when you asked for cut down code. This is in the headder code

#define True 1
#define False 0

Quote:
ReadRPM() always returns a value in the code you posted.

All I get is 0 all the time.

This part of the code from Kartman returns 0

Ray.

if (in_timeout) {  // tacho timeout if no input pulses
      in_timeout--;
      a = (unsigned int)l;
   } else {
      a = 0;      //clear rpm value if timeout
   }
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

rayhall wrote:
Quote:
Where is the type in that declaration ?

I knew I would miss something when you asked for cut down code. This is in the headder code

#define True 1
#define False 0

I didn't ask how True and False are declared/defined. What I asked was where the type of ADCtime is, in the declaration of ADCtime.

rayhall wrote:
Quote:
ReadRPM() always returns a value in the code you posted.

All I get is 0 all the time.

This part of the code from Kartman returns 0

if (in_timeout) {  // tacho timeout if no input pulses
      in_timeout--;
      a = (unsigned int)l;
   } else {
      a = 0;      //clear rpm value if timeout
   }

That part of the code doesn't return anything.

If you mean that a is always 0 after that part of the code, it follows that it's always true that either in_timeout or l is zero upon entry of that block. So you need to figure out why that is.

Do you have C skills ? If you do, you should use them. If you don't you should start with something simpler - if you want to create solutions in C.

Sid

Life... is a state of mind

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ray, Chauncey meant type not value being assigned.

volatile ADCtime = False;

should be something like

volatile bool ADCtime = False;

How is in_timeout defined? EDIT: Missed that in code above.

I think single character variable names are a royal pain, especially "l" as it looks like a "1".  The forum font does not do justice to making my point so I put this in a code block.

EDIT: Crossposted with Chauncey.

"I may make you feel but I can't make you think" - Jethro Tull - Thick As A Brick

"void transmigratus(void) {transmigratus();} // recursio infinitus" - larryvc

"It's much more practical to rely on the processing powers of the real debugger, i.e. the one between the keyboard and chair." - JW wek3

"When you arise in the morning think of what a privilege it is to be alive: to breathe, to think, to enjoy, to love." -  Marcus Aurelius

Last Edited: Thu. Jul 12, 2012 - 03:53 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
volatile ADCtime = False;

Strange that does not cause any errors when compiling. It should be...

Quote:
volatile uint8_t ADCtime = False;

This would make the ADCRead(); to fire every clock cycle, and cause a problem. Correct ? Cannot test until tonight.

Quote:
I think single character variable names are a royal pain, especially "l" as it looks like a "1". The forum font does not do justice to making my point so I put this in a code block.

That is Kartman code. I know it is confusing.

Quote:
Do you have C skills ? If you do, you should use them. If you don't you should start with something simpler - if you want to create solutions in C.

Not sure how to take this statement. I will take it as a joke. Very funny... :lol:

Ray.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
For some reason the ReadRPM(); function is not returning a value.

uint16_t readRPM(void)
{
   static unsigned long rpm_filter = 0;
   unsigned long l;
   unsigned int a,coeff;
   
   cli();
   a = period;       //read the current rpm period with interrupts disabled 

"period" is declared as global but never assigned a value.
Thus "a" is allways 0 and the function returns 0.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

larryvc wrote:

I think single character variable names are a royal pain, especially "l" as it looks like a "1".  The forum font does not do justice to making my point so I put this in a code block.


Ray, I said that, and it wasn't directed at any one particular person's code. It is a statement of my personal opinion about one character variables and that is it.

I hope Visovian's post helps you out, it looks like he nailed it.

"I may make you feel but I can't make you think" - Jethro Tull - Thick As A Brick

"void transmigratus(void) {transmigratus();} // recursio infinitus" - larryvc

"It's much more practical to rely on the processing powers of the real debugger, i.e. the one between the keyboard and chair." - JW wek3

"When you arise in the morning think of what a privilege it is to be alive: to breathe, to think, to enjoy, to love." -  Marcus Aurelius

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
"period" is declared as global but never assigned a value.
Thus "a" is allways 0 and the function returns 0.

Visovian,

Brillant......!!!!!!!

Thank you very much. Like others I could not see the problem.

Ray.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Larryvc,

Thanks for your help.

Ray.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Note that I have deleted about 10 posts from various people from this thread. Those involved know why. Those not involved don't care. Can we try to keep technical threads on topic about technical problems/solutions. If you have other things to say then do it in Off-Topic but note that animosity and personal insults will never be allowed. Also note that anyone publishing private messages exchanged in privacy will simply find that they are deleted. If something is said in private it should remain private.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

volatile ADCtime = False;

Strange that does not cause any errors when compiling.

No, not really. The definition defaults to int. It is strange, however, that it did not produce this error:

../GCCSandbox.c:4: warning: type defaults to 'int' in declaration of 'ADCtime'

Regards,
Steve A.

The Board helps those that help themselves.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ray, when you modify the code and introduce defects, dont blame me. You changed the input capture code and broke it. Why do you calculate the difference then reset the timer? Personally, for your application i would avoid using input captures since it involves external interrupts which should be avoided in anything near safety critical. Poll the input in a timer tick.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Didn't I write a nice paragraph algorithm for reading the delta t between two rising edges of the input? It was at the bottom of the cajoling message to the feuding Aussies. See if you can pull it back and just whack the top bits Cliff. Or pull it back and I'll edit it.

Imagecraft compiler user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

See if you can pull it back and just whack the top bits Cliff

The PDF I have doesn't have anything more technical from you than this post which is still there:

https://www.avrfreaks.net/index.p...

The rest was off topic drivel.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I have finished the EPAS (electronic power assist steering) controller. Thank you to those that helped. So I am not seen as sucking the brains out of you all, I am making this project available to any one that wants it. The AVR code is a good example of..

1. COMMS between hardware and PC software.
2. Using structures and EEPROM.
3. Timers for over flow interrupt, PWM, and input capture.

Here is the information and pictures. I will also make the PC software code, that is written in Builder C++ available to anyone that wants it.

PCB hardware http://www.tfelectronics.com.au/bin/EPAScontrollerPCB.jpg

Controller http://www.tfelectronics.com.au/bin/EPAScontroller.jpg

Schematic http://www.tfelectronics.com.au/bin/EPAScontrollerSCH.PDF

PC Software screen shot http://www.tfelectronics.com.au/bin/EPAS_Software.png

Mega168 code http://www.tfelectronics.com.au/bin/EPAScontroller.zip

Ray.