Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

PWM on a PIC

Status
Not open for further replies.

AtomSoft

Well-Known Member
PWM in title
How would i go about making a PWM signal using software alone.. 38khz of course

i know this much:

Code:
/*
 * PWM registers configuration
 * Fosc = 8000000 Hz
 * Fpwm = 37735.85 Hz (Requested : 38000 Hz)
 * Duty Cycle = 50 %
 * Resolution is 7 bits
 * Prescaler is 1
 * Ensure that your PWM pin is configured as digital output
 * see more details on http://www.micro-examples.com/
 * this source code is provided 'as is',
 * use it at your own risks
 */
PR2 = 0b00110100 ;
T2CON = 0b00000100 ;
CCPR1L = 0b00011010 ;
CCP1CON = 0b00011100 ;

From https://www.micro-examples.com/public/microex-navig/doc/097-pwm-calculator.html

But that just sets the registers... Now what?

Do i just do a high/low with delays? Or would that be just a software PWM by itself?
 
Last edited:
Thx.. Not sure i understand but ..
Code:
    // speed up the clock to 8MHz
    OSCCONbits.IRCF0=1; OSCCONbits.IRCF1=1;
    OSCCONbits.IRCF1=1;
    OSCCONbits.IRCF2=1;
    OSCCONbits.SCS0=0;
    OSCCONbits.SCS1=0;
    //18F1330 Speed clock up to 32MHz using PLL
    OSCTUNEbits.PLLEN=1;
    ADCON1 = 0; // make RA0 digital
    TRISA = 0xFE;
    while(1)
        {
        PORTA = 0xFF;
        delay_us(13);
        PORTA = 0x00;    
        delay_us(13);
    }

so basically i just set the registers and send a high and low to the corresponding pin with a delay right?

So to send 0000001 i would send

Low
Delay
Low
Delay
Low
Delay
Low
Delay
Low
Delay
Low
Delay
Low
Delay
High
?

Like that?

or

High
Delay(small)

High
Delay(small)

High
Delay(small)

High
Delay(small)

High
Delay(small)

High
Delay(small)

High
Delay(small)

High
Delay(longer)
 
Actually no

I understand what it is for. Please look at the code first code that I posted in the other thread.

While it isn't for Sony or the more popular stuff. It is for my Panasonic HD TV. It will turn it on and off every time. The key here is that it uses PWM hardware to generate the 38khz signal.

The second example came first and is a working (at 4mhz) section of code that used to be in the first program.

With the PWM hardware, you tell it the length of the pulse and then in another place the duty cycle. In our case 50%. Then you turn it on and the hardware does it all.

:D
 
Not sure how it works tho....

Um can you comment some of it like um...
You said ... You tell it the length of the pulse and the duty cycle... Is the duty cycle what is sending the actual code?

How would i send 2 bytes? like

0x0D and then 0x00 ?
 
"The SIRC protocol uses a pulse width encoding of the bits. The pulse representing a logical "1" is a 1.2ms long burst of the 40kHz carrier, while the burst width for a logical "0" is 0.6ms long. All bursts are separated by a 0.6ms long space interval. The recommended carrier duty-cycle is 1/4 or 1/3."

so to send a 0x00 i have to send :
start (high) for 2.4ms
.6ms delay
"high' for .6ms
delay .6ms
"high' for .6ms

something like that?

Just setting that 1 pin high and low for periods of time?

Im confused because you use PORTA = 0xFF that sets all of PORTA bits. Even the ones not on the IR led.... right
 
The answers are in the other thread

Please look at Krumlink's thread. I have posted the code in pieces there.


Ok here is the whole thing for 18F1320

Code:
#include <system.h>

//Target PIC18F1320 configuration word

//#pragma DATA _CONFIG, _CP_OFF & _LVP_OFF & _BODEN_OFF & _MCLRE_ON & _PWRTE_ON & _WDT_OFF & _INTOSC_OSC_NOCLKOUT

