为什么我在 proteus 中收到此错误:“PC=0x0008 处的操作码 0xFFFF 无效”

问题描述 投票:0回答:1

我需要为我的 ATmega8 微控制器编写汇编代码,它将生成频率范围为 10 Hz 到 1 kHz 的 12 位三角电压。此外,代码应该允许使用电位计控制频率。

我在Proteus中设计了一个原理图:我将一个电位计连接到ATmega8微控制器的PC0/ADC0端口,并将电源和地连接到它。然后,我将电源连接到微控制器的 AVCC 和 AREF 端口。为了连接 MCP4921 与 ATmega8 微控制器,我使用 PB5/SCK 端口连接 SCK,使用 PB3/MOSI/OC2 端口连接 MCP4921 的 SDI,使用 PB2/SS/OC1B 端口连接 MCP4921 的 CS。之后,我通过 LDAC 端口将 MCP4921 连接到地。我还通过 VREFA 端口向 MCP4921 供电,并将电压表连接到 VOUTA 端口,并与示波器一起接地。

我的代码:

; Assembly code for ATmega8, which generates a 12-bit triangular voltage ranging from 10 Hz to 1 kHz
; and controls the frequency using a potentiometer connected to the PC0/ADC0 port.
; Connection scheme of MCP4921 to ATmega8:
; SCK - PB5
; SDI - PB3
; CS - PB2
; LDAC - GND
; VREFA - VCC
; VOUTA - voltmeter and oscilloscope

.include "m8def.inc" ; Definitions for ATmega8

.equ F_CPU = 8000000 ; Clock frequency
.equ SPI_DDR = DDRB ; Port B data direction register
.equ SPI_PORT = PORTB ; Port B data register
.equ SPI_SCK = PB5 ; SCK pin
.equ SPI_MOSI = PB3 ; MOSI pin
.equ SPI_CS = PB2 ; CS pin

.def temp = r16 ; Temporary register
.def value = r17 ; Register to store potentiometer value
.def step = r18 ; Register to store voltage change step
.def dac = r19 ; Register to store value for MCP4921
.def flag = r20 ; Register to store direction flag for voltage change

.org 0x0000 ; Program start
rjmp start ; Jump to start label

.org 0x0012 ; Timer 2 comparison interrupt vector
rjmp timer2_isr ; Jump to interrupt handler

start:
; SPI initialization
ldi temp, (1\<\<SPI_SCK)|(1\<\<SPI_MOSI)|(1\<\<SPI_CS) ; Set SCK, MOSI, and CS pins as outputs
out SPI_DDR, temp ; Write to Port B data direction register
ldi temp, (1\<\<SPE)|(1\<\<MSTR)|(1\<\<SPR0) ; Enable SPI, set master mode, set clock rate divider to 16
out SPCR, temp ; Write to SPI control register
; ADC initialization
ldi temp, (1\<\<REFS0) ; Select internal reference voltage source
out ADMUX, temp ; Write to ADC channel selection register
ldi temp, (1\<\<ADEN)|(1\<\<ADPS2)|(1\<\<ADPS1)|(1\<\<ADPS0) ; Enable ADC, set clock rate divider to 128
out ADCSRA, temp ; Write to ADC control and status register A

; Timer 2 initialization
ldi temp, (1\<\<WGM21) ; Set CTC mode (clear timer on compare match)
out TCCR2, temp ; Write to Timer 2 control register
ldi temp, 249 ; Set comparison value for 1 kHz interrupt frequency
out OCR2, temp ; Write to Timer 2 compare register
ldi temp, (1\<\<OCIE2) ; Enable Timer 2 comparison interrupt
out TIMSK, temp ; Write to Timer interrupt mask register
ldi temp, (1\<\<CS21)|(1\<\<CS20) ; Start Timer 2 with a frequency divider of 32
out TCCR2, temp ; Write to Timer 2 control register

sei ; Enable global interrupts

ldi step, 1 ; Initialize voltage change step
ldi flag, 0 ; Initialize voltage change direction flag
main:
rcall read_adc ; Read potentiometer value
rcall write_dac ; Write value to MCP4921
rjmp main ; Infinite loop

