Programming PIC18F4520 stopwatch (MPLAB) - microchip

I'm making a code for PIC18F4520 stopwatch using a single 7 segment LED and 8 buttons. Button 1 to stop and button 2 to reset. The following is my code.
LIST p=18F4520
#include <P18F4520.INC>
CONFIG OSC = XT
CONFIG WDT = OFF
CONFIG LVP = OFF
CBLOCK 0x000
DELAY_H
DELAY_L
DELAY_U
input
endc
ORG 0x0000
goto Main
ORG 0x0800
BTFSC INTCON,INT0IF
call INT0_ISR
BTFSC INTCON3,INT1IF
call INT1_ISR
RETFIE
ORG 0x0100
Main
movlw 0x0F
movwf ADCON1
clrf TRISD
clrf PORTD
setf TRISB
BCF INTCON,INT0IF
BSF INTCON,INT0IE
BCF INTCON2,INTEDG0
BCF INTCON3,INT1IF
BSF INTCON3,INT1IE
BCF INTCON2,INTEDG1
BSF INTCON,GIE
movlw 0x00
movwf input
call bcd_7seg
movwf PORTD
count equ 0x25
movlw 0x0A
movwf count
sec
incf input, F
call bcd_7seg
movwf PORTD
call Delay
decf count, F
bnz sec
goto count
bcd_table:
db 0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F, 0x3F
bcd_7seg:
movlw low bcd_table
movwf TBLPTRL
movlw high bcd_table
movwf TBLPTRH
movlw upper bcd_table
movwf TBLPTRU
movf input, W
addwf TBLPTRL, F
movlw 0
addwfc TBLPTRH
addwfc TBLPTRU
TBLRD*
movf TABLAT, W
RETURN
Delay:
MOVLW d'10'
MOVWF DELAY_U
LOP1_0:
MOVLW 0x80
MOVWF DELAY_H
LOP1_1:
MOVLW 0xFF
MOVWF DELAY_L
LOP1_2:
DECF DELAY_L, F
BNZ LOP1_2
DECF DELAY_H, F
BNZ LOP1_1
DECF DELAY_U, F
BNZ LOP1_0
return
INT0_ISR : ?
INT1_ISR : ?
delay:
MOVLW D'100'
MOVWF 1
back
MOVLW D'0'
MOVWF 2
here
NOP
NOP
NOP
NOP
NOP
NOP
decf 2, F
BNZ here
decf 1, F
BNZ back
return
end
Even though I didn't put any instructions in INT0_ISR and INT1_ISR, both button1 and button changes the number on LED to 1. What instructions should I put in INT0_ISR and INT1_ISR to give out the correct result? Thank you for your help!

Related

Problem with stack overflow is forcing device reset

