PIC Projects

Controlling motor speed and rotation direction

The motor speed and direction is controlled by a single pot. If it is in the middle position the motor is stopped. Moving from this position towards the upper end (see schematic) increases the motor speed in the forwards direction, which moving towards the grounded end increases the one in the backwards direction.

To control the motor speed we use PWM as in the previous experiments. The PIC reads the voltage coming out of the pot, which is in the range 0..5V, and redirects it to a built-in ADC with a 10-bit resolution. In this case, however, its two lower bits are ignored. The range of ADC values (0..255) is splitted into two parts: 0..127 and 128..255. If the voltage is in the second range, the motor rotates forwards (and backwards otherwise).

Schematic Layout

The ADC value is used to set up the duty cycle ratio of the PWM running at 244Hz. The low frequency is chosen to improve the motor efficiency. The PWM resolution in this case is 10 bits, out of which just 8 higher ones are used to simplify the code. If the ADC value v is in the range 0..127, it is updated as 128-v, otherwise it is updated as v-128. The obtained value is then multiplied by 2 by using the left shift operation to match the maximum value 255 used for the PWM period. This way we get a number in the range 0..254 which is used to setup the PWM duty cycle ration. Thus, we will get only 127 different PWM values, corresponding to a 7-bit resolution. This is more than sufficient for a smooth motor control. PIC pins RC3 and RC4 are used to control the motor direction. Their binary values must be complimentary, i.e. 10 or 01, corresponding to two rotation directions. This is needed for a correct operation of the L293D buffers. Those buffers introduce approx. 0.7V voltage drop, which suits very good to the normal working conditions of my 3V motor.

The code is as follows:

 TITLE  "pwm_dir.asm"           	; another PWM test 
 List P=PIC16F684, R=DEC
 INCLUDE "p16f684.inc"

; data segment
 CBLOCK 0x20                   
 del  					; variable used for delay
 temp					; local temp variable	
 ENDC

; code segment
 PAGE
 __CONFIG _FCMEN_OFF & _IESO_OFF & _BOD_OFF & _CPD_OFF & 
   _CP_OFF & _MCLRE_OFF & _PWRTE_ON & _WDT_OFF & _INTRC_OSC_NOCLKOUT

  org 0                      		; start program at the beginning of mem
	bcf	STATUS, RP0		; activate BANK 0
	clrf	PORTA			; initialize PORT A
	clrf	PORTC			; initialize PORT C
	movlw	0x07
	movwf	CMCON0			; comparators OFF
	bsf    	STATUS, RP0      	; change to BANK 1

 	; ADC and PWM configuration
	bsf	TRISA ^ 0x80, 0		; enable input on pin A0
	bsf	ANSEL ^ 0x80, 0		; configure A0 as analog input
	movlw 	b'01110000' 		; set ADC Frc clock
	movwf 	ADCON1 ^ 0x80
	movlw	0xFF	
	movwf	PR2 ^ 0x80		; PWM period 244Hz
	clrf	TRISC ^ 0x80		; enable RC for output
	bcf    	STATUS, RP0        	; back to BANK 0

	bsf 	ADCON0, 0 		; Left justify, Vdd Vref, AN0, On	
	movlw	7
	movwf	T2CON			; enable Timer 2 with 1:16 prescaler
	movlw	0x0C			; enable single output PWM
	movwf	CCP1CON 	

loop
	movlw	20
	movwf	del
	call	delay			; 20 msec delay

	bsf	ADCON0, GO		; start ADC operation
	btfsc	ADCON0, GO		; and wait for its completion	
	goto 	$-1

	movf	ADRESH, w		; get 8 higher bits of ADC
	movwf	temp			; and save them in temp
	movlw 	128                 
	subwf	temp, w             	; is ADCvalus greater than 128? 
	btfss	STATUS, C		; NO  - drive motor reverse
	goto 	reverse

forwards				; YES - drive motor forwards
	bcf	STATUS, C		; scale ADC value up to the range
	rlf	temp, w             	;   0..254
	movwf	CCPR1L			; setup new PWM duty cycle ratio
	movlw	b'110111'		; setup motor direction
	movwf	PORTC
	goto 	loop

reverse
	movlw	0x7F
	xorwf	temp, f			; complement ADC value
	bcf	STATUS, C		; scale ADC value up to the range
	rlf	temp, w    	        ;   0..254
	movwf	CCPR1L			; setup new PWM duty cycle ratio
	movlw	b'101111'		; setup motor direction
	movwf	PORTC	
  	goto 	loop			; endless loop


; procedures
delay					; a delay for del milliseconds
	movlw 	200
	
	sublw	1			; this loop takes 5us*200 = 1ms
	sublw	0			; for PIC16F684 @ 4 Mhz
	btfss	STATUS, Z
	goto 	$-3

	decfsz	del, f
	goto 	delay
	return

 end

Download pwm_dir.asm


Last modified:Mon, Jan 23, 2023.

04527