How to create PWM feature using normal pin

Thread Starter

dave3344

Joined Nov 19, 2014
4
I wanted to control the speed of my fan without using PWM configuration
My lecturer say it can be done by set the time of turning on and off the fan using L293D
so I do this program code but it doesn't seem worked, so anyone can provide some help??
By the way I am new in programing microcontroller
Sorry for my broken English

Code:
list p=16f877a
include "p16f877a.inc"
__CONFIG _LVP_OFF & _WDT_OFF & _HS_OSC & _PWRTE_ON & _BODEN_OFF

count1         equ          20h
count2         equ         21h
count3         equ         22h
count0         equ         23h
temp            equ         24h

            org               0x0000
            banksel        TRISB
            clrf               TRISB
            banksel        TRISC
            clrf               TRISC
            banksel        TRISD
            clrf               TRISD
            banksel        TRISA
            bsf                TRISA,0
        
            banksel        PORTB
            clrf              PORTB
            banksel        ADCON1
            movlw        b'01001110'
            movwf        ADCON1
            banksel        ADCON0
            movlw        b'10000001'
            movwf        ADCON0

acqtime:    call         delay50u
                   bsf            ADCON0,GO_DONE

main:        btfsc        ADCON0,GO_DONE
            goto        $-1
            movf        ADRESH,W
            movwf        temp
            call        delayqsec
            call         check
            goto        acqtime

check:        movlw        d'20'
            subwf        temp,0
            btfss        STATUS,0
            goto        temp0

            movlw        d'25'
            subwf        temp,0
            btfss        STATUS,0
            goto        temp40

            movlw        d'30'
            subwf        temp,0
            btfss        STATUS,0
            goto        temp50
            goto        temp60
            return
        
temp0:    
            banksel        PORTB
            clrf        PORTB
            banksel        PORTC
            bcf            PORTC,2
            banksel        PORTD
            bcf            PORTD,0
            bcf            PORTD,1
            return

temp40:        movlw        b'00000010'
            banksel        PORTB
            movwf        PORTB
            banksel        PORTD
            bsf            PORTD,0
            bcf            PORTD,1
            banksel        PORTC
            bsf            PORTC,2
            call         delay60u
            bcf            PORTC,2
            call        delay140u
            return

temp50:        movlw        b'00000100'
            banksel        PORTB
            movwf        PORTB
            banksel        PORTD
            bsf            PORTD,0
            bcf            PORTD,1
            banksel        PORTC
            bsf            PORTC,2
            call        delay120u
            bcf            PORTC,2
            call        delay80u
            return

temp60:        movlw        b'00010000'
            banksel        PORTB
            movwf        PORTB
            banksel        PORTD
            bsf            PORTD,0
            bcf            PORTD,1
            banksel        PORTC
            bsf            PORTC,2
            return

delay60u:    movlw        d'3'
            movwf        count2
            movlw        d'35'
            movwf        count3
            decfsz        count3,f
            goto        $-1
            decfsz        count2,f
            goto        $-5
            return

delay140u:    movlw        d'3'
            movwf        count2
            movlw        d'78'
            movwf        count3
            decfsz        count3,f
            goto        $-1
            decfsz        count2,f
            goto        $-5
            return

delay120u:  movlw        d'3'
            movwf        count2
            movlw        d'67'
            movwf        count3
            decfsz        count3,f
            goto        $-1
            decfsz        count2,f
            goto        $-5
            return

delay80u:   movlw        d'3'
            movwf        count2
            movlw        d'45'
            movwf        count3
            decfsz        count3,f
            goto        $-1
            decfsz        count2,f
            goto        $-5
            return

delayqsec:  movlw        d'7'
            movwf        count1
            movlw        d'255'
            movwf        count2
            movlw        d'255'
            movwf        count3
            decfsz        count3,f
            goto        $-1
            decfsz        count2,f
            goto        $-5
            decfsz        count1,f
            goto        $-9
            return

delay50u:    movlw        d'83'
            movwf        count0
            decfsz        count0,f
            goto        $-1
            return
    
            end
If u guys cannot understand any parts of my program, feel free to ask me :D
 
Last edited:

tshuck

Joined Oct 18, 2012
3,534
Yes, and the PWM he described does not need a hardware-implemented PWM signal. Simply time the toggling of a digital I/O pin according to the desired waveform and duty cycle.
 

Markd77

Joined Sep 7, 2009
2,806
A couple of things I spotted:
You have "goto temp0" but at the end of temp0 is "return", this will lead to stack underflow and unexpected results.
Delayqsec looks like it will take a lot longer than delay50u, etc so the PWM duty cycle would be very small, it might not turn the fan
Double check the banks, I like to step through the code in the simulator and check the right registers are changing.
 

spinnaker

Joined Oct 29, 2009
7,830
PWM is nothing more than keeping a pin on for a period of time and off for a period of time.

A lot easier to do in C IMHO but to each his own but the technique is the same C or assembler.

Start small. Write a program that does nothing but turn a pin on.

Write one that does nothing but turn a pin off.

Next write a program that does a loop and turns the pin off and on. That alone will give you a 50% duty cycle.

You should be able to step through the code and watch the pin go off and on or if you have a scope you can see it there too.

Finally add in your delays. One before turning the pin on and one before turning it off.
 

shteii01

Joined Feb 19, 2010
4,644
Choose a pin, turn it On, turn it Off. Now you have PWM.
Keep it On long time, you have long duty cycle.
Keep it On short time, you have short duty cycle.
Any pin that can be configured for output will work.

So yes, you don't need a specific PWM feature. Any output pin will do the job.
 
Top