16F628 delay bug/quirk

Status
Not open for further replies.

Tableleg

New Member
I'm working out the bugs of a program that will control two mirrors (labeled M1 and M2) that need to be raised up or lowered down. Each of the two bi-directional motors that move the mirrors have two limit switches, one for the 'up' position at the top of the motion, one for the 'down position at the bottom. The positions are controlled by rocker switches on the front of the system.

So we have 6 inputs to keep track of, (four limit switches, two 'directional' switches) and four outputs to control (two for each motor, one to drive the mirror up, the other to drive the mirror down). I'm using a GOTO table look up system that seems to be working out fine since I"ve worked out the truth table, but my test circuit (see the picture for the schematic) is showing me some unusual bugs/quirks.

M2 works like a champ. Every time I switch different scenarios it changes the outputs instantaneously. M1 however will sometimes pause before changing states, as short as .25sec. to as long as 7~8sec! I can't figure out what is causing the delays with the M1 outputs... And because this won't work in the actual set up, (I can't drive the mirrors past the limit switches without causing a bunch of damage to the motors) I don't really want to continue to the next step without figuring this out.

Below are the schematic of my test circuit (once I get this working, I'll figure out how to interface it to the motors via either transistors or relay) and the code. I'm using a regulated benchtop power supply for now and MPLAB IDE v.7.40 to compile my code. If you guys could look over it and see if you could figure out the reason behind this delay, I'd really be appreciative!

Schematic:

**broken link removed**


Code:
;*********************************************************
;Notes
;*********************************************************

;8-15
;Purpose of this code is to drive the mirrors up and down in a spectometer
;The code looks for the current state of the directional switch, then activates
;a bidirectional motor to move it until it hits a limit switch.

;Inputs:
; M1 - directional switch for mirror one : RA0
; M2 - directional switch for mirror two : RA1
; M1LS1 - limit switch for mirror one up position : RA2
; M1LS0 - limit switch for mirror one down position : RA3
; M2LS1 - limit switch for mirror two up position : RA4
; M2LS0 - limit switch for mirror two down position : RA5
; RA6 and RA7 are grounded

;Outputs
; M1MTR1 - Mirror 1 control motor up : RB0
; M1MTR0 - Mirror 1 control motor down : RB1
; M2MTR1 - Mirror 2 control motor up : RB2
; M2MTR1 - Mirror 2 control motor down : RB3


;********************************************
;EQUATES SECTION

TMR0 EQU 1
OPTION_R EQU 1
PORTA EQU 5
PORTB EQU 6
TRISA EQU 5
TRISB EQU 6
STATUS EQU 3
ZEROBIT EQU 2
CARRY EQU 0
EEADR EQU 1BH
EEDATA EQU 1AH
EECON1 EQU 1CH
EECON2 EQU 1DH
RD EQU 0
WR EQU 1
WREN EQU 2
PC EQU 2
PCON EQU 0EH
COUNT EQU 20H
M1 EQU 0
M2 EQU 1
M1LS1 EQU 2
M1LS0 EQU 3
M2LS1 EQU 4
M2LS0 EQU 5
M1MTR1 EQU 0
M1MTR0 EQU 1
M2MTR1 EQU 2
M2MTR0 EQU 3

;*****************************************************
LIST P=16F628 ;using the 628
ORG 0
GOTO START
;*******************************************************
; SUBROUTINE SECTION.

;Note:
;First number after the M indicates which
; mirror it controls M1 or M2
;Second number indicates which
; direction it takes the mirror
; 1 is an upward motion,
; 0 is a downward motion
; S is a stop command
;Example: M11M21 drives mirror one up, mirror two up
; M10M2S drives mirror one down, mirror stops either up or down




M10 BSF PORTB,M1MTR0 ;Sit. 56, 58,
GOTO BEGIN

M11 BSF PORTB,M1MTR1 ;Sit. 53, 55,
GOTO BEGIN

M1S BCF PORTB,M1MTR1 ;Sit. 52, 54, 57, 59
BCF PORTB,M1MTR0
GOTO BEGIN

M20 BSF PORTB,M2MTR0 ;Sit. 44, 45,
GOTO BEGIN

M2S BCF 06h,2 ;Sit. 28, 29, 46, 47,
BCF 06h,3
GOTO BEGIN

M21 BSF PORTB,M2MTR1 ;Sit. 30, 31,
GOTO BEGIN

M1SM2S MOVLW 0 ;Sit. 20, 25, 38, 43,
MOVWF PORTB
GOTO BEGIN

M11M2S MOVLW B'00000001' ;Sit. 21, 39,
MOVWF PORTB
GOTO BEGIN

M1SM21 MOVLW B'00000100' ;Sit. 22,
MOVWF PORTB
GOTO BEGIN

M11M21 MOVLW B'00000101' ;Sit. 23,
MOVWF PORTB
GOTO BEGIN

M10M2S MOVLW B'0000010' ;Sit. 24, 42,
MOVWF PORTB
GOTO BEGIN

M10M21 MOVLW B'00000110' ;Sit. 26,
MOVWF PORTB
GOTO BEGIN

M1SM20 MOVLW B'00001000' ;Sit. 27, 36, 41
MOVWF PORTB
GOTO BEGIN

M11M20 MOVLW B'00001001' ;Sit. 37,
MOVWF PORTB
GOTO BEGIN

M10M20 MOVLW B'00001010' ;Sit. 40,
MOVWF PORTB
GOTO BEGIN
;This table skips down __ lines of code that corrisponds to the numerical value
; of the input switches. Example, if M1 is up, M2 is up, and the directional switches
; has both of the mirros up, PORTA = 00111111, or 63, the program would then skip down to line 63
TABLE ADDWF PC
GOTO BEGIN ;0~~~~~~~~~~~~~~~
GOTO BEGIN ;1 *
GOTO BEGIN ;2 *
GOTO BEGIN ;3 *
GOTO BEGIN ;4 *
GOTO BEGIN ;5 *
GOTO BEGIN ;6 *
GOTO BEGIN ;7 *
GOTO BEGIN ;8 *
GOTO BEGIN ;9 Range not used
GOTO BEGIN ;10 *
GOTO BEGIN ;11 *
GOTO BEGIN ;12 *
GOTO BEGIN ;13 *
GOTO BEGIN ;14 *
GOTO BEGIN ;15 *
GOTO BEGIN ;16 *
GOTO BEGIN ;17 *
GOTO BEGIN ;18 *
GOTO BEGIN ;19~~~~~~~~~~~~~~~
GOTO M1SM2S ;20 M10S AND M20S
GOTO M11M2S ;21 M11 AND M20S
GOTO M1SM21 ;22 M10S AND M21
GOTO M11M21 ;23 M11 AND M21
GOTO M10M2S ;24 M10 AND M20S
GOTO M1SM2S ;25 M11S AND M20S
GOTO M10M21 ;26 M10 AND M21
GOTO M1SM21 ;27 M11S AND M21
GOTO M2S ;28
GOTO M2S ;29
GOTO M21 ;30
GOTO M21 ;31
GOTO BEGIN ;32~~~~~~~~~~~~~~~
GOTO BEGIN ;33~Range not used
GOTO BEGIN ;34~Range not used
GOTO BEGIN ;35~~~~~~~~~~~~~~~
GOTO M1SM20 ;36 M10S AND M20
GOTO M11M20 ;37 M11 AND M20
GOTO M1SM2S ;38 M10S AND M21S
GOTO M11M2S ;39 M11 AND M21S
GOTO M10M20 ;40 M10 AND M20
GOTO M1SM20 ;41 M11S AND M20
GOTO M10M2S ;42 M10 AND M21S
GOTO M1SM2S ;43 M11S AND M21S
GOTO M20 ;44
GOTO M20 ;45
GOTO M2S ;46
GOTO M2S ;47
GOTO BEGIN ;48~~~~~~~~~~~~~~~
GOTO BEGIN ;49~Range not used
GOTO BEGIN ;50~Range not used
GOTO BEGIN ;51~~~~~~~~~~~~~~~
GOTO M1S ;52
GOTO M11 ;53
GOTO M1S ;54
GOTO M11 ;55
GOTO M10 ;56
GOTO M1S ;57
GOTO M10 ;58
GOTO M1S ;59
GOTO M10M20 ;60
GOTO M11M20 ;61
GOTO M10M21 ;62
GOTO M11M21 ;63


;******************************************************************
; CONFIGURATION SECTION.

START
; ***PORTA****
BSF STATUS,5 ;Bank1
MOVLW B'11111111'
MOVWF TRISA ;PortA is input


; ***PORTB****

MOVLW B'00000000'
MOVWF TRISB ;PortB is output

MOVLW B'00000100'
MOVWF OPTION_R ;Option Register, TMR0 / 32
CLRF PCON ;Select 37kHz oscillator.
BCF STATUS,5 ;Bank0
CLRF PORTA
CLRF PORTB
MOVLW 7
MOVWF 1FH ;CMCON turns off comparators.
; __config B'11111100001010' ; Configuration word (20MHz ceramic resonator)
__config B'11111100010000' ; Configuration word (4MHz internal clock, PWRTEN enabled)
; __config B'11111100111000' ; Configuration word (4MHz internal clock, MCLR enabled)
; __config B'11111110011000' ; Configuration word (4MHz internal clock, LV pgm)


;*********************************************************
;*********************************************************
;Program starts.
;*********************************************************
;*********************************************************

PWRUP ; Controller checks whether the driver was powered down mid move.
; When powers up, it checks the input switches and moves the mirror
; accordingly.


MOVLW B'00111100' ;Moves mirros down on power up
SUBWF PORTA
BTFSC STATUS, ZEROBIT
GOTO M10M20

MOVLW B'00111101' ;Moves M1 up, M2 down on power up
SUBWF PORTA
BTFSC STATUS, ZEROBIT
GOTO M11M20

MOVLW B'00111110' ;Moves M1 down, M2 up on power up
SUBWF PORTA
BTFSC STATUS, ZEROBIT
GOTO M10M21

MOVLW B'00111111' ;Moves M1 up, M2 up on power up
SUBWF PORTA
BTFSC STATUS, ZEROBIT
GOTO M11M21

BEGIN
MOVF PORTA,W ; Check current status of mirrors, input switches
CALL TABLE ; Select appropriate motor output for current status

END
;*********************************************************
;Program ends.
;*********************************************************
 
Some tips:
You should not define the inherent symbols for the PIC:
Code:
PORTA EQU 5
PORTB EQU 6
TRISA EQU 5
TRISB EQU 6
STATUS EQU 3
etc
Instead you should do this instead:
Code:
	#include <p16f628.inc>        ; processor specific variable definitions
This reduces the chance of silly errors and makes your code more portable.
Always define the destination of the operand:
Code:
SUBWF PORTA
Like this;
Code:
SUBWF PORTA, W
;or
SUBWF PORTA, F
So we know what you intended to do. In the code you posted it is obvious you want to preserve the value in W so your are discarding the data back into PORTA which is an input so nothing happens with it anyway.
I see a call but no RETURN or RETLW. In this case you should use a goto instead:
Code:
CALL TABLE ; Select appropriate motor output for current status
 
It's a bit confusing trying to work out your table.
It would be a lot simpler if you tested the inputs and set the outputs accordingly. Something like,

Code:
#define		M1	PORTA,0
#define		M1LSup	PORTA,2
#define		M1LSdw	PORTA,3
#define		M1MTRup	PORTB,0
#define		M1MTRdw	PORTB,1



		btfss	M1
		goto	Mirror1Up	
; mirror should be down
		btfsc	M1LWdw		;is it at bottom?
		goto	StopMirror1	;yes, do done
; mirror needs to be moved down
		bcf	M1MTRup		;turn off up
		bsf	M1MTRdw		;turn on down
		goto	DoneMirror1
Mirror1Up	
; mirror should be up
		btfsc	M1LSup		;is it at top
		goto	StopMirror1	;yes, so done
; mirror needs to move up
		bcf	M1MTEdw		;turn off down
		bsf	M1MTRup		;turn on up
		goto	DoneMirror1
StopMirror1	bcf	M1MTRup		; turn up and down off
		bcf	M1MTRdw
DoneMirror1

Mike.
 
After I posted this yesterday, I checked all my hardware I was using to be sure that it wasn't a factor. And wouldn't yo know I found two bad switches!!! They would both eventually toggle, but it wasn't an instantaneous open/close like a switch should be. I could watch the delay on my dmm from the time I toggled the switch to the time I actually registered on the meter! I have never seen a switch do that before and from here on out, I'll probably be very paranoid about the switches I use.

So I threw those away, found two more (and thoroughly tested them before putting them back into the circuit) and now the system works beautifully!

kchriste,
I've only been learning assembler for about two months now and the book I'm learning from is kinda old (PICs in Practice isbn 0-7506-6826-1) and the 'include' function isn't mentioned anywhere, so I've had to some research to figure out what you were talking about. Now that I understand what that file does, it sure does make my life loads easier and will definitely start using that in the future!

I get what you're saying about the operand destination, but I don't think it applies to what I'm trying to do here:

Code:
TABLE   ADDWF   PC

The destination here is the PCL register so that it skips ahead X number lines of code (where X=the value in W) to get the appropriate outputs dependent on what the inputs are (or the value that is loaded into W). If the code read:

Code:
TABLE   ADDWF   PC,W

the table would skip down to the same line ever time, no matter what the inputs were. I suppose I could replace the W in the above example with 'PC', but that would be redundant. Perhaps I'm looking this wrong. Being new to assembler, I'm still figuring the quirks out. If that's the case, try to explain it to me another way.

I did mean to put a GOTO where that CALL was. That has been fixed. I'm just lucky that in the case of this program, it didn't cause any problems because it probably would of taken me forever to find it!


Mike,
I can kinda follow along with your code. The idea behind how I wrote my table is that it gathers the current state of all the inputs and once and switches all the outputs accordingly. Your code checks each input one at a time then changes each output one at a time. Different ways of doing things I suppose.

The table was a pain to make, I'll admit that. I took each possible input variation in PORTA (bits 5-0, 6 and 7 were kept low) and figured out which number that represented. (The example in the book I'm reading only had 3 inputs meaning it would have a maximum table size of 6 different input combinations; much easier than my problem here ) For example:

If the selector switches had the 'up' position selected, and each mirror was in fact in that up position, PORTA would read B'00101011', which in decimal equals 43. So I load PORTA into W and GOTO the table. If you add 43 to the PCL register, it'll skip down and execute the 43rd line of code. So in the case of this input, both mirror are where they are supposed to be, all motor movement needs to stop. So line '43' is a GOTO line that went to a subroutine that stopped all motor movement;
Code:
MOVLW   B'00000000' 
MOVWF   PORTB
GOTO    BEGIN

I suppose it's not as small or efficient as yours is, but you're the uber-experienced here and I'm just the noob. = )

Thanks for your help guys! I really do appreciate it!

Jason
 
I checked all my hardware I was using to be sure that it wasn't a factor. And wouldn't yo know I found two bad switches!!!
Good find!
If the code read:
Code:
TABLE ADDWF PC,W
the table would skip down to the same line ever time, no matter what the inputs were.
You are correct; it would operate that way. But to use the proper syntax you should write it like this:
TABLE ADDWF PC,F
and then the table would work correctly also. What happens is that the compiler defaults to the F destination when neither F or W are defined in your code. It helps clarify and reminds you that you have the option of putting the result of the arithmetic operation into the W register or back into the general/special purpose register defined in the operand.
I did mean to put a GOTO where that CALL was. That has been fixed. I'm just lucky that in the case of this program, it didn't cause any problems because it probably would of taken me forever to find it!
The PIC has a circular buffer for the stack so it didn't really matter in this case. If you were using interrupts or nested subroutines, it would have crashed randomly.
 
Status
Not open for further replies.
Cookies are required to use this site. You must accept them to continue using the site. Learn more…