Ref: baby Orangutan 168, setting up a trigger

ref: baby Orangutan 168, setting up a trigger that executes a EEPROM or
FLASH routine

I received the baby orangutan. I am controling via “RC receiver”, and I am in need of help just to get started with my project.

I would like to be able to set and Detect a digital signal (pulse) on a user digital pin
closest to the Ground( for ease of wiring ) and express in terms of “C/C++” programing ( i have AVRStudio4 )
After detecting this signal from said pin I would execute my own routine, reset the pin
in order to wait for another signal.

Can someone please steer me in the right direction …

thank you

Dave

Hello.

I have split this post into a new topic. In the future, please don’t add your questions onto the ends of unrelated threads (especially threads in the announcement forum, which is intended for Pololu news and reactions/comments about that news).

There are many ways to approach your particular problem:

  1. Poll the state of the digital input in your main loop.
  2. Use one of the external interrupt pins and set up an external interrupt service routine that will be called at the appropriate time (e.g. on the rising edge of the signal).
  3. Use a pin-change interrupt to detect the signal.

I recommend you first take a brief look at the mega168 datasheet. This should give you a better idea of what your options are. It should also help you figure out what you don’t yet understand well enough so that you can ask more specific questions.

I also recommend you take a look at some sample mega168 code. This forum has a lot of code examples spread throughout the various threads, so you might first try searching around. You can also take a look at Orangutan-lib, an open source C library for the Orangutan library of robot controllers. Orangutan-lib is not completely compatible with the Baby Orangutan revision you have, but you might be able to use parts of it and it might be useful as sample code. Lastly, take a look at some of the demo programs for the Orangutan LV-168. The LV-168 has some hardware that the Baby Orangutan B does not, but the common hardware has the same pin mapping, so the code to control the common hardware will work on both units.

- Ben

Sorry Ben for mixing posts

I would like to use PC3 pin as a test for the project.
PC3 : ADC3 (ADC Input Channel 3) PCINT11 (Pin Change Interrupt 11) as shown in the datasheet

To keep it simple, the yellow (signal) lead from my “rc Rx” to PC3 of the baby-O and black to ground of the baby-O, The signal will be triggered by controlling a switch on my “rc TX”.

What I am not understanding is how to initialize/or/setup PC3 for polling and using the pin change interrupt 11 to detect the signal
specifically I willl need a simple example of how to maniplulate PC3(ADC3) and PCINT11

please advise

The simplest method for detecting a signal would be polling. To do this you would want to use pin PC3 as a digital input. This is the state of PC3 by default after power up or a reset, but you can explicitly set it to be an input by clearing bit 3 of the DDRC register:

DDRC &= ~(1 << PC3);

You can then read the input value of the pin by looking at pin 3 of the PINC register:

if (PINC & (1 << PC3)) // if bit 3 of PINC is high, PC3 is high
do something;
else // otherwise PC3 is low
do something else;

So in your program’s main loop you would repeatedly read the value of PINC waiting for bit 3 to go from low to high, at which point you have detected your signal.

After this you might want to do some fancier things like ensuring that the signal is valid and not just a noise spike, and you might want to time the duration of the signal.

- Ben

Ben

thank you for helping

the motor routine is using timer0 and timer2 not shown. Motors are controled by another routine.
here is what my routine looks like for PC3 PIN, I have not programed the avr yet as I am still setting up the conntections
please let me know your opinion.

thx dave

int main()  
{ 
  // Declare Pin Duration 
  int pinHighduration;
  
  // Initialize Motors
  motors_init();  

  // reset PIN3 PC3
  DDRC &= ~(1 << PC3);

  while (1)						 // loop forever
     {
	  pinHighduration=0;
	  while(PINC & (1 << PC3))	 // while PIN3 is high for a certain duration
		pinHighduration++;		 // record duration

	   if (pinHighduration>499)
	   		{
     		        Move2Motors();		 // Run Motor Routine for 2 Motors
			DDRC &= ~(1 << PC3); // Reset PIN3 and wait for another signal
			}
     }
return 0;
}

This line doesn’t reset pin PC3, it just designates it as a digital input. You only need to call this once outside your main loop.

If you want to record the duration for which the pin is high, you probably need to put some kind of delay in your loop or else use one of the mega168’s timers. The way you have things now, pinHighduration will reach 499 after maybe 150 microseconds, which is incredibly fast. The variable will overflow and become negative after maybe 8 ms. I guess it depends on what kind of variation you might see in your pulse lengths and how accurately you want to measure them. Note that if you ever have a pulse that’s longer than the overflow duration your timing will be entirely unreliable.

- Ben

Ben

Thank you for the tip on the PIN reset

I have tested the baby0 using a BlinkLed all set everything works.

Microsecounds is too fast, how about a larger number like 10,000 ? as opposed to 499.

