Converting basic servo code from C code to Arduino

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

Hello,

 

I have to do a project that has to be written mainly in register level, with some exception that can be written in arudino code. I'm using a nano, so ATmega328P. I found this code that does the basic thing I need to do and I'm trying to build on it.

 

#include <avr/io.h>
#include <util/delay.h>

int main(void) {

  DDRB |= 1 << PINB1; // Set pin 9 on arduino to output

  /* 1. Set Fast PWM mode 14: set WGM11, WGM12, WGM13 to 1 */
  /* 3. Set pre-scaler of 8 */
  /* 4. Set Fast PWM non-inverting mode */
  TCCR1A |= (1 << WGM11) | (1 << COM1A1);
  TCCR1B |= (1 << WGM12) | (1 << WGM13) | (1 << CS11);

  /* 2. Set ICR1 register: PWM period */
  ICR1 = 39999;

  /* Offset for correction */
  int offset = 800;

  /* 5. Set duty cycle */
  while(1) {
    OCR1A = 3999 + offset;

    _delay_ms(1000);

    OCR1A = 1999 - offset;

    _delay_ms(1000);
  }

  return 0;
}

The code works and everything when I upload it. However, when I change the int main to void setup() and remove the return, it doesn't work. I tried putting what's in the while loop to void loop(), but still doesn't work. Any idea why it's not working and what should I do to fix it? I know it sounds like something simple, but I've been trying for several hours now and still no luck. I'm trying to learn how to do this.

 

 

#include <avr/io.h>
#include <util/delay.h>

 
#include <Arduino.h>



void setup() {

  Serial.begin(115200);
  
  DDRB |= 1 << PINB1; // Set pin 9 on arduino to output

  /* 1. Set Fast PWM mode 14: set WGM11, WGM12, WGM13 to 1 */
  /* 3. Set pre-scaler of 8 */
  /* 4. Set Fast PWM non-inverting mode */
  TCCR1A |= (1 << WGM11) | (1 << COM1A1);
  TCCR1B |= (1 << WGM12) | (1 << WGM13) | (1 << CS11);

  /* 2. Set ICR1 register: PWM period */
  ICR1 = 39999;

 
  
}

void loop(){

   /* Offset for correction */
  int offset = 800;

  /* 5. Set duty cycle */
  while(1) {
    OCR1A = 3999 + offset;

    _delay_ms(1000);

    OCR1A = 1999 - offset;

    _delay_ms(1000);
  }

  
}

 

I'm not getting any errors. It's just not doing anything.

This topic has a solution.
Last Edited: Mon. Apr 13, 2020 - 03:25 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

In Arduino you do PWM with analogWrite(). You shouldn't need to go anywhere near timer registers (because that's exactly what's going on "inside" analogWrite()).

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

I understand with normal arduino code I don't need it. But for this project we're not allowed to use the arduino library. Everything has to be done with registers. So that's why I'm trying to get this to work. I realize that in the second code I have the arduino.h library included. This is because I was testing something and will be removed at the end.

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

If you are not allowed to use Arduino why are you going anywhere near setup()/loop()?

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

I'm sorry, I should've phrased it a little better. We're not allowed to use the arduino library except for serial communication and a library for wireless transmitter and receiver. So for the servo, it has to be written manually using PWM and timers. Same goes for the analog sensors, and the digital ones. The professor has some examples for the ADC and a bit of the basic bit manipulation and he uses Setup() and loop() in them. I'll have to include the wireless module library, so I'll need to use setup and loop too for that (I think).

 

For now I'm trying to get this to work. Theoretically, it should work. I don't see anything that is wrong with. I had a few ideas cross my mind and I tried them but still, no luck. I'm obviously missing something and would like someone with more knowledge than me to help me out.

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

Try taking the while(1) {} out of the loop() function.    Make the offset a define statement. 

 

#define OFFSET 600

 

void loop() {

   set first PWM value

   wait a second

   set second PWM value

   wait a second

}

Last Edited: Sun. Apr 12, 2020 - 11:36 PM
This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1
 /* 1. Set Fast PWM mode 14: set WGM11, WGM12, WGM13 to 1 */
  /* 3. Set pre-scaler of 8 */
  /* 4. Set Fast PWM non-inverting mode */
  TCCR1A = (1 << WGM11) | (1 << COM1A1);
  TCCR1B = (1 << WGM12) | (1 << WGM13) | (1 << CS11);

Don't use |= as Arduino has probably touched those registers already. By doing a straight assignment, you are ensuring the registers get set as you want.

 

You can explore the Arduino core code to see exactly what it does.

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

You're right! That worked perfectly. I guess using the setup(), it preconfigures the bits. THANK YOU! I actually looked at the core files. But to be honest, I don't really understand how objects work and it relies a lot on it. I can understand in general what is happening, but not the specific details, honestly that detail, I would still have missed. I know this isn't the best way of doing it, I should learn the fundamentals first so I can build on it. But with the limited time in the semester and almost all my courses have been completely reworked, I'm trying to cheat my way through stuff, just so I can get something that is working and then focus on learning the basics later. Thank you!

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

Simonetta wrote:

Try taking the while(1) {} out of the loop() function.    Make the offset a define statement. 

 

 

I had already tried that in another instance, but still didn't work. But someone posted the problem and it finally worked!

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

Don't use |= 

Where does this ailment come from (if anywhere)?  It seems like a somewhat recent thing where folks are no longer initializing using = , and instead using |= , leading to constant mayhem.

Maybe this is an unintended consequence of some new book or teaching, or methodology in general.

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

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

Honestly that come purely from my own stupidity and lack of knowledge. I did not get my information from a book. The professor taught us to add the bits, but I suppose we also told us to set everything to zero before.

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

It is wise to use = when initialising all the bits in a register.

 

There are occasions when you want to set or clear an individual bit in a register.  Use |= or &=~

 

It is fairly obvious with a PORT register.  i.e. initialise all bits or wiggle a specific bit.

 

The datasheet will tell you the Reset value of every SFR.   In which case you can change an individual bit.

Note that Arduino has initialised PWM, Timers, ... with init() before you see setup()

 

Assignment with = is safer and quicker than a read-modify-write operation like |=

 

David.