I am doing a small voltmeter with PIC18f4550, I am using the ADC converter of the PIC and based on the binary value I receive I show an approximation in a 7 segment display, the problem is that the program stays cycled and does not perform any action. I enclose the code I am using.
list p=18f4550
include <p18f4550.inc>
;CONFIG FOSC = HS
CONFIG PWRT = ON
CONFIG BOR = OFF
CONFIG WDT = OFF
CONFIG MCLRE = OFF
CONFIG PBADEN = OFF
CONFIG LVP = OFF
CONFIG DEBUG = OFF
CONFIG XINST = OFF
;se utiliza para asignar variables de forma secuencial
CBLOCK 0x00
adclecturaH
adclecturaL
Tiempo
aux1
ENDC
org 0x00 ;incia desde posicion 0
goto Inicio
;
Inicio
CLRF PORTB
MOVLW 0x00
MOVWF TRISB ;asignar como salidas
CLRF PORTC
MOVLW 0x00
MOVWF TRISC ;asignar como salidas
MOVLW b'00011110'
MOVWF ADCON1
MOVLW b'00000001'
MOVWF ADCON0
Ciclo
BSF ADCON0, 1
BTFSC ADCON0, 1
MOVFF ADRESH,adclecturaH
movlw adclecturaH
movwf aux1
MOVLW 0X00
;-------------------------------------------------COMPROBACIONES
;movlw b'00010000'
COM0
movlw b'00000000'
sublw aux1
btfsc STATUS,Z
call COM1 ;otra comprobacion
call DIS0
COM1
movlw b'11001100'
sublw aux1
btfsc STATUS,Z
call COM2 ;otra comprobacion
call DIS1
COM2
movlw b'01100110'
sublw aux1
btfsc STATUS,Z
call COM3 ;otra comprobacion
call DIS2
COM3
movlw b'10011001'
sublw aux1
btfsc STATUS,Z
call COM4 ;otra comprobacion
call DIS3
COM4
movlw b'00110011'
sublw aux1
btfsc STATUS,Z
call COM5 ;otra comprobacion
call DIS4
COM5
movlw b'11111111'
sublw aux1
btfsc STATUS,Z
CALL COM1
call DIS5
;----------------------------------------------MOSTRAR VALORES
DIS0
MOVLW h'3f'
MOVWF PORTB
CALL RETARDO
GOTO Ciclo
DIS1
MOVLW h'06'
MOVWF PORTB
CALL RETARDO
GOTO Ciclo
DIS2
MOVLW h'5b'
MOVWF PORTB
CALL RETARDO
GOTO Ciclo
DIS3
MOVLW h'4f'
MOVWF PORTB
CALL RETARDO
GOTO Ciclo
DIS4
MOVLW h'66'
MOVWF PORTB
CALL RETARDO
GOTO Ciclo
DIS5
MOVLW h'6d'
MOVWF PORTB
CALL RETARDO
GOTO Ciclo
RETARDO
MOVLW D'245'
MOVWF Tiempo
DEC
decfsz Tiempo
GOTO DEC
RETURN
END
The error I receive in Proteus 7 is:
[PIC18 STACK] PC = 0x0082 stack overflow is forcing device reset
Every CALL needs a RET statment.
CALL will put the PC onto the stack and RET will get it back. Without RET the stack will overrun:
main:
CALL Subfunc ;CALL subfunction
..... ;continue here after finish subfunction
Sunfunc:
MOVLW 0x00 ;example
....
RET ;jump back to main function

AVR TWI (I2C) problem: Operand 1 out of range

I´m using Atmega2560 and 24c16A EEPROM for testing an I2C code. For every state transition, controller responds by changing the status register TWSR. After start condition is transmitted, EEPROM responds and then also for Device address and write instruction (SLA+R/W), status register updates fine. But when I transmit next 8 bits, instead of ACK (Data byte sent ACK), status changes to repeated start. The code is given below. I never could find the possible solution to make it work.
.include "./m2560def.inc"
.list
.cseg
.org 0x00
jmp inicio ; PC = 0x0000 RESET
inicio:
LDI R21, HIGH(RAMEND) ;Set Up Stack
OUT SPH, R21
LDI R21, LOW(RAMEND)
OUT SPL, R21
CALL I2C_INIT ;Initialize TWI(I2C)
CALL I2C_START ;Transmit START condition
LDI R27, 0b11010000 ;SLA(0b1001100) + W(0)
CALL I2C_WRITE ;Write R27 ato the I2C bus
LDI R27, 0b11110000 ;Data to be transmitted
CALL I2C_WRITE ;Write R27 ato the I2C bus
CALL I2C_STOP ;Transmit STOP condition
HERE: RJMP HERE
;----------------------------I2C_INIT-----------------------------
I2C_INIT:
LDI R21, 0
OUT TWSR, R21 ;Set prescaler bits to 0
LDI R21, 0x47 ;R21 = 0x47
OUT TWBR, R21 ;Fclk = 50 KHz (8 MHz Xtal)
LDI R21, (1<<TWEN) ;R21 = 0x04
OUT TWCR, R21 ;HEnable TWI (I2C)
RET
;----------------------------I2C_START-----------------------------
I2C_START:
LDI R21, (1<<TWINT)|1<<(TWSTA)|(1<<TWEN)
OUT TWCR, R21 ;Transmit START condition
WAIT1:
IN R21, TWCR ;Read Control Register TWCR into R21
SBRS R21, TWINT ;Skip the next line if TWINT is 1
RJMP WAIT1 ;Jump a WAIT1 if TWINT is 1
RET
;----------------------------I2C_WRITE -----------------------------
I2C_WRITE:
OUT TWDR, R27 ;Move the byte into TWRD
LDI R21, (1<<TWINT)|(1<<TWEN)
OUT TWCR, R21 ;Configure TWCR to send TWDR
WAIT3:
IN R21, TWCR ;Read Control Register TWCR into R21
SBRS R21, TWINT ;Skip the next line if TWINT is 1
RJMP WAIT3 ;Jump a WAIT3 if TWINT is 1
RET
;----------------------------I2C_STOP------------------------------
I2C_STOP:
LDI R21, (1<<TWINT)|1<<(TWSTO)|(1<<TWEN)
OUT TWCR, R21 ;Transmit STOP condition
RET
;----------------------------I2C_READ------------------------------
I2C_READ:
LDI R21, (1<<TWINT)|(1<<TWEN)
OUT TWCR, R21
WAIT2:
IN R21, TWCR ;Read Control Register TWCR into R21
SBRS R21, TWINT ;Skip the next line if TWINT is 1
RJMP WAIT2 ;Jump a WAIT2 if TWINT is 1
IN R27, TWCR ;Read received data into R21
RET
The output is
D:\ATMEL_AVR\I2C_TWI\I2C_TWI.asm(41,0): error: Operand 1 out of range: 0xb9
D:\ATMEL_AVR\I2C_TWI\I2C_TWI.asm(43,0): error: Operand 1 out of range: 0xb8
D:\ATMEL_AVR\I2C_TWI\I2C_TWI.asm(45,0): error: Operand 1 out of range: 0xbc
D:\ATMEL_AVR\I2C_TWI\I2C_TWI.asm(51,0): error: Operand 1 out of range: 0xbc
D:\ATMEL_AVR\I2C_TWI\I2C_TWI.asm(53,0): error: Operand 2 out of range: 0xbc
D:\ATMEL_AVR\I2C_TWI\I2C_TWI.asm(60,0): error: Operand 1 out of range: 0xbb
D:\ATMEL_AVR\I2C_TWI\I2C_TWI.asm(62,0): error: Operand 1 out of range: 0xbc
D:\ATMEL_AVR\I2C_TWI\I2C_TWI.asm(64,0): error: Operand 2 out of range: 0xbc
D:\ATMEL_AVR\I2C_TWI\I2C_TWI.asm(72,0): error: Operand 1 out of range: 0xbc
D:\ATMEL_AVR\I2C_TWI\I2C_TWI.asm(78,0): error: Operand 1 out of range: 0xbc
D:\ATMEL_AVR\I2C_TWI\I2C_TWI.asm(80,0): error: Operand 2 out of range: 0xbc
D:\ATMEL_AVR\I2C_TWI\I2C_TWI.asm(83,0): error: Operand 2 out of range: 0xbc
Assembly failed, 12 errors, 0 warnings
The code lines involved in these errors are:
OUT TWSR, R21
OUT TWBR, R21
OUT TWCR, R21
OUT TWCR, R21
IN R21, TWCR
OUT TWDR, R27
OUT TWCR, R21
IN R21, TWCR
OUT TWCR, R21
OUT TWCR, R21
IN R21, TWCR
IN R27, TWCR
In AVR normally all I/O registers are mapped into the memory space, starting from address 0x0020
in and out instructions could be used ONLY with the first 64 of them (with 0x20...0x5F memory addresses)
sbi, cbi, sbis and sbic has further limitation and can be used only with first 32 I/O registres (with memory address 0x20...0x3F). Please refer to the AVR Instruction Set Manual
In the datasheet to ATmega2560, section 33 "Register Summary", page 401, you can see the TWI registers have addresses 0xB8 thru 0xBD, i.e. they cannot be accessed using in and out instructions. You have to use STS and LDS.
I.e. LDS R21, TWCR instead of IN R21, TWCR etc.
Also, always be careful when accessing the first 64 registers. Make sure the corresponding names are defining their I/O and not RAM addresses. I.e. PORTA should be equal to 0x02 (IO address for in / out instruction) and not 0x22 (RAM address or PORTA, which, when accessed using in or out, equals to EEARH register).

PIC18 How to make the dot move on a 8x8 matrix display?

I am trying to make a dot move up and down an 8x8 matrix display of column RA1. I use switches on a microcontroller to make the dot to move Up(RB5) and Down (RB0). I have the dot start in the position 0x08. The code works fine but the dot moves down when both switches are on. I was thinking that something like XORWF would help? Any ideas?
#include "p18F4520.inc"
;:::::CONFIG::::::::::::::::::::::::
CONFIG OSC = HS
CONFIG PWRT = OFF
CONFIG WDT = OFF
CONFIG PBADEN = OFF
CONFIG LVP = OFF
org 0x000000
PORST GOTO MAIN
org 0x000020
;:::::DELAY:::::::::::::::::::::::::
IDSHORT equ 0x20
IDLONG equ 0x21
ED10MS CLRF IDSHORT
MOVLW 0XFF
MOVWF IDLONG
LDLOOP DECFSZ IDSHORT
GOTO LDLOOP
DECFSZ IDLONG
GOTO LDLOOP
RETURN
;:::::::::::::::::::::::::::::::::::
MAIN CLRF TRISD
CLRF PORTD
CLRF TRISA
CLRF PORTA
BCF PORTA,RA1
BSF PORTA,RA1
SETF TRISB
MOVLW 0X08
MOVWF PORTD
LOOP BSF PORTA,RA1
CALL ED10MS
BCF PORTA,RA1
BTFSS PORTB,RB0 ;CHECKS IF SWHITCH IS ON - MOVE DOWN IF TRUE
GOTO DOWN
BTFSS PORTB,RB5 ;CHECKS IF SWHITCH IS ON - MOVE UP IF TRUE
GOTO UP
GOTO LOOP
UP MOVLW 0X80
CPFSEQ PORTD,W ;CHECKS IF IT REACHED THE TOP
RLNCF PORTD
GOTO LOOP
DOWN MOVLW 0X01
CPFSEQ PORTD,W ;CHECKS ID IT REACHED THE BOTTOM
RRNCF PORTD
GOTO LOOP
END
You can copy the bits in the PORTB reg and use XORLW. If all your other bits on PORTB are zero, ignore the ANDLW. If not, clear the other bits (other than RB0 and RB5) by using the ANDLW line. In LOOP, replace your bit tests with this. Whenever your switches are either both off or both on, this code will simply fall through and loop. STATUS and Z should be defined in the INC file, but you'll define TEMP. Note, this will work on one "snapshot" of PORTB, if you will. And this maintains your use of GOTOs for UP and DOWN:
MOVF PORTB,W ; put PORTB bits in w
ANDLW b'00100001' ; clr unused bits
MOVWF TEMP ; save w in TEMP
XORLW 0X20 ; look for RB0 'on', RB5 'off'
BTFSC STATUS,Z ; if untrue, Z bit clr, skip
GOTO DOWN ; if true, goto DOWN
MOVF TEMP,W ; get saved copy of PORTB bits
XORLW 0X01 ; look for RB0 'off', RB5 'on'
BTFSC STATUS,Z ; if untrue, Z bit clr, skip
GOTO UP ; if true, goto UP
GOTO LOOP ; any other case, goto LOOP

Is this a hardware or Software issue?

I'm using Atmel Studio 6.1 and an Arduino Uno board with an Atmega328P microcontroller. Included below is my code and a picture of my hardware. I can't figure out if this is a hardware or software issue... All LEDs start off. When the button is pressed, it is supposed to change to a determined pattern. Pushing the button again results in a different pattern being displayed. I can't use C and I haven't been able to use real time debugging since I don't have JTAG or some other debugging supported interface. What ends up happening is that the button is pressed and I'm shorting the circuit and the power to the board gets reset. Oddly enough, the pattern changes once but then never again.
.def counter = R23
.def TimeLoopMax = R24
.def AllOnes = R16
.def DisplayPattern = R17
.def AllZeros = R18
MAIN:
LDI AllOnes, 0xFF ; assign 1 - make an output
LDI DisplayPattern, 0x00 ; start with all the LEDS ON; Holds the Light Pattern
LDI AllZeros, 0x00 ; assign 0 - make an input
LDI r19, 0x00 ; to hold the value read from PORTB0
LDI counter, 0x00 ; value for counter
LDI TimeLoopMax, 0x70
;According to the breakout board, PORTB5 is connected on spot 13 on the board
OUT DDRD, AllOnes ;set PORT D as an output
;make PORTB an input
OUT DDRB, AllZeros ;set PORT B as an input
;Start by turning all LEDS OFF
OUT PORTD, DisplayPattern
LOOP:
;read in the value from PORTB0 (ie the push button)
IN r19, PORTB0
;CPI r19, 0x05 ; might need to do a compare; compare with 5 since we're using 5V
CP r19, AllZeros
BRNE LOOP
JMP IncreasePatternCounter
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;; Blinking Pattern Definitions ;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;This defines a blinking sequence for Pattern 0
P0:
;P0, start at a value of 1, and shift the bit to the MSB
LDI DisplayPattern, 0x01
P0_LOOP:
OUT PORTD, DisplayPattern
LSL DisplayPattern ;Logic shift Left
;need to check butotn press every time the light switches
; since we are not using interrupts
/*IN r19, PORTB0
SBRC r19, 0 ;skip if Bit in Reg. is clear
JMP IncreasePatternCounter*/
JMP TimeWastingLoop
;This defines a blinking sequence for Pattern 1
P1:
;P1, start at a value of AA, and shift the bit to the MSB
LDI DisplayPattern, 0xAA
P1_LOOP:
OUT PORTD, DisplayPattern
LSL DisplayPattern
/*IN r19, PORTB0
SBRC r19, 0
JMP IncreasePatternCounter*/
JMP TimeWastingLoop
;This defines a blinking sequence for Pattern 1
P2:
;P1, start at a value of AA, and shift the bit to the MSB
LDI DisplayPattern, 0xFF
P2_LOOP:
OUT PORTD, DisplayPattern
LSR DisplayPattern
/*IN r19, PORTB0
SBRC r19, 0
JMP IncreasePatternCounter*/
JMP TimeWastingLoop
;This defines a blinking sequence for Pattern 1
P3:
;P1, start at a value of AA, and shift the bit to the MSB
LDI DisplayPattern, 0x00
P3_LOOP:
OUT PORTD, DisplayPattern
INC DisplayPattern
/*IN r19, PORTB0
SBRC r19, 0
JMP IncreasePatternCounter*/
JMP TimeWastingLoop
IncreasePatternCounter:
INC counter
SequenceSelect:
CPI counter, 0x01
BREQ P0;
CPI counter, 0x02
BREQ P1;
CPI counter, 0x03
BREQ P2
CPI counter, 0x04
BREQ P3
JMP P0
; Time wasting loop registers: r20,21,22
; R16 is all 1's
TimeWastingLoop:
LDI R20, 0x05
LDI R21, 0x05
LDI R22, 0x04
OutMostLoop:
CP TimeLoopMax, R20;(TLM - R20)
BREQ EndLoop
FirstInnerLoop:
/*IN r19, PORTB0
SBRC r19, 0
JMP IncreasePatternCounter*/
CP TimeLoopMax, R21; (TLM - R21)
BREQ EndOutMostLoop
SecondInnerLoop:
IN r19, PORTB0
SBRC r19, 0
JMP IncreasePatternCounter
CP TimeLoopMax, R22; (TLM - R22)
BREQ EndSecondInnerLoop
INC R22
JMP SecondInnerLoop
EndSecondInnerLoop:
CLR R22 ;reset the register for the next pass
INC R21 ; increment 1st inner loop counter
JMP FirstInnerLoop
EndOutMostLoop:
CLR R21
INC R20
JMP OutMostLoop
EndLoop:
;this is where we do the compare statements with counter
;Need to perform a compare here to see which loop we bounce back in
CPI counter, 0x01
BREQ P0_TWL ; Pattern0 Time Wasting Loop
CPI counter, 0x02
BREQ P1_TWL
CPI counter, 0x03
BREQ P2_TWL
;OUT PORTD, counter
P0_TWL:
CPI DisplayPattern, 0b00000000
BREQ BtnPressCheckP0
BRNE P0_LOOP
P1_TWL:
CPI DisplayPattern, 0b00000000
BREQ P1
BRNE P1_LOOP
P2_TWL:
CPI DisplayPattern, 0b00000000
BREQ P2
BRNE P2_LOOP
BtnPressCheckP0:
IN r19, PORTB0
SBRC r19, 0
JMP IncreasePatternCounter
JMP LOOP
Can't comment on the code portion, but the circuit around the button looks like the cause of your short circuit. This tutorial shows a good button circuit.

I want to run my motors connected to PIC16F628A ..? I need PIC BASIC code?

I have a PIC16F628A, and I have 2 motors coonnected to pins of that PIC. Pins RB0 and RB1 are connected to right motor. Pins RB2 and RB3 are connected to left motor. I'm using MPLAB as compiler from .pbp to .hex. I want to write a PIC BASIC program (.pbp) that will move one of these motors( for ex: left one) ... I have just written a simple code segment like this.
TRISB= %11110000
PORTB.2=0
PORTB.3=0
MAINLOOP:
PORTB.2=1
PAUSE 50
PORTB.3=1
PAUSE 50
GOTO MAINLOOP
END
Compiler compiles it correctly, after I burn the hex file successfully, I place the pig, then I start it, I see nothing...! I'm really so amateur in this programming language, I just want to ask that do I need to write any other code segment to run my motors? Or is there anybody who had such kind of project before?
list p=16F628A
include <P16F628A.INC>
cblock 0x20
COUNT1
COUNT2
endc
org 0x00
init movlw .50
movwf COUNT1
movwf COUNT2
;;;SET PWM FREQUENCY;;;
bank1 ;SELECT BANK 01
movlw D'128' ;SET PR2 TO 128 DECIMAL SO THE PWM PERIOD = 2064uS => PWM FREQUENCY = 484Hz
movwf PR2
bank0 ;SELECT BANK 00
clrf CCPR1L ;SET PWM STARTING DUTY CYCLE;;;
comf CCPR1L
movlw B'00001100' ;SET PWM MODE, BITS 5 AND 4 ARE THE TWO LSBs OF THE 10BIT DUTY CYCLE REGISTER (CCPR1L:CCP1CON<5:4>)
movwf CCP1CON ;SET PWM PIN TO OUTPUT MODE;;;
bank1 ;SELECT BANK 01
bcf TRISB, 3 ;SET RB3 AS OUTPUT, TO USE FOR PWM
bank0 ;SELECT BANK 00
movlw B'00000010' ;SET TIMER 2 PRESCALE VALUE;;;PRESCALE = 16 SO THE PWM PERIOD = 2064uS => PWM FREQUENCY = 484Hz
movwf T2CON
clrf TMR2 ;CLEAR TIMER 2 MODULE;;;
bsf T2CON, TMR2ON ;ENABLE TIMER 2 MODULE;;;
main call DELAY
goto main
DELAY
loop1 decfsz COUNT1,1
goto loop1
decfsz COUNT2,1
goto loop1
return
end

Resources