#pragma DATA  _CONFIG1H, _INTIO2_OSC_1H & _FSCM_OFF_1H
#pragma DATA  _CONFIG2L, _PWRT_ON_2L & _BOR_OFF_2L & _BORV_27_2L
#pragma DATA  _CONFIG2H, _WDT_OFF_2H & _WDTPS_32K_2H
#pragma DATA  _CONFIG3H, _MCLRE_ON_3H
#pragma DATA  _CONFIG4L, _DEBUG_OFF_4L & _LVP_OFF_4L & _STVR_ON_4L

#pragma DATA  _CONFIG5L, _CP0_OFF_5L & _CP1_OFF_5L
#pragma DATA  _CONFIG5H, _CPB_OFF_5H & _CPD_OFF_5H
#pragma DATA  _CONFIG6L, _WRT0_OFF_6L & _WRT1_OFF_6L
#pragma DATA  _CONFIG6H, _WRTC_OFF_6H & _WRTB_OFF_6H & _WRTD_OFF_6H
#pragma DATA  _CONFIG7L, _EBTR0_OFF_7L & _EBTR1_OFF_7L
#pragma DATA  _CONFIG7H, _EBTRB_OFF_7H

//Set clock frequency
#pragma CLOCK_FREQ    8000000


// 38 khz

#define CCP1Period    12
#define    CCP1DutyCy    25



bit        running = 0;

unsigned char    turnon[6] = { 0x40, 4, 1, 0, 0xbc, 0xbd};

void interrupt( void )
{
    // Handle timer1 interrupt
    // Used to time the length of pulses
    if( pir1.TMR1IF )
    {
        running = 0;
        t1con.TMR1ON = 0;    // Turn TIMER1 off
        pir1.TMR1IF = 0; //clear timer 1 interrupt bit
    }
}

void xmit_pulse(short micro_pulse)
{
    static short    clock_count;
    clock_count = 65536 - micro_pulse;
    LOBYTE( tmr1l, clock_count);
    HIBYTE( tmr1h, clock_count);
    pir1.TMR1IF = 0;        // Reset overflow bit
    t1con.TMR1ON = 1;    // Turn TIMER1 on
    running = 1;

    trisb.3 = 0;
    t2con.TMR2ON = 1;
    while (running) ;        // Wait for pulse time to end    
    t2con.TMR2ON = 0;
    tmr2 = 0;
    portb.3 = 0;
    trisb.3 = 1;
}

void send_on(void) {
    static char    i;
    static char    j;
    static char    t;
    static unsigned char    *ovalue;
    static unsigned char    k;

//    Send it 3 times
    for (k = 0; k < 3; k++) {
        ovalue = &turnon;
        xmit_pulse(3550);    // 4 ms header
        delay_100us(10);    // 1 ms
        delay_10us(6);        // .6 ms
        for (i = 0; i < 6; i++) {
            for (j = 8; j > 0; j--) {
                t = j - 1;
                if (test_bit(*ovalue, t)) {
//                    A one
                    xmit_pulse(512);        // 400 micro s 
                    delay_100us(10);        // 1 ms
                    delay_10us(2);            // .2 ms
                }
                else {
//                    A zero
                    xmit_pulse(512);        // 400 micro s
                    delay_100us(3);            // 400 micro s
                }
            }
            ovalue++;
        }
//        End bit
        xmit_pulse(400);
        delay_ms(70);
    }
}
void main( void )
{
    static unsigned char    Low;
    static unsigned char    High;
    static unsigned int        Duty = CCP1DutyCy;
    // Set speed to 8 mhz
    set_bit(osccon, IRCF2);
    set_bit(osccon, IRCF1);
    set_bit(osccon, IRCF0);
    ccp1con = 0;        // CCP Module off
    tmr2 = 0;            // Clear Timer 2
    //Configure port B
    trisb = 0x00;
    trisb.3 = 1;
    intcon2.NOT_RBPU = 0;
    //Initialize port B
    portb = 0;

    //Set timer 1
    //prescaler rate 1:1
    //Internal clock (FOSC/4)
    t1con = 00001000b;

    // Configure Capture/Compare/PWM for PWM
    // at 38khz.  
    //Set timer 2 prescaler rate
    // T2CPS = 1:4
    t2con = 00000001b;
    //t2con = 0;
    pr2 = CCP1Period;
    Low = Duty & 3;
    High = Duty >> 2;
    ccpr1l = High;
    ccp1con = 00001100b;
    ccp1con.5 = Low.1;
    ccp1con.4 = Low.0;

    intcon.PEIE = 1;        // Enable peripheral interrupts
    intcon.GIE = 1;         // Enable global interrupt
    pie1.TMR1IE = 1;        // Enable Timer 1 interrupts

// test    
    trisb.3 = 0;
    t2con.TMR2ON = 1;
    while (1) ;
//  test

//    Main Loop
    send_on();
    while (1) {
    }
}
Configuring the PWM using TMR2

