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.