read_adc:
sbi ADCSRA, ADSC ; Start ADC conversion
adc_wait: ; Wait for conversion to complete
in temp, ADCSRA ; Read ADC control and status register
sbrs temp, ADSC ; Check ADSC bit
rjmp adc_wait ; Continue waiting if bit is not cleared
in value, ADCH ; Read high byte of ADC result
ret ; Return from subroutine

write_dac:
ldi temp, 0b00110000 ; Set configuration bits for MCP4921
or temp, dac ; Add high 4 bits of value for MCP4921
cbi SPI_PORT, SPI_CS ; Set CS pin low
rcall spi_send ; Send byte over SPI
swap dac ; Swap high and low nibbles of value for MCP4921
andi dac, 0b00001111 ; Clear high 4 bits of value for MCP4921
rcall spi_send ; Send byte over SPI
sbi SPI_PORT, SPI_CS ; Set CS pin high
ret ; Return from subroutine

spi_send:
out SPDR, temp ; Write byte to SPI data register
spi_wait: ; Wait for transmission to complete
in temp, SPSR ; Read SPI status register
sbrs temp, SPIF ; Check SPIF bit
rjmp spi_wait ; Continue waiting if bit is not set
ret ; Return from subroutine

timer2_isr:
; Timer 2 comparison interrupt handler
; Changes the value for MCP4921 based on potentiometer value and direction flag
push temp ; Save temp register to stack
push value ; Save value register to stack
push step ; Save step register to stack
push dac ; Save dac register to stack
push flag ; Save flag register to stack
rcall read_adc ; Read potentiometer value
lsr value ; Right shift value by 1 bit
lsr value ; Right shift value by another bit
mov step, value ; Copy value to step register
tst step ; Check if value is zero
breq timer2_exit ; Exit handler if value is zero
tst flag ; Check direction flag
breq timer2_up ; Jump to timer2_up if flag is zero
timer2_down: ; Label for decreasing voltage
sub dac, step ; Subtract step from value for MCP4921
brcc timer2_exit ; Exit handler if no carry
ldi dac, 0xFF ; Set value for MCP4921 to maximum if carry
timer2_up: ; Label for increasing voltage
add dac, step ; Add step to value for MCP4921
brcc timer2_exit ; Exit handler if no carry
ldi dac, 0x00 ; Set value for MCP4921 to minimum if carry
ldi flag, 1 ; Change direction flag to 1
rjmp timer2_exit ; Jump to exit label
timer2_exit: ; Exit label for handler
pop flag ; Restore flag register from stack
pop dac ; Restore dac register from stack
pop step ; Restore step register from stack
pop value ; Restore value register from stack
pop temp ; Restore temp register from stack
reti ; Return from interrupt

my scheme

留言:

PROSPICE 8.13.00 (Build 32709) (C) Labcenter Electronics 1993-2023. Loaded netlist 'C:\\Users\\maxim\\AppData\\Local\\Temp\\LISA7525.SDF' for design 'Kursach.pdsprj' AVR Release 8.3SP0 build 33337 for ATMEGA8. \[U1\] QPainter::begin: Paint device returned engine == 0, type: 1 Invalid opcode 0xFFFF at PC=0x0008 @0.016216000s

我发现了这个(为什么我在proteus中遇到这个错误:“Invalid opcode 0xFFFF at PC=0x002A”)但我不知道如何使用它

assembly atmega proteus
1个回答
0
投票

编译器告诉您,中断向量表中没有

TIMER2
的有效指令。它告诉你这一点是因为这两行:

.org 0x0012 ; Timer 2 comparison interrupt vector
rjmp timer2_isr ; Jump to interrupt handler

地址

0x0012
不是
TIMER2
比较匹配中断的正确地址,它属于
USART RXC
(数据表中的第46页列出了中断向量的地址)。为了修复编译错误,您需要做的就是将其更改为正确的地址:
0x0003

© www.soinside.com 2019 - 2024. All rights reserved.