📄 f411_vr.c
字号:
}
// the REC_PLAY switch was not pressed
else
{
// clear the END_MEM recording flag after the ADC ISR has turned off
// the ADC
if ((system_state & END_MEM) == END_MEM)
{
system_state &= ~RECORDING;
}
// the system is currently recording - stop recording
if (system_state == RECORDING)
{
system_state &= ~RECORDING;
ADC_STOP_FLAG = 1; // notify the ADC to stop recording
MEM_END_NEAR_FLAG = 0; // clear all flags
MEM_END_FLAG = 0;
LED_DCH = &LED0_DC; // point to the record LED's duty cycle
// address
Dim_LED (); // dim off the record LED
}
// check if the playback has reached the end of the recording
if (REC_END_FLAG == 1)
{
// stop playing
system_state &= ~PLAYING;
REC_END_FLAG = 0;
LED_DCH = &LED1_DC; // point to the play LED's duty cycle
// address
Dim_LED (); // dim off the play LED
}
}
}
// ERASE button pressed
if (ERASE == 0)
{
// do nothing if the device is currently recording or playing
// ignore the ERASED and END_MEM bits
if ((system_state & 0x03) == IDLE)
{
// Indicate to the user that the microcontroller is busy
LED_DCH = &LED1_DC;
Brighten_LED ();
LED_DCH = &LED0_DC;
Brighten_LED ();
rec_end_addr = 0x00000000; // reset the counter
system_state |= ERASED; // set the erase bit
Erase_MEM (); // erase the external SST Flash
LED_DCH = &LED1_DC;
Dim_LED ();
LED_DCH = &LED0_DC;
Dim_LED ();
}
switch_pressed_flag = 1; // record the user interaction
}
if (switch_pressed_flag == 0)
{
// check if the recorder is sitting and idle
// ignore the ERASED and END_MEM bits
if ((system_state & 0x03) == IDLE)
{
suspend_counter++;
// if no interaction occurs in 5 seconds, enter suspend mode
if (suspend_counter == 320)
{
suspend_counter = 0;
ENTER_SUSPEND = 1;
}
}
}
else
{
suspend_counter = 0; // reset the SUSPEND mode counter
// if the user is interacting with the
// recorder
reload_value = PRCHANGE; // interrupt again in 150 ms
}
// reload the timer for the next interrupt
TL1 = (-reload_value) & 0x00FF;
TH1 = ((-reload_value) & 0xFF00) >> 8;
}
//-----------------------------------------------------------------------------
// ADC0_ISR
//-----------------------------------------------------------------------------
//
// Handle the 8kHz Timer 2 interrupt.
//
// Timer 2 controls the rate at which the ADC samples the input (RECORD).
//
void ADC0_ISR (void) interrupt 10 using 2
{
// RECORD
// DPCM variables
static data unsigned short predicted_value = mid_range;
static data unsigned char packed_code = 0x00;
data unsigned char dpcm_code = 0x00;
// indicates how the current dpcm_code should be packed to be sent to memory
// sample 1 dpcm_code = A, sample 2 dpcm_code = B, sample 3 dpcm_code = C
// sample 4 dpcm_code = D, sample 5 is the same as sample 1, etc
// [A|A|A|A|A|A|B|B] = byte 1
// [B|B|B|B|C|C|C|C] = byte 2
// [C|C|D|D|D|D|D|D] = byte 3
static unsigned char state = 0;
static short sample = 0x0000;
AD0INT = 0; // clear the interrupt flag
// check if the memory was erased
if ((system_state & ERASED) == ERASED)
{
system_state &= ~ERASED; // clear the erased bit
predicted_value = mid_range; // reset the dpcm predictor
state = 0; // reset the packing state machine
}
// check for the end of memory
if (rec_end_addr == MAX_MEM_ADDR)
{
TR2 = 0; // turn off T2
MEM_END_NEAR_FLAG = 0;
MEM_END_FLAG = 1; // tell the T1 ISR to turn off the LED
predicted_value = mid_range; // reset the dpcm predictor
state = 0; // reset the state machine
}
else
{
// check if the REC_PLAY switch was released and the recording should
// stop
if (ADC_STOP_FLAG == 1)
{
TR2 = 0; // turn off T2
ADC_STOP_FLAG = 0; // reset the flag
// do not reset the state or the predicted_value variables here
// the playback ISR doesn't know when a recording starts or ends,
// so it will also not reset the state and predicted_value
}
// take the sample, average it, compress it, and send it to memory
else
{
// since 16 samples are automatically accumulated by the ADC,
// average them by dividing by 16 (right shifting by 4)
sample = (ADC0DAT >> 4) & 0x0FFF;
// calculate the difference between the sample and the predictor
// and compress the sample to a 6-bit DPCM code
dpcm_code = DPCM_Encode ((sample - predicted_value));
// pack the DPCM code into the bytes sent to the Flash memory
switch (state)
{
// state machine: 0 -> 1 -> 2 -> 3
// ^______________|
case 0:
// move the DPCM code into the 6 high bits
// [A|A|A|A|A|A| | ] = byte 1
packed_code = (dpcm_code << 2) & 0xFC;
state = 1;
break;
case 1:
// move the DPCM code into the 2 low bits
// of the previously packed byte
// [-|-|-|-|-|-|B|B] = byte 1
packed_code |= (dpcm_code >> 4) & 0x03;
Write_MEM (rec_end_addr, packed_code);
rec_end_addr++;
// move the rest of the DPCM code into the
// 4 high bits of the next packed byte
// [B|B|B|B| | | | ] = byte 2
packed_code = (dpcm_code << 4) & 0xF0;
state = 2;
break;
case 2:
// move the next DPCM code into the
// 4 low bits of the previously packed byte
// [-|-|-|-|C|C|C|C] = byte 2
packed_code |= (dpcm_code >> 2) & 0x0F;
Write_MEM (rec_end_addr, packed_code);
rec_end_addr++;
// move the rest of the DPCM code into the
// 2 high bits of the next packed byte
// [C|C| | | | | | ] = byte 3
packed_code = (dpcm_code << 6) & 0xC0;
state = 3;
break;
case 3:
// move the next DPCM code into the
// 6 low bits of the previously packed byte
// [-|-|D|D|D|D|D|D] = byte 3
packed_code |= dpcm_code & 0x3F;
Write_MEM (rec_end_addr, packed_code);
rec_end_addr++;
state = 0;
break;
default:
state = 0;
break;
}
// indicate that the T1 ISR should flutter the LED, since the end of
// memory is close
if (rec_end_addr == NEAR_END_ADDR)
{
MEM_END_NEAR_FLAG = 1;
}
// update the predictor for the next sample
predicted_value += DPCM_Decode (dpcm_code);
}
}
}
//-----------------------------------------------------------------------------
// Timer3_ISR
//-----------------------------------------------------------------------------
//
// Handle the 8kHz Timer 3 interrupt.
//
// Timer 3 controls the rate at which the DAC outputs decompressed samples
// (PLAY).
//
void Timer3_ISR(void) interrupt 14 using 2
{
// PLAY
// next unwritten address
static unsigned long current_play_addr = 0x00000000;
// DPCM variables
static unsigned short predicted_value = mid_range;
static unsigned char packed_code = 0x00;
unsigned char dpcm_code = 0x00;
// indicates how the current dpcm_code should be unpacked when retrieved
// from memory
// sample 1 dpcm_code = A, sample 2 dpcm_code = B, sample 3 dpcm_code = C
// sample 4 dpcm_code = D, sample 5 is the same as sample 1, etc
// [A|A|A|A|A|A|B|B] = byte 1
// [B|B|B|B|C|C|C|C] = byte 2
// [C|C|D|D|D|D|D|D] = byte 3
static unsigned char state = 0;
TMR3CN &= 0x7F; // clear the T3 interrupt flag
// check if the PLAY switch was pressed and playing should stop
if (DAC_STOP_FLAG == 1)
{
TMR3CN = 0x00; // turn off T3
DAC_STOP_FLAG = 0; // reset the flag
current_play_addr = 0x00000000; // start at the beginning address
predicted_value = mid_range; // reset the predictor
state = 0; // reset the playback state machine
}
else
{
// check for the end of the recording
if (current_play_addr >= rec_end_addr)
{
TMR3CN = 0x00; // turn off the timer
REC_END_FLAG = 1; // tell the T1 ISR to turn off the LED
current_play_addr = 0x00000000;
predicted_value = mid_range; // reset the predictor
state = 0; // reset the playback state machine
}
else
{
// unpack the DPCM code bytes retrieved from memory
switch (state)
{
// state machine: 0 -> 1 -> 2 -> 3
// ^______________|
case 0:
packed_code = Read_MEM (current_play_addr);
current_play_addr++;
// take the DPCM code from the 6 high bits
// [A|A|A|A|A|A| | ] = byte 1
dpcm_code = (packed_code >> 2) & 0x3F;
state = 1;
break;
case 1:
// take the next DPCM code from the 2 low bits
// of the previously retrieved byte
// [-|-|-|-|-|-|B|B] = byte 1
dpcm_code = (packed_code << 4) & 0x30;
packed_code = Read_MEM (current_play_addr);
current_play_addr++;
// take the rest of the DPCM code from the
// 4 high bits of the next retrieved byte
// [B|B|B|B| | | | ] = byte 2
dpcm_code |= (packed_code >> 4) & 0x0F;
state = 2;
break;
case 2:
// take the next DPCM code from the
// 4 low bits of the previously retrieved byte
// [-|-|-|-|C|C|C|C] = byte 2
dpcm_code = (packed_code << 2) & 0x3C;
packed_code = Read_MEM (current_play_addr);
current_play_addr++;
// take the rest of the DPCM code from the
// 2 high bits of the next retrieved byte
// [C|C| | | | | | ] = byte 3
dpcm_code |= (packed_code >> 6) & 0x03;
state = 3;
break;
case 3:
// take the next DPCM code from the
// 6 low bits of the previously retrieved byte
// [-|-|D|D|D|D|D|D] = byte 3
dpcm_code = packed_code & 0x3F;
state = 0;
break;
default:
state = 0;
break;
}
// calculate the new predicted value
predicted_value += DPCM_Decode (dpcm_code);
// output the new sample to the speaker
IDA0DAT = predicted_value;
// overwrite the very last sample so the output is at the mid-range
// when stopped
// the discontinuity causes a small "clicking" sound when playback
// starts and stops
if (current_play_addr >= rec_end_addr)
{
IDA0DAT = mid_range;
}
}
}
}
//-----------------------------------------------------------------------------
// End Of File
//-----------------------------------------------------------------------------
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -