I have got the code below working on a ATtiny85 micro (Datasheet) . It outputs a PWM signal of 500Hz, 0-100% duty cycle using an analogue voltage (potentiometer) to vary the duty cycle. I need to alter the frequency to 2Khz instead of 500Hz. My programming knowledge is very basic and would appreciate if anybody could help me achieve this? Thanks!
//Constants:
const int ledPin = 0; //pin 0 has PWM funtion on attiny85 pin 5
const int potPin = A1; //pin A1 to read analog input pin 7. A0-A5 are labeles on the UNO for analogue input.
//Variables:
int value; //save analog value
void setup(){
//Input or output?
pinMode(ledPin, OUTPUT);
pinMode(potPin, INPUT); //Optional
}
void loop(){
value = analogRead(potPin); //Read and save analog value from potentiometer
value = map(value, 0, 1023, 0, 255); //Map value 0-1023 to 0-255 (PWM)
analogWrite(ledPin, value); //Send PWM value to led
delay(100); //Small delay
}
What is this for and how are you going to verify the results ?
I don't know of a ready made Arduino library solution. You'll probably have to directly manipulate the timer registers. Since you are using delay() you want to avoid using timer0 so you should look at timer1.
Just trying to pop in the parameters into the calculator for my sample code to get 25Khz. Not sure what to enter for some of the fields?
System Clock Frequency (Hz):8,000,000
Timer Resolution:8 bit
Prescaler: clk/8
Total Timer Ticks:?
Overflow Count:?
Remainder Timer Ticks:?
Real Time (sec):?
Like you said, if I change the pinMode() to INPUT there will be zero output. I would ideally want 0% duty cycle when the potentiometer reached 0V and 100% when it reaches 5V.
I put in the required frequency and the calculator gave me the total timer ticks. I can get down to 4Khz and no lower, when I change the OCR0A. Code below.
Yes, I'm using a scope to check the signals.
System Clock Frequency (Hz): 8000000
Timer Resolution: 8 bit
Prescaler: (2) Clk/8
Total Timer Ticks: 250.6265664160401
Overflow Count: 0
Remainder Timer Ticks: 250.6265664160401
Real Time (sec): 0.0002506265664160401
New Freq (Hz): 3990
/*
* ATtiny85
* -------u-------
* RST - A0 - (D 5) --| 1 PB5 VCC 8 |-- +5V
* | |
* A3 - (D 3) --| 2 PB3 PB2 7 |-- (D 2) - A1 --> 10K Potentiometer
* | |
* A2 - (D 4) --| 3 PB4 PB1 6 |-- (D 1) - PWM --> Fan Blue wire
* | |
* Gnd ---| 4 GND PB0 5 |-- (D 0) - PWM --> Disabled
* -----------------
*/
// normal delay() won't work anymore because we are changing Timer1 behavior
// Adds delay_ms and delay_us functions
#include <util/delay.h>
// Clock at 8mHz
#define F_CPU 8000000 //F_CPU 8000000. This is used by delay.h library
const int PWMPin = 1; // Only works with Pin 1(PB1)
const int PotPin = A1;
void setup()
{
pinMode(PWMPin, OUTPUT);
// Fast PWM Mode, Prescaler = /8
// PWM on Pin 1(PB1), Pin 0(PB0) disabled
// 8Mhz / 8 / (39 + 1) = 25Khz
TCCR0A = _BV(COM0B1) | _BV(WGM01) | _BV(WGM00);
TCCR0B = _BV(WGM02) | _BV(CS01);
// Set TOP and initialize duty cycle to zero(0)
OCR0A = 250; // 39 TOP - DO NOT CHANGE, SETS PWM PULSE RATE
OCR0B = 0; // duty cycle for Pin 1(PB1) - generates 1 500nS pulse even when 0
}
void loop()
{
int in, out;
in = analogRead(PotPin);
out = map(in, 0, 1023, 0, 255);//(in, 0, 1023, 0, 39)
OCR0B = out;
_delay_ms(200);
}
I think the issue is that the potentiometer is actually at 0V and my scope is showing I have a duty cycle of 0.5% still present. Even if I force 'in' to zero it results in no change. Is there something else I could try?
/*
* ATtiny85
* -------u-------
* RST - A0 - (D 5) --| 1 PB5 VCC 8 |-- +5V
* | |
* A3 - (D 3) --| 2 PB3 PB2 7 |-- (D 2) - A1 --> 10K Potentiometer
* | |
* A2 - (D 4) --| 3 PB4 PB1 6 |-- (D 1) - PWM --> Fan Blue wire
* | |
* Gnd ---| 4 GND PB0 5 |-- (D 0) - PWM --> Disabled
* -----------------
*/
// normal delay() won't work anymore because we are changing Timer1 behavior
// Adds delay_ms and delay_us functions
#include <util/delay.h>
// Clock at 8mHz
#define F_CPU 8000000 //F_CPU 8000000. This is used by delay.h library
const int PWMPin = 1; // Only works with Pin 1(PB1)
const int PotPin = A1;
void setup()
{
pinMode(PWMPin, OUTPUT);
TCCR0A = 1<<COM0B1 | 0<<COM0B0 | 1<<WGM01 | 1<<WGM00;
TCCR0B = 1<<WGM02;
// disable interrupts
TIMSK = 0;
// set TOP to generate ~2 kHz
OCR0A = 63;// 63=2Khz, 127=1Khz, 500Khz=255
// 50% duty cycle
OCR0B = 31;//31
// start timer at 125 kHz (8 MHz / 64)
TCCR0B = 1<<WGM02 | 0<<CS02 | 1<<CS01 | 1<<CS00;
}
void loop()
{
int in, out;
in = analogRead(PotPin);
if(in<10) in=0; //initially 10
out = map(in, 0, 1023, 0, 255);//(in, 0, 1023, 0, 39)
OCR0B = out;
_delay_ms(200);
}
Also, on the potentiometer I have 0.00V, this represents ~1.6% duty cycle.
~1.25V represents 100% duty cycle. Is there a way I can use the entire potentiometer range (0-5V) to represent the 0-100% duty cycle?
Both of your suggestions have worked perfectly, thanks you so much. I may come back to pick your brains again so I can get a deeper understanding of how the code functions.