Thank you for the help! It works now. Reading the signal on Pin 10 works. Now I have connected Pin 9 and Pin 6 by a cable. My current code looks like this:
#include "TimerOne.h"
unsigned long pwm_high = 0;
unsigned long current_t = 0;
volatile byte flag = LOW;
void setup()
{
Serial.begin(9600);
pinMode(10, OUTPUT);
pinMode(9, OUTPUT);
pinMode(6, INPUT);
Timer1.initialize(50000); // initialize timer1, and set a 1/2 second period
Timer1.pwm(9, 128); // setup pwm on pin 9, 50% duty cycle
Timer1.attachInterrupt(callback);
sei();
}
void loop()
{
Serial.print(digitalRead(6));
/*if(flag == HIGH)
{
Serial.print(millis());
Serial.print(F(": "));
Serial.println(digitalRead(10));
flag = LOW;
}*/
}
void callback()
{
digitalWrite(10, !digitalRead(10));
flag = HIGH;
Serial.print("X");
}
And the output on my Serial Monitor like: 00011X11100000000000000000000000000000000000000000011X1110000
The goal was to actual see the PWM with duty cycle ~25%. But I am not sure how this works. When my timer1 overflows after 50ms so is the period of time for my pwm equal to 50ms right? And 25% of these 50ms should be on HIGH, but it turned out as wrong.
I've read the TimerOne.cpp and TimerOne.h a bit to understand the actual code in there in order to get how setting up a PWM signal even works.
So we have pwm():
void TimerOne::pwm(char pin, int duty, long microseconds) // expects duty cycle to be 10 bit (1024)
{
if(microseconds > 0) setPeriod(microseconds);
if(pin == 1 || pin == 9) {
DDRB |= _BV(PORTB1); // sets data direction register for pwm output pin
TCCR1A |= _BV(COM1A1); // activates the output pin
}
else if(pin == 2 || pin == 10) {
DDRB |= _BV(PORTB2);
TCCR1A |= _BV(COM1B1);
}
setPwmDuty(pin, duty);
start();
}
And in there setPeriod():
void TimerOne::setPeriod(long microseconds)
{
long cycles = (F_CPU * microseconds) / 2000000; // the counter runs backwards after TOP, interrupt is at BOTTOM so divide microseconds by 2
if(cycles < RESOLUTION) clockSelectBits = _BV(CS10); // no prescale, full xtal
else if((cycles >>= 3) < RESOLUTION) clockSelectBits = _BV(CS11); // prescale by /8
else if((cycles >>= 3) < RESOLUTION) clockSelectBits = _BV(CS11) | _BV(CS10); // prescale by /64
else if((cycles >>= 2) < RESOLUTION) clockSelectBits = _BV(CS12); // prescale by /256
else if((cycles >>= 2) < RESOLUTION) clockSelectBits = _BV(CS12) | _BV(CS10); // prescale by /1024
else cycles = RESOLUTION - 1, clockSelectBits = _BV(CS12) | _BV(CS10); // request was out of bounds, set as maximum
ICR1 = pwmPeriod = cycles; // ICR1 is TOP in p & f correct pwm mode
TCCR1B &= ~(_BV(CS10) | _BV(CS11) | _BV(CS12));
TCCR1B |= clockSelectBits; // reset clock select register
}
So my first question is what exactly "long cycles = (F_CPU * microseconds) / 2000000;" does do? Is it the timer cycle? But what is F_CPU e.g. and why dividing by 2000000?
gamd:
So my first question is what exactly "long cycles = (F_CPU * microseconds) / 2000000;" does do? Is it the timer cycle? But what is F_CPU e.g. and why dividing by 2000000?
It is a predefined constant that is set according to the speed of the processor you are using. For example, a Uno runs at 16MHz.
That code is just determining what the prescale values need to be in order to achieve the desired period. (The 2 is in there since the timer counts up and then down before an interrupt - look at the comment)
Thank you. To understand this I need to have a closer look here:
So cycles is the number who represents the period of time after that the timer should get interrupted. It is divided by 2, because the timer counts first up then down and the interrupt routine is called. Is that right?
But then I am wondering how exactly this pwm gets generaded. Let's take a closer look at setPwmDuty() in the code I posted below. There is "unsigned long dutyCycle", which is basically the number of cycles we determined in setPeriod();
After that dutyCacle gets multiplied with duty (this is a value from 0 to 1024 and represents the duty cycle, which means how long the signal is HIGH) and binary shifted right by 10dec.
But how does this determine how long the signal on e.g. output PIN 9 is HIGH?
void TimerOne::setPeriod(long microseconds)
{
long cycles = (F_CPU * microseconds) / 2000000; // the counter runs backwards after TOP, interrupt is at BOTTOM so divide microseconds by 2
if(cycles < RESOLUTION) clockSelectBits = _BV(CS10); // no prescale, full xtal
else if((cycles >>= 3) < RESOLUTION) clockSelectBits = _BV(CS11); // prescale by /8
else if((cycles >>= 3) < RESOLUTION) clockSelectBits = _BV(CS11) | _BV(CS10); // prescale by /64
else if((cycles >>= 2) < RESOLUTION) clockSelectBits = _BV(CS12); // prescale by /256
else if((cycles >>= 2) < RESOLUTION) clockSelectBits = _BV(CS12) | _BV(CS10); // prescale by /1024
else cycles = RESOLUTION - 1, clockSelectBits = _BV(CS12) | _BV(CS10); // request was out of bounds, set as maximum
ICR1 = pwmPeriod = cycles; // ICR1 is TOP in p & f correct pwm mode
TCCR1B &= ~(_BV(CS10) | _BV(CS11) | _BV(CS12));
TCCR1B |= clockSelectBits; // reset clock select register
}
void TimerOne::setPwmDuty(char pin, int duty)
{
unsigned long dutyCycle = pwmPeriod;
dutyCycle *= duty;
dutyCycle >>= 10;
if(pin == 1 || pin == 9) OCR1A = dutyCycle;
else if(pin == 2 || pin == 10) OCR1B = dutyCycle;
}
void TimerOne::pwm(char pin, int duty, long microseconds) // expects duty cycle to be 10 bit (1024)
{
if(microseconds > 0) setPeriod(microseconds);
if(pin == 1 || pin == 9) {
DDRB |= _BV(PORTB1); // sets data direction register for pwm output pin
TCCR1A |= _BV(COM1A1); // activates the output pin
}
else if(pin == 2 || pin == 10) {
DDRB |= _BV(PORTB2);
TCCR1A |= _BV(COM1B1);
}
setPwmDuty(pin, duty);
start();
}
That is the register the chip uses to count up to. It is all done in the hardware of the '328 chip. As part of the functionality, given the mode it is configured to operate in, it will toggle pin 9. Download the Atmel '328 datasheet and read all about it here