Andre Abelian [aabelian@mason-electric.com]
I needed software PWM and I used Scott Dattalo's software PWM idea and I can tell he is a genus. The test I did on my demo board I only had 2 leds and 1 pot. The pot is dimming one of the led and the other PWM is fixed number entered manually before compiling. The resolution is 10 bit and the result is excellent. see attachment file. It is written in CCS C. Note that there are some extra unused stuff. I am using timer 0 interrupt. Also thanks to CCS for making nice compiler.
Andre
// // Scott Dattalo's Software PWM idea // Thanks to him // #include <18F4550.h> #rom int 0xf00000={0x19,0x11,0x09,0x00} // write to eeprom project number #device ADC=10 #define DEBUG // comment this line (to program): Remove comment (to debug) #ifdef DEBUG #fuses HS,NOWDT,NOPROTECT,NOLVP,MCLR // use this line to debug #else #fuses NOMCLR,STVREN,BORV20,WDT2048,HS,PROTECT,NOLVP // use this line to programmer #endif #use delay(clock=20000000) #use rs232(DEBUGGER) #use rs232(baud=57600,xmit=PIN_B5,bits=8,invert) #ZERO_RAM // clear all variables #define pwm_output1_on output_high(PIN_B5); #define pwm_output1_off output_low(PIN_B5); #define pwm_output2_on output_high(PIN_B4); #define pwm_output2_off output_low(PIN_B4); #define pwm1 1023 #define pwm2 1023 #define cycle_t0 0xFF5a long int duty_cycle1,rising_edge1,falling_edge1; long int duty_cycle2,rising_edge2,falling_edge2; ///////////////////////////////////////////////////// // Main Program ///////////////////////////////////////////////////// void main (void) { set_tris_a (0xFF); // make all output no use for now set_tris_b (0b11111111); // make all input set_tris_c (0xff); // all output set_tris_d (0b00010000); // set_tris_e (0xff); // make all output OUTPUT_D (0xff); // OUTPUT_C (0xff); // turn off all setup_adc( ADC_CLOCK_INTERNAL); // setup_counters (RTCC_INTERNAL, RTCC_DIV_1); enable_interrupts (int_RTCC); enable_interrupts (GLOBAL); set_timer0(cycle_t0); // adjust timer0 pwm_output1_on; rising_edge1= 0; // falling_edge1 = pwm1 - duty_cycle1; pwm_output2_on; rising_edge2= 0; // falling_edge2 = pwm2 - duty_cycle2; while (TRUE) { set_adc_channel(0); delay_ms(1); duty_cycle1 = read_ADC(); // set_adc_channel(1); // delay_ms(1); // duty_cycle2 = read_ADC(); } } #int_rtcc void pwm_isr() { set_timer0(cycle_t0); // adjust timer0 if (rising_edge1 ++ > pwm1) { rising_edge1= 0; pwm_output1_on; falling_edge1 = pwm1 - duty_cycle1; } if (falling_edge1 ++ > pwm1) { falling_edge1 = 0; pwm_output1_off; } if (rising_edge2 ++ > pwm2) { rising_edge2 = 0; pwm_output2_on; falling_edge2 = pwm2 - 900; } if (falling_edge2 ++ > pwm2) { falling_edge2 = 0; pwm_output2_off; } }
Comments:
set_tris_a (0xFF); // make all output no use for nowJames Newton of MassMind replies: Yeah, that's certainly a typo. A 1 in any tris register makes the pin an input. So A is being set to all input, not all output. This is a common problem with commenting programs where the programmer sets something up, and comments it, then changes the settings and forgets to change the comment. A better comment would be // set TRIS, 0 = output, 1 = input because it's always true.
set_tris_b (0b11111111); // make all input
what is the difference in both commands how one is input and one is output
Questions: