View previous topic :: View next topic |
Author |
Message |
malaika7
Joined: 22 Jan 2012 Posts: 3 Location: UK
|
square wave code |
Posted: Sun Jan 22, 2012 3:21 am |
|
|
Hi everyone. I am learning Pic and C programming. I'm trying to generate a squarewave (ac) output of period 20ms using full bridge pwm. However, I'm getting a square wave sometimes and then at times the PIC seems to lockup with an undefined output more like a modified sine wave. Can someone please give me some direction. The code is attached.
Code: |
#include "16f690.h"
#device adc=16
#FUSES NOWDT //No Watch Dog Timer
#FUSES INTRC_IO //Internal RC Osc, no CLKOUT
#FUSES PUT //Power Up Timer ON
#FUSES NOMCLR //Master Clear pin used for I/O
#FUSES NOBROWNOUT //No brownout reset
#FUSES IESO //Internal switch over mode ON
#FUSES FCMEN //Fail safe clock monitor enabled
#FUSES NOCPD //No code protection from EE
#FUSES NOPROTECT //No code read protection
#use delay(internal=31kHz)
void main()
{
setup_adc_ports(NO_ANALOGS|VSS_VDD);
setup_adc(ADC_OFF);
setup_spi(SPI_SS_DISABLED);
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
setup_timer_1(T1_DISABLED);
setup_timer_2(T2_DIV_BY_1,22, 1); //prescaler and post scaler set>> 1
setup_ccp1(CCP_PWM | CCP_PWM_FULL_BRIDGE | CCP_PWM_H_H | CCP_SHUTDOWN_AC_L | CCP_SHUTDOWN_BD_L); //set shutdown mode
set_pwm1_duty(700); // duty cycle
setup_comparator(NC_NC_NC_NC); //not used>> no comparator.
setup_oscillator(OSC_31KHZ);
while(TRUE)
{
// Positive half cycle.
setup_ccp1(CCP_PWM_FULL_BRIDGE | CCP_PWM_H_H);
set_pwm1_duty(700);
delay_ms(1); //delay to avoid both forward and reverse at same time
// Negative half cycle.
setup_ccp1(CCP_PWM_FULL_BRIDGE_REV | CCP_PWM_H_H);
set_pwm1_duty(700);
delay_ms(1); //delay to avoid reverse and forward at same time
}
}
|
_________________ 'He who riseth late shall trot all day' |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19499
|
|
Posted: Sun Jan 22, 2012 5:31 am |
|
|
Comments inline:
Code: |
#include "16f690.h"
#device adc=16
#FUSES NOWDT //No Watch Dog Timer
#FUSES INTRC_IO //Internal RC Osc, no CLKOUT
#FUSES PUT //Power Up Timer ON
#FUSES NOMCLR //Master Clear pin used for I/O
#FUSES NOBROWNOUT //No brownout reset
#FUSES IESO //Internal switch over mode ON
#FUSES FCMEN //Fail safe clock monitor enabled
#FUSES NOCPD //No code protection from EE
#FUSES NOPROTECT //No code read protection
#use delay(internal=31kHz)
void main(void) {
setup_adc_ports(NO_ANALOGS); //don't set a voltage range
setup_adc(ADC_OFF);
setup_spi(FALSE); //Error in the wizard - FALSE turns the SPI off
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1); //Are you using this?.
//Disable if not.
setup_timer_1(T1_DISABLED);
setup_timer_2(T2_DIV_BY_1,22, 1); //prescaler and post scaler set>> 1
//Frequency = 31000/(4*23)Hz = 337Hz - Not what you describe
setup_ccp1(CCP_PWM | CCP_PWM_FULL_BRIDGE | CCP_PWM_H_H | CCP_SHUTDOWN_AC_L | CCP_SHUTDOWN_BD_L); //set shutdown
mode
//Are you using shutdown inputs ?. If not this could result in random
//shutdown of the PWM.....
set_pwm1_duty(700); // duty cycle
//Big problem here - max duty cycle is (Timer2 max count+1)*4
//All that will happen is this will lock the PWM 'on' permanently....
//Same applies with the same value below - changing it again does
//nothing, the value is stored unless changed...
setup_comparator(NC_NC_NC_NC); //not used>> no comparator.
setup_oscillator(OSC_31KHZ); //Not needed
while(TRUE) {
// Positive half cycle.
setup_ccp1(CCP_PWM_FULL_BRIDGE | CCP_PWM_H_H);
set_pwm1_duty(700);
delay_ms(1); //delay to avoid both forward and reverse at same time
// Negative half cycle.
setup_ccp1(CCP_PWM_FULL_BRIDGE_REV | CCP_PWM_H_H);
set_pwm1_duty(700);
delay_ms(1); //delay to avoid reverse and forward at same time
}
}
|
As it stands, you are not using the PWM at all. Just loading a value larger than it'll accept into the timing register, so the output is locked on, and reversing using the loop.....
The intermittent behaviour may well be because the shutdown inputs are floating.
Also as a further comment, if you had a PWM running at 50Hz (20mSec), how can you reverse this every 1000th second.....
Best Wishes |
|
|
malaika7
Joined: 22 Jan 2012 Posts: 3 Location: UK
|
square wave code |
Posted: Sun Jan 22, 2012 6:24 am |
|
|
Thank you for your response but I'm sorry I don't understand. I'm only beginning playing with these things. I have setup PWM and yet you say I'm not using it. I have tried a count of 154 but no luck. I tried a delay of 10ms per half cycle to give me a total of 20ms but the period extended even further. However, your explanation of duty cycle and frequency is eye opening. Thanks loads. Suppose I remove the delay, would that be safe? Please advise. _________________ 'He who riseth late shall trot all day' |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19499
|
|
Posted: Sun Jan 22, 2012 8:51 am |
|
|
Have a look at the data sheet. Page 131. Particularly the 'note' above the table. This is what you are doing.
Just to show the PWM running, try:
Code: |
//Obviously in a 'main' as for your code
setup_timer_2(T2_DIV_BY_1,154, 1);
//Frequency = 31000/(4*155)Hz = 50Hz
setup_ccp1(CCP_PWM | CCP_PWM_FULL_BRIDGE | CCP_PWM_H_H);
set_pwm1_duty(308L);
do {
delay_ms(1000);
setup_ccp1(CCP_PWM_FULL_BRIDGE_REV | CCP_PWM_H_H);
delay_ms(1000);
setup_ccp1(CCP_PWM_FULL_BRIDGE | CCP_PWM_H_H);
} while; //Just sit letting the PWM run on it's own, reversing every second.
|
Best Wishes |
|
|
malaika7
Joined: 22 Jan 2012 Posts: 3 Location: UK
|
square wave code |
Posted: Sun Jan 22, 2012 11:06 am |
|
|
I think I understand this one . The duty 308L however bits me. I thought duty would be between 1 and (154+1)*4. I know L stands for 'long' but what does it mean here? Does the 50Hz translate onto my square wave output or is it just the modulation frequency?
Once more thank you so much. _________________ 'He who riseth late shall trot all day' |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19499
|
|
Posted: Sun Jan 22, 2012 3:45 pm |
|
|
The 'L' forces a constant to be treated as a 'long'.
Now with '308', it actually does nothing, _but_ when you "tried 154", it'd make a huge difference. If you read the manual for the set_pwm_duty function, it has two different modes of operation. If you call it with a 'long' value, the value is placed into the ten bits of the full PWM duty cycle register. However if you call it with a 'short' value, the number is put into just the top eight bits of the PWM duty cycle (quicker). Problem is that this means that the behaviour will change when a value goes below 256, unless you _explicitly_ tell the code to treat the vale as a 'long'. So when you tried 154, this (since it was > 256), it was treated as an 8bit value, and put into the upper 8 bits of the ten bit register (effectively multiplied by 4), so gave the same behaviour as 616!.....
Hence it is good practice when putting a constant into the PWM function, to be _explicit_, and tell the compiler to treat it as long, no matter what the value involved.
A search on the PWM here will find a lot of threads explaining this/
Best Wishes |
|
|
|