This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[参考译文] MSP430FR2355:具有计时器触发器的 MSP430FR2355多通道 ADC 不工作

Guru**** 2519150 points
Other Parts Discussed in Thread: MSP430FR2355, MATHLIB

请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/912792/msp430fr2355-msp430fr2355-multiple-channel-adc-with-timer-trigger-not-working

器件型号:MSP430FR2355
主题中讨论的其他器件: MATHLIB

大家好、

IAM 尝试使用 MSP430FR2355 Launchpad 的 ADC 使用计时器触发器对两个 SAC (即 SAC0和 SAC2)的输出进行采样。

根据 Launchpad 的用户指南、OA0 OUT 可在内部连接到 ADC 输入、OA20 OUT 需要在外部连接到 ADC 输入。

我已按照这些示例操作、并尝试编写以下代码、如图所示  

/******* SAC0配置 /
P1SEL0 |= BIT1|BIT2; //选择 P1.2 P1.1作为 OA0输出 OA0-引脚功能
P1SEL1 |= BIT1 | BIT2; //选择 P1.2 OA0-引脚功能

SAC0DAC = DACSREF_1; //选择2.5V 内部 Vref 作为 DAC 基准
SAC0DAT = 2048; //将 SAC DAC 数据设置为1.25V
SAC0DAC |= DACEN; //启用 DAC
SAC0OA |= NMUXEN | PMUXEN | PSEL_1 | NSEL_0;//选择正输入作为 DAC、选择负引脚输入作为外部
// SAC0PGA |= MSEL_0; //反相 PGA 模式
SAC0OA &=~OAPM; //选择高速和高功率模式
SAC0OA |= SACEN + OAEN; //启用 SAC 和 OA

/********* SAC2配置为反相 PGA ***** /
P3SEL0 |= BIT1; //选择 P3.1 OA2输出功能
P3SEL1 |= BIT1; //选择 P3.1 OA2输出功能

SAC2DAC = DACSREF_1; //选择2.5V 内部 Vref 作为 DAC 基准
SAC2DAT = 2048; // DAC 为放大器提供偏置
SAC2DAC |= DACEN; //启用 DAC
SAC2OA |= NMUXEN | PMUXEN | PSEL_1 | NSEL_1;//选择正输入作为 DAC、选择负引脚输入作为 OA0的 O/P
SAC2PGA |= GAIN0 + GAIN2 + MSEL_3;//设置增益= 16的反相 PGA 模式
SAC2OA &=~OAPM; //选择高速和高功率模式
SAC2OA |= SACEN | OAEN;//启用 SAC 和 OA 
/*** ADC 配置*** / ADCCTL0 &=~ADCENC; //禁用 ADC ADCCTL0 |= ADCSHT_4 | ADCMSC | ADCON;//0000010010010;64个 ADCLK 周期、MSC 位高电平、ADC 打开 ADCCTL1 |= ADCSHP | ADCSHS_1 | ADCCONSEQ_1_ADCSSEL_1;//0000010010010010; ADCCTL2 &=~ADCRES;//清除分辨率 ADCCTL2 |= ADCRES_2;//12位分辨率 ADCMCTL0 |= ADCSREF_1|ADCINCH_1|ADCINCH_3;// OA0输出作为 A1 ADC 输入,VR+= VREF+,OA2输出从外部连接到 A3 ADC 输入 ADCIE |= ADCIE0;//启用转换完成中断 __enable_interrupt ();//启用可掩码 /******** 配置计时器 / TB0CTL = TBSSEL_ACLK + TBCLR;//ACLK 和复位定时器 TB0CCTL1 = OUTMOD_2;//切换和复位 TB0CCTL0 = CCIE;//中断使能 TB0CCR0 = 31;//采样率为512SPS TB0CCR1 = 10;//在采样前留出足够的时间使信号变得稳定 TB0CTL |= MC_1;//向上计数模式 ADCCTL0 |= ADCENC;//启用转换并在 (1) { } //在主函数 #if defined (__TI_Compiler_version__)||Defined (__IAR_systems_ICC__) #pragma vector=ADC_vector __interrupt #ADC_ISR ( supported)#Elif Compiler_version__(supporteded)#elif_void (void)(void)_ adc_agc (void)(void)(void)(void _transl_interrupt! #endif { ADCIFG &=~ADCIFG0;//清除中断标志 } //主引脚 #pragma vector=TIMER0_B0_vector __interrupt void Timer0_B0_ISR (void) { x = ADCMEM0; Y= ADCMEM0; }之外的计时器 B0中断服务例程

我尝试在 ADC ISR 中放入断点、但它从未包含在 ADC ISR 中。 定时器 ISR 正在运行、但 X& Y 两个值始终为1。 两个 SAC 都在工作、因为我已检查示波器上的 SAC 输出。
我在哪里做错了?
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    我尝试在 ADC ISR 中放入断点、但它从未包含在 ADC ISR 中。 定时器 ISR 正在运行、但 X& Y 两个值始终为1。 两个 SAC 都在工作、因为我已经检查了示波器上的 SAC 输出。我在哪里做错了?

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Sumit、

    检查 ADCSHS 配置。 根据数据表中的表6-22、 ADCSHS_1表示 RTC 事件将触发您可能未使用的 ADC。

    您可能需要考虑使用 ADCSHS_2来使用 TB1.1B 触发源。 您正在使用 TB0、但可以将代码更改为使用 TB1。 如果使用此触发方法、则不需要计时器 ISR。

    作为替代方案、您可以使用 ADCSHS_0、然后在计时器 ISR 中设置软件触发器(ADCSC)。 然后、您可以在 ADC ISR 中读取 ADCMEM0。

    希望这对您有所帮助。

    此致、

    James

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好 James、

    我已经尝试将 ADCSHS 寄存器更改为 ADCSHS_2并将定时器更改为 TIMERB1、但 ADC 仍然没有结果。 实际上,IAM 正在尝试实施脉动式血氧计设计,并 希望以每秒1000个样本的速率对 ADC 进行采样,并读取 OA0和 OA2输出。 我正在切换  计时器 ISR 内部的两个 LED 我检查哪个 LED 亮起 、然后关闭另一个 LED。 在滑动 LED 之后、我想读取打开的 LED 的输出。 下面是代码。 根据 ADC 输出、我需要调整 DAC 电压、以进一步调整 LED 强度。

    /*** ADC 配置*** /
    
    ADCCTL0 &=~ADCENC; //禁用 ADC
    ADCCTL0 |= ADCSHT_4 | ADCMSC | ADCON;//0000010010010;64个 ADCLK 周期、MSC 位高电平、ADC 打开
    
    ADCCTL1 |= ADCSHP | ADCSHS_2 | ADCCONSEQ_3|ADCSSEL_1;//0000010010010010;
    ADCCTL2 &=~ADCRES;//清除分辨率
    ADCCTL2 |= ADCRES_2;//12位分辨率
    ADCMCTL0 |= ADCSREF_1|ADCINCH_1|ADCINCH_3;// OA0输出作为 A1 ADC 输入,VR+= VREF+,OA2输出从外部连接到 A3 ADC 输入
    ADCIE |= ADCIE0;//启用转换完成中断
    __enable_interrupt ();//启用可掩码
    
    
    /******** 配置计时器 /
    
    TB1CTL = TBSSEL_ACLK + TBCLR;//ACLK 和复位定时器
    TB1CCTL1 = OUTMOD_2;//切换和复位
    TB1CCTL1 = CCIE;//中断使能
    TB1CCR0 = 31;//采样率为512SPS
    TB1CCR1 = 10;//在采样前留出足够的时间使信号变得稳定
    TB1CTL |= MC_1;//向上计数模式
    ADCCTL0 |= ADCENC|ADCSC;//启用转换和开始转换
    
    //计时器 A0中断服务例程
    #pragma vector=Timer1_B1_vector
    __interrupt void Timer1_B1_ISR (void)
    
    {
    
    
    int i;
    
    if (SAC1OA & SACEN))//检查 IR LED 是否亮起
    
    {
    
    SAC1OA &=~SACEN;//禁用 IR LED SAC。
    SAC1DAC &=~DACEN;//禁用 IR LED DAC
    P2OUT |= BIT2;//2.2 =1 //打开 Vsled
    SAC3OA |= SACEN;//ENABLE VS LED SAC。
    SAC3DAC |= DACEN;//使能 VS LED DAC
    SAC3DAT = VS_LED_LEVEL;
    SAC2DAT = VS_dc_offset;
    P2OUT &=~BIT0;//2.0 =0关闭红外 LED
    
    
    IS _IR = 0; // IR LED 关闭
    
    IR_SAMPLE = ADCMEM0; //读取 IR LED 结果
    I = ADCMEM0;
    //启用下一个转换序列。
    //序列由 TB1启动
    ADCCTL0 &=~ADCENC;
    ADCCTL0 |= ADCENC;
    ADCCTL0 |= ADCSC;
    
    IR_Heart 信号= IR_FILTER (I);//过滤掉50/60Hz 的电气拾取和100/120Hz 的室内照明光学拾取
    IR_Heart _ac_signal = ir_heet_signal - dc_estimator (&ir_2nd _dc_register、ir_heet_signal);//过滤掉传感器上的大直流分量
    
    /*通过第二个运算放大器将 IR 信号置于范围内*/
    如果(I >= 4095)
    {
    如果(ir_dc_offset > 100)
    IR_dc_offset--;
    }
    否则、如果(I < 100)
    {
    如果(ir_dc_offset < 4095)
    IR_dc_offset++;
    }
    
    sq_ir_heal_ac_signal +=(mul16 (ir_heal_ac_signal、ir_heal_ac_signal)>> 10);
    
    if (ir_sample > first_stage_target_high || ir_sample < first_stage_target_low)
    
    {
    如果(ir_sample > first_stage_target_high)
    {
    if (ir_sample >= first_stage_target_high_fine)
    IR_LED_LEVEL-= FIRST_STEP_STEP;
    其他
    IR_LED_LEVEL -= FIRST_STEP_FIND_STEP;
    //钳位到 DAC 的范围
    如果(ir_LED_level < 0)
    IR_LED_LEVEL = 0;
    }
    其他
    {
    if (ir_sample < first_stage_target_low_fine)
    IR_LED_LEVEL += FIRST_STEP_STEP;
    其他
    IR_LED_LEVEL += FIRST_STEP_FIND_STEP;
    //钳位到 DAC 的范围
    如果(ir_LED_level > 4095)
    IR_LED_LEVEL = 4095;
    }
    }
    /*跟踪心脏跳动*/
    Heart _signal_sample_counter++;
    IF (pos_edge)
    {
    如果(EDGE_去 抖< 120)
    {
    EDGE_去 抖++;
    }
    其他
    {
    如果(ir_heart _ac_signal <-200)
    {
    EDGE_去 抖= 0;
    POS_EDGE = 0;
    // display_pulse (0);
    }
    }
    
    其他
    {
    如果(EDGE_去 抖< 120)
    {
    EDGE_去 抖++;
    }
    其他
    {
    如果(ir_heart _ac_signal > 200)
    {
    EDGE_去 抖= 0;
    POS_EDGE = 1;
    //display_pulse (1);
    // display_correcting (1、0);
    如果(+Heart (+Heart)_Bear_counter >= 3)
    {
    LOG_Heart、signal_sample_counter = Heart、signal_sample_counter;
    log_sq_ir_heart ac_signal = sq_ir_heart ac_signal;
    log_sq_vs_Heart、ac_signal = sq_vs_Heart、ac_signal;
    Heart _signal_sample_counter = 0;
    SQL_IR_Heart;AC_SIGNAL = 0;
    SQL_VS_Heart:AC_SIGNAL = 0;
    Heart Bear_counter = 0;
    //_BIC_SR_IRQ (LPM0_Bits);
    //大致执行虚拟唤醒
    //每2秒
    }
    }
    
    }
    
    
    
    
    
    
    否则
    {
    SAC3OA &=~SACEN;//禁用 VS LED SAC。
    SAC3DAC &=~DACEN;//禁用 VS LED DAC
    P2OUT |= BIT0;//2.0 = 1
    SAC1OA |= SACEN;//启用 IR LED SAC。
    SAC1DAC |= DACEN;//启用 IR LED DAC
    SAC1DAT = ir_LED_level;
    SAC2DAT = ir_dc_offset;
    
    P2OUT &=~BIT2;//2.2 =0
    
    
    IS _IR = 1; // IR LED 亮起
    
    VS_SAMPLE = ADCMEM0; //读取可见的 LED 结果
    I = ADCMEM0;
    
    //启用下一个转换序列。
    //序列由 TB1启动
    ADCCTL0 &=~ADCENC;
    
    ADCCTL0 |= ADCENC;
    ADCCTL0 |= ADCSC;
    
    
    //过滤掉50/60Hz 电气频率
    //pickup 和100/120Hz 室
    //照明光学拾取器*/
    VS_Heart 信号= VS_FILTER (I);
    //过滤掉大 DC
    来自传感器的//组件*/
    VS_Heart AC_SIGNAL = VS_Heart 信号- dc_estimator (&Vs_2nd dc_register、VS_Heart 信号);
    
    /*通过第二个运算放大器使 VS 信号处于范围内*/
    如果(I >= 4095)
    {
    如果(Vs_dc_offset > 100)
    VS_dc_offset--;
    }
    否则、如果(I < 100)
    {
    如果(Vs_dc_offset < 4095)
    VS_dc_offset++;
    }
    
    SQL_VS_Heart:ac_signal +=(mul16 (VS_Heart:ac_signal、VS_Heart:ac_signal)>> 10);
    
    IF (VS_SAMPLE > FIRST_TARGET_HIGH || VS_SAMPLE < FIRST_TARGET_LOW)
    
    
    {
    /*我们超出目标范围*/
    // display_correcting (1、1);
    如果(Vs_sample > FIRST_TARGET_HIGH)
    {
    if (Vs_sample >= first_stage_target_high_fine)
    VS_LED_LEVEL -= FIRST_STEP_STEP;
    其他
    VS_LED_LEVEL -= FIRST_STEP_FIND_STEP;
    如果(VS_LED_LEVEL<0)
    VS_LED_LEVEL = 0;
    }
    其他
    {
    如果(Vs_sample < FIRST_TARGET_LOW_Fine)
    VS_LED_LEVEL += FIRST_STEP_STEP;
    其他
    VS_LED_LEVEL += FIRST_STEP_FIND_STEP;
    IF (VS_LED_LEVEL> 4095)
    VS_LED_LEVEL = 4095;
    }
    }
    
    
    
    
    
    
    
    
    
    void}// ADC 中断服务例程#if defined (__TI_Compiler_version__)|| defined (__IAR_systems_ICC__)#pragma vector=adc_vector __interrupt void adc_isr (void)#elif defined (__GNU__) void __attribute__((interrupt (adc_vector))))#adc_isr
    
    (void #else not supported!
    #endif
    
    {
    ADCIFG &=~ADCIFG0;//清除中断标志
    SAC1DAT = 0;//关闭两个 LED
    SAC3DAT = 0;
    //完全关闭 H 桥
    IF (Is_IR) //如果 TA0 ISR 中的 IR LED 亮起
    P2OUT |= BIT2; // P2.2 = 1
    其他 //否则、如果 VS LED 在 TA0 ISR 中打开
    P2OUT |= BIT0; // P2.0=1
    
    }
    

    请帮助我解决问题。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    SPO2传感器的 SAC O2O 输出如下所示。 我需要 ADC 根据所示的时序图读取该值。 为了实现这一点、我已经在我的帖子中编写了上面显示的代码、但 ADC 数据始终为1。 我一直关注 TI 文档 slaa897和 slaa458  

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    1) 1)不要在定时器 ISR 中获取 ADCMEM0。 在 ADC ISR 中获取它(James 建议)。 在 ADC 的结果准备就绪之前、定时器 ISR 被称为一个很长的时间(~2ms)。

    2) 2) ADCINCH 是一个数字、而不是一个位字段。 (SO (ADCINCH_1|ADCINCH_3)=ADCINCH_3。) ADC 序列从 INCH 向下阶跃到0、在本例中为 A3-A2-A1-A0。 每个 ADC 中断都提供其中一个中断。 跟踪哪一个由您决定。 通常最简单的方法是仅保留全局(循环)计数器变量。

    3)每次转换都会使您(64+15)/32768 = 2.4ms、并且您正在进行其中4次转换= 9.6ms、因此采样率大约为100Hz。 您的定时器每(31+1)/32768 = 1ms 触发一次、即比 ADC 转换的速度快得多。 我建议您调整此值、以便定时器以正确的速率触发(但请参阅下面的(4))。 [未经请求:您真的需要2ms S/H 时间吗? 很长一段时间。 我希望 SAC 输出具有非常低的阻抗。]

    4)当 CONSEQ=3且 MSC=1时、您的定时器触发被忽略(在第一次触发之后)。 通常、我会说返回到 CONSEQ=1、但在本例中、我不会这样做。 由于您的预期采样率(和 S/H 时间)将使 ADC 始终保持或多或少的持续运行、因此请保持 CONSEQ=3、但将 MSC=0。 在该设置下、每个触发器将启动一个新的转换、但 ADC 仍将循环通道。 您仍然可以对采样率进行一定的控制(通过调整 TB1CCR0)。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    Bruce、您好!

    感谢您的回复、并帮助我更好地了解 MCU 工作原理。 我通过设置 ADCSSEL_0将 ADC 的时钟更改为5MHz 的 MODCLK。 因此,我的一次转换将采用(64+15)/5000000=15.8us。 我已将英寸数更改为 INCH1、因为我的 OA0输出从内部连接到 ADC 输入 A1、而 OA2输出从外部连接到 A0上(引脚3.1连接到 Launchpad 上的引脚1.0)。 因此、我的双通道转换将花费~32us。 即使我的定时器 ISR 每1ms 出现一次、TB1CCR1 = 10也意味着我的 ADC 将被触发并在1ms 之前获得我的两个通道的转换结果。

    它是在触发 ADC 的 TB1CCR1?  我的代码仍然不在 ADC ISR 内部。 我不明白为什么? 我尝试了您的建议、即保持 CONSEQ3和 MSC =0、但不起作用。

    我是否必须配置主函数内的任何时钟?  我希望 ACLK 和 MODCLK 的默认值为32768Hz 和5MHz  

    我已附上我的完整代码。  

    int main (void)
    {
    
    双 F1;
    int x;
    int y;
    WDTCTL = WDTPW | WDTHOLD;//停止看门狗计时器
    
    //设置 GPIO
    
    //配置 ADC A0引脚
    P1SEL0 |= BIT0;
    P1SEL1 |= BIT0;
    
    P2DIR |= BIT0 + BIT2; // P2.0和 P2.2 o/p 方向-
    //驱动 H 桥中的 NPN 晶体管
    P2OUT &=~BIT0;
    P2OUT &=~BIT2;
    
    PM5CTL0 &=~LOCKLPM5;
    
    //配置参考模块
    PMMCTL0_H = PMMPW_H; //解锁 PMM 寄存器
    PMMCTL2 = INTREFEN | REFVSEL_2; //启用内部2.5V 基准
    while (!(PMMCTL2 & REFGENRDY)); //轮询直至内部基准稳定
    
    
    
    
    /******* SAC0配置为 TIA **** /
    P1SEL0 |= BIT1|BIT2; //选择 P1.2 P1.1作为 OA0输出 OA0-引脚功能
    P1SEL1 |= BIT1 | BIT2; //选择 P1.2 OA0-引脚功能
    
    SAC0DAC = DACSREF_1; //选择2.5V 内部 Vref 作为 DAC 基准
    SAC0DAT = 2048; //将 SAC DAC 数据设置为2.5V
    SAC0DAC |= DACEN; //启用 DAC
    SAC0OA |= NMUXEN | PMUXEN | PSEL_1 | NSEL_0;//选择正输入作为 DAC、选择负引脚输入作为光电二极管
    // SAC0PGA |= MSEL_0; //反相 PGA 模式
    SAC0OA &=~OAPM; //选择高速和高功率模式
    SAC0OA |= SACEN + OAEN; //启用 SAC 和 OA
    
    /********* SAC2配置为反相 PGA ***** /
    P3SEL0 |= BIT1; //选择 P3.1 OA2输出功能
    P3SEL1 |= BIT1; //选择 P3.1 OA2输出功能
    
    SAC2DAC = DACSREF_1; //选择2.5V 内部 Vref 作为 DAC 基准
    SAC2DAT = 0; // DAC 为放大器提供偏置
    SAC2DAC |= DACEN; //启用 DAC
    SAC2OA |= NMUXEN | PMUXEN | PSEL_1 | NSEL_1;//选择正输入作为 DAC、选择负引脚输入作为 OA0的 O/P
    SAC2PGA |= GAIN0 + GAIN2 + MSEL_3;//设置增益= 16的反相 PGA 模式
    SAC2OA &=~OAPM; //选择高速和高功率模式
    SAC2OA |= SACEN | OAEN;//启用 SAC 和 OA
    
    /********* SAC0配置为反相 PGA *********** /
    /*P1SEL0|= BIT1 | BIT2 | BIT3; //选择 P1.1 P1.2 P1.3 OA0函数
    P1SEL1 |= BIT1 | BIT2 | BIT3; //选择 P1.1 P1.2 P1.3 OA0函数
    SAC0DAC = DACSREF_1; //选择2.5V 内部 Vref 作为 DAC 基准
    SAC0DAT = 819; //将 SAC DAC 数据设置为0.5V
    SAC0DAC |= DACEN; //启用 DAC
    SAC0OA = NMUXEN + PMUXEN + PSEL_1 + NSEL_1;//选择正输入作为 DAC、选择负引脚输入作为光电二极管
    SAC0PGA |= GAIN0 + GAIN2 + MSEL_0;//设置增益= 16的反相 PGA 模式
    SAC0OA &=~OAPM; //选择高速和高功率模式
    SAC0OA |= SACEN | OAEN;//启用 SAC 和 OA*/
    
    /******* SAC2配置为 TIA **** /
    
    /* P3SEL0 |= BIT1 | BIT2 | BIT3; //选择 P3.1 P3.2 P3.3 OA2函数
    P3SEL1 |= BIT1 | BIT2 | BIT3; //选择 P3.1 P3.2 P3.3 OA2函数
    SAC2DAC = DACSREF_1; //选择2.5V 内部 Vref 作为 DAC 基准
    SAC2DAT = 819; //将 SAC DAC 数据设置为0.5V
    SAC2DAC |= DACEN; //启用 DAC
    SAC2OA = NMUXEN + PMUXEN + PSEL_1 + NSEL_0;//选择正输入作为 DAC、选择负引脚输入作为光电二极管
    SAC2PGA |= MSEL_0;
    
    SAC2OA |= SACEN + OAEN;//启用 SAC 和 OA*/
    
    
    
    /**** SAC3配置为 DAC 输出**** /
    P3SEL0 |= BIT6|BIT5; //选择 P3.6作为 OA3-VE P3.5 OA3O 功能
    P3SEL1 |= BIT6|BIT5; // OA 用作 DAC 的缓冲器
    
    SAC3DAC = DACSREF_1; //选择2.5V 内部 Vref 作为 DAC 基准
    SAC3DAT = 3340; //将 SAC DAC 数据设置为2.5V
    SAC3DAC |= DACEN; //启用 DAC
    SAC3OA = NMUXEN + PMUXEN + PSEL_1 + NSEL_0;//选择 DAC 模式
    SAC3PGA |= MSEL_1; //将 OA 设置为缓冲模式
    SAC3OA &=~OAPM; //选择高速和高功率模式
    SAC3OA |= SACEN | OAEN;//启用 SAC 和 OA
    
    /******* SAC1配置 AS DAC 输出******** /
    P1SEL0 |= BIT6|BIT5; //选择 P1.6作为 OA1-VE P1.5 OA1O 函数
    P1SEL1 |= BIT6|BIT5; // OA 用作 DAC 的缓冲器
    
    SAC1DAC = DACSREF_1; //选择2.5V 内部 Vref 作为 DAC 基准
    SAC1DAT = 3340; //将 SAC DAC 数据设置为初始值2.5V
    SAC1DAC |= DACEN; //启用 DAC
    SAC1OA = NMUXEN + PMUXEN + PSEL_1 + NSEL_0;//选择 DAC 模式
    SAC1PGA |= MSEL_1; //将 OA 设置为缓冲模式
    SAC1OA &=~OAPM; //选择高速和高功率模式
    SAC1OA |= SACEN | OAEN;//启用 SAC 和 OA
    
    //设置 LED 亮度的初始值
    IR_LED_LEVEL = 1300;//1300
    VS_LED_LEVEL = 1450;//1450
    
    /*** ADC 配置*** /
    
    ADCCTL0 &=~ADCENC; //禁用 ADC
    ADCCTL0 |= ADCSHT_4|ADCMSC|ADCON;//0000010010010;64个 ADCLK 周期、MSC 位、ADC 打开
    ADCCTL1 |= ADCSHP|ADCSHS_2 | ADCCONSEQ_3|ADCSSEL_0;//5MHz 时钟
    // ADCCTL1 |= ADCSHP | ADCSHS_2 | ADCCONSEQ_3|ADCSSEL_1;//0000010010010010;
    ADCCTL2 &=~ADCRES;//清除分辨率
    ADCCTL2 |= ADCRES_2;//12位分辨率
    ADCMCTL0 |= ADCINCH_1|ADCSREF_1;// OA0输出作为 A1 ADC 输入,VR+= VREF+,同时 OA2输出从外部连接到 A0 ADC 输入
    ADCIE |= ADCIE0;//启用转换完成中断
    ADCCTL0 |= ADCENC|ADCSC;//启用转换并开始转换
    //__enable_interrupt ();//启用可掩码
    
    
    /******** 配置计时器 /
    
    TB1CTL = TBSSEL_ACLK + TBCLR;//ACLK 和复位定时器
    TB1CCTL1 = OUTMOD_4;//切换和复位
    TB1CCTL1 = CCIE;//中断使能
    TB1CCR0 = 31;//采样率为512SPS
    TB1CCR1 = 10;//在采样前留出足够的时间使信号变得稳定
    TB1CTL |= MC_1;//向上计数模式
    
    
    while (1)
    {
    _bis_SR_register (LPM0_bits | GIE);
    
    /*心率计算*/
    F1 = 60.0*512.0*3.0/(浮点) LOG_Heart 信号_sample_counter;
    Heart Rate = F1;
    // display_number (hear_rate、3、3);
    Heart Rate (心率) LSB = Heart (心率)和0x00FF;
    
    /* SaO2计算*/
    x = log_sq_ir_heal_ac_signal/log_heal_signal_sample_counter;
    y = log_sq_vs_Heart、ac_signal/log_Heart、signal_sample_counter;
    比率=(unsigned int)(100.0*log(y)/log(x));
    IF (比率> 66)
    SaO2 =查找[比率- 66]; //比率- 50 (查找表偏移)- 16 (比率偏移)
    否则(比率> 50)
    SaO2 =查找[比率- 50]; //比率- 50 (查找表偏移)
    其他
    SaO2 = 100;
    // display_number (SaO2、7、3);
    SaO2_LSB = SaO2和0x00FF;
    
    }
    
    //返回0;
    }
    
    //计时器 B1中断服务例程
    #pragma vector=Timer1_B1_vector
    __interrupt void Timer1_B1_ISR (void)
    
    {
    
    
    int i;//在 main if (
    
    (SAC1OA 和 SACEN))外部声明)//检查 IR LED 是否亮起
    
    {
    
    SAC1OA &=~SACEN;//禁用 IR LED SAC。
    SAC1DAC &=~DACEN;//禁用 IR LED DAC
    P2OUT |= BIT2;//2.2 =1 //打开 Vsled
    SAC3OA |= SACEN;//ENABLE VS LED SAC。
    SAC3DAC |= DACEN;//使能 VS LED DAC
    SAC3DAT = VS_LED_LEVEL;
    SAC2DAT = VS_dc_offset;
    P2OUT &=~BIT0;//2.0 =0关闭红外 LED
    
    
    IS _IR = 0; // IR LED 关闭
    
    IR_SAMPLE = ADC_RESULT[0]; //读取 IR LED 结果
    I = ADC_Result [1];
    //启用下一个转换序列。
    //序列由 TB1启动
    // ADCCTL0 &=~ADCENC;
    // ADCCTL0 |= ADCENC |ADCSC;
    // ADCCTL0 |= ADCSC;
    
    // ir_heart 信号= ir_filter (i);//滤除50/60Hz 电气拾取和100/120Hz 室内照明光学拾取
    // ir_Heart _ac_signal = ir_heart - dc_estimator (&ir_2nd _dc_register、ir_Heart _signal);//过滤掉传感器上的大直流分量
    
    /*通过第二个运算放大器将 IR 信号置于范围内*/
    如果(I >= 4095)
    {
    如果(ir_dc_offset > 100)
    IR_dc_offset--;
    }
    否则、如果(I < 100)
    {
    如果(ir_dc_offset < 4095)
    IR_dc_offset++;
    }
    
    // sq_ir_heal_ac_signal +=(mul16 (ir_heal_ac_signal、ir_heal_ac_signal)>> 10);
    
    if (ir_sample > first_stage_target_high || ir_sample < first_stage_target_low)
    
    {
    如果(ir_sample > first_stage_target_high)
    {
    if (ir_sample >= first_stage_target_high_fine)
    IR_LED_LEVEL-= FIRST_STEP_STEP;
    其他
    IR_LED_LEVEL -= FIRST_STEP_FIND_STEP;
    //钳位到 DAC 的范围
    如果(ir_LED_level < 0)
    IR_LED_LEVEL = 0;
    }
    其他
    {
    if (ir_sample < first_stage_target_low_fine)
    IR_LED_LEVEL += FIRST_STEP_STEP;
    其他
    IR_LED_LEVEL += FIRST_STEP_FIND_STEP;
    //钳位到 DAC 的范围
    如果(ir_LED_level > 4095)
    IR_LED_LEVEL = 4095;
    }
    }
    /*跟踪心脏跳动*/
    Heart _signal_sample_counter++;
    IF (pos_edge)
    {
    如果(EDGE_去 抖< 120)
    {
    EDGE_去 抖++;
    }
    其他
    {
    如果(ir_heart _ac_signal <-200)
    {
    EDGE_去 抖= 0;
    POS_EDGE = 0;
    // display_pulse (0);
    }
    }
    
    其他
    {
    如果(EDGE_去 抖< 120)
    {
    EDGE_去 抖++;
    }
    其他
    {
    如果(ir_heart _ac_signal > 200)
    {
    EDGE_去 抖= 0;
    POS_EDGE = 1;
    //display_pulse (1);
    // display_correcting (1、0);
    如果(+Heart (+Heart)_Bear_counter >= 3)
    {
    LOG_Heart、signal_sample_counter = Heart、signal_sample_counter;
    log_sq_ir_heart ac_signal = sq_ir_heart ac_signal;
    log_sq_vs_Heart、ac_signal = sq_vs_Heart、ac_signal;
    Heart _signal_sample_counter = 0;
    SQL_IR_Heart;AC_SIGNAL = 0;
    SQL_VS_Heart:AC_SIGNAL = 0;
    Heart Bear_counter = 0;
    //_BIC_SR_IRQ (LPM0_Bits);
    //大致执行虚拟唤醒
    //每2秒
    }
    }
    
    }
    
    
    
    
    
    
    否则
    {
    SAC3OA &=~SACEN;//禁用 VS LED SAC。
    SAC3DAC &=~DACEN;//禁用 VS LED DAC
    P2OUT |= BIT0;//2.0 = 1
    SAC1OA |= SACEN;//启用 IR LED SAC。
    SAC1DAC |= DACEN;//启用 IR LED DAC
    SAC1DAT = ir_LED_level;
    SAC2DAT = ir_dc_offset;
    
    P2OUT &=~BIT2;//2.2 =0
    
    
    IS _IR = 1; // IR LED 亮起
    
    VS_SAMPLE = ADC_RESULT[0]; //读取可见的 LED 结果
    I = ADC_Result [1];
    
    //启用下一个转换序列。
    //序列由 TB1启动
    // ADCCTL0 &=~ADCENC;
    
    // ADCCTL0 |= ADCENC|ADCSC;
    
    
    
    //过滤掉50/60Hz 电气频率
    //pickup 和100/120Hz 室
    //照明光学拾取器*/
    // Vs_Heart 信号= Vs_filter (i);
    //过滤掉大 DC
    来自传感器的//组件*/
    // Vs_Heart ac_signal = Vs_Heart 信号- dc_estimator (&Vs_2nd dc_register、Vs_Heart 信号);
    
    /*通过第二个运算放大器使 VS 信号处于范围内*/
    如果(I >= 4095)
    {
    如果(Vs_dc_offset > 100)
    VS_dc_offset--;
    }
    否则、如果(I < 100)
    {
    如果(Vs_dc_offset < 4095)
    VS_dc_offset++;
    }
    
    //sq_vs_Heart、ac_signal +=(mul16 (vs_Heart、ac_signal、vs_Heart、ac_signal)>> 10);
    
    IF (VS_SAMPLE > FIRST_TARGET_HIGH || VS_SAMPLE < FIRST_TARGET_LOW)
    
    
    {
    /*我们超出目标范围*/
    // display_correcting (1、1);
    如果(Vs_sample > FIRST_TARGET_HIGH)
    {
    if (Vs_sample >= first_stage_target_high_fine)
    VS_LED_LEVEL -= FIRST_STEP_STEP;
    其他
    VS_LED_LEVEL -= FIRST_STEP_FIND_STEP;
    如果(VS_LED_LEVEL<0)
    VS_LED_LEVEL = 0;
    }
    其他
    {
    如果(Vs_sample < FIRST_TARGET_LOW_Fine)
    VS_LED_LEVEL += FIRST_STEP_STEP;
    其他
    VS_LED_LEVEL += FIRST_STEP_FIND_STEP;
    IF (VS_LED_LEVEL> 4095)
    VS_LED_LEVEL = 4095;
    }
    }
    
    
    
    
    
    
    
    
    
    void}// ADC 中断服务例程#if defined (__TI_Compiler_version__)|| defined (__IAR_systems_ICC__)#pragma vector=adc_vector __interrupt void adc_isr (void)#elif defined (__GNU__) void __attribute__((interrupt (adc_vector))))#adc_isr
    
    (void #else not supported!
    #endif
    
    {
    switch (__evo_in_range (ADCIV、ADCIV_ADCIFG))
    {
    案例 ADCIV_NONE:
    中断;
    ADCIV_ADCOVIFG 案例:
    中断;
    案例 ADCIV_ADCTOVIFG:
    中断;
    ADCIV_ADCHIIFG 案例:
    中断;
    ADCIV_ADCLOIFG 案例:
    中断;
    ADCIV_ADCINIFG 案例:
    中断;
    ADCIV_ADCIFG 案例:
    ADC_Result = ADCMEM0;
    如果(s = 0)
    {
    //__BIC_SR_REGISTER_ON_EXIT (LPM0_Bits);
    SAC1DAT = 0;//关闭两个 LED
    SAC3DAT = 0;//
    //完全关闭 H 桥
    IF (Is_IR) //如果 TA0 ISR 中的 IR LED 亮起
    P2OUT |= BIT2; // P2.2 = 1
    其他 //否则、如果 VS LED 在 TA0 ISR 中打开
    P2OUT |= BIT0; // P2.0=1
    //将 P1.2 LED 设置为打开
    }
    其他
    {
    S-;
    }
    
    
    ADCIFG = 0;
    中断; //将 CPUOFF 位从0 (SR)清零
    默认值:
    中断;
    }
    
    
    
    
    // ADCIFG &=~ADCIFG0;//清除中断标志
    
    }
    
    int16_t ir_filter (int16_t sample)
    {
    静态 int16_t buf[32];
    静态 int 偏移= 0;
    int32_t z、test;
    int i;
    //硬高于几赫兹的滤波器、
    //使用对称 FIR。
    //这具有良性相位
    //Characteristics */
    buf[offset]=采样;
    z = mul16 (coeffs[11]、buf[(offset - 11)& 0x1F]);
    对于(I = 0;I < 11;I++)
    z += mul16 (coeffs[i]、buf[(offset - i)& 0x1F]+ buf[(offset - 22 + i)& 0x1F]);
    偏移=(偏移+ 1)& 0x1F;
    返回 z >> 15;
    }
    
    int16_t vs_filter (int16_t sample)
    {
    静态 int16_t buf[32];
    静态 int 偏移= 0;
    int32_t z;
    int i;
    
    //硬高于几赫兹的滤波器、
    //使用对称 FIR。
    //这具有良性相位
    //Characteristics */
    buf[offset]=采样;
    z = mul16 (coeffs[11]、buf[(offset - 11)& 0x1F]);
    对于(I = 0;I < 11;I++)
    z += mul16 (coeffs[i]、buf[(offset - i)& 0x1F]+ buf[(offset - 22 + i)& 0x1F]);
    偏移=(偏移+ 1)& 0x1F;
    返回 z >> 15;
    }
    int16_t dc_estimator (寄存器 int32_t * p、寄存器 int16_t x)
    {
    /*噪声形状直流估算器。 *
    *p +=(((((int32_t) x << 16)-*p)>> 9);
    返回(*p >>16);
    } 

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    好的,我得到了解决方案。 我使用 TB0来切换 LED、使用 TB1.1进行 ADC 转换。 现在、ADC 正在正确读取这些值。

    我想再问一件事。 在我的代码中、IAM 收到 mul16函数未解析符号的错误。 文档 SLAA458有一个 mul16汇编器文件。 如何在代码中包含此汇编器文件、或者是否需要为此包含任何 mathlib? mul16在滤波器代码中使用。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    如果是.asm 文件、我认为您只需将其复制到项目中、CCS 就会将其计算出来。 但这看起来像是一个.s43文件、它是 IAR 汇编语言、正如我所记得的、它与 TI 汇编语言略有不同。 但您可以尝试一下、看看您得到的结果。

    乍一看,它看起来像是一个16x16->32乘法函数。("int32_t mul16 (寄存器 int16_t x、寄存器 int16_t y)")。 可能是因为 FG437没有硬件乘法器、所以包含了它。 但 FR2355确实如此、编译器非常适合使用它。 如果.s43文件不起作用,可能只需定义您自己的“mul16(x),y”{return(x*y);”