millis() и отключенный таймер

joey
Offline
Зарегистрирован: 20.04.2012

 Всем доброго времени суток! Я в программировании новичек) Вобщем взял уже готовый код (сниффер i2c шины fm тюнера) и стал его редактировать под свои нужды. Но сейчас упёрся в одну проблему, а именно:

В коде, как я понял, используются прерывания и встроенный таймер принудительно отключен. Мне нужно использовать задержку, а также измерение промежутка времени между данными  block_2 и block_4, но я не могу работать с millis() из-за отключенного таймера. Если его активировать, то стабильная работа нарушается. Поэтому помогите советом, что можно сделать в данной ситуации)

/*
  
  Arduino program for interfacing the Sony XDR-F1HD Receiver to RDS Spy.
  (Tested on both ATMEGA168 and ATMEGA328 based Arduinos.)
  
  (c) 2010-2011 by Ray H. Dees
  
  Version   Modified By     Date         Comments
  .10       R. Dees      12/23/2010      Initial Release.
  .11       R. Dees      01/04/2011      Modified to support RDS Spy (Version 0.94) "RESET" command.
  .12       R. Dees      04/10/2011      Modified to support Arduinos running at 16mHz on 3.3v.
  
  
  Inputs:
  
  Serial Data (SDA)  -  Arduino Digital Pin 2.
  Serial Clock (SCK) -  Arduino Digital Pin 3.
  
  Ouputs:
  
  RDS data formatted in RDS Spy protocol via the Arduino USB port.
  
  Setup:
  
  RDS Spy should be configured as follows:
  
  Select Configure,
  Select RDS Source,
  Select P75/P175 FM Analyzer,
  Set Connection Type RS232/USB,
  Select the RS232 COM Port that your Arduino appears as. 
  
  You may use this program for personal purposes only.  The use of this program
  in a commercial product requires explicit written permission from the author.
  The author is not responsible or liable for damage or loss that may be caused
  by the use of this program.

*/
#include <WProgram.h>
//
//  Definitions
//
#define SDA              2
#define SCK              3
#define BUFFER_LENGTH   64
#define DELAY  asm volatile("nop"); asm volatile("nop"); asm volatile("nop"); asm volatile("nop"); asm volatile("nop");
//
enum {IDLE, START, RCVG, STOP};
//
//  Global variables
//
byte* rxBuffer = 0;
volatile byte rxBufferIndex = 0;
volatile byte rxBits = 0;
volatile byte rxComplete = 0;
volatile byte rxCount = 0;
volatile byte rxState = 0;
//
word address = 0;
word data = 0;
byte block = 0;
word block_1;
word block_2;
word block_3;
word block_4;
byte group_complete = 0;
byte synchronized = 0;
//
//  Setup begins here.
//
void setup()
{
  delay(500);      //  A 500ms delay, change this to suit your taste!
  pinMode(SDA, INPUT);
  digitalWrite(SDA, HIGH);
  pinMode(SCK, INPUT);
  digitalWrite(SCK, HIGH);
  delay(100);  
  initialize();    // Call initialize to set everything up.
  delay(100);
  Serial.begin(19200);
}
//
//  Main Program Loop.
//
void loop()
{
   while(1)
    {
      if (rxComplete)
        {
          update_blocks();
          rxComplete = 0;
        }  
            
      if (group_complete)
        {
          send_data();
          group_complete = 0;
        }
    }      
}    
//
//  RDS Blocks get updated and sorted here.  First the register address, then the corresponding data.
//
void update_blocks()
{
  if (rxBuffer[0] != 0x38)  //  This version does not support HD, return. 
    return;
  
  if (rxBuffer[4] == 0xC4)  //  Any write to address 0xC4 is a channel change.
    {
      clear();              //  Reset RDS Spy.
      return;
    }   
  
  if (rxBuffer[3] == 0x30)   
    {
      address = 0x0000 | rxBuffer[5] << 8 | rxBuffer[6];
      synchronized = 1;
      
      switch (address)
        {
          case 0x0080:
            block = 1;
            break;
          
          case 0x0084:
            block = 2;
            break;
          
          case 0x0088:
            block = 3;
            break;
            
          case 0x008C:
            block = 4;
            break;
            
          default:
            block = 0;
            synchronized = 0;
        }      
      return;
    }
  
  if (!synchronized)
    return;
    
  if (rxBuffer[3] == 0x31)
    {
      data = 0x0000 | rxBuffer[5] << 8 | rxBuffer[6];
      
      switch (block)
        {
          case 1:
            block_1 = data;
            break;
          
          case 2:
            block_2 = data;
            break;    
          
          case 3:
            block_3 = data;
            break;
          
          case 4:
            block_4 = data;
            group_complete = 1;
            break;
       }
    }    
}
//
//  Send the data to RDS Spy.
//
void send_data()
{
  Serial.println("G:");
  printHex(block_1);
  printHex(block_2);
  printHex(block_3);
  printHex(block_4);
  Serial.println();
  Serial.println();
}  
//
//  Four digit hexadecimal print routine.
//
void printHex(word value)
{
  Serial.print(value >> 12 & 0x0F, HEX);
  Serial.print(value >>  8 & 0x0F, HEX);
  Serial.print(value >>  4 & 0x0F, HEX);
  Serial.print(value >>  0 & 0x0F, HEX);
}
//
//  This routine resets RDS Spy.
//
void clear()
{
  Serial.println("G:");
  Serial.println("RESET");
  Serial.println();
  rxState = IDLE;
  group_complete = 0;
}  
//
//  Setup the microprocessor.
//
void initialize()
{
  cli();   //  Disable global interrupts while we make our changes.
     
  EICRA |= (1 << ISC11 | 1 << ISC10 | 1 << ISC00);  //  Setup Interrupt 0 & 1.
  EIMSK |= (1 << INT1 | 1 << INT0);  //  Enable Interrupt 0 & 1;
  
  ADCSRA &= ~(1 << ADEN);    //  Disable the analog comparator.
  TIMSK0 &= ~(1 << TOIE0);   //  Disable Timer 0.
  TIMSK1 &= ~(1 << TOIE1);   //  Disable Timer 1 - Turns Off PWM.
  TIMSK2 &= ~(1 << TOIE2);   //  Disable Timer 2.
  
  rxBuffer = (uint8_t*) calloc(BUFFER_LENGTH, sizeof(uint8_t));  //  Initialize the receive buffer.
  
  sei();    //  Enable global interrupts.
}
//
//  Interrupt 0 Service Routine - Triggered on the Rising and Falling edge of Serial Data.
//
ISR(INT0_vect, ISR_NOBLOCK)
{
  byte mask = (PIND & 0x0C);
  
  switch (rxState)
    {
      case IDLE:
        if (mask != 0x08)
          return;
        rxBufferIndex = 0;
        rxState = START;
        break;
                
      case START:
        rxBits = 0;
        rxCount = 0;
        rxState = RCVG;
        break;
        
      case RCVG:
        if (mask == 0x08)
          {
            rxState = START;
            return;
          }  
      
      case STOP:    
        if (mask != 0x0C)
          return;
        rxComplete = 1;
        rxState = IDLE;
        break;
        
      default:
        rxState = IDLE;
        break;    
    }
} 
//
//  Interrupt 1 Service Routine - Triggered on the Rising edge of Serial Clock.
//
ISR(INT1_vect, ISR_NOBLOCK)
{
  DELAY;
  switch (rxCount)
    {
      case 0:
      case 1:
      case 2:
      case 3:
      case 4:
      case 5:
      case 6:
      case 7:
        if (PIND & _BV(2))
          bitSet(rxBits, (7 - rxCount));
        rxCount++;
        break;
      case 8:
        rxBuffer[rxBufferIndex] = rxBits;
        rxBufferIndex++;
        rxBits = 0;
        rxCount = 0;
        break;
      default:
        rxState = IDLE;
        break;  
    }
} 
//
//  That's all.
// 

 

joey
Offline
Зарегистрирован: 20.04.2012

 Решено.

fiberline
Offline
Зарегистрирован: 07.04.2012

Ну хоть кратенько, как решено???

joey
Offline
Зарегистрирован: 20.04.2012

 Помогли на arduino.cc, тема здесь. Более подробно о работе с таймерами, а также примеры можно посмотреть тут

Я просто добавил в код:

TCCR1A = (0,0); // переводит таймер-1 в 16 битный режим вместо стандартного 8 битного.
TCCR1B = _BV (CS20) | _BV (CS22); // prescaler of 128 

Дальше считываешь TCNT1 и при каждом его переполнении увеличиваешь переменную count на один. Другую переменную, например timer, используешь уже на замену millis. (timer = count*65536 + TCNT1)

Только нужно подобрать нужный предделитель, чтобы 1 мс соответствовала +1 в переменной timer, но мне это было не нужно)).