Code:
// 38 khz

#define CCP1Period    12
#define    CCP1DutyCy    25

    static unsigned char    Low;
    static unsigned char    High;
    static unsigned int        Duty = CCP1DutyCy;

    // Configure Capture/Compare/PWM for PWM
    // at 38khz.  
    //Set timer 2 prescaler rate
    // T2CPS = 1:4
    t2con = 00000001b;
    //t2con = 0;
    pr2 = CCP1Period;
    Low = Duty & 3;
    High = Duty >> 2;
    ccpr1l = High;
    ccp1con = 00001100b;
    ccp1con.5 = Low.1;
    ccp1con.4 = Low.0;
Turn it on

Code:
    trisb.3 = 0;
    t2con.TMR2ON = 1;
 
That seems like way too much code just to send a pulse....

And just telling me to look at the code doesnt really help... I thank you for trying to point me to the right direction but this doesnt answer my question.

which was:

HIGH(4ms) - would be start bit
LOW(1ms) - a space
HIGH(1ms) - a 0
LOW(1ms) - a space
HIGH(2ms) - a 1

would it be something like that to send a start then 0 and 1 bit?

Maybe its me or this code isnt commented well enough. Remember im a nooB still and well... this seems too much for something that seems so simple to achieve.
 
This code starts the PWM on Junebugs RB3, you can watch RB3 using MPLABS simulator / logic analyzer.
Code:
// 37.7kHZ PWM IR carrier signal
#include <p18f1320.h>
#pragma config WDT = OFF,OSC = INTIO2,LVP = OFF
void main(void) {    
    OSCCON=0x72; // speed up the clock to 8MHz
    ADCON1 = 0; 
    TRISBbits.TRISB3 = 0;
    PR2 = 0b00110100 ;
    T2CON = 0b00000100 ;
    CCPR1L = 0b00011010 ;
    CCP1CON = 0b00011100 ;
    while(1) {
     }    
}
An IR LED on RB3 with this running should pretty much jam any nearby IR receivers.
 

Attachments

  • PWMJunebug.png
    PWMJunebug.png
    7.5 KB · Views: 233
ok i can see how it starts it ...

To turn it off i do...
T2CON = 0b00000000 ;

i assume... But how do i send out the data still? :D still no straight answer..

To send data does it require me to set RB3 HIGH? If so :

When i set it high do i have to make a delay for the amount of time it has to be high to represent a logical 1, 0 and space. (also start)
 
I would set the duty to 0% for a zero; then to 50% for a 1. The 38KHz is a carrier (envelope) for the data, as long as the data timing is correct the IR decoder will strip away the carrier automatically and pass the raw data to the PIC.
http://www.sixca.com/eng/articles/remote/index.html
**broken link removed**

Also read this for the data format for Sony RC5
http://www.sbprojects.com/knowledge/ir/sirc.htm
**broken link removed**
Those black squares are actually a 38KHz square wave! (the carrier)
 
Last edited:
OK ok ok i think im getting it but still confusing just a little maybe lol

CCPR1L = 157 ;//Would this be high? or good enough :D
CCPR1L = 0; // I guess good enough for low

Now all i have to do is make a delay of 600uS and for a 2.4ms i can call it 4 times? while at 50% then drop to 0% and call the delay 1 time for a space..

Does that sound about right so far?
 
CCPR1L = 0b00011010 ; // this should set it to 50%

I've got to sleep but will look tomorrow, sounds like you've got the right idea.

If you have an older Sony TV or VCR they may have a SIRCs jack on the (1/8" stereo phone plug). You can send unmodulated TTL level RC5/SIRC (0-5V) data to that connector.

Search for SONY+ RC5 or SIRC
 
Last edited:
Thanks for the help so far bill (and everyone else also)..
This is what i have so far just as a text looks promising :D
Trying to send 0x0D or in BINARY 0001101 since the command code is only 7 bits long i assume you take out the first zero which would usually be bit 7.
Code:
// 37.7kHZ PWM IR carrier signal
#include <p18f1320.h>
#pragma config WDT = OFF,OSC = INTIO2,LVP = OFF

void MyDelay(int xD)
{
	int countA = xD ;
     	
	while (countA > 1)
   	{
		countA = countA - .1;
	}
}
void main(void) {    
	char dc ;
	char dc2 ;

    OSCCON=0x72; // speed up the clock to 8MHz
    ADCON1 = 0; 
    TRISBbits.TRISB3 = 0;
    PR2 = 0b00110100 ;
    T2CON = 0b00000100 ;
    CCPR1L = 0b00011010 ;
    CCP1CON = 0b00011100 ;
/*

CCP1CON = 0C ; // 0%
CCP1CON = 1C ; // 50%

*/
    while(1) {
		CCPR1L = 0x1A; // Start
		MyDelay(24);

		CCPR1L = 0x00; //Space
		CCP1CON = 0x0C ; // 0%
		MyDelay(6);

		CCPR1L = 0x1A; // 0
		CCP1CON = 0x1C ; // 50%
		MyDelay(6);

		CCPR1L = 0x00; //Space
		CCP1CON = 0x0C ; // 0%
		MyDelay(6);

		CCPR1L = 0x1A; // 0
		CCP1CON = 0x1C ; // 50%
		MyDelay(6);

		CCPR1L = 0x00; //Space
		CCP1CON = 0x0C ; // 0%		
		MyDelay(6);

		CCPR1L = 0x1A; // 0
		CCP1CON = 0x1C ; // 50%
		MyDelay(6);

		CCPR1L = 0x00; //Space
		CCP1CON = 0x0C ; // 0%
		MyDelay(6);

		CCPR1L = 0x1A; // 1
		CCP1CON = 0x1C ; // 50%
		MyDelay(12);

		CCPR1L = 0x00; //Space
		CCP1CON = 0x0C ; // 0%
		MyDelay(6);

		CCPR1L = 0x1A; // 1
		CCP1CON = 0x1C ; // 50%
		MyDelay(12);

		CCPR1L = 0x00; //Space
		CCP1CON = 0x0C ; // 0%
		MyDelay(6);

		CCPR1L = 0x1A; // 0
		CCP1CON = 0x1C ; // 50%
		MyDelay(6);

		CCPR1L = 0x00; //Space
		CCP1CON = 0x0C ; // 0%
		MyDelay(6);

		CCPR1L = 0x1A; // 1
		CCP1CON = 0x1C ; // 50%
		MyDelay(12)	;	
	
		CCPR1L = 0x00; //Space
		CCP1CON = 0x0C ; // 0%
		MyDelay(6);

		MyDelay(6);
     }    
}
 
Now i have .. .Any better? Looks ok might test it soon!

Code:
// 37.7kHZ PWM IR carrier signal
#include <p18f1320.h>
#include <delays.h>
#pragma config WDT = OFF,OSC = INTIO2,LVP = OFF

void Delay10TCYx(PARAM_SCLASS unsigned char);

/* Delay100TCYx
 * Delay multiples of 100 Tcy
 * Passing 0 (zero) results in a delay of 25,600 cycles.
 * The full range of [0,255] is supported.
 */
void Delay100TCYx(PARAM_SCLASS unsigned char);

/* Delay1KTCYx
 * Delay multiples of 1000 Tcy
 * Passing 0 (zero) results in a delay of 256,000 cycles.
 * The full range of [0,255] is supported.
 */
void Delay1KTCYx(PARAM_SCLASS unsigned char);

/* Delay10KTCYx
 * Delay multiples of 10,000 Tcy
 * Passing 0 (zero) results in a delay of 2,560,000 cycles.
 * The full range of [0,255] is supported.
 */
void Delay10KTCYx(PARAM_SCLASS unsigned char);

void main(void) {    
	char dc ;
	char dc2 ;

    OSCCON=0x72; // speed up the clock to 8MHz
    ADCON1 = 0; 
    TRISBbits.TRISB3 = 0;
    PR2 = 0b00110100 ;
    T2CON = 0b00000100 ;
    CCPR1L = 0b00011010 ;
    CCP1CON = 0b00011100 ;
/*

CCP1CON = 0C ; // 0%
CCP1CON = 1C ; // 50%

*/
    while(1) {
		CCPR1L = 0x1A; // Start
		Delay1KTCYx(2);
		Delay100TCYx(4);

		CCPR1L = 0x00; //Space
		CCP1CON = 0x0C ; // 0%
		Delay100TCYx(6);

		CCPR1L = 0x1A; // 0
		CCP1CON = 0x1C ; // 50%
		Delay100TCYx(6);

		CCPR1L = 0x00; //Space
		CCP1CON = 0x0C ; // 0%
		Delay100TCYx(6);

		CCPR1L = 0x1A; // 0
		CCP1CON = 0x1C ; // 50%
		Delay100TCYx(6);

		CCPR1L = 0x00; //Space
		CCP1CON = 0x0C ; // 0%		
		Delay100TCYx(6);

		CCPR1L = 0x1A; // 0
		CCP1CON = 0x1C ; // 50%
		Delay100TCYx(6);

		CCPR1L = 0x00; //Space
		CCP1CON = 0x0C ; // 0%
		Delay100TCYx(6);

		CCPR1L = 0x1A; // 1
		CCP1CON = 0x1C ; // 50%
		Delay1KTCYx(1);
		Delay100TCYx(2);

		CCPR1L = 0x00; //Space
		CCP1CON = 0x0C ; // 0%
		Delay100TCYx(6);

		CCPR1L = 0x1A; // 1
		CCP1CON = 0x1C ; // 50%
		Delay1KTCYx(1);
		Delay100TCYx(2);

		CCPR1L = 0x00; //Space
		CCP1CON = 0x0C ; // 0%
		Delay100TCYx(6);

		CCPR1L = 0x1A; // 0
		CCP1CON = 0x1C ; // 50%
		Delay100TCYx(6);

		CCPR1L = 0x00; //Space
		CCP1CON = 0x0C ; // 0%
		Delay100TCYx(6);

		CCPR1L = 0x1A; // 1
		CCP1CON = 0x1C ; // 50%
		Delay1KTCYx(1);
		Delay100TCYx(2);
	
		CCPR1L = 0x00; //Space
		CCP1CON = 0x0C ; // 0%
		Delay100TCYx(6);
     }    
}
 
Trying
I know my Address is 0x0D and my command is 0x00 for sending a 1. But nothing happens with below code....
Code:
// 37.7kHZ PWM IR carrier signal
#include <p18f1320.h>
#include <delays.h>
#pragma config WDT = OFF,OSC = INTIO2,LVP = OFF

void Delay10TCYx(PARAM_SCLASS unsigned char);

/* Delay100TCYx
 * Delay multiples of 100 Tcy
 * Passing 0 (zero) results in a delay of 25,600 cycles.
 * The full range of [0,255] is supported.
 */
void Delay100TCYx(PARAM_SCLASS unsigned char);

/* Delay1KTCYx
 * Delay multiples of 1000 Tcy
 * Passing 0 (zero) results in a delay of 256,000 cycles.
 * The full range of [0,255] is supported.
 */
void Delay1KTCYx(PARAM_SCLASS unsigned char);

/* Delay10KTCYx
 * Delay multiples of 10,000 Tcy
 * Passing 0 (zero) results in a delay of 2,560,000 cycles.
 * The full range of [0,255] is supported.
 */
void Delay10KTCYx(PARAM_SCLASS unsigned char);

void main(void) {    
	char dc ;
	char dc2 ;

    OSCCON=0x72; // speed up the clock to 8MHz
    ADCON1 = 0; 
    TRISBbits.TRISB3 = 0;
    PR2 = 0b00110100 ;
    T2CON = 0b00000100 ;
    CCPR1L = 0b00011010 ;
    CCP1CON = 0b00011100 ;

    while(1) {
		CCPR1L = 0x1A; // Start
		CCP1CON = 0x1C ; // 50%
		Delay1KTCYx(4);
		Delay100TCYx(8);

		CCPR1L = 0x00; //Space
		CCP1CON = 0x0C ; // 0%
		Delay1KTCYx(1);
		Delay100TCYx(2);

		CCPR1L = 0x1A; // 0
		CCP1CON = 0x1C ; // 50%
		Delay1KTCYx(1);
		Delay100TCYx(2);

		CCPR1L = 0x00; //Space
		CCP1CON = 0x0C ; // 0%
		Delay1KTCYx(1);
		Delay100TCYx(2);

		CCPR1L = 0x1A; // 0
		CCP1CON = 0x1C ; // 50%
		Delay1KTCYx(1);
		Delay100TCYx(2);

		CCPR1L = 0x00; //Space
		CCP1CON = 0x0C ; // 0%
		Delay1KTCYx(1);
		Delay100TCYx(2);

		CCPR1L = 0x1A; // 0
		CCP1CON = 0x1C ; // 50%
		Delay1KTCYx(1);
		Delay100TCYx(2);

		CCPR1L = 0x00; //Space
		CCP1CON = 0x0C ; // 0%
		Delay1KTCYx(1);
		Delay100TCYx(2);

		CCPR1L = 0x1A; // 0
		CCP1CON = 0x1C ; // 50%
		Delay1KTCYx(1);
		Delay100TCYx(2);

		CCPR1L = 0x00; //Space
		CCP1CON = 0x0C ; // 0%
		Delay1KTCYx(1);
		Delay100TCYx(2);

		CCPR1L = 0x1A; // 0
		CCP1CON = 0x1C ; // 50%
		Delay1KTCYx(1);
		Delay100TCYx(2);


		CCPR1L = 0x00; //Space
		CCP1CON = 0x0C ; // 0%
		Delay1KTCYx(1);
		Delay100TCYx(2);

		CCPR1L = 0x1A; // 0
		CCP1CON = 0x1C ; // 50%
		Delay1KTCYx(1);
		Delay100TCYx(2);


		CCPR1L = 0x00; //Space
		CCP1CON = 0x0C ; // 0%
		Delay1KTCYx(1);
		Delay100TCYx(2);

		CCPR1L = 0x1A; // 0
		CCP1CON = 0x1C ; // 50%
		Delay1KTCYx(1);
		Delay100TCYx(2);

		CCPR1L = 0x00; //Space
		CCP1CON = 0x0C ; // 0%
		Delay1KTCYx(1);
		Delay100TCYx(2);

		CCPR1L = 0x1A; // 1
		CCP1CON = 0x1C ; // 50%
		Delay1KTCYx(2);
		Delay100TCYx(4);

		CCPR1L = 0x00; //Space
		CCP1CON = 0x0C ; // 0%
		Delay1KTCYx(1);
		Delay100TCYx(2);

		CCPR1L = 0x1A; // 0
		CCP1CON = 0x1C ; // 50%
		Delay1KTCYx(1);
		Delay100TCYx(2);

		CCPR1L = 0x00; //Space
		CCP1CON = 0x0C ; // 0%
		Delay1KTCYx(1);
		Delay100TCYx(2);

		CCPR1L = 0x1A; // 1
		CCP1CON = 0x1C ; // 50%
		Delay1KTCYx(2);
		Delay100TCYx(4);

		CCPR1L = 0x00; //Space
		CCP1CON = 0x0C ; // 0%
		Delay1KTCYx(1);
		Delay100TCYx(2);

		CCPR1L = 0x1A; // 1
		CCP1CON = 0x1C ; // 50%
		Delay1KTCYx(2);
		Delay100TCYx(4);

		CCPR1L = 0x00; //Space
		CCP1CON = 0x0C ; // 0%
		Delay1KTCYx(1);
		Delay100TCYx(2);

		CCPR1L = 0x1A; // 0
		CCP1CON = 0x1C ; // 50%
		Delay1KTCYx(1);
		Delay100TCYx(2);


		CCPR1L = 0x00; //Space
		CCP1CON = 0x0C ; // 0%
		Delay1KTCYx(1);
		Delay100TCYx(2);

		Delay100TCYx(6);
     }    
}
 
Status
Not open for further replies.

Latest threads

Back
Top