I have successfully loaded the hex in to FLASH ram. and connected the motors. and connected the trigger to PC3
I am increasing the 499 -> 10,000 which may have the effect of several seconds PIN High Duration.

I am using 6volt mini motors these here:
pololu.com/catalog/product/641

My setting was M1_FORWARD(150) which may not be enough power so I am increasing to 200.

let me know if you see something i am doing wrong

You’re getting dangerously close to an integer overflow here. To avoid complications from this I’d suggest changing your pinHighduration variable to a long (four bytes) rather than an int (two bytes).

- Ben

Yes Ben

I already changed the int to long I did not show this in my oringinal example.

off hand how would one tackle the delay method you mentioned

while(PIN3 is High) // loop as long as PC3 is High
{
ms_delay(50) ; // delay of 50 milliseconds
pinHighDuration++; // increment High Counter
if (pinHighDuration > 40) // this would equal 2 seconds
{
RunRoutine;
break; // end loop
}
}

Your code above is what I had in mind when I suggested a delay method to get more control over your timing. It will work so long as the length of the delay is much greater than the amount of time it takes for the rest of the code in the loop to execute (50 ms definitely meets this criteria).

- Ben

Thank you Ben great

only one thing

how can I now test the routine to know it will work without having to hook up wires ect …

In the AVR-Studio there is a “I/O view” also when I press the “>” run button I get a “processor view” also.
what would i look for to know the routine is running as planned, how can the I/O view tell if the pin3 is low or high?

You should be able to use AVR Studio to simulate your program. I don’t have too much experience with it, but I think you can step through your code instruction by instruction and toggle register bits in the simulator as you go. I think this will let you set and clear pin 3 in the PINC register as you simulate your program.

- Ben

BEN,

Ok almost there, 90% there, it works with one exception, there is no sensing of PIN3 high or low. It simply executes the motor routine over and over, probably because the pin is never seen as low.

RECAP:
i am feeding PC3(on the babyO168) a signal in from my “rc reciever” (yellow wire), and black to ground. my rc radio is setup to control the babyO via channel 6 which is a phyical switch with 3 postions ( down, middle, up = which might mean right, center/neutral/left ) . the BabyO is self powered by another power source. As soon as I power on the receiver, the babyO
starts executing the motor routine over and over, without stopping. channel 6 on my Radio has no effect of stopping or starting
the process.

JAN SAID:
Jan never said anything about pin High/Low
At one point JAN did say that for this type of application with RC I would need to sense 1-2ms pulses at 50hz
and the pulse width determines the servo position ? do you know what he is talking about? Jan said nothing further
on this except that i should search the forums, which I could not find anything on RC/pluses width/and servo positions.

It appears that either the delay is too short, which its seems ok, or I am looking for the wrong type of signal on
PIN3 (PC3). Just to make sure I have stayed within convention I have included my program below.

MY PROGRAM AS IT IS NOW:

#include <avr/io.h>  
#define F_CPU 20000000  // system clock is 20 MHz  
#include <util/delay.h>  // uses F_CPU to achieve us and ms delays  
      
  // Motor Control Macros -- pwm is an 8-bit value  
  //  (i.e. ranges from 0 to 255)  
      
#define M1_FORWARD(pwm)        OCR0A = 0; OCR0B = pwm  
#define M1_REVERSE(pwm)        OCR0B = 0; OCR0A = pwm  
#define M2_FORWARD(pwm)        OCR2A = 0; OCR2B = pwm  
#define M2_REVERSE(pwm)        OCR2B = 0; OCR2A = pwm  
     
// Motor Initialization routine -- this function must be called  
//  before you use any of the above macros  
void motors_init()  
  {  
  // configure for inverted PWM output on motor control pins:  
  //  set OCxx on compare match, clear on timer overflow  
  //  Timer0 and Timer2 count up from 0 to 255  
  TCCR0A = TCCR2A = 0xF3;  
     
  // use the system clock/8 (=2.5 MHz) as the timer clock  
  TCCR0B = TCCR2B = 0x02;  
     
  // initialize all PWMs to 0% duty cycle (braking)  
  OCR0A = OCR0B = OCR2A = OCR2B = 0;  
    
  // set PWM pins as digital outputs (the PWM signals will not  
  // appear on the lines if they are digital inputs)  
  DDRD |= (1 << PD3) | (1 << PD5) | (1 << PD6);  
  DDRB |= (1 << PB3);  
  }  
  

void Move2Motors()
  {
          	 M1_FORWARD(100);  // open door
			 delay_ms(1500);
			 M1_FORWARD(0);

             M2_FORWARD(75);  // control shaft
			 delay_ms(1000);
			 M2_FORWARD(0);

			 M1_REVERSE(100); // close door
			 delay_ms(1500);
			 M1_REVERSE(0);

			 M2_REVERSE(75);  // return control shaft
			 delay_ms(1000);
			 M2_REVERSE(0);
  }
 
  // delay for time_ms milliseconds by looping  
  //  time_ms is a two-byte value that can range from 0 - 65535
  //  a value of 65535 (0xFF) produces an infinite delay  
void delay_ms(unsigned int time_ms)  
  {  
  // _delay_ms() comes from <util/delay.h> and can only  
  //  delay for a max of around 13 ms when the system  
  //  clock is 20 MHz, so we define our own longer delay  
  //  routine based on _delay_ms()  
     
  unsigned int i;  
     
  for (i = 0; i < time_ms; i++)  
  	_delay_ms(1);          
  }  
     
int main()  
{ 
  // Declare Pin Duration 
 long pinHighduration;
  
  // Initialize Motors
  motors_init();  

  //Set PIN3 PC3 as Input Port
  DDRC &= ~(1 << PC3);

  while (1)						 // loop forever
     {
	  pinHighduration=0;
	  while(PINC & (1 << PC3))	 // while PIN3 is high for a cert duration
	  	{
		delay_ms(50);
		pinHighduration++;		 // record duration

	   	if (pinHighduration > 40) // test duration  / total of 2 secounds
	   		{
     		Move2Motors();		 // Run Motor Routine for 2 Motors
			break; // end inner loop
			}
		}
     }
return 0;
}

Ben

After a lot of thinking
I think i have the answer, what I need to do is sense the rate of time between PC3-High and PC3-low
the measure of time in 1-2ms will tell me how the radio is controlling from 0 degress to 180 degrees.
0 degrees would be 1ms pulse
90 degrees would 1.5ms pulse
190 degrees (full throttle) would be 2ms

what i don’t know, is how to express this concept in the “C” lauguage

I would guess it would be something like

while (1) // loop forever
{
repeat = 1;
 while(repeat)  // repeat to make sure we have an accurate reading
     {
      repeat++;
      while   (PC3 high)
              {
              settimer1
              if Test(PC3 low)
                   {
                   StopTimer1;
                   TimePulse = timer1Reading;
                   if TestTimePulse(> 1ms && < 2.1 ms)
                           do some routine;
                   resettimer1
                   break; // loop and watch for other pulses
                   }
              }

     if (TimePulse == 1ms)
           ;// we are at 0 degress
     else     if (TimePulse > 1ms && TimePulse < 1.6ms)
           ; // we are between 1 degree and 90 degrees
     else if (TimePulse > 1.5ms && TimePulse < 2.1ms)
           ; // we are between 91 degress and 180 degress
     }
}

return(0); // return 0 on exit

BEN

do you know how to express this in more practicle programming terms?
do you think and & oring bits would be a faster method of determining ms time frames rather than calling bulky functions?
Is there a way to to shift or and or “Or” bits to achieve this?

please let me know

thx

dave

I think you’ve got the solution, and since you’re only trying to measure one channel there really isn’t too much you can do with bitwise manipulation (you’re just deaing with a single bit that’s changing between 0 and 1).

If I were coding this in pseudo code it would be something like:

while (1)
{
while (!(PINC & (1 << PC3))); // wait while pin PC3 is low
start timer (or record current time)
while (PINC & (1 << PC3)); // wait while pin PC3 is high
get elapsed time since timer was started

do something with elapsed time
reset timer;
}

If the elapsed time is less than 0.5 ms or greater than 2.5 ms, you have gotten a bad pulse and can reject it. The elapsed time will probably be between 1 and 2 ms, as you have said.

So the first thing you need to figure out is how to achieve the timing. As I said before, if you don’t need high accuracy you can do this by counting a series of short delays (maybe 50 microseconds per delay?), or you can use one of the mega168’s timers. The timers are the easier route once you’re familiar with them. I suggest you look at the timer section of the mega168 datasheet and then ask if you have questions about it.

Once you have the timing down, I suggest you test your code using something simple, such as the Baby Orangutan’s red user LED. For example, have your program turn on the LED if it gets a pulse between 1.5 and 2.0 ms, otherwise turn off the LED. If your code is working you should be able to easily control the state of the LED with your RC transmitter.

- Ben

Ben

yes i do have questions about the LOW and setting and reading of timer1.

this is what you wrote for LOW PIN test
could this be used as well for LOW PIN while (PINC & (0 << PC3)); ??

Timer0 and Timer2 for the baby-0 are already being used for the motors.
I would like to be able to use Timer1 to meausure the Pulse. a) Can you give an syntax example of how to
reset Timer1. b) setTimer1 in Motion c) StopTimer1 d) Read Timer1’s in terms of “milliseconds” ??

Yes
An LED is an exellent idea I will incorporate.

please advise

No, you will never see something like (0 << x) because 0 bitshifted left or right is still just 0. What you end up with is that

