Wednesday, March 6, 2013

Controlling DC Motor speed and direction with AVR Atmega

updated library here: http://davidegironi.blogspot.it/2015/02/driving-dc-motor-using-pwm-with-avr.html

A DC motor is a mechanically commutated electric motor powered from direct current (DC). The stator is stationary in space by definition and therefore so is its current. The current in the rotor is switched by the commutator to also be stationary in space. This is how the relative angle between the stator and rotor magnetic flux is maintained near 90 degrees, which generates the maximum torque.



Here you can find three libraries to control DC Motor using Atmega micro.

The first one (lib_dcmotor) allow you to synchronously control motor in direction.

The second one (lib_dcmotorpwm) implements a way to control motor direction and speed asynchronously, using timers, by hardware PWM capabilities of Atmega micro. The average value of voltage (and current) fed to the load is controlled by turning the switch between supply and load on and off at a fast pace. The longer the switch is on compared to the off periods, the higher the power supplied to the load is, and the more the motor spin.

The third one (lib_dcmotorpwmsoft) does exactly the things of the library above, but implements a software PWM, leaving free the hardware PWM resource for other device, or for micro that does not have PWM hardware embedded.

All libraries can control up to 2 motors, more motors can be controlled with the third one libraries using output port expander.




All libraries was developed on Eclipse, built with avr-gcc on Atmega8 @ 1MHz.


Code


Notes
  • read risk disclaimer
  • excuse my bad english

26 comments:

  1. Your Tutorial is very instructive. It helps me a lot. Can you please post the wiring connection of the Atmega16 interfacing with the L293D?

    ReplyDelete
    Replies
    1. hello and thank you,
      use the schematics as above, but connect RA2 and RA3 from L293D to two port of your ATmega, then you have to change ports in the config file (.h) or the library you are using.

      Delete
    2. Thank you, i really appreciate your help.
      May God bless you.

      Delete
    3. your are welcome.
      you can find a more advanced solution (with slow start / stop for example) here: http://davidegironi.blogspot.it/2013/11/driving-dc-motor-using-software-pwm.html

      Delete
  2. This comment has been removed by the author.

    ReplyDelete
    Replies
    1. To me, the most simple way to compile, is Eclipse, with AVR plugin installed, and avrgcc as compiler.
      Search for a tutorial, you can find a lot.

      Delete
  3. i done compiling.....now sir i want to use atmega 16,,,,the diagrm is not clear...will u please upload the circuit with proper connections

    ReplyDelete
    Replies
    1. Hello, you just have to select two free port of your microcontroller, for each motor, setup that ports in the header file of the library. Then connect the two port stright in your motor driver (note: check your motor driver to be shure you can connect that type of input, as example: sn754410 support this type of input). You may also search online for that type of connection.
      Additional note: please do not remove your comment with my reply, or my reply to comments are useless for other users.

      Delete
  4. in this diagram i can't understand the connections,,,,,please upload the protious diagram

    ReplyDelete
  5. your comment dosen't helping me in making the circuit....:(

    ReplyDelete
    Replies
    1. You have got an email with a schematics i've just found googling. It may be what you are looking for.

      Delete
  6. how can i control speed and direction of 2 DC Motors using atmega328 and L298N Driver by Tx and Rx??

    ReplyDelete
    Replies
    1. Hello have to write your own protocol, that reads byte from UART, then interpreter those byte and use a DC motor library like this http://davidegironi.blogspot.it/2013/11/driving-dc-motor-using-software-pwm.html to drive the motors.

      Delete
    2. i have got 6 channel 2.4ghz flight controller of flysky which sends PPM signal..and i think L298 is a PWM based ic...how to control now??

      Delete
  7. i have got 6 channel 2.4ghz flight controller of flysky which sends PPM signal..how can i control speed and direction of 2 dc motor?

    ReplyDelete
    Replies
    1. You can use the ICP of avr, or the external interrupt input. There are a few posts on avrfreaks forum about reading PPM.

      Delete
  8. This comment has been removed by a blog administrator.

    ReplyDelete
  9. Hello Davide,

    Good to see your post. Its quite helpful. I have some doubt, please help me to get clear this..

    In the case of Forward/Reverse motion of motor, how can I set the duty to achieve 4ms pulse.

    Also I didnt understand this formula:
    orctop = ((ICR1 - top_min) * (speed - 1)) / ((100 - 1) + top_min);
    Is the speed means"duty" ?

    Please suggest. Thanks.

    ReplyDelete
    Replies
    1. Hello, thank you for your feedback. About the duty cicle question, it depends on which driver are you using, for the PWM (non bitbang version) you have to setup the timer registers, you can find settings explanation in the header file. You have to consider the duty part and the pwm frequency.
      The ocrtop settings formula is a mapping. You are basically mapping orc from min to max, given a speed from 1 to 100. Take a look here for furhter info: https://www.arduino.cc/en/Reference/Map

      Delete
    2. Hello Davide,
      Thanks for your reply. I configured the timer registers. My requirement is to control the bidirectional DC motor connected at Atmega8.

      The initial pwm pulse is of 20KHz (50us) and later I have to set it to 4ms pulse. I can change the duty and check the pulse period (its close to 4ms) but not accurate. How can I set the condition to get the pulse of exact 4ms.
      plz suggest. Thanks.

      Delete
    3. Hello, frequency is setted up by the timer definitions definitions DCMOTORPWM_ICR1 DCMOTORPWM_PRESCALER.
      Look at the dcmotorpwm.h file comments on that macro. I can't understand if you have to change the duty period of the PWM frequency. Anyway, you can perform a precise frequancy and duty cycle rewriting the set speed function (dcmotorpwm_backward and dcmotorpwm_forward). You will have to set OCR1B or OCR1A to a calculated number.

      Delete
    4. Hello Davide..
      Let me explain in detail:

      Issue: At Atmega8(Clk: 4MHz), Using timer1, generate two PWM signals (OC1A(Fw)/OC1B(Rv)) of 20KHz(50us).
      Later, external interrupt is generating while motor is running in parallel. Need to change the PWM signals of 4ms while changing its duty.

      So, I defined timer in this way...

      (calculated using prescalar = 1, Fast PWM mode14)
      TCCR1A=(1<<COM1A1) | (1<<COM1A0) | (1<<COM1B1) | (1<<COM1B0) | (1<<WGM11) | (0<<WGM10);

      TCCR1B=(1<<WGM13) | (1<<WGM12) | (1<<CS10);

      ICR1 = 199;
      OCR1A = 0;
      OCR1B = 0;

      TIMSK = 0;
      TIFR = 0;

      Please suggest me, how can i set the condition to increase/decrease the duty to set the pulse of 4ms.

      Thanks.

      Delete
    5. Again it's not clear to me why it will be usefull. Consider the the "standard" PWM frequancy for a motor is 20Mhz, Anyway, what you can do, is set the PWM at 250Hz. In order to change the PWM, set the ICR1 according to this. With a 4Mhz crystal you have got an ICR1 a little low to me. I will set it to 8Mhz at least, and use ICR1 = 400, with a prescaler of 1 for 20Mhz, ICR1 = 500 with a prescaler of 64 for 250Hz. Consider that 250Hz is not a good PWM for a motor.

      Delete