📄 lab-02-mucic.c
字号:
//******************************************************************************
// MSP430FG4619/F2013 Experimenter's Board - Voice Recorder Demo
//
// This software demonstrates voice recording and playback using an
// MSP430FG4619 MCU. Audio is recorded and stored using in-system self-
// programming into Flash memory until the entire device memory is
// filled with audio data. Both recording and playback are implemented
// using the DMA controller - allowing the CPU to be switched off (LPM0)
// during this entire process.
//
// ACLK = 32.768kHz, MCLK = SMCLK = DCO = default FLL = 1.048576MHz
//
// MSP430FG4619
// ------------------
// /|\| XIN|-
// | | | 32kHz
// --|RST XOUT|-
// | |
// Audio Out<--|P6.5/OA2O P5.1|-->LED
// Sallen-Key <--|P6.7/DAC1 |
// Low-Pass Filter <--|P6.3/OA1O S4|--> +-------------+
// Circuitry -->|P6.4/OA1I0 ...|--> | LCD DISPLAY |
// | S25|--> +-------------+
// VCC_Mic<--|P2.3 |
// Microphone -->|P6.0/OA0I0 P1.0|<--SW1 (Record Button)
// Circuitry -->|P6.2/OA0I1 P1.1|<--SW2 (Playback Button)
// <--|P6.1/OA0O |
//
// NOTE: Refer to the MSP430FG4619/F2013 Experimenter's Board schematic
// for details on the external circuitry.
//
// A. Dannenberg
// Texas Instruments Inc.
// Ver 1.00 - October 2006
// Built with IAR Embedded Workbench Version: 3.42A
//******************************************************************************
#include "msp430xG46x.h"
#define Memstart 0x6000 // Memory1 起始地址
#define Memend 0xfc00 // Memory1 结束地址
#define Memstart2 0x10000 // Memory2 起始地址
#define Memend2 0x20000 // Memory2 结束地址
#define SamplePrd 118 // 设置录音时间
#define SEG_A 0x01 // LCD段码定义
#define SEG_B 0x02
#define SEG_D 0x04
#define SEG_G 0x08
#define SEG_C 0x10
#define SEG_F 0x20
#define SEG_H 0x40
#define SEG_E 0x80
__root unsigned int DMA2CTL_Const_R = DMADSTINCR_3 + DMAEN + DMAIE;
// 单一传输模式 ,目的地址增加
// 边沿触发 使能DMA
__root const unsigned int DMA2CTL_Const_P = DMASRCINCR_3 + DMAEN + DMAIE;
// S单一传输模式 源地址增加
//边沿触发 使能DMA
void Record(void);
void Playback(void);
void Erase(void);
void main(void)
{
volatile unsigned int i;
WDTCTL = WDTPW + WDTHOLD; // 关看门狗
FLL_CTL0 |= XCAP14PF; // 设置匹配电容
do
{
IFG1 &= ~OFIFG; // 清晶振失效标志位
for (i = 0x47FF; i > 0; i--); // 延时
}
while (IFG1 & OFIFG); // 晶振失效标志位仍存在?
P1OUT = 0; // 所有 P1.x 输出低
P1IE = 0x03; // P1.0, P1.1 中断使能
P1IES = 0x03; // P1.0, P1.1 下降沿触发
P1DIR = 0xFC; // P1.0/1 输入
P2OUT = 0; // 所有 P2.x 输出低
P2DIR = 0xDF; // UCA0RXD
P3OUT = 0x20; // P3.5 接蜂鸣器
P3DIR = 0xF9; // I2C
P4OUT = 0; // 所有 P4.x 输出低
P4DIR = 0xFF; // P4.x 输出方向
P5OUT = 0; // 所有 P5.x 输出低
P5SEL = 0x1C; // P5.2/3/4 = LCD COM
P5DIR = 0xFF; // P5.x 输出方向
P6OUT = 0; // 所有 P6.x 输出低
P6SEL = 0xBF; // P6.6 OA
P6DIR = 0xFF; // P6.x 输出方向
P7OUT = 0; // 所有 P7.x 输出低
P7DIR = 0xFF; // P7.x 输出方向
P8OUT = 0; // 所有 P8.x 输出低
P8DIR = 0xFF; // P8.x 输出方向
P9OUT = 0; // 所有 P9.x 输出低
P9DIR = 0xFF; // P9.x 输出方向
P10OUT = 0; // 所有 P10.x 输出低
P10DIR = 0xFF; // P10.x 输出方向
for (i = 19; i > 0; i--) LCDMEM[i] = 0; // 清 LCD
LCDACTL = LCDON + LCD4MUX + LCDFREQ_128; // 4mux LCD, ACLK/128
LCDAPCTL0 = 0x7E; // 段 S4-S27
while (1)
{
P1IFG &= ~0x03; // 清中断标志
P1IE |= 0x03; // 中断使能
__bis_SR_register(LPM4_bits + GIE);
__disable_interrupt();
if (P1IFG & 0x02) // S1按下
Record();
else if (P1IFG & 0x01) // S2按下
Playback();
}
}
void Record(void)
{
P5OUT |= 0x02; // LED4 亮
P2OUT |= 0x08; // 麦克风
OA0CTL0 = OAP_1 + OAPM_3; // 反向输入, fast模式
OA0CTL1 = OARRIP; // 输入信号范围有限
ADC12CTL0 = ADC12ON; // 打开 ADC12
ADC12CTL1 = SHS_3 + CONSEQ_2; // Timer_B.OUT1触发,单通道序列采样
ADC12IFG = 0x00; // 清ADC12 中断标志位
ADC12MCTL0 = 0x0001; // 输入通道 A1
ADC12CTL0 |= ENC; // 使能转换
TBCTL = TBSSEL_2; // SMCLK 作为 Timer_B时钟源
TBR = 0;
TBCCR0 = SamplePrd; // 初始化 TBCCR0
TBCCR1 = SamplePrd - 20; // 触发 ADC12
TBCCTL1 = OUTMOD_7; // 复位/置位
DMACTL0 = DMA2TSEL_6 + // ADC12IFGx 触发 DMA2
DMA1TSEL_14 + // DMA0IFG 触发 DMA1
DMA0TSEL_6; // ADC12IFGx 触发 DMA0
DMA0SA = (unsigned int)&ADC12MEM0; // DMA操作起始地址
DMA0DA = Memstart; // DMA操作结束地址
DMA0SZ = (Memend - Memstart) >> 1; // 长度
DMA0CTL = DMADSTINCR1 + DMADSTINCR0 + DMAEN;
// 单一传输 目的地址增加
// 边沿触发 使能 DMA
DMA1SA = (unsigned int)&DMA2CTL_Const_R; // 源地址
DMA1DA = (unsigned int)&DMA2CTL; //目的地址
DMA1SZ = 1; // 长度
DMA1CTL = DMAEN; // 单一传输 使能DMA
DMA2SA = (unsigned int)&ADC12MEM0; // 源地址
__data16_write_addr((unsigned short)&DMA2DA, Memstart2);
// 目的地址
DMA2SZ = (Memend2 - Memstart2) >> 1;
FCTL2 = FWKEY + FSSEL1 + FN1; // 时钟 SMCLK/3 = ~333kHz
FCTL3 = FWKEY; // 写操作
Erase(); // 调用写flash程序
FCTL1 = FWKEY + WRT; // 写flash
LCDM8 = SEG_A + SEG_B + SEG_C + SEG_E + SEG_F + SEG_G; // "R"
LCDM7 = SEG_A + SEG_D + SEG_E + SEG_F + SEG_G; // "E"
LCDM6 = SEG_A + SEG_D + SEG_E + SEG_F; // "C"
LCDM5 = 0x00; // " "
LCDM4 = 0x00; // " "
P1OUT |= 0x01; // LED4 亮
TBCTL |= MC0; // Timer_B 增计数模式
__bis_SR_register(LPM0_bits + GIE); // 中断使能 ,进入LPM0
__disable_interrupt(); // 关中断
FCTL1 = FWKEY; // 结束写flash操作
FCTL3 = FWKEY + LOCK; // 锁flash
ADC12CTL1 &= ~CONSEQ_2; // 立即停止ADC采样
ADC12CTL0 &= ~ENC; // 禁止ADC12转换
ADC12CTL0 = 0; // 关 ADC12 、参考电压
TBCTL = 0; // 关 Timer_B
OA0CTL0 = 0; // 关 OA0
P2OUT &= ~0x08; // 关麦克风
P5OUT &= ~0x02; // LED4 灭
LCDM8 = 0x00; // " "
LCDM7 = 0x00; // " "
LCDM6 = 0x00; // " "
}
void Playback(void)
{
volatile unsigned int i;
LCDM8 = SEG_A + SEG_B + SEG_E + SEG_F + SEG_G; // "P"
LCDM7 = SEG_D + SEG_E + SEG_F; // "L"
LCDM6 = SEG_A + SEG_B + SEG_C + SEG_E + SEG_F + SEG_G; // "A"
LCDM5 = SEG_B + SEG_C + SEG_D + SEG_F + SEG_G; // "Y"
LCDM4 = 0x00; // " "
P5OUT |= 0x02; // LED4 亮
DAC12_0CTL = DAC12IR + DAC12AMP_2 + DAC12ENC + DAC12OPS;
DAC12_0DAT = 0x057F;
OA1CTL0 = OAPM_3 + OAADC1; // Sfast模式
OA1CTL1 = OAFC_1 + OARRIP; // rail-to-rail 输入
OA2CTL0 = OAN_2 + OAP_2 + OAPM_3 + OAADC1;// Sfast模式 内部DAC0
OA2CTL1 = OAFC_6 + OAFBR_2 + OARRIP; // 反向比例放大
ADC12CTL0 = REFON + REF2_5V; // ADC12 参考电压2.5V
DAC12_1CTL = DAC12IR + DAC12AMP_7 + DAC12LSEL_3 + DAC12ENC;
// 设置 DAC12T imer_B.OUT2
for (i = 0; i < 0x3fff; i++); // 等待参考电压稳定
TBCTL = TBSSEL_2; // SMCLK 作为 Timer_B 时钟源
TBCCR0 = SamplePrd; // 初始化 TBCCR0
TBCCR2 = SamplePrd >> 1; // EQU2 触发 DMA
TBCCTL2 = OUTMOD_7; // 复位/置位
DMACTL0 = DMA2TSEL_2 + // Timer_B.CCIFG2 触发 DMA2
DMA1TSEL_14 + // DMA0IFG 触发 DMA1
DMA0TSEL_2; // Timer_B.CCIFG2 触发 DMA0
DMA0SA = Memstart; // 源地址
DMA0DA = (unsigned int)&DAC12_1DAT; // 目的地址
DMA0SZ = (Memend - Memstart) >> 1; // DMA 大小
DMA0CTL = DMASRCINCR1 + DMASRCINCR0 + DMAEN;
// 单一传输 源地址增加 使能DMA
DMA1SA = (unsigned int)&DMA2CTL_Const_P; // 源地址
DMA1DA = (unsigned int)&DMA2CTL; // 目的地址
DMA1SZ = 1; // 长度
DMA1CTL = DMAEN; // 使能DMA
__data16_write_addr((unsigned short)&DMA2SA, Memstart2);
DMA2DA = (unsigned int)&DAC12_1DAT;
DMA2SZ = (Memend2 - Memstart2) >> 1;
TBCTL |= MC0; // Timer_B 增计数模式
__bis_SR_register(LPM0_bits + GIE); // 中断使能 进入 LPM0
__disable_interrupt(); // 关中断
TBCTL = 0; // 关 Timer_B
ADC12CTL0 = 0; // 关ADC12
DAC12_0CTL &= ~DAC12ENC; // 禁止 DAC12 转换
DAC12_0CTL = 0; // 关 DAC12
DAC12_1CTL &= ~DAC12ENC; // 禁止 DAC12 转换
DAC12_1CTL = 0; // 关 DAC12
OA1CTL0 = 0; // 关 OA1
OA2CTL0 = 0; // 关 OA2
P5OUT &= ~0x02; // LED4 灭
LCDM8 = 0x00; // " "
LCDM7 = 0x00; // " "
LCDM6 = 0x00; // " "
LCDM5 = 0x00; // " "
}
void Erase(void)
{
unsigned int Ptr = Memstart;
unsigned long FarPtr = Memstart2;
LCDM8 = SEG_A + SEG_D + SEG_E + SEG_F + SEG_G; // "E"
LCDM7 = SEG_E + SEG_G; // "R"
LCDM6 = SEG_A + SEG_B + SEG_C + SEG_E + SEG_F + SEG_G; // "A"
LCDM5 = SEG_A + SEG_C + SEG_D + SEG_F + SEG_G; // "S"
LCDM4 = SEG_A + SEG_D + SEG_E + SEG_F + SEG_G; // "E"
do
{
if (Ptr & 0x1000)
P5OUT |= 0x02;
else
P5OUT &= ~0x02;
FCTL1 = FWKEY + ERASE;
*(unsigned char *)Ptr = 0x00; // 空写 段擦除
Ptr += 0x0200; //指向下一段
}
while (Ptr < Memend);
do
{
if (FarPtr & 0x1000)
P5OUT |= 0x02;
else
P5OUT &= ~0x02;
FCTL1 = FWKEY + ERASE;
__data20_write_char(FarPtr, 0x00); //空写 段擦除
FarPtr += 0x0200; // 指向下一段
}
while (FarPtr < Memend2);
}
#pragma vector=PORT1_VECTOR
__interrupt void Port1_ISR (void)
{
P1IE &= ~0x03; // 关中断
__bic_SR_register_on_exit(LPM4_bits); //退出低功耗
}
#pragma vector=DMA_VECTOR
__interrupt void DMA_ISR(void)
{
DMA2CTL &= ~DMAIFG; // 清 DMA2 中断标志
__bic_SR_register_on_exit(LPM0_bits); // 退出低功耗
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -