⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 exercise-8.c

📁 TI MSP430针对cap sense 按键的源码, 可实现单击或滑动键, 如IPOD上的人机接口.
💻 C
字号:
/* Exercise 8

    The simple voice recorder from exercise 6, modified to use a low-complexity ADPCM codec to
    quadruple the storage time.
*/
#include <stdint.h>
#include <msp430xG43x.h>

#define AUDIO_MEM_START     0x2000
#define AUDIO_MEM_END       0xFE00

typedef struct
{
    int16_t last;
    int16_t step_index;
} adpcm_state_t;

/* ADPCM working data */
adpcm_state_t state;
uint16_t adpcm_val = 0;
int16_t adpcm_nibble = 0;

/* Routines to convert 12 bit linear samples to the ADPCM coding format
   originated by Oki, and widely used in CTI. */
static const int16_t step_size[49] =
{
      16,   17,   19,   21,   23,   25,   28,   31,
      34,   37,   41,   45,   50,   55,   60,   66,
      73,   80,   88,   97,  107,  118,  130,  143,
     157,  173,  190,  209,  230,  253,  279,  307,
     337,  371,  408,  449,  494,  544,  598,  658,
     724,  796,  876,  963, 1060, 1166, 1282, 1408,
    1552
};

static const int16_t step_adjustment[8] =
{
    -1, -1, -1, -1, 2, 4, 6, 8
};

/* Decode the lower 4 bits of "adpcm" */
int16_t adpcm_decode(uint8_t adpcm)
{
    int16_t e;
    int16_t ss;
    int16_t linear;

    ss = step_size[state.step_index];
    e = ss >> 3;
    if (adpcm & 0x01)
        e += (ss >> 2);
    /*endif*/
    if (adpcm & 0x02)
        e += (ss >> 1);
    /*endif*/
    if (adpcm & 0x04)
        e += ss;
    /*endif*/
    if (adpcm & 0x08)
        e = -e;
    /*endif*/
    linear = state.last + e;

    /* Saturate the values to +/- 2^11 (supposed to be 12 bits) */
    if (linear > 2047)
        linear = 2047;
    else if (linear < -2048)
        linear = -2048;
    /*endif*/

    state.last = linear;
    state.step_index += step_adjustment[adpcm & 0x07];
    if (state.step_index < 0)
        state.step_index = 0;
    else if (state.step_index > 48)
        state.step_index = 48;
    /*endif*/
    /* Note: the result here is a 12 bit value */
    return  linear;
}

/* Encode to a 4 bit ADPCM value */
uint8_t adpcm_encode(int16_t linear)
{
    int16_t e;
    int16_t ss;
    uint8_t adpcm;

    /* Saturate the values to +/- 2^11 (supposed to be 12 bits) */
    if (linear > 2047)
        linear = 2047;
    else if (linear < -2048)
        linear = -2048;
    /*endif*/

    ss = step_size[state.step_index];
    e = linear - state.last;
    adpcm = (uint8_t) 0x00;
    if (e < 0)
    {
        adpcm = (uint8_t) 0x08;
        e = -e;
    }
    /*endif*/
    if (e >= ss)
    {
        adpcm |= (uint8_t) 0x04;
        e -= ss;
    }
    /*endif*/
    if (e >= (ss >> 1))
    {
        adpcm |= (uint8_t) 0x02;
        e -= ss;
    }
    /*endif*/
    if (e >= (ss >> 2))
        adpcm |= (uint8_t) 0x01;
    /*endif*/

    /* Use the decoder to set the estimate of the last sample. */
    /* It also will adjust the step_index for us. */
    state.last = adpcm_decode(adpcm);
    return  adpcm;
}

/* Initialise the ADPCM state */
void adpcm_init(void)
{
    state.last = 0;
    state.step_index = 0;
}

int16_t *ptr;

void record(void)
{
    long int i;

    /* Set up timer A to kick the ADC at 6.5536kHz, which will be our audio
     * sampling rate. */
    TAR = 0;
    TACCR0 = 5 - 1;
    TACCR1 = 5 - 2;
    TACCTL0 = 0;
    TACCTL1 = OUTMOD_3;
    TACTL = TACLR | MC_1 | TASSEL_1;

    /* Make the earpiece pins outputs driven to 0, to power the mic */
    P6SEL &= ~(BIT5 | BIT3);
    P6DIR |= (BIT5 | BIT3);
    P6OUT &= ~(BIT5 | BIT3);

    /* Set up the mic amp */
    /* Input 0 is the mic signal.
     * Output goes to the feedback resistor.
     * We want a general purpose amp.
     * We want DAC1 to bias the +ve input of the amp.
     * We want the amp in high performance mode. */
    P6SEL |= (BIT1 | BIT0);
    OA0CTL0 = OAN_0 | OAP_3 | OAPM_3 | OAADC1;
    OA0CTL1 = OAFC_0;
    /* Second amplifier stage */
    OA1CTL0 = OAN_2 | OAP_3 | OAPM_3 | OAADC0;              // -ve=OA1I0, +ve=DAC1
    OA1CTL1 = OAFC_6 | OAFBR_4;

    /* Must disable conversion while reprogramming the ADC */
    ADC12CTL0 &= ~ENC;
    ADC12CTL0 = ADC12ON | SHT0_4 | REFON | REF2_5V;         // Turn on the ADC12, and set the sampling time
    ADC12CTL1 = SHP | SHS_1 | CONSEQ_2;                     // Use sampling timer, single sample repeating, TA1 trigger
    ADC12MCTL0 = INCH_13 | SREF_1;                          // ref += Vref, channel = A13 = OA1
    ADC12IE = BIT0;
    ADC12IFG = 0x00;

    /* Configure DAC 1 to provide bias for the mic amplifier */
    P6SEL |= BIT7;
    DAC12_1CTL = DAC12CALON | DAC12IR | DAC12AMP_7 | DAC12ENC;
    DAC12_1DAT = 0x800;

    for (ptr = (int16_t *) AUDIO_MEM_START;  ptr != (int16_t *) AUDIO_MEM_END;  ptr += 0x100)
    {
        FCTL3 = FWKEY;                  /* Lock = 0 */
        FCTL1 = FWKEY | ERASE;
        *ptr = 0;                       /* Erase flash segment */
        FCTL1 = FWKEY;                  /* Erase, write = 0 */
        FCTL3 = FWKEY | LOCK;
    }

    adpcm_init();
    adpcm_val = 0;
    adpcm_nibble = 0;

    /* Wait for the mic amp to settle */
    for (i = 150000;  i > 0;  i--)
        _NOP();

    /* Set the recording off, and wait in LPM0 for it to complete */
    _EINT();
    P1OUT |= BIT0;                      /* Turn on the LED */
    ADC12CTL0 |= ENC;
    ptr = (int16_t *) AUDIO_MEM_START;
    for (;;)
    {
        _BIS_SR(LPM0_bits);
        _NOP();
        if (ptr >= (int16_t *) AUDIO_MEM_END)
            break;
    }
    ADC12CTL0 &= ~ENC;
    P1OUT &= ~BIT0;                     /* Turn off the LED */
    _DINT();
}

void play(void)
{
    /* Ensure the ADC12 is not running, but is providing the reference
       voltage for the DAC12. */
    ADC12CTL0 &= ~ENC;
    ADC12CTL0 = ADC12ON | REFON | REF2_5V;
    ADC12IE = 0;
    ADC12CTL0 |= ENC;

    /* Set up timer A to kick the DAC at 6.5536kHz, which will be our audio
     * sampling rate. */
    TAR = 0;
    TACCR0 = 5 - 1;
    TACCR1 = 5 - 2;
    TACCTL0 = CCIE;
    TACCTL1 = OUTMOD_3;
    TACTL = TACLR | MC_1 | TASSEL_1;

    /* Make a differential drive for the earpiece */
    P6SEL |= (BIT5 | BIT3);
    /* Chain two amps to make an inverting buffer with a gain of one */
    OA0CTL0 = OAP_2 | OAPM_3;
    OA0CTL1 = OAFC_1;
    OA1CTL0 = OAN_2 | OAP_3 | OAPM_3 | OAADC1;
    OA1CTL1 = OAFC_6 | OAFBR_2;
    /* Use the third amp as a non-inverting buffer with a gain of one */
    OA2CTL0 = OAP_2 | OAPM_3 | OAADC1;
    OA2CTL1 = OAFC_1;

    /* Configure DAC0 to provide the audio signal for the earpiece amp.
       The data will be latched by TACCR1 */
    DAC12_0CTL = DAC12CALON | DAC12IR | DAC12AMP_7 | DAC12ENC | DAC12LSEL_2;
    DAC12_0DAT = 0x800;
    /* Configure DAC1 to provide a bias signal for the inverting PGA */
    DAC12_1CTL = DAC12CALON | DAC12IR | DAC12AMP_7 | DAC12ENC;
    DAC12_1DAT = 0x800;

    adpcm_init();
    adpcm_val = 0;
    adpcm_nibble = 0;

    _EINT();
    ptr = (int16_t *) AUDIO_MEM_START;
    for (;;)
    {
        _BIS_SR(LPM0_bits);
        _NOP();
        //if (ptr >= (int16_t *) AUDIO_MEM_END)
        //    break;
    }
    _DINT();
}

void main(void)
{
    WDTCTL = WDTPW | WDTHOLD;       // Stop watchdog timer

    SCFI0 = FN_3 | FLLD_4;
    FLL_CTL0 = XCAP18PF;            // set load capacitance for xtal
    SCFQCTL = 64 - 1;               // 256*32768Hz = 8.388608MHz
    FLL_CTL0 |= DCOPLUS;

    P1DIR = 0xE7;                   // All P1.x outputs
    P1OUT = 0;                      // All P1.x reset
    P2DIR = 0x00;                   // All P2.x outputs
    P2OUT = 0;                      // All P2.x reset
    P3DIR = 0xFF;                   // All P3.x outputs
    P3OUT = 0;                      // All P3.x reset
    P4DIR = 0xFF;                   // All P4.x outputs
    P4OUT = 0;                      // All P4.x reset
    P5DIR = 0xFF;                   // All P5.x outputs
    P5OUT = 0;                      // All P5.x reset
    P6DIR = 0xFF;                   // All P6.x outputs
    P6OUT = 0;                      // All P6.x reset

    /* Configure UART0 */
    UCTL0 = CHAR;                   /* 8-bit character */
    UTCTL0 = SSEL1;                 /* UCLK = SMCLK */
    UBR00 = 72;                     /* 115200 bps, based on the 256*32768Hz clock */
    UBR10 = 0;
    UMCTL0 = 0x7F;
    P2SEL |= (BIT5 | BIT4);
    U0ME |= UTXE0;                  /* Enable only USART0 TXD */

    record();

    for (;;)
        play();
    _NOP();
}

#pragma vector=ADC_VECTOR
__interrupt void adc_interrupt(void)
{
    int16_t val;

    val = ADC12MEM0;

    if (ptr < (int16_t *) AUDIO_MEM_END)
    {
        adpcm_val <<= 4;
        adpcm_val |= adpcm_encode(val - 0x800);
        if (++adpcm_nibble == 4)
        {
            FCTL3 = FWKEY;                      /* Lock = 0 */
            FCTL1 = FWKEY | WRT;
            *ptr++ = adpcm_val;                 /* Write to the flash */
            FCTL1 = FWKEY;                      /* Erase, write = 0 */
            FCTL3 = FWKEY | LOCK;
            adpcm_nibble = 0;
        }
        val >>= 4;
        TXBUF0 = val;
    }
    else
    {
        _BIC_SR_IRQ(LPM3_bits);
    }
}

#pragma vector=TIMERA0_VECTOR
__interrupt void timera_interrupt(void)
{
    int16_t val;

    if (ptr >= (int16_t *) AUDIO_MEM_END)
    {
        adpcm_init();
        ptr = (int16_t *) AUDIO_MEM_START;
    }
    if (ptr < (int16_t *) AUDIO_MEM_END)
    {
        if (++adpcm_nibble == 4)
        {
            adpcm_val = *ptr++;
            adpcm_nibble = 0;
        }
        val = adpcm_decode((adpcm_val >> 12) & 0xF);
        adpcm_val <<= 4;
        val += 0x800;
        DAC12_0DAT = val;

        val >>= 4;
        TXBUF0 = val;
    }
    else
    {
        _BIC_SR_IRQ(LPM3_bits);
    }
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -