Hi there,
I wanted to control a digital potentiometer - Microchips MCP42100. It requires the sending of two bytes serially (via an SPI Interface) from the PIC. The first byte is a command byte and controls which potentiometer (there are two in the package) to write to and the second byte is a number between 0 and 256 indicating the wiper position from 0 to 100k ohms.
One of the application notes details exactly how to interface to these ICs so I pretty much copied the code (all I changed was the ports being used). It looked pretty easy...
Basically it doesnt work and I have no idea why... below is the schematic for the way its wired up to the PIC... simple connection to the PIC PORTE 0 -> /CS, 1 -> SCK and 2 -> SO.
Again the code has been copied from AN746 "Interfacing Microchip's MCP41XXX/42XXX Digital Potentiometers to a PICmicro Microcontroller". The Application Note (attached also) is really just one page and then source code... I used Appendix D for my code and it really only consists of two key routines and some delay routines.... my code is below..
Hoping someone might find an obvious mistake... right now the potentiometer reads 0.1k and if I check between the two terminals I get 187k... not 100k as I would have expected... I should get 40k ohms with the wiper position set to D'100'.
Thanks
Simon
I wanted to control a digital potentiometer - Microchips MCP42100. It requires the sending of two bytes serially (via an SPI Interface) from the PIC. The first byte is a command byte and controls which potentiometer (there are two in the package) to write to and the second byte is a number between 0 and 256 indicating the wiper position from 0 to 100k ohms.
One of the application notes details exactly how to interface to these ICs so I pretty much copied the code (all I changed was the ports being used). It looked pretty easy...
Basically it doesnt work and I have no idea why... below is the schematic for the way its wired up to the PIC... simple connection to the PIC PORTE 0 -> /CS, 1 -> SCK and 2 -> SO.
Again the code has been copied from AN746 "Interfacing Microchip's MCP41XXX/42XXX Digital Potentiometers to a PICmicro Microcontroller". The Application Note (attached also) is really just one page and then source code... I used Appendix D for my code and it really only consists of two key routines and some delay routines.... my code is below..
Hoping someone might find an obvious mistake... right now the potentiometer reads 0.1k and if I check between the two terminals I get 187k... not 100k as I would have expected... I should get 40k ohms with the wiper position set to D'100'.
Thanks
Simon
Code:
; ADD INCLUDE STATEMENT.
list p=16f877A ; list directive to define processor
include <p16F877A.inc>
; SUPPRESS ERROR WARNINGS.
errorlevel -302,-207 ; suppress message 302 from list file
errorlevel -305,-207 ; suppress message 302 from list file
; FUSES.
__config _CP_OFF & _WDT_OFF & _BODEN_OFF & _PWRTE_ON & _XT_OSC & _WRT_OFF & _LVP_OFF & _CPD_OFF
;=============================================================================
; DECLARATIONS
;=============================================================================
RESET_V equ 0X0000 ; ADDRESS OF RESET VECTOR.
ISR_V equ 0X0004 ; ADDRESS OF INTERRUPT VECTOR.
OSC_FREQ equ D'4000000' ; OSCILLATOR FREQUENCY IS 4 MHZ.
;POTENTIOMETER VARIABLES
CS EQU 0 ;PORTE: <1> CHIP SELECT
SCLK EQU 1 ;PORTE: <2> SERIAL CLOCK
SI EQU 2 ;PORTE: <3> SERIAL DATA
; REGISTERS.
cblock H'20' ; NOTE: START DATA BLOCK.
;DELAY VARIABLES.
DELAY_VAL ; USED IN DELAY ROUTINES.
X_DLY_VAL ; "
;POTENTIOMETER VARIABLES.
OUT
COMMAND1
COMMAND2
R_VALUE1
R_VALUE2
COUNT
endc ; NOTE: END OF DATA BLOCK.
org RESET_V ; RESET vector location
reset goto MAIN ; JUMPING TO AVOID THE INTERRUPT VECTOR.
MAIN
call WAIT_15MS ;GIVE THE MICRO A CHANCE TO SETTLE DOWN.
clrf STATUS ; DO INITIALIZATION, SELECT BANK 0
clrf INTCON ; CLEAR INT-FLAGS, DISABLE INTERRUPTS
clrf PCLATH ; KEEP IN LOWER 2KBYTE
clrf PORTA ; ALL PORT OUTPUT SHOULD OUTPUT LOW.
clrf PORTB ; ALL PORT OUTPUT SHOULD OUTPUT LOW.
clrf PORTC ; ALL PORT OUTPUT SHOULD OUTPUT LOW.
clrf PORTD ; ALL PORT OUTPUT SHOULD OUTPUT LOW.
clrf PORTE ; ALL PORT OUTPUT SHOULD OUTPUT LOW.
bcf STATUS, RP1 ; FOR BANK 1 RP1=0 RP0=1.
bsf STATUS, RP0 ; SELECT BANK 1.
movlw B'00000111'
movwf ADCON1 ;SETTING FIRST THREE PINS TO DIGITAL I/O.
clrf PORTA ;LATCH ALL LOW.
movlw B'00000000' ;SET RA4-RA7 TO OUTPUTS.
movwf TRISA
clrf PORTB ;LATCH ALL LOW.
movlw B'11110011' ;SET RB0/INT - RB1 AND RB4-RB7 TO INPUTS.
movwf TRISB
movlw B'00000000' ;SET RD4-7 TO OUTPUTS.
movwf TRISD
movlw B'00000000' ;SET RE0-2 TO OUTPUTS.
movwf TRISE
bsf OPTION_REG, NOT_RBPU ; DISABLE WEAK PULL-UPS ON PORT B.
;NOTE - We want to know which edge the interrupt
; is triggering off. This set the RISING edge
; as the triggering edge.
bsf OPTION_REG, INTEDG ; SET RB0/INT TO RESPOND TO RISING
; LEADING EDGE.
bcf STATUS, RP1 ; FOR BANK 0 RP1=0 RP0=0.
bcf STATUS, RP0 ; SELECT BANK 0.
;NOTE - There are two of pages for the FSR.
; we want are working with the first page.
bcf STATUS,IRP ;MAKING SURE THAT THE FIRST PAGE OF THE FSR
; IS SELECTED.
;*******************************************************************************
;SET OUR VALUE TO 100 OUT OF A POSSIBLE 256 POSITIONS.... (PAGE16 DATASHEET)
;THEREFORE SET WIPER RESISTANCE BETWEEN PA AND PW (WIPER) TO:
;
;RWA = ((100K * (256 - 100))/256)+52
;RWA = 60.9K
;RWB = ((100K * (100))/256)+52
;RWB = 39K
;
;ADDS TO 100K.
;
;USING THE PROGRAMMING INSTRUCTIONS FROM AN746.
;
;HERE WE SET OUR "R_VALUE1" TO D'100' AND SET OUR COMMAND TO H'13'. THEN
;WE SET CS LOW AND SEND TWO BYTES TO THE CHIP VIA PORTE.
;*******************************************************************************
START
bsf PORTE, CS ;SET PORTE CS HIGH SO WE CAN SET IT LOW LATER.
movlw D'100'
movwf R_VALUE1
movlw H'13' ;JUST SET BOTH POTS FIRST JUST TO GET IT WORKING.
movwf COMMAND1
bcf PORTE, CS ;SELECT THE POT BY BRINING CS TO GROUND.
movlw COMMAND1 ;LOAD THE COMMAND BYTE IN THE ACCUMULATOR B '00010011'
call TRANSMIT ;TRANSMIT THE COMMAND BYTE
movlw R_VALUE1 ;LOAD THE RESISTANCE VALUE IN THE ACCUMULATOR
call TRANSMIT ;TRANSMIT THE RESISTANCE VALUE
bsf PORTE, CS ;SET CS HIGH.
;*******************************************************************************
;FINISH LOOP.
;*******************************************************************************
FIN ;FINISH!
goto FIN
;*******************************************************************************
;THIS IS OUR TRANSMIT ROUTINE AS PER AN746.
;*******************************************************************************
TRANSMIT
movwf OUT ;MOVE W TO ’OUT’ VARIABLE
movlw 0X08 ;LOAD A COUNTER TO ’COUNT’ THE BIT
movwf COUNT ;TRANSMISSION
L_SHIFT
btfsc OUT, 7 ;IS THE 7TH BIT A "1"?
goto HI ;YES. ITS A "1" SO GOTO HI AND CLOCK IN A "1".
bcf PORTE, SI ;NO. ITS A "0" SO CLOCK IN A ZERO.
goto PASS
HI
bsf PORTE, SI ;ITS A "1" SO CLOCK IN A "1".
PASS
bsf PORTE, SCLK ;SET SERIAL CLOCK: HI
rlf OUT, F ;ROTATE OUT LEFT
bcf PORTE, SCLK ;SET SERIAL CLOCK: LOW
decfsz COUNT, F ;DECREMENT COUNTER UNTIL ITS ZERO
goto L_SHIFT
clrf PORTE ;WHEN COUNTER IS ZERO IT’S END OF TRANSMISSION
return ;RETURN FROM SUBROUTINE
;*******************************************************************************
;DELAY ROUTINES.
;*******************************************************************************
WAIT_A_SEC
call WAIT_500MS
call WAIT_500MS
return
WAIT_750MS
call WAIT_256MS
call WAIT_256MS
call WAIT_256MS
return
WAIT_500MS
call WAIT_128MS
call WAIT_128MS
call WAIT_128MS
call WAIT_128MS
return
WAIT_256MS
call WAIT_128MS
call WAIT_128MS
return
WAIT_128MS
movlw D'240' ; 128 msec
movwf X_DLY_VAL
LOOP_128MS
call DELAY ;WAIT 500uSec
decfsz X_DLY_VAL, F
goto LOOP_128MS
return
WAIT_64MS
movlw D'120' ; 64 msec
movwf X_DLY_VAL ;
LOOP_64MS
call DELAY ;WAIT 500uSec
decfsz X_DLY_VAL, F
goto LOOP_64MS
return
WAIT_32MS
movlw D'60' ; 30 msec
movwF X_DLY_VAL
LOOP_32MS
call DELAY ; WAIT 500uSec
decfsz X_DLY_VAL, F
goto LOOP_32MS
return
WAIT_15MS
movlw D'30' ; 15 msec
movwf X_DLY_VAL
LOOP_15MS
call DELAY ;wait 500uSec
decfsz X_DLY_VAL, F
goto LOOP_15MS
return
WAIT_4MS
movlw D'08' ; 4 msec
movwf X_DLY_VAL
LOOP_4MS
call DELAY ;wait 500uSec
decfsz X_DLY_VAL, F
goto LOOP_4MS
return
WAIT_1MS
movlw D'02' ; 4 msec
movwf X_DLY_VAL
LOOP_1MS
call DELAY ;wait 500uSec
decfsz X_DLY_VAL, F
goto LOOP_1MS
return
;DELAY ROUTINE = 500uSec OR 1/2 A MILISECOND.
DELAY
movlw H'FF' ; +1 1 CYCLE
movwf DELAY_VAL ; +2 1 CYCLE
DELAY_LOOP
decfsz DELAY_VAL, F; step 1 1 CYCLE
goto DELAY_LOOP ; step 2 2 CYCLE
return ; +3 2 CYCLE
END