十年專注單片機方案開發的方案公司英銳恩,分享PIC單片機實現帶反饋控制的PWM信號發生器源碼。英銳恩現提供服務產品涉及主控芯片:8位單片機、16位單片機、32位單片機及各類運算放大器等。
這個實現了一個帶反饋控制的PWM發生器。PWM信號的占空比由電位器決定,電位器上的電壓被采樣后,與PWM信號經過低通濾波的電壓比較,根據比較的結果調整占空比,從而實現用電位器控制占空比。
LIST p=PIC16F877A,r=hex ;microcontroller & base
INCLUDE "P16F877A.inc" ;register memory mapping file
;************************
; global variables
;************************
i equ 0x21 ;general purpose counter 1
j equ 0x22 ;general purpose counter 2
pot_ana_value equ 0x23 ;Analog value of the potentiometer
pwm_ana_value equ 0x24 ;Analog value of the PWM output after low filtering
#define timer_trigger 0x25, 0 ;This bit indicating the timer has been triggered
w_temp equ 0x26 ; temp variable for W register
status_temp equ 0x27 ; status variable for STATUS register
temp equ 0x28 ; general temp
variable;************************
; port definitions
;************************
#define led_data PORTD ;portD outputs 7-segment data
#define led_pot_high PORTB, 0 ;portB.0 selects high 4-bit value of pot
#define led_pot_low PORTB, 1 ;portB.1 selects low 4-bit value of pot
#define led_pwm_high PORTB, 2 ;portB.2 selects high 4-bit value of pwm
#define led_pwm_low PORTB, 3 ;portB.3 selects low 4-bit value of pwm
#define led_inc PORTB, 4 ;portB.4 drive the LED indicating PWM
;duty cycle increasing.
#define led_dec PORTB, 5 ;portB.5 drive the LED indicating PWM
;duty cycle decreasing.
;************************
; reload value of TMR0
; Timer 0 Interval = 5000 us
; 64 * ( 256 - TMR0 ) = 5000, TMR0 = 178 (0xB2);************************
tmr0_reload equ 0xB2
;************************
; 7-segment LED definitions
; a
; +----------+
; | |
; f| |b
; | g |
; +----------+
; | |
; e| |c
; | |
; +----------+ o dp
; d
;************************
LED_SEGa equ 0x40 ;7-segment display segment A
LED_SEGb equ 0x20 ;7-segment display segment B
LED_SEGc equ 0x10 ;7-segment display segment C
LED_SEGd equ 0x08 ;7-segment display segment D
LED_SEGe equ 0x04 ;7-segment display segment ELED_SEGf equ 0x02 ;7-segment display segment F
LED_SEGg equ 0x01 ;7-segment display segment G
LED_SEGdp equ 0x80 ;not used
LED_BLANK equ 0x00
;****************************************************************
;reset vector
;****************************************************************
ResetVec:
org 0x0000 ;reset vector address
goto Start ;start program execution
org 0x0004
Tmr0IntServ: ; Timer 0 interrupt service routing
movwf w_temp ; save W register
swapf STATUS, W clrf STATUS
movwf status_temp ; save STATUS register
bcf INTCON, T0IF ; clear Timer 0 interrupt flag
bsf timer_trigger
movlw tmr0_reload ; reload timer 0
movwf TMR0
swapf status_temp, W
movwf STATUS ; restore STATUS register
swapf w_temp, F
swapf w_temp, W ; restore W register
retfie
Start: org 0x0100 ;start of program
goto SysInit
;****************************************************************
; LED DISPLAY DECODER FROM BINARY TO 7-SEGMENT
; the hex value to be displayed is stored in W before calling this
; function. The function will return the output value of LED in W
;****************************************************************
LEDDecoder:
addwf PCL,f ;W DISPLAY
retlw LED_SEGa|LED_SEGb|LED_SEGc|LED_SEGd|LED_SEGe|LED_SEGf ;0 - "0"
retlw LED_SEGb|LED_SEGc ;1 - "1"
retlw LED_SEGa|LED_SEGb|LED_SEGd|LED_SEGe|LED_SEGg ;2 - "2"
retlw LED_SEGa|LED_SEGb|LED_SEGc|LED_SEGd|LED_SEGg ;3 - "3"
retlw LED_SEGb|LED_SEGc|LED_SEGf|LED_SEGg ;4 - "4"
retlw LED_SEGa|LED_SEGc|LED_SEGd|LED_SEGf|LED_SEGg ;5 - "5"
retlw LED_SEGa|LED_SEGc|LED_SEGd|LED_SEGe|LED_SEGf|LED_SEGg ;6 - "6"
retlw LED_SEGa|LED_SEGb|LED_SEGc ;7 - "7"
retlw LED_SEGa|LED_SEGb|LED_SEGc|LED_SEGd|LED_SEGe|LED_SEGf|LED_SEGg ;8 - "8"
retlw LED_SEGa|LED_SEGb|LED_SEGc|LED_SEGd|LED_SEGf|LED_SEGg ;9 - "9"
retlw LED_SEGa|LED_SEGb|LED_SEGc|LED_SEGe|LED_SEGf|LED_SEGg ;0xA - "A"
retlw LED_SEGc|LED_SEGd|LED_SEGe|LED_SEGf ;0xB - "b"
retlw LED_SEGa|LED_SEGd|LED_SEGe|LED_SEGf ;0xC - "C"
retlw LED_SEGb|LED_SEGc|LED_SEGd|LED_SEGe|LED_SEGg ;0xD - "d"
retlw LED_SEGa|LED_SEGd|LED_SEGe|LED_SEGf|LED_SEGg ;0xE - "E"
retlw LED_SEGa|LED_SEGe|LED_SEGf|LED_SEGg ;0xF - "F"
retlw LED_BLANK ;0x10- " "
;****************************************************************
; System initialization
;****************************************************************
SysInit:
bcf STATUS, RP1
bsf STATUS, RP0
clrf TRISB ;portB output
clrf TRISC ;portC output
clrf TRISD ;portD output
movlw 0xff
movwf TRISA ;portA input
bcf STATUS, RP0 ;set initial value of the I/O ports
clrf PORTB
clrf PORTD
clrf PORTC bcf timer_trigger
; Timer 0 config
movlw tmr0_reload ; timer 0 initial value
movwf TMR0
bsf STATUS, RP0
movlw 0x05 ; timer 0 freq div = 64, use internal clock
movwf OPTION_REG
; PWM config
movlw 0xff ; PWM cycle = 256us
movwf PR2
bcf STATUS, RP0
movlw 0x80 ; CCP1RL initial value, 50% duty cycle
movwf CCPR1L
movlw 0x0C ; PWM mode for CCP1
movwf CCP1CON
movlw 0x04 ; T2 control: 1:1 freq div, enable T2
movwf T2CON
; ADC config
bsf STATUS, RP0
clrf ADCON1 ; left alignment, 8 analog channel
bcf STATUS, RP0
movlw 0x81 ; Focs/32 A/D clock freq,
enable ADC
movwf ADCON0
; Interrupt config
movlw 0xA0
movwf INTCON ; enable Timer 0 interrupt
;****************************************************************
; The main loop of the program
;****************************************************************
Mainloop: btfsc timer_trigger
call AdjustPWM
call ScanLED
goto Mainloop ;endless loop
;****************************************************************
; Adjust PWM duty cycle
;****************************************************************
AdjustPWM:
bcf timer_trigger
call UpdateAnalogValue
movf pot_ana_value, W
subwf pwm_ana_value, W
btfss STATUS, Z
goto need_adjustment
no_adjustment:
bcf led_inc ; equal, no adjustment needed
bcf led_dec ; turn-off the LEDs
returnneed_adjustment:
btfss STATUS, C
goto need_decreament
movlw 0xff ; need increament
subwf CCPR1L, W
btfsc STATUS, Z
goto no_adjustment ; if CCPR1L = 0xff, can't increase any more
bsf led_inc
bcf led_dec
incf CCPR1L, F
return
need_decreament
movlw 0x00
subwf CCPR1L, W
btfsc STATUS, Z
goto no_adjustment ; if CCPR1L = 0x00, can't decrease any more
bsf led_dec
bcf led_inc
decf CCPR1L, F
return;****************************************************************
; SCAN the 7-Segment LEDs
;****************************************************************
ScanLED:
movf pot_ana_value, W
andlw 0x0f ; low 4-bit
call LEDDecoder
movwf led_data ; output value
bsf led_pot_low
movlw 0x32
call Delayx10us ; delay 500us
bcf led_pot_low
swapf pot_ana_value, W ; high 4-bit pot analog value
andlw 0x0f
call LEDDecoder movwf led_data
bsf led_pot_high
movlw 0x32
call Delayx10us
bcf led_pot_high
movf pwm_ana_value, W ; low 4-bit pwm analog value
andlw 0x0f
call LEDDecoder
movwf led_data
bsf led_pwm_low
movlw 0x32
call Delayx10us
bcf led_pwm_low
swapf pwm_ana_value, W ; high 4-bit pwm analog value
andlw 0x0f
call LEDDecoder
movwf led_data
bsf led_pwm_high
movlw 0x32
call Delayx10us
bcf led_pwm_high
return
;****************************************************************
UpdateAnalogValue:
bcf ADCON0, CHS0 ; select RA0 for analog input, POT value
movlw 0x03
call Delayx10us ; delay for 30us
bsf ADCON0, GO_DONE
UAV_loop1:
btfsc ADCON0, GO_DONE ; wait for A/D conversion
goto UAV_loop1 movf ADRESH, W
movwf pot_ana_value ; update value
movlw 0x03 ; delay 30us for next conversion
call Delayx10us
bsf ADCON0, CHS0 ; select RA1 for analog input, PWM value
movlw 0x03
call Delayx10us ; delay for 30us
bsf ADCON0, GO_DONE
UAV_loop2:
btfsc ADCON0, GO_DONE ; wait for A/D conversion
goto UAV_loop2
movf ADRESH, W
movwf pwm_ana_value ; update value
return
END
(文源網絡,侵刪)