1
\$\begingroup\$

I have a problem on ATMega16. I can't seem to be able to make a subroutine run for a set amount of time. Here is the code:

void reverse(unsigned x){
    OCR0=x;                 //PWM 100%
    PORTB &= ~(1<<PB0);     //+ of Motor1   LOW
    PORTB |= (1<<PB1);      //- of Motor1   HIGH
    PORTB &= ~(1<<PB2);     //+ of Motor2   LOW
    PORTB |= (1<<PB4);      //- of Motor2   HIGH
}

so it's basically a motor control subroutine which applies a Fast PWM Signal using Port PB3. The input is the duty cycle. The 2 motors are controlled using a L298.

Now, I want to transform the code so that it takes for input the duty cycle AND a certain value for the time, such as 50ms.

I'm using Atmel Studio 6.0 on Windows XP.

Thank you in advance.

\$\endgroup\$
  • \$\begingroup\$ I think you should fix your question slightly. First, the subroutine that you have doesn't meaningfully run for some duration. It runs once, and the change is permanent. You need to run another funtion or add more code to this, which reverses the effect after some time. Its a critical distinction, that. Secondly, you should clarify your explanation of why you want to do this. I cant understand anything of that paragraph about sensors. Its not required to answer anyway, so you should either explain clearly or replace it with less detail about your robot and more about what you need. \$\endgroup\$ – Chintalagiri Shashank Jan 30 '13 at 23:47
  • 2
    \$\begingroup\$ Any particular reason you don't use the PWM hardware in the microcontroller? \$\endgroup\$ – Phil Frost Jan 30 '13 at 23:59
  • \$\begingroup\$ @Chintalgiri Shashank Thank you for your answer, I think I will add a stop subroutine which stops the motors. I don't need to do anything else during the maneuver. My code is much larger and I didnt want to add it all as I assumed it was a very simple answer. Phil Frost I dont use PWM hardware because I dont know how to implement it and this Fast PWM was very simple to implement. \$\endgroup\$ – user18476 Jan 31 '13 at 0:00
  • 1
    \$\begingroup\$ @user18476 I'm not saying you should add the whole code to the question. My comment was that you should clarify the question by including details specific to the question, and reduce irrelevant detail which can confuse people looking at the question. Getting something closed that way is far too easy here. \$\endgroup\$ – Chintalagiri Shashank Jan 31 '13 at 0:30
  • 1
    \$\begingroup\$ Thank you for your suggestion and help, I have removed that paragraph. \$\endgroup\$ – user18476 Jan 31 '13 at 0:31
1
\$\begingroup\$

There are plenty of ways you could do something like this. Assuming you're using AVR gcc, you could use the utility functions in util/delay.h, specifically _delay_ms() would be applicable for your requirement. You can find the documentation at www.nongnu.org/avr-libc/user-manual/group_util_delay.html. Note, however, that there is a maximum delay that you can generate using these functions, depending on your clock speed. If you want to delay for longer, then you'll have to use some sort of a loop that calls it repeatedly. The typical way to use it in your case would be to do what your function has, then delay, and then disable your motors and such. There are some disadvantages to using this method, though. First, these delays are essentially for loops simply looping around for some number of iterations. This means that they aren't exactly accurate. Also, any interrupts that may be happening will cause this time to stretch.

When writing firmware it is often best to avoid using these kinds of delays. Not only are they inaccurate, they are also blocking calls. For the duration of the delay, the processor can't run any other code (unless from within an interrupt, which throws off the delay). There are better ways to solve your problem, but they do need more work. One way is to configure a timer to interrupt after the time you require, and then use code that is called by the interrupt handler to stop the motor. The 'good' way to do this would be to set a flag inside the interrupt and have the main loop check for this flag. This way, the main loop can keep tabs on multiple things in parallel and execute code at the correct time.

More complicated systems could use an RTOS to do this, but they often come with more baggage than is worthwhile unless you really need high precision and have many different things that have to happen in parallel.

\$\endgroup\$
0
\$\begingroup\$

Why don't you use a timer interrupt registers and pwm outputs built into the ATMega. That would be the most robust and accurate way to do this other than using a RTOS already suggested. You can even verify output duty cycle with an oscilloscope.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.