I know this is silly but I got really confused.
I want to make a PWM pulse with 3 modes on Atmega16:
1- 1Khz with Duty cycle 100%
2- 4Khz with Duty cycle 100%
3- 1Khz with Duty cycle 50%
I was away from AVR for almost 2 years and I forgot everything, so I just need the calculations of Timer 1 in a simple way.
any thing I have read makes me more confused. Is there something that could help me?
I'm using Codevision AVR.
1- 1Khz with Duty cycle 100%
2- 4Khz with Duty cycle 100%
are the same thing. There is no actual PWM at all. The output is high all the time and frequency doesn't matter.
3- 1Khz with Duty cycle 50%
is actually PWM. There are a few types to choose from, but if the duty cycle is going to be exactly 50%, then there are easy ways to achieve this with a toggle. From the manual,
A frequency (with 50% duty cycle) waveform output in fast PWM mode can be achieved by setting OC1A to toggle its logical level on each compare match (COM1A1:0 = 1). This applies only if OCR1A is used to define the TOP value (WGM13:0 = 15).
That is, set the COM1A1 and COM1A0 bits of TCCR1A to be 01, and set all the WGM bits of TCCR1A and TCCR1B to be 1. Choose OCR1A and the CSx prescalar bits of TCCR1B so that OCR1A is reached every 0.5 ms.
I did this, but I got exams so it got too long to post it.
I set the Fcpu to 4MHz
and here is the code:
void set1KhzDC100()
{
// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: 500.000 kHz
// Mode: Fast PWM top=0x01FF
// OC1A output: Non-Inv.
// OC1B output: Discon.
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: Off
// Compare B Match Interrupt: Off
TCCR1A=0x82;
TCCR1B=0x0A;
TCNT1H=0;
TCNT1L=0;
ICR1H=0x00;
ICR1L=0x00;
OCR1A=511;
}
void Set4KhzDC100()
{
// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: 4000.000 kHz
// Mode: Fast PWM top=0x03FF
// OC1A output: Non-Inv.
// OC1B output: Discon.
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: Off
// Compare B Match Interrupt: Off
TCCR1A=0x83;
TCCR1B=0x09;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1A=1023;
OCR1BH=0x00;
OCR1BL=0x00;
}
void Set1KhzDC50()
{
// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: 500.000 kHz
// Mode: Fast PWM top=0x01FF
// OC1A output: Non-Inv.
// OC1B output: Discon.
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: Off
// Compare B Match Interrupt: Off
TCCR1A=0x82;
TCCR1B=0x0A;
TCNT1H=0;
TCNT1L=0;
ICR1H=0x00;
ICR1L=0x00;
OCR1A=255;
}
Related
Trying to understand timing / dimming and interrupts using an Arduino Uno (or any other AVR) is being made very difficult by a serious lack of example code. Having found a sketch that starts from zero and ramps up the brightness, I have tried to adapt the code to prevent the continuous loop which occurs when the 16-bit register overflows.
The attached sketch starts up from zero light output and increases over a period of time - currently using the delay() function.
Attempting to adapt the code to prevent the loop from starting the entire process again and to allow the led to remain at the "top" brightness output for x (variable) number of hours has proved to be most elusive. As one of the contributors have noted this area of coding is one of the most difficult to master.
Any advice or guidance which will put me in the right direction will be most appreciated.
...
//fade over 65535 steps
// 16 bit PWM on any pin
// Example uses built in LED on pin 13 (PORTB bit 5)
// https://forum.arduino.cc/index.php?topic=348170.0
void setup() {
pinMode(13, OUTPUT);
cli(); // Disable all interrupts
TCCR1A = 0; // Clear all flags in control register A
TCCR1B = 0; // Clear all flags in control register B
TCNT1 = 0; // Zero timer 1 count
OCR1A = 32768; // Preload compare match register (50% duty cycle)
// No prescaler
//TCCR1B |= _BV(CS12);
//TCCR1B |= _BV(CS11);
TCCR1B |= _BV(CS10);
TIMSK1 |= _BV(OCIE1A); // Enable timer compare interrupt
TIMSK1 |= _BV(TOIE1); // Enable timer overflow interrupt
sei(); // enable all interrupts
}
void loop() {
for (unsigned int x = 1; x < 65535; x++) {
//cli();
OCR1A = x;
//sei();
delay(20);
}
}
ISR(TIMER1_OVF_vect) { // Timer1 overflow interrupt service routine
PORTB |= _BV(PORTB5); // Turn LED (pin 13) on
}
ISR(TIMER1_COMPA_vect) { // Timer1 compare interrupt service routine
PORTB &= ~_BV(PORTB5); // Turn LED off
}
...
Using the Arduino Mini Pro 3.3V I just stumbled over a problem when switching between the "INTERNAL" and "DEFAULT" voltage reference for the ADC.
I want to measure the output of a voltage divider [GND - 110kOhm - A2 - 500kOhm - VCC] for calculating VCC. VCC has been measured as 3.3V. It is provided by a voltage regulator.
In the loop I firstly measure the voltage divider output with the internal reference and afterwards with the default voltage reference.
I saw code examples where people recommend to wait some milliseconds before reading the next value and the (analogReference() documentation) recommends to ignore the first readings after calling analogReference(). I follow these guidlines.
I'll provide a minimum example sketch:
// the setup function runs once when you press reset or power the board
void setup()
{
pinMode(A2, INPUT); // ADC pin
Serial.begin(9600);
Serial.println("----------------");
}
void burn8Readings(int pin)
{
for (int i = 0; i < 8; i++)
{
analogRead(pin);
}
}
// the loop function runs over and over again forever
void loop()
{
uint16_t nResult1, nResult2;
analogReference(INTERNAL); // set the ADC reference to 1.1V
delay(10); // idle some time
burn8Readings(A2); // make 8 readings but don't use them to ensure good reading after ADC reference change
nResult1 = analogRead(A2); // read actual value
analogReference(DEFAULT); // set the ADC reference back to internal for other measurements
delay(10); // idle again
burn8Readings(A2); // make 8 readings but don't use them to ensure good reading after ADC reference change
nResult2 = analogRead(A2); // do other measurements
// print result to serial interface..
Serial.print("1: ");
Serial.print(nResult1);
Serial.print(" - 2: ");
Serial.println(nResult2);
delay(2000);
}
The first pair of ADC results seems correct (553 / 184), but in the following iterations the first value is faulty without changing the actual voltage on the ADC pin. (240 / 183)
The ADC result of the DEFAULT reference is always fine.
For a 2.56V reference the value of 240 would be feasible. I know that some ATmegas use a 2.56V reference voltage, but the ATmega328 should have 1.1V only. Strangely the (ATmega328/P datasheet) mentions a 2.56V reference in an ADC example in chapter 28.7, so I'm confused.
Is there a possibility there is a 2.56V ADC reference in a certain ATmega328p version?
It turns out the similarity to the 2.56V was a coincidence and probably an error in the datasheet (or in my understanding).
The problem was that after the analogReference(INTERNAL) call the ADC value has to be read immediately! Not after some milliseconds as I did it. (Source)
Still it is important to also wait some milliseconds after doing the dummy readout. For me one readout and delay(5) was just enough, but I guess that depends on the charge left in the capacitor of the ADC: So I'd recommend higher delays.
The correct sequence is:
analogReference(INTERNAL); // set the ADC reference to 1.1V
burn8Readings(A2); // make 8 readings but don't use them
delay(10); // idle some time
nResult1 = analogRead(A2); // read actual value
and
analogReference(DEFAULT); // set the ADC reference back to internal
burn8Readings(A2); // make 8 readings but don't use them
delay(10); // idle again
nResult2 = analogRead(A2); // read actual value
Changing the reference back to DEFAULT seems to be less prone...but at least one readout still was necessary for precise results.
I hope no one has to spend time on this one anymore...
I want to make sure my code looks like working, since I don't have a lot of time with a signal generator tomorrow and I want to know how to set the sample rate.
I want to sample a 2kHz signal with a samplerate of 6kHz with a Arduino MEGA 2560.
It, doesn't have to be in real time, so i'm thinking of filling a buffer and then sending those over the serial connection.
Can anyone say if this code defenitly wouldn't work for this?
And how could i set the samplerate to 6kHz?
void setup() {
Serial.begin(9600);
}
void loop() {
for(int x = 0; x < 1000; x++){
// read the input on analog pin 0:
int sensorValue[x] = analogRead(A0);
}
for( x = 0; x < 1000; x++){
// Convert the analog reading (which goes from 0 - 1023) to a voltage (0 - 5V):
float voltage[x] = sensorValue[x] * (5.0 / 1023.0);
// print out the value you read:
Serial.println(voltage[x]);
}
}
Thank you.
Well, as I've mentioned in another thread, you can use auto triggering mode of ADC (for UNO and ATMega328p based Arduinos):
void setup() {
Serial.begin(256000);
// ADC setup is done by arduino framework, but it's possible to change it slightly (for ATMega328) :
ADCSRB = _BV(ADTS2) | _BV(ADTS1) | _BV(ADTS0); // ADTS2..0 = 111, Timer 1 input capture event trigger source
ADCSRA |= _BV(ADATE); // enable auto trigger mode
ADCSRA |= _BV(ADIF); // reset conversion end flag (= interrupt flag)
// timer 1 setting:
TCCR1A = 0; // clear all
ICR1 = F_CPU/6000U; // 1 should be substracted here but result is about 2665.7 and it will be truncated to 2665
TCCR1B = _BV(WGM12) | _BV(WGM13) | _BV(CS10); // CTC mode with ICR1 as TOP value, enabled with no prescaling
TIMSK1 = _BV(ICF1); // not working without this... Flag must be cleaned up after the trigger ADC, otherwise it's stucked
analogRead(A0); // dummy read to set correct channel and to start auto trigger mode
pinMode(13, OUTPUT);
}
void loop() {
if (ADCSRA & _BV(ADIF)) {
ADCSRA |= _BV(ADIF); // reset flag by writing logic 1
Serial.println(ADC);
}
}
ISR(TIMER1_CAPT_vect) { // to clear flag
PINB = _BV(PB5); // and toggle d13 so frequency can be measured (it'd be half of real rate)
// it might be enabled on PWM pin too by setting force output compare and some compare register to half of value ICR1
}
This sketch uses baud rate 250000 but it's still too slow. The space character can be used as an separator, this'll save one character (as new line are usually two characters: \r\n). One value can be 1 to 4 characters long so for values:
0-9 - 3B you need baud rate 3*10*6000 = 180000
10-99 - 4B and you need baud rate 240000
and for the rest of cases you're too slow.
So the only way is sending those integers binary and without separator it'd be even better. The 2B per value results into minimal baud rate around 120000 baud/s.
I am trying to change the frequency of the digital pwm pin #9 on an Arduino Uno to 70hz. I have found some code examples for changing a pins frequency, but nothing is very clear. Can someone please explain this? Thanks
The Atmel ATMega Pulse-width modulation (PWM) hardware capabilities primarily supports changing the duty cycle. The frequencies can only be selected from a few fixed choices.
There is a very good and detailed explanation at arduino.stackexchange.com. Check out the the post: How can I set two PWM at two different frequencies?.
You can change pin 9 PWM to 70Hz by changing IRC1 anc OCRA1 values.
double freq = 70.0; // Set frequency to 70Hz
// Set Timer1 to phase and frequency correct mode. NON-inverted mode
TCCR1A = _BV(COM1A1) | _BV(COM1B1);
// Set Timer1 prescaler to clk/8 (outputs from 15,259Hz to 500000Hz
TCCR1B = _BV(WGM13) | _BV(CS11);
//ICR Register, which controls the PWM total pulse length
double icr = 8000000.0/8.0/freq; //ICR1 = (clk/2)/tmr_prescaler/freq.
ICR1 = round(icr); // defines total PWM length in clock/8
// Now to change the PWM output value (duty cycle):
double pwm_duty = 50.0 // Set PWM duty cycle to 50% (higher precision)
// OR (delete line above or below)
double pwm_duty = 120 /255.0; // is the same as analogWrite(9, 120)
//OCR Registers, which control the PWM duty cycle.
OCR1A = round(icr * pwm_duty/100.0);
OCR1B = round(icr * (100.0-pwm_duty)/100.0);
TIP: You can use other freq values for other frequencies.
Just remember that the higher the frequency, lower the duty cycle resolution will be.
NOTE:
Any Arduino code that uses TIMER1 won´t work after this (or will work erratically). Arduino uses TIMER1 for Servo library.
I'm trying to play a tone while changing something on an LCD display. I've searched around and tried protothreads, but it seems that the delay still blocks the program. I've also tried removing the delay altogether, but it skipped everything except the last note. Is there a way to play a tone without using delay? (millis perhaps?)
Sample tone sequence:
//Beats per Minute
#define BPM 250
//Constants, try not to touch, touch anyways.
#define Q 60000/BPM //Quarter note
#define W 4*Q //Whole note
#define H 2*Q //Half note
#define E Q/2 //Eigth note
#define S Q/4 //Sixteenth note
void toneFunction()
{
tone(tonePin,C5,Q);
delay(1+W);
tone(tonePin,C5,Q);
delay(1+W);
tone(tonePin,C5,Q);
delay(1+W);
tone(tonePin,C6,W);
}
You can set up a timer and put note changing logic into an interrupt service routine (ISR).
Each X milliseconds, the timer will reset and interrupt your main loop. The ISR will run and pick the next note and call the tone function. After exiting the ISR, the program continues from the point it was interrupted.
I have attached a code I used in one of my projects. The timer will interrupt the main loop every 50ms (20 Hz), therfore you will have to put your own numbers in OCR1A and the pre-scaler. Please read more about timer interrupt in arduino so that you will understand how to do it (for example here: http://www.instructables.com/id/Arduino-Timer-Interrupts/step2/Structuring-Timer-Interrupts/). You can also see the example at the end of this page (http://playground.arduino.cc/Code/Timer1) for a more user friendly way of doing this.
setup() {
....
/* Set timer1 interrupt to 20Hz */
cli();//stop interrupts
TCCR1A = 0;// set entire TCCR1A register to 0
TCCR1B = 0;// same for TCCR1B
TCNT1 = 0;//initialize counter value to 0
OCR1A = 781; // approximately 20Hz
TCCR1B |= (1 << WGM12);// turn on CTC mode
TCCR1B |= (1 << CS12) | (1 << CS10); // 1024 presxaler
TIMSK1 |= (1 << OCIE1A); // enable timer compare interrupt
sei();//allow interrupts
}
...
ISR(TIMER1_COMPA_vect){
// pick next note
}