ve_avr.h Портит код

AlexandreVN
Offline
Зарегистрирован: 16.04.2017

Прошу прощения за возможно простецкие вопросы, но ответа в инете не нашел. Последний раз писал на ассемблере и под PIC16. Сейчас решил попробовать ардуино UNO. Написал небольшой скетч  который измеряет напряжение, отдает его в порт, записывает в  eeprom, читает входы, управляет выходами. Все работает. Но мне потребовался еще тактовый сигнал (t=50мкс, T=250мкс) для моего устройства. Входы/выходы ардуины все заняты, решил использовать А1, а сам сигнал генерировать в прерывании по достижению ТС1 числа A с применением библиотеки ve_avr.h . На этом все хорошее закончилось. Сигнал генерируется, но основная программа живет своей жизнью. Вопрос, что не так? Код уже изрядно перепахан, поэтому многое закоментированно. Изначально пробовал на функциях типа micros реализовать -не понравилось.

int k=4;
int dk=0;
int kreg;
float sensorValue;
byte voltage;
// unsigned long ct; //currentTime
int lt = 0; //loopTime
// volatile bool tau = false; //
#include <EEPROM.h>
#include <ve_avr.h>  
// #define tau  A1  
void setup() {
  // initialize serial communication at 9600 bits per second:
  Serial.begin(9600);
  pinMode(2,INPUT); //UP_K
  pinMode(3,INPUT); //DOWN_K
  pinMode(4,INPUT); //K_REG
  pinMode(5,INPUT); //On
  pinMode(6,INPUT); //MEM_K
  pinMode(8,OUTPUT);  //UP
  pinMode(9,OUTPUT);  //DOWN
  pinMode(10,OUTPUT); //HC_ON
  pinMode(15,OUTPUT); //step
  digitalWrite(2,HIGH);
  digitalWrite(3,HIGH); 
  digitalWrite(4,HIGH); 
  digitalWrite(5,HIGH);  
  digitalWrite(6,HIGH);  
  digitalWrite(8,LOW);
  digitalWrite(9,LOW);  
  digitalWrite(A1,LOW);  
//  ct = micros();
//  lt = ct;
    DEV_TIMER1.setClockSelect(TimerW::Prescaler_8);
    DEV_TIMER1.setWaveGenMode(TimerW::FastPWM_OCRA);
    DEV_TICTRL1.outCompIntEnableA();
    DEV_TIMER1.setOutputCompareA(10);
        interrupts();    
}

// DEV_TIMER1 Output Compare A interrupt handler

void loop() {
// алгоритм генерации сигнала step
//ct = micros();
//if (ct <= lt + 50) {
 // digitalWrite(A1,HIGH);
//}
//else {
 // digitalWrite(A1,LOW);
//}
//if (ct >= lt + 250) {
 // lt = ct;
//}
// конец алгоритма генерации step


  digitalWrite(10,LOW);
kreg = digitalRead(4);
if (kreg == LOW) {
  // read the input on analog pin 0:
  sensorValue = analogRead(A0);
  // Convert the analog reading 
  voltage = sensorValue * (5.0 / 1023.0) * 240.0 / 4.0 ;
 // voltage = voltage * 240.0 / 4.0 ;
  // print out the value you read:
  Serial.println(voltage);  
int  upk = digitalRead(2);
if (upk == LOW) {
  digitalWrite(8,HIGH);
  digitalWrite(9,LOW); 
  } 
int  downk = digitalRead(3);
if (downk == LOW) { 
  digitalWrite(8,LOW);
  digitalWrite(9,HIGH);    
} 
if (downk == HIGH) {
  if (upk == HIGH) {
    digitalWrite(8,LOW);
    digitalWrite(9,LOW);
  }
}
int  memk = digitalRead(6);
 if (memk == LOW) {
  if (dk == 0) {
    EEPROM.write(1,voltage);
      Serial.println("voltage memory:");
      voltage = EEPROM.read(1);
      Serial.println(voltage);
      Serial.println(".........................");
// float    uf = voltage;
    dk=1;
  }
 }
 else {
  dk = 0;
 }
}
 else {
  // ветка автоматического режима
int thc = digitalRead(5);
if (thc == LOW) {
  digitalWrite(10,HIGH);
  int uf = EEPROM.read(1);
    sensorValue = analogRead(A0);
  voltage = sensorValue * (5.0 / 1023.0) * 240.0 / 4.0 ;
 // voltage = voltage * 240.0 / 4.0 ;
  // print out the value you read:
  Serial.println(voltage); 
  if (voltage <= uf - k) {
    digitalWrite(8,HIGH);
    digitalWrite(9,LOW);
  }
  if (voltage >= uf + k) {
    digitalWrite(8,LOW);
    digitalWrite(9,HIGH);
  }
  if (voltage > uf - k) {
      if (voltage < uf + k) {
      digitalWrite(8,LOW);
      digitalWrite(9,LOW);
    }
  }
}
else {
  digitalWrite(8,LOW);
  digitalWrite(9,LOW);
  digitalWrite(10,LOW);
}
}
}
  ISR(TIMER1_COMPA_vect)
{
 //   DEV_TIMER1.setOutputCompareA(potValue);  // This sets next interrupt timeout. 
//    tau = ! tau;            // 
if (lt == 0) {
  digitalWrite(A1,HIGH);
}
else {
  digitalWrite(A1,LOW);
}
lt ++;
if ( lt >= 5) {
  lt = 0;
}
}

 

VanyambaElectronics
Offline
Зарегистрирован: 21.04.2017

Не стоит вызывать функцию digitalWrite() из функции-обработчика прерывания ISR(TIMER1_COMPA_vect).

Дело в том, что компилятор avr-gcc использует соглашение о вызовах "вызывающий сохраняет регистры". Регистров в микроконтроллерах AVR8 - 32. При вызове функции из обработчика прерывания компилятор должен сохранить все регистры. То есть добавить в тело функции 32 команды PUSH и 32 команды POP.

Вариантов для того, чтобы установить значение на выводе микроконтроллера из функции-обработчика прерывания (для вывода A1 в данном случае), суть два:

1) Написать нечто не слишком читаемое

PORTC |= _BV(1);   // digitalWrite(A1, HIGH)
PORTC &= ~_BV(1);  // digitalWrite(A1, LOW)

2) Использовать преимущества библиотеки VEduino (ve_avr.h)

DEV_GPIOC.setHigh(1);
DEV_GPIOC.setLow(1);

Преимущество состоит в том, что код становится более читабельным, при том, что он будет скомпилирован в те же самые три команды ассемблера, что и в первом случае.