I recently acquired a nice Synrad CO2 laser for my laser cutter project. This laser has its power controlled by an opto-isolated PWM input. Synrad recommends a carrier frequency of 5 kHz. In addition they have a minimum duty cycle requirement, which they claim will possibly damage the laser if violated. The minimum duty cycle is 0.5%, which means 1.0 µs pulses at 5 kHz. They call these pulses 'Tickle Pulses'.
I needed a way to generate these pulses, as my laser did not come with the appropriate Synrad controller. I decided to program a PIC micro to perform this task, and like the Synrad controller allow me to set the power level with a potentiometer. I used a pic18f1220 for the task. This is my favorite microcontroller, and I've used it in many projects. I didn't need super high accuracy, so I opted to use the internal 8 MHz oscillator and no crystal.
First, to set the PWM frequency. I used timer 2 as the PWM clock. When using the 8MHz internal clock in the PIC, the basic instruction clock is 2 MHz. I set timer 2 to use that as it's clock source, with a /4 prescaler to give 500 kHz. Then I set the timer 2 period register to 99, meaning divide by 100, to get 5 kHz. So timer 2 repeatedly countes from 0 thru 99, resetting itself every 200 µs. The PWM works by comparing this timer to another register (CCPR1L, CCP1CON). It turns the PWM output on when timer 2 resets, and turns if off when timer 2 equals the CCPR1L value. Since timer 2 never exceeds a count of 99, setting the PWM duty cycle to any value greater than 99 will cause 100% duty cycle.
Now, the a/d convertor has 10 bits of resolution, giving values from 0 thru 1023. Since I need 0..99, I throw away the lo 3 bits of the a/d convertor value. This gives me a range of 0..127. To get full use of my potentiometer, I put a resistor in series with it so that when set to full scale, I get an a/d value of about 99. Then I added some math so that whatever the a/d value is, the PWM duty cycle will never provide pulses less than 1 µs.
Next, I added a pushbutton, connected to RA5. RA5 is normally the reset input, so I disabled the reset input and used the internal reset circuit instead. I also connected an LED to RA2. I setup the code for the LED so it blinks at a few Hz to indicate that tickle pulses are being generated. If I press the 'fire' button, the code uses the value from the potentiometer to set the PWM duty cycle, and the LED turns on continuously.
This works well. When the button is not pressed, the 'lase' indicator on the back of the laser lights up dimly, and there's no output from the laser. When I press the button, the 'lase' indicator lights up with brightness proportional to the duty cycle. When the duty cycle gets above a certain threshold, the laser action begins and you can hear a 5 kHz tone coming from it. The laser has an auxiliary DC output, so I used that to power the TPG. So as soon as the laser receives power, it also starts getting tickle pulses on its PWM input. The power supply has an enable input, so I can use that to switch power to both the laser and the TPG.
Ultimately, I'll use EMC to control this laser, and will connect a signal from it to the signal on RA5 so that the EMC G-Code can turn the laser on and off. Note that while this is intended for use with a Synrad laser, it should work fine with any of the Chinese disposable CO2 tubes that have a PWM input on their power supply. Here's the PIC source code for those interested:
;
; tickle.asm
;
; Generate tickle pulses for Synrad laser
;
list st=on ;dump the symbol table
list n=9999 ;lines per page
radix dec
processor 18f1220
#include <P18F1220.INC>
#include utility.inc
;noexpand
list
__CONFIG _CONFIG1H, _IESO_ON_1H & _FSCM_OFF_1H & _INTIO1_OSC_1H
__CONFIG _CONFIG2L, _PWRT_ON_2L & _BOR_OFF_2L
__CONFIG _CONFIG2H, _WDT_OFF_2H & _WDTPS_32K_2H
__CONFIG _CONFIG3H, _MCLRE_OFF_3H
__CONFIG _CONFIG4L, _DEBUG_OFF_4L & _LVP_OFF_4L & _STVR_OFF_4L
__CONFIG _CONFIG5L, _CP0_OFF_5L & _CP1_OFF_5L
__CONFIG _CONFIG5H, _CPB_OFF_5H & _CPD_OFF_5H
__CONFIG _CONFIG6L, _WRT0_OFF_6L & _WRT1_OFF_6L
__CONFIG _CONFIG6H, _WRTC_OFF_6H & _WRTB_OFF_6H & _WRTD_OFF_6H
__CONFIG _CONFIG7L, _EBTR0_OFF_7L & _EBTR1_OFF_7L
__CONFIG _CONFIG7H, _EBTRB_OFF_7H
;
; Declare RAM locations
;
udata 0
duty_lo res 1 ;PWM Duty cycle ls bits
duty_hi res 1 ;PWM duty cycle ms bits
a_d_lo res 1 ;A/D convertor ls bits
a_d_hi res 1 ;A/D convertor ms bits
blink res 1
duty_min_lo equ 0x80
duty_min_hi equ 0x00
;
; Reset and interrupt vectors
;
org 0 ; Reset vector: 8 bytes
goto main
main movlb 0 ;initialize bank select reg
rcall init
clrf LATA
idle
btfss INTCON, TMR0IF ;Timer expired?
bra idle_10 ;Branch if not
bcf INTCON, TMR0IF ;Reset the flag
incf blink,f
idle_10
btfss PORTA, RA5 ;Is the button pressed?
bra fire ;Branch if so
movlwf duty_min_lo, duty_lo
movlwf duty_min_hi, duty_hi
rcall set_pwm_duty ;Set minimum duty cycle for tickle pulse
btfsc blink,0 ;Should LED be on ?
bra idle_20 ;Branch if so
bcf LATA, RA2 ;Else turn LED off
bra idle
idle_20
bsf LATA, RA2 ;Turn the LED on
bra idle
;;
;; The fire button is pressed. If the a/d conversion is done, read the value
;; and set the pwm duty cycle. Otherwise, use the most recent a/d value.
;; Then force the LED on.
;;
fire
btfsc ADCON0, GO_DONE ;Is A/D conversion complete?
bra a_d_busy ;Branch if not
a_d_done
movff ADRESL, a_d_lo
movff ADRESH, a_d_hi
bsf ADCON0, GO_DONE ;Start another conversion
movfw a_d_lo
rrcf a_d_hi,f ;Divide by 2
rrcf WREG,w
andlw 0xc0
movwf a_d_lo
tstfsz a_d_hi
bra a_d_busy
btfsc a_d_lo, 7
bra a_d_busy
movlwf 0x80, a_d_lo ;Clamp value at 1 usec
a_d_busy
movff a_d_lo, duty_lo
movff a_d_hi, duty_hi
rcall set_pwm_duty
bsf LATA, RA2 ;Force the LED on
bra idle
init
;;
;; Initialize clock frequency
;;
movlwf 0x72, OSCCON ;Internal 8 Mhz clock
;
; Initialize Port pins as inputs or outputs
;
movlwf 0x21, TRISA ;RA0 is analog input. RA5 is pushbutton in.
clrf PORTA
movlwf 0x0, TRISB ;Set port B direction bits as described
clrf PORTB
;
; initialize A/D convertor
;
movlwf 0x7e, ADCON1 ;Make only channel 0 an Analog input
movlwf 0x3e, ADCON2 ;Setup A/D timing, and left justify.
movlwf 0x01, ADCON0 ;Turn A/D convertor on
bsf ADCON0, 1 ;Start conversion
;
; Initialize Timer 2 for PWM
;
movlwf 99, PR2 ;Setup PWM period for 5 kHz
movlwf 0x05, T2CON ;Timer 2 on, /4 Prescaler
call set_pwm_duty
;
; Initialize Timer 0 for LED blink
;
movlwf 0xc7, T0CON ;Divide instruction clock by 256
return
set_pwm_duty
movff duty_hi, CCPR1L ;Set ms 8 bits of duty cycle
rrncf duty_lo, w,1
rrncf WREG, w
andlw 0x30
iorlw 0x0c
movwf CCP1CON ;Write PWM mode and 2 ls bits
return
end