millis() и отключенный таймер
- Войдите на сайт для отправки комментариев
Пт, 20/04/2012 - 18:27
Всем доброго времени суток! Я в программировании новичек) Вобщем взял уже готовый код (сниффер 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. //
Решено.
Ну хоть кратенько, как решено???
Помогли на 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, но мне это было не нужно)).