Reputation: 1
Write an assembly language program to create a 1 Hz square waveform on PORT A0. a) First write your code to toggle PORT A0 without any delay b) Then add a delay subroutine to produce the required delay. You are not allowed to use Timer Interrupt for the delay subroutine.
I keep getting an error about my delay but i tried may ways and still wrong
The goal of this task is to write an assembly code which can count every 1 second from 0000 to 1111 or in reverse order from 1001 to 0000 based on the 2 inputs RA0 and RA1 shown in the Table 1.
When the counting has reaches maximum (1111 for count up) or minimum (0000 for count down), the counting will loop back to the other end (start from 0000 again for count up, or start from 1111 again for count down). The 4-bit output of the counting should be sent to outputs RB7:4, where RB7 as MSB and RB4 as LSB. See the requirement table below.
for this one i cant count up or down , during pause it works
__CONFIG _CONFIG1, _FOSC_HS & _WDTE_OFF & _PWRTE_ON & _PWRTE_OFF & _BOREN_ON & _LVP_OFF & _CPD_OFF & _WRT_OFF & _DEBUG_OFF
__CONFIG _CONFIG2, _CP_OFF
START:
bcf STATUS, RP0 ; Select Bank 0
clrf PORTB ; Clear PORTB
movlw 0x00 ; Initialize PORTB to 0
movwf PORTB
movlw b'00001111' ; Set RB7:4 as outputs, RB3:0 as inputs
movwf TRISB
movlw b'11111100' ; Set RA0 and RA1 as inputs
movwf TRISA
MainLoop:
btfsc PORTA, 1 ; Check if RA1 is low (counter disable)
goto MainLoop ; If RA1 is low, do nothing
btfsc PORTA, 0 ; Check if RA0 is low (count down)
goto CountDown
goto CountUp
CountUp:
call Delay1Sec ; Wait for 1 second
incf PORTB, F ; Increment PORTB
movf PORTB, W
andlw b'11110000' ; Mask the lower 4 bits
xorlw b'11110000' ; Check if it is 1111
btfss STATUS, Z ; If it is not 1111, skip the next line
movlw b'00000000' ; Reset to 0000 if it was 1111
movwf PORTB
goto MainLoop
CountDown:
call Delay1Sec ; Wait for 1 second
decf PORTB, F ; Decrement PORTB
movf PORTB, W
andlw b'11110000' ; Mask the lower 4 bits
btfsc STATUS, Z ; If result is not 0000, skip the next line
movlw b'11110000' ; Set to 1111 if it was 0000
movwf PORTB
goto MainLoop
Delay1Sec:
; Implement a delay here that approximates 1 second
; This delay loop is just a placeholder and should be calibrated
movlw D'255'
movwf count1
OuterDelayLoop:
movlw D'255'
movwf count2
InnerDelayLoop:
decfsz count2, f
goto InnerDelayLoop
decfsz count1, f
goto OuterDelayLoop
return
END
ORG 0x00
goto START
ORG 0x04 ; Interrupt vector
START:
bcf STATUS, RP0 ; Select Bank 0
clrf PORTB ; Clear PORTB
movlw 0x00 ; Initialize PORTB to 0
movwf PORTB
movlw b'00001111' ; Set RB7:4 as outputs, RB3:0 as inputs
movwf TRISB
movlw b'11111100' ; Set RA0 and RA1 as inputs
movwf TRISA
MainLoop:
btfsc PORTA, 1 ; Check if RA1 is low (counter disable)
goto MainLoop ; If RA1 is low, do nothing
btfsc PORTA, 0 ; Check if RA0 is low (count down)
goto CountDown
goto CountUp
CountUp:
call Delay1Sec ; Wait for 1 second
incf PORTB, F ; Increment PORTB
movf PORTB, W
andlw b'11110000' ; Mask the lower 4 bits
xorlw b'11110000' ; Check if it is 1111
btfss STATUS, Z ; If it is not 1111, skip the next line
movlw b'00000000' ; Reset to 0000 if it was 1111
movwf PORTB
goto MainLoop
CountDown:
call Delay1Sec ; Wait for 1 second
decf PORTB, F ; Decrement PORTB
movf PORTB, W
andlw b'11110000' ; Mask the lower 4 bits
btfsc STATUS, Z ; If result is not 0000, skip the next line
movlw b'11110000' ; Set to 1111 if it was 0000
movwf PORTB
goto MainLoop
Delay1Sec:
; Implement a delay here that approximates 1 second
; This delay loop is just a placeholder and should be calibrated
movlw D'255'
movwf count1
OuterDelayLoop:
movlw D'255'
movwf count2
InnerDelayLoop:
decfsz count2, f
goto InnerDelayLoop
decfsz count1, f
goto OuterDelayLoop
return
END
Upvotes: 0
Views: 91
Reputation: 1225
user25136115,
It seems that you may need someone to show actual working code for all three parts of your assignment.
Here is task 1a:
;
; File: task1a.asm
; Target: PIC16F84A
; Author: dan1138
; Date: 2024-05-31
; Compiler: MPASM v5.22
;
; Description:
;
; Homework example
; See: https://stackoverflow.com/questions/78504317/issue-with-the-delay-and-the-toggle
; Task 1:
; Create a 1 Hz Square Waveform on PORTA bit 0
; Write an assembly language program to create a 1 Hz square waveform on PORT A0.
; a) First write your code to toggle PORT A0 without any delay
; b) Then add a delay subroutine to produce the required delay.
; You are not allowed to use Timer Interrupt for the delay subroutine.
;
; PIC16F84A
; +----------:_:----------+
; <> 1 : RA2 RA1 : 18 <>
; <> 2 : RA3 RA0 : 17 <> Output
; <> 3 : RA4/T0CKI OSC1 : 16 <- 4MHz crystal
; ICSP_VPP -> 4 : MCLR OSC2 : 15 -> 4MHz crystal
; GND -> 5 : GND VDD : 14 <- 5v0
; <> 6 : RB0/INT PGD/RB7 : 13 <> ICSP_PGD
; <> 7 : RB1 PGC/RB6 : 12 <> ICSP_PGC
; <> 8 : RB2 RB5 : 11 <>
; <> 9 : RB3 RB4 : 10 <>
; +-----------------------:
; DIP-18
include "p16f84a.inc"
list n=0,c=132,r=dec
errorlevel -302
__CONFIG (_FOSC_HS & _WDTE_OFF & _PWRTE_OFF & _CP_OFF)
org 0
START:
bsf STATUS, RP0 ; Select Bank 1
movlw b'11111110' ; Set RA0 as output
movwf TRISA
bcf STATUS, RP0 ; Select Bank 0
movlw b'00000001'
MainLoop:
xorwf PORTA,F
goto MainLoop
END
Here is task 1b:
;
; File: task1b.asm
; Target: PIC16F84A
; Author: dan1138
; Date: 2024-05-31
; Compiler: MPASM v5.22
;
; Description:
;
; Homework example
; See: https://stackoverflow.com/questions/78504317/issue-with-the-delay-and-the-toggle
; Task 1:
; Create a 1 Hz Square Waveform on PORTA bit 0
; Write an assembly language program to create a 1 Hz square waveform on PORT A0.
; a) First write your code to toggle PORT A0 without any delay
; b) Then add a delay subroutine to produce the required delay.
; You are not allowed to use Timer Interrupt for the delay subroutine.
;
; PIC16F84A
; +----------:_:----------+
; <> 1 : RA2 RA1 : 18 <>
; <> 2 : RA3 RA0 : 17 <> One_Hz_Output
; <> 3 : RA4/T0CKI OSC1 : 16 <- 4MHz crystal
; ICSP_VPP -> 4 : MCLR OSC2 : 15 -> 4MHz crystal
; GND -> 5 : GND VDD : 14 <- 5v0
; <> 6 : RB0/INT PGD/RB7 : 13 <> ICSP_PGD
; <> 7 : RB1 PGC/RB6 : 12 <> ICSP_PGC
; <> 8 : RB2 RB5 : 11 <>
; <> 9 : RB3 RB4 : 10 <>
; +-----------------------:
; DIP-18
include "p16f84a.inc"
list n=0,c=132,r=dec
errorlevel -302
__CONFIG (_FOSC_HS & _WDTE_OFF & _PWRTE_OFF & _CP_OFF)
;
#define T0_COUNTS_PER_TICK 125
#define TICKS_PER_TENTH_SEC 25
;
; Allocate RAM
cblock 0x10
T0_Sample : 1
TicksInTenthSecCount : 1
TenthSecondCount : 1
endc
;
org 0
START:
bsf STATUS, RP0 ; Select Bank 1
movlw b'11111110' ; Set RA0 as output
movwf TRISA
movlw 0x84 ; TMR0 clock source Fosc/4, TMR0 prescale 1:32
movwf OPTION_REG
bcf STATUS, RP0 ; Select Bank 0
clrf TMR0
clrf T0_Sample
movlw TICKS_PER_TENTH_SEC
movwf TicksInTenthSecCount
movlw 10
movwf TenthSecondCount
MainLoop:
call Wait4ms
decfsz TicksInTenthSecCount,F
goto MainLoop
movlw TICKS_PER_TENTH_SEC
movwf TicksInTenthSecCount
;
; count tenths of seconds
movf TenthSecondCount,F
skpz
decfsz TenthSecondCount,F
goto MainLoop
movlw 10
movwf TenthSecondCount
movlw b'00000001'
xorwf PORTA,F ; Toggle RA0
goto MainLoop
;
; Wait 4 milliseconds
Wait4ms:
movf T0_Sample,W
subwf TMR0,W
sublw T0_COUNTS_PER_TICK
skpnc
goto Wait4ms
movlw T0_COUNTS_PER_TICK
addwf T0_Sample,F
return
END
Here is task 2:
;
; File: task2.asm
; Target: PIC16F84A
; Author: dan1138
; Date: 2024-05-31
; Compiler: MPASM v5.22
;
; Description:
;
; Homework example
; See: https://stackoverflow.com/questions/78504317/issue-with-the-delay-and-the-toggle
;
; Task 2:
; Up/Down Counter on PORT A
; The goal of this task is to write an assembly code which can count
; every 1 second from 0000 to 1111 or in reverse order from 1111 to 0000
; based on the 2 inputs RA0 and RA1 shown in the Table 1.
;
; When the counting has reaches maximum (1111 for count up) or
; minimum (0000 for count down), the counting will loop back to
; the other end (start from 0000 again for count up,
; or start from 1111 again for count down).
;
; The 4-bit output of the counting should be sent to outputs RB7:4,
; where RB7 as MSB and RB4 as LSB.
;
; Table 1:
; +-------+-------+-------------------------+
; : Input : output :
; +-------+-------+-------------------------+
; : RA0 : RA1 : Counting(RB7:4) :
; +-------+-------+-------------------------+
; : 0 : 0 : paused :
; +-------+-------+-------------------------+
; : 0 : 1 : Count up :
; +-------+-------+-------------------------+
; : 1 : 0 : Count down :
; +-------+-------+-------------------------+
; : 1 : 1 : Reset to 0000 and pause :
; +-------+-------+-------------------------+
;
; PIC16F84A
; +----------:_:----------+
; <> 1 : RA2 RA1 : 18 <> Button_2
; <> 2 : RA3 RA0 : 17 <> Button_1
; <> 3 : RA4/T0CKI OSC1 : 16 <- 4MHz crystal
; ICSP_VPP -> 4 : MCLR OSC2 : 15 -> 4MHz crystal
; GND -> 5 : GND VDD : 14 <- 5v0
; <> 6 : RB0/INT PGD/RB7 : 13 <> LED_3/ICSP_PGD
; <> 7 : RB1 PGC/RB6 : 12 <> LED_2/ICSP_PGC
; <> 8 : RB2 RB5 : 11 <> LED_1
; <> 9 : RB3 RB4 : 10 <> LED_0
; +-----------------------:
; DIP-18
include "p16f84a.inc"
list n=0,c=132,r=dec
errorlevel -302
__CONFIG (_FOSC_HS & _WDTE_OFF & _PWRTE_OFF & _CP_OFF)
;
#define T0_COUNTS_PER_TICK 125
#define TICKS_PER_TENTH_SEC 25
;
; Allocate RAM
cblock 0x10
T0_Sample : 1
TicksInTenthSecCount : 1
TenthSecondCount : 1
OneSecondCount : 1
endc
;
org 0
START:
bsf STATUS, RP0 ; Select Bank 1
movlw b'11111111' ; Set RA0:1 as input
movwf TRISA
movlw b'00001111' ; Set RB7:4 as output
movwf TRISB
movlw 0x84 ; TMR0 clock source Fosc/4, TMR0 prescale 1:32
movwf OPTION_REG
bcf STATUS, RP0 ; Select Bank 0
clrf TMR0
clrf T0_Sample
movlw TICKS_PER_TENTH_SEC
movwf TicksInTenthSecCount
movlw 10
movwf TenthSecondCount
clrf OneSecondCount
MainLoop:
call Wait4ms
decfsz TicksInTenthSecCount,F ; Count number of 4ms ticks in 100ms
goto MainLoop
movlw TICKS_PER_TENTH_SEC
movwf TicksInTenthSecCount
;
; count tenths of seconds
movf TenthSecondCount,F ; When tenths of second counter is zero
skpz ; stop all counting.
decfsz TenthSecondCount,F ; When tenths of second counter decrement
goto MainLoop ; from 1 to zero one second has elapsed.
movlw 10
movwf TenthSecondCount ; Restart tenths of second counter
;
; count seconds
movf PORTA,W
andlw b'00000011' ; check for no button pressed
skpnz
goto ShowCount ; no button pressed so pause
xorlw b'00000011' ; check for both buttons pressed
skpz
goto CheckForWhichButton
clrf OneSecondCount ; both buttons pressed so reset
goto ShowCount
CheckForWhichButton:
xorlw b'00000011' ^ b'0000001'; Check for RA0 pressed
skpnz
decf OneSecondCount,F ; RA0 pressed so count down
xorlw b'0000001' ^ b'0000010' ; Check for RA1 pressed
skpnz
incf OneSecondCount,F ; RA1 pressed so count up
ShowCount:
swapf OneSecondCount,W ; Put bit 3:0 in bits 7:4 of WREG
xorwf PORTB,W ; Make mask of what to change on PORTB
andlw b'11110000' ; Change only RB7:4
xorwf PORTB,F ; Show current 4-bit count on PORTB
goto MainLoop
;
; Wait 4 milliseconds
Wait4ms:
movf T0_Sample,W
subwf TMR0,W
sublw T0_COUNTS_PER_TICK
skpnc
goto Wait4ms
movlw T0_COUNTS_PER_TICK
addwf T0_Sample,F
return
END
My expectation is that you must submit the completed assignment in the next week or less.
So good luck.
Upvotes: 0
Reputation: 1225
First off be warned this answer is a lot more code than your homework assignment requires. Submit this and you will fail the assignment.
This code does conform to the "letter" of your tasks but it does them all in one application.
The stipulation to not use the timer interrupt is a bit of a problem but nowhere does it say you cannot use the timer to determine how much real time has elapsed.
I suspect that your instructor wants you doing a lot of tedious instruction cycle counting to create a callable delay function.
The code uses techniques your instructor may not have mentioned, so until you can explain how this code works to yourself don't let your instructor think you wrote it.
;
; File: main.S
; Target: PIC16F84A
; Author: dan1138
; Date: 2024-05-30
; Compiler: pic-as v2.45
; IDE: MPLABX v6.15
;
; Add this line in the project properties box, pic-as Global Options -> Additional options:
; -Wa,-a -Wl,-pPor_Vec=0h,-pIsr_Vec=4h
;
; Description:
;
; Homework example
; See: https://stackoverflow.com/questions/78504317/issue-with-the-delay-and-the-toggle
; Task 1:
; Create a 1 Hz Square Waveform on PORTA bit 0
; Write an assembly language program to create a 1 Hz square waveform on PORT A0.
; a) First write your code to toggle PORT A0 without any delay
; b) Then add a delay subroutine to produce the required delay.
; You are not allowed to use Timer Interrupt for the delay subroutine.
;
; Task 2:
; Up/Down Counter on PORT A
; The goal of this task is to write an assembly code which can count
; every 1 second from 0000 to 1111 or in reverse order from 1001 to 0000
; based on the 2 inputs RA1 and RA2 shown in the Table 1.
;
; When the counting has reaches maximum (1111 for count up) or
; minimum (0000 for count down), the counting will loop back to
; the other end (start from 0000 again for count up,
; or start from 1111 again for count down).
;
; The 4-bit output of the counting should be sent to outputs RB7:4,
; where RB7 as MSB and RB4 as LSB.
;
; Table 1:
; +-------+-------+-------------------------+
; : Input : output :
; +-------+-------+-------------------------+
; : RA1 : RA2 : Counting(RB7:4) :
; +-------+-------+-------------------------+
; : 0 : 0 : paused :
; +-------+-------+-------------------------+
; : 0 : 1 : Count up :
; +-------+-------+-------------------------+
; : 1 : 0 : Count down :
; +-------+-------+-------------------------+
; : 1 : 1 : Reset to 0000 and pause :
; +-------+-------+-------------------------+
;
; PIC16F84A
; +----------:_:----------+
; Button_2 <> 1 : RA2 RA1 : 18 <> Button_1
; <> 2 : RA3 RA0 : 17 <> One_Hz_Output
; <> 3 : RA4/T0CKI OSC1 : 16 <- 4MHz crystal
; ICSP_VPP -> 4 : MCLR OSC2 : 15 -> 4MHz crystal
; GND -> 5 : GND VDD : 14 <- 5v0
; <> 6 : RB0/INT PGD/RB7 : 13 <> LED_3/ICSP_PGD
; <> 7 : RB1 PGC/RB6 : 12 <> LED_2/ICSP_PGC
; <> 8 : RB2 RB5 : 11 <> LED_1
; <> 9 : RB3 RB4 : 10 <> LED_0
; +-----------------------:
; DIP-18
PROCESSOR 16F84A
PAGEWIDTH 132
RADIX DEC
#include <xc.inc>
; PIC16F84A Configuration Bit Settings
CONFIG FOSC = HS ; Oscillator Selection bits (HS oscillator)
CONFIG WDTE = OFF ; Watchdog Timer (WDT disabled)
CONFIG PWRTE = OFF ; Power-up Timer Enable bit (Power-up Timer is disabled)
CONFIG CP = OFF ; Code Protection bit (Code protection disabled)
;
; Skip macros
;
skpndc MACRO
btfsc STATUS,STATUS_DC_POSITION
ENDM
skpdc MACRO
btfss STATUS,STATUS_DC_POSITION
ENDM
skpnc MACRO
btfsc STATUS,STATUS_C_POSITION
ENDM
skpc MACRO
btfss STATUS,STATUS_C_POSITION
ENDM
skpnz MACRO
btfsc STATUS,STATUS_Z_POSITION
ENDM
skpz MACRO
btfss STATUS,STATUS_Z_POSITION
ENDM
;
; Power-On-Reset entry point
;
PSECT Por_Vec,global,class=CODE,delta=2
global resetVec
resetVec:
goto main
;
; Data space use by interrupt handler to save context
PSECT Isr_Data,global,class=RAM,space=1,delta=1,noexec
;
GLOBAL WREG_save,STATUS_save,PCLATH_save
GLOBAL Segments
;
WREG_save: ds 1
STATUS_save: ds 1
PCLATH_save: ds 1
Segments: ds 2
;
; Interrupt vector and handler
PSECT Isr_Vec,global,class=CODE,delta=2
GLOBAL IsrVec
;
IsrVec:
movwf WREG_save
swapf STATUS,W
movwf STATUS_save
movf PCLATH,W
movwf PCLATH_save
;
IsrHandler:
;
IsrExit:
movf PCLATH_save,W
movwf PCLATH
swapf STATUS_save,W
movwf STATUS
swapf WREG_save,F
swapf WREG_save,W
retfie ; Return from interrupt
;
;objects in bank 0 memory, note PIC16F84 does not have banked memory
PSECT MainData,global,class=RAM,space=1,delta=1,noexec
GLOBAL T0_Sample,TicksInTenthSecCount,TenthSecondCount,OneSecondCount
GLOBAL SW_Flags
GLOBAL BTN_sample,BTN_stable,BTN_change,BTN_bounce
T0_Sample: ds 1
#define T0_COUNTS_PER_TICK 125
#define TICKS_PER_TENTH_SEC 25
TicksInTenthSecCount: ds 1
TenthSecondCount: ds 1
OneSecondCount: ds 1
#define SW_1 SW_Flags,0
#define SW_1_MASK 0x01
#define SW_2 SW_Flags,1
#define SW_2_MASK 0x02
SW_Flags: ds 1
#define DEBOUNCE_COUNT 2
#define BTN1_POSITION 1
#define BTN1_MASK 0x02
#define BTN2_POSITION 2
#define BTN2_MASK 0x04
BTN_sample: ds 1
BTN_stable: ds 1
BTN_change: ds 1
BTN_bounce: ds 1
;
; Applicaiton initialization
PSECT MainCode,global,class=CODE,delta=2
main:
clrf INTCON
BANKSEL TRISB
movlw 0x0F
movwf TRISB
movlw 0xFE ; RA0 output, RA1,RA2 inputs
movwf TRISA
movlw 0x84 ; TMR0 clock source Fosc/4, TMR0 prescale 1:32
movwf OPTION_REG
banksel TMR0
clrf TMR0
clrf T0_Sample
movlw TICKS_PER_TENTH_SEC
movwf TicksInTenthSecCount
movlw 10
movwf TenthSecondCount
clrf OneSecondCount
clrf BTN_sample
clrf BTN_stable
clrf BTN_change
clrf BTN_bounce
clrf SW_Flags
;
; Application process loop
AppLoop:
call Wait4ms
;
; debounce switches
call BTN_Poll
iorlw 0
skpnz ; Skip if a button changed state
goto Count4msTicks
;
; Process button inputs
movf BTN_stable,W
andwf BTN_change,F
btfsc BTN_change,BTN2_POSITION
bsf SW_2 ; button 2 changed to pressed
btfsc BTN_change,BTN1_POSITION
bsf SW_1 ; button 1 changed to pressed
clrf BTN_change
;
; Process when button changed to pressed
btfsc SW_1
call SW_1_Process
btfsc SW_2
call SW_2_Process
;
; count 4ms ticks
Count4msTicks:
;
decfsz TicksInTenthSecCount,F
goto AppLoop
movlw TICKS_PER_TENTH_SEC
movwf TicksInTenthSecCount
;
; count tenths of seconds
movf TenthSecondCount,F
skpz
decfsz TenthSecondCount,F
goto AppLoop
movlw 10
movwf TenthSecondCount
;
; do one Hz toggle on PORTA
movlw 1
xorwf PORTA,F
btfsc BTN_stable,BTN1_POSITION
goto ButtonPressed
btfsc BTN_stable,BTN2_POSITION
goto ButtonPressed
;
; No buttons pressed, state pause
goto ShowCount
ButtonPressed:
btfss BTN_stable,BTN1_POSITION
goto ButtonOneNotPressed
btfss BTN_stable,BTN2_POSITION
goto ButtonOneNotPressed
;
; Both buttons pressed, state Reset pause
clrf OneSecondCount
goto ShowCount
ButtonOneNotPressed:
btfsc BTN_stable,BTN2_POSITION
incf OneSecondCount,F
btfsc BTN_stable,BTN1_POSITION
decf OneSecondCount,F
ShowCount:
swapf OneSecondCount,W
xorwf PORTB,W
andlw 0xF0
xorwf PORTB,F
goto AppLoop
;
; ============================================
; Button changed to pressed event processing
SW_1_Process:
bcf SW_1
return
;
SW_2_Process:
bcf SW_2
return
;
; ============================================
; Button polling
;
; poll buttons
; Returns: WREG = 0, no buttons changed
; WREG = 1, buttons changed
BTN_Poll:
clrw
btfsc PORTA,1
iorlw BTN1_MASK
btfsc PORTA,2
iorlw BTN2_MASK
xorwf BTN_sample,W
skpnz
goto BTN_debounce
xorwf BTN_sample,F
movlw DEBOUNCE_COUNT
movwf BTN_bounce
retlw 0
BTN_debounce:
movf BTN_bounce,F
skpnz
goto BTN_debounce_done
decfsz BTN_bounce,F
retlw 0
BTN_debounce_done:
movf BTN_sample,W
xorwf BTN_stable,W
skpnz
retlw 0
iorwf BTN_change,F
xorwf BTN_stable,F
retlw 1
;
; Wait 4 milliseconds
Wait4ms:
movf T0_Sample,W
subwf TMR0,W
sublw T0_COUNTS_PER_TICK
skpnc
goto Wait4ms
movlw T0_COUNTS_PER_TICK
addwf T0_Sample,F
return
END resetVec
This does run in the MPLABX simulator but I don't use Proteus so that's on you.
Upvotes: 0