📄 mp3menus.c
字号:
PositionLCDcursor(4, 1);
uart1_putwaitPROGstr((u08*)pgm_read_word(FnArrayPtr+IRFuncString));
break;
case BUT_DOWN:
ButtonPress = 0; // clear out the button press so we don't do this again
// clear out the old menu name on the LCD display
ClearLCDlines(4, 2);
// Point to next menu record (ie next in the linked list)
FnArrayPtr = (PGM_VOID_P)pgm_read_word(FnArrayPtr+IRNextFunc);
// Display the name of our new menu item (first move cursor to start of 4th line)
PositionLCDcursor(4, 1);
uart1_putwaitPROGstr((u08*)pgm_read_word(FnArrayPtr+IRFuncString));
break;
}
}
// If we're here it's because the MENUSEL button was pressed, exiting us from the above switch statement,
// because the user selected a player function (play, stop, next, etc) so learn the IR code for that .
// Then wrap-up & return to the player.
ButtonPress = 0; // clear out the button press that got us here
ClearLCDlines(1, 8); // blank all the LCD display lines
PositionLCDcursor(1, 1);
uart1_putwaitPROGstr(PSTR("Hold remote control 30 cm from MP3 player IR reciever then press remote control button."));
TrainIRfunction(pgm_read_word(FnArrayPtr+IRFuncEEPROM)); // learn IR code, passing in eeprom location to store results
// Now ask the user if they want to train again
ClearLCDlines(1, 8); // blank all the LCD display lines
PositionLCDcursor(1, 1);
uart1_putwaitPROGstr(PSTR("IR code received."));
PositionLCDcursor(3, 1);
uart1_putwaitPROGstr(PSTR("Do you wish to train another function?"));
PositionLCDcursor(6, 1);
uart1_putwaitPROGstr(PSTR("Select=yes, others=no"));
ButtonPress = 0;
while (!ButtonPress); // wait until a button is pressed
if (ButtonPress != BUT_MENUSEL)
trainon = 0; // clear flag if Select not pressed
ButtonPress = 0; // clear out the button press
ClearLCDlines(1, 8); // blank all the LCD display lines
} // bottom of "do you want to train another?" loop
}
// TrainIRfunction
//
// This is the routine that does the "heavy lifting" for IR remote control learning. It
// receives the IR code bit sequence, analyses it, and then stores the result in the eeprom,
// at the passed-in eeprom address. It MUST receive an IR signal; it'll wait here forever
// if it doesn't see one.
void TrainIRfunction (u16 eepromaddr)
{
u08 starttime;
u16 *buffpointer;
u16 periodcount, i, j, sum, lowbar, highbar, T;
T = 0;
// disable input capture 3 interrupt; we want to poll the captures in this routine
// ensure other capture parameters set up correctly. With prescaler set to /256, each increment
// of TCNT3 takes 16 us.
*AVR_ETIMSK = *AVR_ETIMSK & 0xdf; // disable input capture 3 interrupt
*AVR_TCCR3B = 0x84; // prescaler = /256, noise canceller ON, capture on falling edge
*AVR_ETIFR = *AVR_ETIFR | 0x20; // ensure capture3 interrupt flag clear
// init location to put periods data
buffpointer = (u16*)&MP3DATAQ[10]; // point into MP3 data Q. Partway in to avoid changing the Q headers.
// Now sit back & wait for the start of the IR signal (a falling edge). When it arrives, clear the
// counter, kick off the timeout, and start recording periods. Wait until bit 5 (ICF3 flag) in ETIFR
// register is set; when set this indicates a capture has occurred.
while (!(*AVR_ETIFR & 0x20));
// Capture has occurred - falling edge detected. An IR signal has begun. Start recording periods.
// Record periods until either we get 200 of them, or 200 ms has passed.
*AVR_TCNT3H = 0;
*AVR_TCNT3L = 0; // zero the counter register; ready for next period measurement
*AVR_TCCR3B = *AVR_TCCR3B ^ 0x40; // tell AVR to do next capture on the other edge (rising edge)
*AVR_ETIFR = 0x20; // clear ICF3 interrupt flag so we can detect next capture
starttime = Tick100ms; // start timeout
periodcount = 0;
while ((Tick100ms-starttime)<2) {
while (!(*AVR_ETIFR & 0x20)); // wait for input capture to occur
*AVR_TCNT3H = 0;
*AVR_TCNT3L = 0; // zero the counter register; ready for next period measurement
*AVR_TCCR3B = *AVR_TCCR3B ^ 0x40; // tell AVR to do next capture on the other edge (opposite edge)
*buffpointer++ = *AVR_ICR3L + ((*AVR_ICR3H)<<8); // store timeperiod
periodcount++;
if (periodcount>200) break;
*AVR_ETIFR = 0x20; // clear ICF3 interrupt flag so we can detect next capture
} // end while loop
// execute here when we've timed out - we've now captured all the IR period data we're going to
if (periodcount < 10) goto WrapUp; // exit if too short a received code (array of periods)
// Now we go through a bunch of work to determine an estimate for "T", the bit period. The sole point of
// this exercise is that knowing the bit period is very useful for determining when one sequence of IR periods
// has finished and a new one has begun. Remote controls transmit continuously while you're holding a button
// down; they will retransmit the IR sequence over and over until you release their button, each IR sequence
// separated by a gap. That gap is easiest to detect if you know the bit period.
// Determine initial value for "T", the bit period, by finding the second-smallest period in the array
// of periods, excluding the first 2 and last 2 periods (header & trailer).
buffpointer = (u16*)&MP3DATAQ[10];
buffpointer++;
buffpointer++; // skip over the first 2 periods in the array
j=*buffpointer++; // (initial value for...) j is smallest period
T=j; // (initial value for...) T is second-smallest period
i = periodcount - 5; // this is how many periods we want to check (not 1st & last 2, & we just did one)
do {
if (*buffpointer < j) { // if we've found a new smallest-period value...
T = j; // then previous smallest-period is now the second-smallest period
j = *buffpointer; // and record new smallest-period value
}
buffpointer++; // move on to next period entry
} while (i--); // repeat until all periods have been checked
// At this point T contains our initial period estimate, being the second-smallest period value found in
// the bulk of the periods array. Now we want to refine that T estimate. We do that by trying to find the
// first eight periods in the bulk of the array of approximate length T, summing them and dividing by 8.
// To get a new, much more accurate, value of T. "Approximate value of T" is defined as the period value
// being within 1/2T (ie 0.5T to 1.5T is acceptable as being a T).
buffpointer = (u16*)&MP3DATAQ[10];
buffpointer++;
buffpointer++; // skip over the first 2 periods in the array
sum = 0; // this is the sum of the (hopefully 8) T's
j = 0; // how many T's we've found
lowbar = T>>1; // low acceptable threshold value for T (0.5*T)
highbar = T + lowbar; // high acceptable threshold value for T
i = periodcount - 4; // this is how many periods we want to check (not 1st & last 2)
while (i-- && (j<8)) {
if ( (*buffpointer>lowbar) && (*buffpointer<highbar) ) { // if current period is valid as a T then...
sum += *buffpointer; // add it to the sum
j++; // and increment our T's count
}
buffpointer++; // point to next period in the array
}
// Now do the division. New T value is sum / j.
if (j) // if (j) avoids divide-by-error possibility
T = DivRound (sum, j); // integer division with rounding
// At this point we have a new, fairly well refined, value for T - the received IR datastream bit period.
// Now let's find out how many periods are actually in the IR sequence. We've captured "periodcount" number
// of periods, including the first two which are the header periods (long periods, used for locking the PLL
// in the IR detectors). Beyond the header periods, we're going to look for a period of duration greater than
// 15 "T"s, ie greater than 15 bit periods. This will indicate the gap between repeating IR sequences.
// Finally, note that we cannot store more than 63 periods in the eeprom, so if we find the sequence is longer
// than 63 periods, we set it to 63. Store the result in j.
buffpointer = (u16*)&MP3DATAQ[10]; // point to start of raw periods data
buffpointer++;
buffpointer++; // skip past the two header periods
j = 2; // we still need to count them though
i = periodcount-2; // how many remaining periods to check
// check each period's length in "T"s; break out of while loop if length exceeds 15 T's
while ( (i--) && (DivRound(*buffpointer++, T)<16) ) {
j++;
}
if (j>63) j=63;
// DEBUG - print the periods raw data to the debug RS232 port
if (IRtrain_debug) {
uart0_putwaitPROGstr(PSTR("\r\nStart of IR period raw data\r\n"));
uart0_putwaitPROGstr(PSTR("Number of raw periods: "));
PrintASCIIword (periodcount, 0);
uart0_putwaitPROGstr(PSTR("\r\nValue of T (bit period): "));
PrintASCIIword (T, 0);
uart0_putwaitPROGstr(PSTR("\r\nNumber of periods in IR sequence: "));
PrintASCIIword (j, 0);
uart0_putwaitPROGstr(PSTR("\r\n"));
buffpointer = (u16*)&MP3DATAQ[10]; // point to start of periods data
i = periodcount;
while (i--) {
PrintASCIIword (*buffpointer++, 0);
uart0_putwaitPROGstr(PSTR("\r\n"));
}
uart0_putwaitPROGstr(PSTR("End of IR period raw data\r\n"));
}
// End DEBUG code section
// Store the resultant array of periods in the eeprom. Including the length (number of periods, ie "j").
// There are "j" number of periods of interest in the array, which we want to store into the eeprom.
EEPROM_Write(eepromaddr++, (u08)j); // write the number of periods into the eeprom (length byte)
eepromaddr++; // skip over "buttonpress" value in eeprom; point to start of periods eeprom space
buffpointer = (u16*)&MP3DATAQ[10]; // point to start of periods data
while (j--) {
EEPROM_Write(eepromaddr++, (u08)*buffpointer); // write low byte of period value into eeprom
EEPROM_Write(eepromaddr++, (u08)(*buffpointer++>>8)); // write high byte of period value into eeprom
}
// all done; re-enable input capture 3 interrupts for normal IR receiver operation. Fix MP3 data Q.
// Clear the IR decoder count bytes.
WrapUp:
// Zero the IR decoder sequence count values. So that the IR decoder (the regular decoder, not this special
// training one) is starting from the beginning when attempting the decode a received sequence.
i = IR_numcodes;
while (i--)
IRdecode_cnt[i] = 0;
Q_clear_C((u08*)&MP3DATAQ[0]); // ensure MP3 data Q empty (note we didn't overwrite the Q headers)
*AVR_TCCR3B = 0x84; // prescaler = /256, noise canceller ON, capture on falling edge
*AVR_ETIMSK = *AVR_ETIMSK | 0x20; // enable input capture 3 interrupt
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -