I wrote this code for the PIC16F84 to control the CNC (red) laser output power with a PWM.
The idea was to burn with different levels of output power to obtain a picture with some levels of shading as in this website.
I abandoned the PWM project when the laser diode get burned, and started testing with a blue laser diode (no PWM just Switch ON/OFF).
Bellow are the diagram, schematic and code.
Please notice that the schematic needs some changes in the way the laser diode must be controlled!
This material can be used for free, but for your own risk!
PWM diagram
In this diagram a feedback must be taken from laser output current or Z-axis position to the microcontroller, because after few seconds of printing, the counter is not synchronized with the Z-axis position.
PWM picture
A picture to show different parts used as in the diagram.
The parts can be found in a old DVD reader and printers.
PWM schematic
This schematic must be modified! I dont have time to make the necessary changes now, but maybe some day I will update it.
I share this information only to help other people, so they can avoid the same mistakes.

Here are different blocks of control for the red laser marked with a green circles.

With the red colors I pointed the problem why the laser get burned. The Cathode of the laser diode must be always connected to the GND to avoid damaging the diode by electrostatic discharge (ESD).

In my case, when no current present through the IRF740 transistor, a 5V is present in the LM317 output (the LM317 is a current source here not a voltage regulator!). So, when the transistor is driving, a short time the diode is under 5V, with a repetitive ON/OFF the diode will be burned.

The transistor must cut the current from 5V coming to LM317 is a better option but I didnt test it yet.

PWM low-pass filter
Using an oscilloscope, this is the output voltage obtained after a low-pass filter.
The sensors and dark/light pattern
Printers uses this films to follow the X-axis position, I used this with only one sensor not the 90 degree option.
To detect the direction, I used the Z-axis direction coming from the motor driver.
PWM asm code for the PIC16F84
;*******************************************************************************************************************************************
; Pulse Width Modulation PIC16F84
; Karim Lakra
; 12.07.14
; PWM to control the laser power for DIY CNC
; PortB4 Pulse, B5 direction.
; detect the falling edge.
; Output PortA0.
; range from 5 to 255 step
;*******************************************************************************************************************************************
LIST P=16F84, R=DEC
__FUSES _XT_OSC & _WDT_OFF & _CP_OFF & _PWRTE_ON
include "P16F84.inc"
;*******************************************************Set up the Constants***********************************************************
STATUS
equ
03h
;Address of the STATUS register
TRISA
equ
85h
;Address of the tristate register for port A
PORTA
equ
05h
;Address of Port A
TRISB
equ
86h
;Address of the tristate register for port B
PORTB
equ
06h
;Address of Port B
COUNT1
equ
08h
;First counter for delay loops
COUNT2
equ
09h
;Second counter for delay loops
MAX
equ
255
;max value for the counter
;************************************************************Set up the port**************************************************************
bsf
STATUS,5
;Switch to Bank 1
movlw
00h
;Set the Port A pins
movwf
TRISA
;to outputs.
bcf
STATUS,5
;Switch back to Bank 0
clrf
1eh
;clear the counter
movlw
01h
;load w with 1
addwf
1eh,1
;set the counter at 1
clrf
1fh
;clear the counter holder (used as a count-down counter)
;*****************************************************************ORG********************************************************************
Start
btfss
PORTB,4
;test bit PortB4 (+/- frequency) if set to 1 skip next line
Call
DIRI
;if the pin B4=0 (pulse) check wich direction(0=- or 1=+)
Call
Toogle
;toogle the output A0
Call
Delay
;add a timer, which is the number of press saved in 1eh counter
Goto
Start
;**************************************************************Test input*****************************************************************
DIRI
btfsc
PORTB,5
;test bit PortB5 (direction pin) if 0 skip next line
Call
INC
;increment if (B5=1) goto INC
btfss
PORTB,5
;test bit PortB5 (direction pin) if 1 skip next line
Call
DEC
;decrement if (B5=0) goto DEC
goto
Wait
return
;***************************************************************Increase******************************************************************
INC
movlw
MAX
; the max for the the counter(lowest duty cycle)
subwf
1eh,w
; sub from 255
btfsc
STATUS,C
; if negative means the counter go from 255 to 0, so return without sub
return
movlw
01h
;increment the
addwf
1eh,1
;counter by 5 adding w to 1eh and(,1)--> store the result to 1eh
return
;*************************************************************Decrease******************************************************************
DEC
movlw
01h
;w=5
subwf
1eh,w
; sub w (zero) from counter
btfsc
STATUS,Z
; if the z is set to 1, the 1eh is equal to zero so return without dec 1eh
return
movlw
01h
;increment the
subwf
1eh,1
;decrement the counter by 5
return
;*****************************************************************Wait********************************************************************
Wait
btfss
PORTB,4
;stay here if the pulse is still =0
Goto
Wait
return
;****************************************************************Toogle*******************************************************************
Toogle
xorwf
PORTA,1
;toogle the output
return
;*****************************************************************Delay*******************************************************************
Delay
movf
1eh,w
; copy the value of the counter into w
Movwf
1fh
; paste w into the counter holder
Loop1
movlw
00h
; put zero to w
subwf
1fh,w
; sub w (zero) from counter holder
btfsc
STATUS,Z
; if the z is set to one, the 1fh is equal to zero so return without dec 1fh
return
decfsz
1fh,1
;decrement 1fh counter by 1 and return, if =0 jump to return
goto
Loop1
return
end
Bellow are the .asm and HEX files for download (right click the icon, and choose "Save Link As.." from the drop down menu)