Мульти-прерывание для регистрации данных в реальном времени с MCU-ATMega 1280
Мой вопрос о регистрации данных в реальном времени и мульти-прерывании. Я пытаюсь запрограммировать MCU-ATMega 1280 с помощью winAVR, чтобы он считывал импульсы с квадратурного кодера (20um/pitch) и сохранял данные во флэш-памяти (Microchip SST25VF080B, протокол последовательного интерфейса SPI). После того, как кодер завершит свою работу (около 2 минут), MCU экспортирует данные из памяти на экран. Мой код ниже.
Но я не знаю, почему это не работает правильно. Существует 2 вида ошибок: одна ошибка - некоторые точки неожиданно вышли из тренда, другая ошибка - внезапное скачкообразное значение, хотя кодировщик работает медленно. Прыжки, кажется, появляются только тогда, когда есть поворот.
Я думаю, что проблема может заключаться только в хранении данных, потому что эта тенденция происходит так, как я ожидал, за исключением скачков. Я просто хочу спросить, запускаю ли я оба ISR так, как я делал в программе. В каком случае ISR будет вмешиваться другим ISR, когда он работает? В соответствии с таблицей данных atmega 1280, кажется, что когда происходит одно ISR, никакое другое прерывание не может произойти после того, как предыдущее прерывание завершило свою процедуру.
#include <stdlib.h>
#include <stdio.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include "USART.h" // this header is for viewing the data on the computer
#include "flashmemlib.h" // this header contains the function to read n
//write on the memory
#define MISO PB3
#define MOSI PB2
#define SCK PB1
#define CS PB0
#define HOLD PB6
#define WP PB7
#define sigA PD0 //INT0
#define sigB PD2 //INT2
#define LED PD3
uint8_t HADD,MADD,LADD, HDATA, LDATA,i; //HADD=high address, MADD-medium address, LADD-low address
volatile int buffer[8]; //this buffer will store the encoder pulse
uint32_t address = 0;
uint16_t DATA16B = 0;
int main(void)
{
INITIALIZE(); //initialize the IO pin, timer CTC mode, SPI and USART protocol
for(i=0;i<8;i++)
buffer[i]=0;
sei();
//AAI process- AAI is just one writing mode of the memory
AAIInit(address,0);
while (address < 50) //just a dummy loop which lasts for 5 secs (appox)
{
_delay_ms(100);
address++;
}
AAIDI();//disable AAI process
cli(); //disable global interrupt
EIMSK &= ~(1<<INT0);
TIMSK1 &= ~(1<<OCIE1A);
//code for reading procedure. i thought this part is unnecessary because i am quite //confident that it works correcly
return (0);
}
ISR(INT0_vect) // this interrupt is mainly for counting the number of encoder's pulses
{ // When an interrupt occurs, we only have to check the level of
// of pB to determine the direction
PORTB &= ~(1<<HOLD);
for(i=0;i<8;i++)
buffer[i+1]=buffer[i];
if (PIND & (1<<sigB))
buffer[0]++;
else buffer[0]--;
PORTB |= (1<<HOLD);
}
ISR(TIMER0_COMPA_vect) //after around 1ms, this interrupt is triggered. it is for storing the data into the memory.
{
HDATA =(buffer[7]>>8)&0xFF;
LDATA = buffer[7]&0xFF;
PORTB &= ~(1<<CS);
SEND(AD);
SEND(HDATA);
SEND(LDATA);
PORTB |=(1<<CS);
}
void SEND(volatile uint8_t data)
{
SPDR = data; // Start the transmission
while (!(SPSR & (1<<SPIF))){} // Wait the end of the transmission
}
uint8_t SREAD(void)
{
uint8_t data;
SPDR = 0xff; // Start the transmission
while (!(SPSR & (1<<SPIF))){} // Wait the end of the transmission
data=SPDR;
return data;
}
1 ответ
В подпрограмме обработки прерываний INT0 вы пишете:
for(i=0;i<8;i++)
buffer[i+1]=buffer[i];
Означает, что когда i=7
вы пишете вне предопределенного пространства массива и, вероятно, перезаписываете другую переменную. Итак, вы должны сделать:
for(i=0;i<7;i++)
buffer[i+1]=buffer[i];
AVR будет управлять прерываниями, как вы описали, на основании таблицы данных ATmega1280. В качестве альтернативы, если вы хотите разрешить прерывание вектора ISR другим прерыванием, вам нужно сделать следующее (пример):
ISR(INT0_vect, ISR_NOBLOCK)
{...
...}