PINC & (0 << PC3) == PINC & 0 == 0

and your loop becomes

while (0)

which doesn’t do anything for you.

The whole point of the (1 << x) is to act as a mask that selects only the bit of PINC you care about. Once you have that bit you need to check its state. That’s what my

while (!(PINC & (1 << PC3)))

does.

I could accomplish the same thing using the bitwise NOT operator ~:

while (~PINC & (1 << PC3))

To start timer 1 you would use:

TCCR1B = 0x02; // clock timer1 using I/O clock divided by 8 (2.5 MHz)

To read the current timer1 count you would use the TCNT1 register, and to clear the current timer count you would use

TCNT1 = 0;

So putting it together, the code would become something like:

unsigned char error = 0;  // ignore this pulse if error is 1
TCCR1B = 0x02;
while (1)
{
  while (!(PINC & (1 << PC3))); // wait while pin PC3 is low
  error = 0;
  TCNT1 = 0;  // effectively start timing now
  while (PINC & (1 << PC3)) // wait while pin PC3 is high
  {
    if (TCNT1 > 50000)
      error = 1;  // identify this as a bad pulse before timer1 overflows
  }
  unsigned char pulseLength = TCNT1;

  if (!error)
  {
    do something with pulseLength
  }
}

You don’t want to represent the pulse length in milliseconds because then you would have to use floating point numbers. Instead you should represent it in microseconds, or you can convert your desired threshold values (e.g. 1.5ms) into timer1 counts. Each timer1 tick is 1/2.5MHz = 0.4us, so a pulseLength of 3750 represents 1.5ms:

1.5ms/0.4us = 1500/0.4us = 3750 timer1 counts
1.0ms/0.4us = 1000/0.4us = 2500 timer1 counts
etc

- Ben

Yes an LED simulator is a great idea!

I might as well go all the way and really learn how to use the counters to measure even the fine detail. i have like a few thousand questions about Timers.

For this purpose I would like to use Timer1 as it is free and not being used by my routine.

Is this timer1 OCR1A ? ( what does A or B stand for )

Timer1 has different modes, which mode should i use
is WGM01:0 = 2 a way of setting Time1 to mode 2 which is “Clear Timer on Compare Match (CTC) Mode”

Should I use Normal Mode?

Is 8 bit Timer enough resolution to measure the 1-2ms I am looking for?

How do I reset a Timer1 like this: OCR1A = 0x00 ??
How do I get the Timer1 to start Counting?
At what rate does Timer1 Count ( Milli or Micro seconds ? )
If Timer1 is 8 bit this means a top count of ?
How would I stop TImer1 in order to reading it’s count?
and Finally How do I convert the TImer1 count into milli-seconds?

I am asking the right questions?

please advise

I answered some of these questions in my post above, so please take a look at that again. Specifically, my sample code above starts timer1 and uses it to measure a pulse length.

OCR1A is used to generate compare matches with the timer1 counter. This is usually used for generating a PMW. There are two compare-match registers that can be used, each of which can be used to generate an independent PWM output. For this application you don’t need to worry about compare matches or PWMs.

It is sufficient for you to use normal mode, in which timer1 counts from 0 to 0xFFFF and then overflows back to 0.

Probably not. This is why I recommend you use timer1, which is a 16-bit timer.

The timer1 count register is TCNT1. This holds the current timer count (i.e. the current “time”, so to speak). To reset the count you would just do:

TCNT1 = 0;

[quote]How do I get the Timer1 to start Counting?
At what rate does Timer1 Count ( Milli or Micro seconds ? )[/quote]
Somewhere in the initialization phase of your program you would write:

TCCR1B = 0x02;

The status registers TCCR1A, TCCR1B, and TCCR1C control the operation of timer1. For normal mode running at 2.5 MHz (the system clock divided by 8), you want TCCR1A = 0 (default value), TCCR1B = 0x02, and TCCR1C = 0 (default value). Running timer1 at 2.5 MHz means you can time for a duration of 65536 * 1000 / 2.5 MHz = 26.2 ms before overflowing, with a resolution of 0.4 us. This is most likely the setting you want for your particular application.

Timer1 is 16-bit. Timers 0 and 2 are 8-bit.

You don’t need to stop timer1 to read its count. I recommend you just leave it running constantly. When you want to reset it, set its count equal to 0. When you want to get the elapsed time, read the value of the register TCNT1. See my sample code in my previous post.

I went over this in my previous post. Timer1 is counting in increments of 0.4 us when you are clocking it at 2.5 MHz. So to get its time in microseconds you need to multiply TCNT1 by 0.4. You can avoid using floating point numbers in your program by working in units of timer1 and converting your target pulse lengths into expected timer1 count values. Once again, please see my previous post for examples of this.

- Ben

I am sorry I didn’t realize the post went on to 2 pages, I will take time to study carefully

thank you BEN