Hello all,
Long story short, I want to write my own code to do PWM on pin 9 of an Arduino Ethernet. I've been reading a lot of the ATmega168/328 datasheet sections that deal with PWM - especially PWM on Timer1. I want to control a serv with a refresh rate of 200 hz (I called the company and they said their servo can refresh anywhere from 50-250 hz and the faster the better). I currently believe I have code written to output at 50 HZ. I'm using the phase and freq corrected PWM with ICR1 as my TOP for PWM.
Registry in Binary
TCCR1A = 1 1 0 0 0 0 0 0
TCCR1B = 0 0 0 1 0 1 0 0
This gives me
WGM1 = 8 - Phase and freq corrected PWM with ICR1 as top
COM1A = 3 - inverted PWM
CS = 256 - prescaler used to give me 50 Hz (Question about this at the bottom of the post).
NOTE: The code below is a blend of code I found online and what I've written. the stuff commented out is stuff I found online but I keep it for reference. I also haven't changed the first few lines to re describe what the code does.
//Code example for Arduino Uno by Bart Borghuis
//This program drives a servo motor using timer0 interrupts at 50kHz.
//Receipt of character '0' through the serial port sets the motor in the 'closed' position
//defined by motorstate0. Receipt of '1' sets the motor in the 'open' position defined by motorstate1.
#include <avr/interrupt.h>
//storage variables
boolean PWM_State=0;
int startbyte, PWM_On=5, PWM_Count=0, PWM_Max=10;
byte ledPin=13;
void setup(){
Serial.begin(9600);
//set pins as outputs
pinMode(9, OUTPUT);
cli();//stop interrupts
//set timer0 interrupt at 2kHz
TCCR1A = 0;// set entire TCCR1A register to 0
TCCR1B = 0;// same for TCCR1B
TCNT1 = 0;//initialize counter value to 0
// set compare match register for 50khz increments
ICR1 = 0x0271;
// turn on phase and freq corect PWM mode
TCCR1A = 0xC0;
// Set CS11 and CS10 bits for 64 prescaler
TCCR1B = 0x14;
// enable timer compare interrupt
TIMSK1 |= (1 << OCIE1A);
OCR1A=0;
sei();//allow interrupts
}//end setup
void loop(){
// if (Serial.available() > 0) {
// startbyte = Serial.read();
// switch (startbyte){
// case 48:
// motorenabled=1;
// digitalWrite(ledPin, LOW);
// motorstate=0;
// break;
// case 49:
// motorenabled=1;
// digitalWrite(ledPin, HIGH);
// motorstate=1;
// break;
// }
// }
}
//ISR(TIMER1_COMPA_vect){
////timer1 interrupt 50Hz to drive servo motor connect to pin 9
// PWM_Count++;
// if(PWM_Count < PWM_On){
// digitalWrite(9,LOW);
// }
// if(PWM_Count>=PWM_On){
// digitalWrite(9,HIGH);
// }
// if(PWM_Count>=PWM_Max){
// PWM_Count=0;
// }
//}
When I hooked up an Oscope to pin 9, I saw a pulse width of ~150us at ~50Hz. I then set OCR1A = to 100 and I noticed that my freqency of said pulses increased from 50 Hz to 100 Hz but the pulse width did not grow larger - it was still ~150 us. I thought that pin 9 was supposed to go high when TCNT1=OCR1A on the upcount and go low when TCNT1=OCR1A on the downcount, thus giving me PWM. I was going to vary OCR1A to create my PWM.
Everything that I've read says the COM1A will determine what happens on the OC1A pin - pin 9 - and the PWM isn't showing up like I thought it would. What exactly am I missing here?
The code that is commented out at the bottom was trying to keep tract of how often the interrupt happens when OCR1 = TCNT1 and if pin 9 is high, go low, and vice versa.
Prescaler question:
So I know I can set ICR to top, but what is the most I can set ICR to? I ask because right did some math and found out that if my prescaler is 256, then the top will be 0x0271 (625 decimal). However, I believe ICR1 is a 16bit registry, so does that mean it can go up to 0xFFFF (65535 dec)? If so, I could use a smaler prescaler, which gives me better resolution...? If so, I could use a prescaler of 8 and set ICR1 to 0x4E20 (20000 dec) for 50 Hz.