This thread has been locked.
If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.
Hi,
I am interested in generating a PWM at p1.6 such that the duty cycle changes every say 5 seconds to a new value but the frequency stays the same. For example, a pwm that run at 10Khz frequency and the duty cycles changes from 5% to 50% in steps of 5%.
Please help!
Sahar
Hi Dennis,
Thank you very much for your help. I wrote the code below but have not had a chance to compile it yet since I left my microcontroller in my lab today. For now, can you please tell me if it looks reasonable.
I used a for loop to increment and update the values into TA0CCR1, which runs from 10% to 100% duty cycle. I also used an if loop to count to 5 seconds before TA0CCR1 is updated again.
Sorry for any obvious mistakes, I am very new to this field.
#include "msp430g2553.h"
#include <stdint.h>
unsigned int counter = 0;
unsigned int n[10];
unsigned int i;
void main( void )
{
WDTCTL = WDTPW | WDTHOLD; // Stop watchdog timer
BCSCTL1 = CALBC1_1MHZ; // Set range to 1MHz
DCOCTL = CALDCO_1MHZ; // Set DCO step and modulation to 1MHz
BCSCTL2 = DIVS_3; // SMCLK divider 1
P1SEL = 0x40; // Set special function of P1.6 (LED2) to timer module
P1SEL2 = 0x00; // Clear P1SEL2
P1DIR = 0x40; // Set P1.6 (LED2) to output direction
TA0CCR0 = 100; // Frequency 10Khz;
TA0CCR1 = 0;
TA0CCTL1 = OUTMOD_7; // Reset/set
TA0CTL = TASSEL_2 | ID_0 | MC_1 | TACLR | TAIE; // SMCLK, divider 1, up-mode, clear
_BIS_SR(LPM0_bits); // Enter Low power mode 0
}
#pragma vector=TIMER0_A0_VECTOR
__interrupt void Timer0_A0 (void) {
for (i=1; i<10; i++){
if (counter ==50000) {
n[i]=i*10;
TA0CCR1 = n[i]; // duty-cycle
counter = 0;
}
else
counter++;
}
}
Hi Sahar,
From the first look, you are definitely on the right way! I did not test your program, but I can see three things immediately:
But first test the program yourself.
Dennis
Sahar,
this was my approach to your problem - I wrote it yesterday when I had a few minutes of free time.
Since you tried to solve it yourself already, I post it just for comparison.
#include "msp430G2553.h" #include <stdint.h> void main( void ) { WDTCTL = (WDTPW | WDTHOLD); // Stop watchdog timer BCSCTL1 = CALBC1_8MHZ; // Set range to 8MHz DCOCTL = CALDCO_8MHZ; // Set DCO step and modulation to 8MHz P1SEL = 0x40; // Set special function of P1.6 (LED2) to timer module P1DIR = 0x40; // Set P1.6 (LED2) to output direction TA0CCR0 = (800 - 1); // Frequency 10kHz TA0CCR1 = 40; // Duty cycle 5% TA0CCTL1 = OUTMOD_7; // Reset / set TA0CTL = (TASSEL_2 | ID_0 | MC_1 | TACLR | TAIE); // SMCLK, divider 1, up-mode, clear, interrupt enabled _BIS_SR( GIE ); // Enable global interrupts while( 1 ); // Endless loop } // Timer0 A1 interrupt service routine #pragma vector = TIMER0_A1_VECTOR __interrupt void Timer0_A1_ISR( void ) { static uint16_t counter = 0; // Cycle counter static uint8_t direction = 1; // 1: up, 0: down TA0CTL &= ~TAIFG; // Clear interrupt flag if( ++counter >= 50000 ) // 5s { if( direction ) // Direction is up { TA0CCR1 += 40; // Add 5% to existing value if( TA0CCR1 == 400 ) // Reached 50% duty cycle { direction = 0; // Next time down } } else // Direction is down { TA0CCR1 -= 40; // Subtract 5% from existing value if( TA0CCR1 == 40 ) // Reached 5% duty cycle { direction = 1; // Next time up } } counter = 0; // Reset counter } }
This program increments your PWM in 5% steps, starting from 5% up to 50%, then decrements in 5% steps down to 5% again. Increment and decrement happens every 5 seconds. This cycle is looped over and over again.
Dennis
Sahar Elyahoodayan said:Would you please let me know why you used an 8MHz clock?
In terms of power consumption, is it more efficient to run the clock at lower clk cycle?
Yes, absolutely right. Lower clock speed means lower power. But as you can see I also did not use any low power mode. This was just an example, not trimmed to save energy.
Why I used 8MHz instead of 1MHz? Well, it is only because you get larger values for the timer's CCR registers. When using 1MHz, you have
TA0CCR0 = (100 - 1); // Frequency 10kHz TA0CCR1 = 5; // Duty cycle 5%
And any increment is += 5 as well, instead of 40. In this case this does not make a difference. You can use 1MHz and 5 as increment.
But I prefer higher values. Imagine you want to increment 0.5% while running the timer @ 1MHz - you would now need to add 0.5 which is not possible. When having 8MHz as clock source, you increment by 4 and get your desired percentage. So larger numbers for the timer are simply more flexible. 16MHz would also be possible, of course.
But it depends on the application - if you want 5% and low power then you're absolutely right, use 1MHz instead of 8.
Dennis
Hi Sahar!
I used Timer0 A1 because I used TAIFG to trigger the interrupt, look:
TA0CTL = (TASSEL_2 | ID_0 | MC_1 | TACLR | TAIE); // SMCLK, divider 1, up-mode, clear, interrupt enabled
Since the timer is running in up-mode, this IFG is set each time when one frequency cycle is completed - this was set here:
TA0CCR0 = (800 - 1); // Frequency 10kHz
And the TAIFG is handled by
pragma vector = TIMER0_A1_VECTOR
CCR0 always has it's own interrupt vector, this would be
pragma vector = TIMER0_A0_VECTOR
But CCR1, CCR2, CCR3 (if available), ... and TAIFG share the A1 vector. And since I only used TAIFG, I do not have to determine which source caused the interrupt.
But I do not understand your problem. Please explain it once again and / or upload your code.
Dennis
**Attention** This is a public forum