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.

[参考译文] MSP430FR2311:调试器、ADC10读取和 LPM0的异常行为

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

https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/843409/msp430fr2311-strange-behavior-with-debugger-adc10-reading-and-lpm0

器件型号:MSP430FR2311

您好!

很抱歉、这个主题的标题太可怕了、但很难描述这个问题。  我看到了一些奇怪的行为。  有时、当我运行代码时、调试器似乎总是在其中一个 ADC 读取调用中的"_bis_SR_register (LPM0_bits + GIE);"中停止。  如果点击"Play"、它将再次循环浏览代码并再次停止。  我没有设置断点。  奇怪的是、如果我删除其中一个 ADC 读取调用、它将消失(例如 ADC0_SAMPLE())。  我进一步探讨了这一点、并在 CPU 处于唤醒状态时开始切换 P2.3、并注意到当它执行这种奇怪的行为时、GPIO P2.3将始终处于高电平、这在某种程度上意味着 CPU 永远不会回到睡眠状态。  我甚至断开调试器并看到相同的行为。   就像我之前说过的、如果我移除其中一个 ADC 读取调用、它就会消失。  然后我在每个 ADC_SAMPLE()调用中添加了更多代码,这些代码会在 P2.3进入睡眠状态之前将其设置为低电平,等待 ADC 转换完成。  转换完成后、我再次将 P2.3设置为高电平。  我这么做后、问题又消失了。  我看到了我的预期。  P2.3在短时间内保持高电平、然后进入睡眠模式。  它执行此操作三次、然后在更长的时间间隔内保持高电平以处理其他所有内容、然后最终恢复睡眠更长的时间间隔、直到下一个 RTC 中断在 while (1)中开始下一个周期。

因此、如果我有某种竞争状态、或者如果我有实施错误、我会感到非常困惑。  下面我附上了我的代码的一般概念。 值得注意的是、我正在对编译器中的大小进行最高级别的优化。

#include "driverlib.h"
#include 

/*
main.c
*/
int main (void){
//停止 WDT
WDT_A_HOLD (WDT_A_base);
initClockTo16MHz();
inituart();

/*初始化外设*/
initGPIO();
initrtc();

_delay_cycles (10000);

EUSCI_A_UART_ENABLE (EUSCI_A0_BASE);

while (1){

//由 RTC 中断唤醒

P2OUT |= BIT3;//检查 CPU 使用情况

adc1Sample();
ADC1_READING = ADC_Conversion_Result;

adc0Sample();
ADC0_READING = ADC_Conversion_Result;

tempSample ();
temp_reading = ADC_Conversion_Result;

do _Other_processing ();

P2OUT &=~BIT3;//检查 CPU 使用情况

_bis_SR_register (LPM0_bits + GIE); //更改为 LPM0

}



void enable_ADC10 (uint8_t ADC_channel){
//初始化 ADC 模块
//
* ADC 模块的基地址
*使用内部 ADC 位作为采样/保持信号来启动转换
*使用 MODOSC 5MHZ 数字振荡器作为时钟源
*使用默认的1个时钟分频
器*/
ADC_init (ADC_base、 ADC_SAMPLEHOLDSOURCE_SC、ADC_CLOCKSOURCE_ADCOSC、ADC_CLOCKDIVIDER_1);


ADC_ENABLE (ADC_BASE);

ADC_setupSamplingTimer (ADC_base、ADC_CYCLEHOLD_1024_cycles、ADC_MULTIPLESAMPLESDISABLE);

IF (ADC_CHANNEL = ADCINCH_12)
{
ADC_configureMemory (ADC_base、ADC_channel、ADC_VREFPS_INT、ADC_VREFNEG_AVSS);
}
否则
{
ADC_configureMemory (ADC_base、ADC_channel、ADC_VREFPOS_AVCC、ADC_VREFNEG_AVSS);
}

ADC_clearInterrupt (ADC_base、 ADC_completed_interrupt);

//启用存储器缓冲器中断
ADC_enableInterrupt (ADC_base、ADC_completed_interrupt);
}

void disable_ADC10 (void){
ADC_disableConversions (ADC_base、0);
ADC_disable (ADC_base);
}

void adc1Sample (void)
{
ENABLE_ADC10 (ADCINCH_1);

_DELAY_CYCLES (15);

//启用并开始转换
//在单通道、单次转换模式中
ADC_startConversion (ADC_base、ADC_SINGLECHANNEL);
//LPM0、ADC 转换完成将强制退出
_bis_SR_register (LPM0_bits + GIE);

disable_ADC10 ();
}

void adc0Sample (void)
{
ENABLE_ADC10 (ADCINCH_0);//应为0

_DELAY_CYCLES (15);

//启用并开始转换
//在单通道、单次转换模式中
ADC_startConversion (ADC_base、ADC_SINGLECHANNEL);
//LPM0、ADC 转换完成将强制退出
_bis_SR_register (LPM0_bits + GIE);

disable_ADC10 ();
}

void tempSample (void)
{
ENABLE_ADC10 (ADCINCH_12);

_DELAY_CYCLES (15);

//启用并开始转换
//在单通道、单次转换模式中
ADC_startConversion (ADC_base、ADC_SINGLECHANNEL);

//LPM0、ADC 转换完成将强制退出
_bis_SR_register (LPM0_bits + GIE);

disable_ADC10 ();
}

void initGPIO (void){

P1DIR |= 0b01000000;

P2DIR |= 0b00001111;// P0-P3所有输出
P2OUT = 0x00;

PMM_enableTempSensor ();//启用温度传感器
PMM_enableInternalReference();

P1SEL1 |= GPIO_PIN6;// PWM 模式

P1SEL1 &=~(BIT7); // USCI_A0 UART 操作仅发送
P1SEL0 |= BIT7;

// I2C 引脚
P1SEL0 |= BIT2 | BIT3;
P1SEL1 &=~(BIT2 | BIT3);

//ADC 引脚
P1SEL0 |= BIT0 | BIT1;
P1SEL1 |= BIT0 | BIT1;
/*
*禁用 GPIO 上电默认高阻抗模式以激活
*先前配置的端口设置
*
PMM_unlockLPM5 ();
}

// ADC 中断服务例程
#if defined (__TI_Compiler_version__)|| defined (__IAR_systems_ICC__)
#pragma vector=ADC_vector
__interrupt void ADC_ISR (void)
#Elif defined (__GIC_)
void ___attribute_isr (
nc
)(void)(nc) interrupt!
#endif
{
ADC_Conversion_Result = ADCMEM0;// AP

__ BIC_SR_register_ON_EXIT (LPM0_BITS); //退出 LPM0
}

void initClockTo16MHz()
{
//根据 MCLK 的器件数据表的要求配置一个 FRAM 等待状态
//在配置时钟系统之前在8MHz 以上运行。
FRCTL0 = FRCTLPW | NWAITS_1;

_bis_SR_register (SCG0);//禁用 FLL
CSCTL8 |= MODOSCREQEN;
CSCTL3 |= SELREF_REFOCLK;//将 REFO 设置为 FLL 基准源
CSCTL0 = 0; //清除 DCO 和 MOD 寄存器
CSCTL1 &=~(DCORSEL_7); //首先清除 DCO 频率选择位
CSCTL1 |= DCORSEL_5; //设置 DCO = 16MHz
CSCTL2 = FLLD_0 + 487; //设置为 fDCOCLKDIV =(FLLN + 1)*(fFLLREFCLK/n)
// =(487 + 1)*(32.768 kHz/1)
// = 16MHz

_DELAY_CYCLES (3);
_BIC_SR_register (SCG0); //启用 FLL
while (CSCTL7 &(FLLUNLOCK0 | FLLUNLOCK1)); // FLL 锁定

CSCTL4 = SELMS_DCOCLKDIV | SELA_REFOCLK;
}


// RTC 中断服务例程
#if defined (__TI_Compiler_version__)|| defined (__IAR_systems_ICC__)
#pragma vector=RTC_vector
__interrupt RTC_ISR (void)
#Elif defined (__IAR_systems_ICC_)(void


)(void)(void)(n_rtc)(void)(void)(void)
#endif
{
_BIC_SR_REGISTER_ON_EXIT (LPM0_BITS); //睡眠定时器退出 LPM0

开关(__evo_in_range (RTCIV、RTCIV_RTCIF)

{
案例 RTCIV_NONE:中断; //无中断
案例 RTCIV_RTCIF: // RTC 溢出
中断;
默认值:break;
}


void initrtc()
{
RTCMOD = 16-1;//设置为256Hz
SYSCFG2 |= RTCCKSEL; //选择 ACLK 作为 RTC 时钟
RTCCTL = RTCSS_1 | RTCSR | RTCPS__16 | RTCIE;
}


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

    我在我的 Launchpad 上看不到这种行为。 我使用了 initUART 和 do_otel_processing、并使用"-O4 -opt_for_speed=0进行构建。 我的示波器显示整个周期在7.8ms 周期中花费0.68ms、这大概是代码所说的那样。 我在调试器中没有看到任何错误的断点。

    Do_Other_processing()有什么作用? 是否有任何东西连接到引脚? (我几乎有最小值。)

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

    主循环为128Hz。  当 CPU 在每次 ADC 读取前运行时、我得到3个10uS 的脉冲、每次读取之间的睡眠时间为214us。  执行其他操作需要大约66uS。  执行其他操作、只处理 ADC 读数、并根据正在进行的操作做出一些决策。  我有时还添加了一些来自 UART 的基本 dBUG 消息。  就像我说过的、这种行为非常奇怪、看起来与代码相关。

    从中断的角度来看、我是否做了任何错误。  我想我的假设是、我从 RTC 中断中唤醒、 然后启动 ADC 读取并进入睡眠模式、ADC 转换完成会唤醒 CPU、CPU 会在 ADC 转换例程中选择它关闭的位置、然后继续进行主代码中的下一次转换。  最后一次转换完成后、它将完成处理、然后继续进入睡眠状态并等待下一个 RTC 中断。

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

    足够公平。 但是、根据您发布的内容、我无法重复您的症状、这表明问题在其他地方。 (代码? 项目? 环境?)

    未经请求(可能不相关):

    首先、我发现您有两个(匿名)唤醒源。 如果你总是遵守你所有的最后期限,这可以解决--并在你发布的代码中完成。 但是、如果您错过了一个、则很容易在唤醒中脱离同步(因为唤醒不会闭锁)。 66us 当然是在您的最后期限内完成的、但如果您不是很小心、那么介绍 UART 消息是一种很好的方法。

    需要记住的另一点是、某些 MCU 时钟不会立即停止、甚至在您处于断点时继续运行、因此断点本身可以关闭定序。  

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

    那么、您是否建议我在每次进入睡眠状态时设置一个唯一的标志、以便现在我设置唤醒源、然后根据该标志仅运行 main 中的相应部分?

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

    我认为这是一个好主意、但我无法说它会解决您的症状。 您的描述确实让人想起了如果唤醒被人蒙混的话您会看到的各种事物。 下面是一个更深入的讨论:

    https://e2e.ti.com/support/microcontrollers/msp430/f/166/p/820313/3034992

    如上所述、您的代码(假设两个缺失的函数为空)会以确定性方式运行、并且在其截止日期内正常运行。 它也(原谅表达式)没有太多作用。 在未知情况下、我怀疑存在隐藏的代码(I2C? PWM? UART ISR?) 它足够大、可以微调这个简单可靠的环路、直到它掉下来。

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

    有趣的是、有足够的处理时间。  例如、如果我删除了第二个 ADC 读数、而没有执行任何其他操作、则问题将消失、观察 CPU 使用情况会发现有足够的时间来完成所有操作。  然后、我重新加入第二个 ADC 读数、突然 CPU 一直忙、调试器在 CPU 唤醒时一直停止。

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

    这与缺失/额外唤醒(截止日期)一致、因为移除其中一个 ADC 调用会从循环中移除大约200us。

    似乎无论它是什么、它都不在您发布的内容之外、所以我能做的就是猜测。

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

    [引用用户="Bruce McKenney47378"]

    这与缺失/额外唤醒(截止日期)一致、因为移除其中一个 ADC 调用会从循环中移除大约200us。

    [/报价]

    是的,我通常同意这种说法,但当我向多个 O_Other_processing()中添加额外的 UART 消息时,所有3个 ADC 读数都会重新起作用,根据使用情况 LED,仍有大量的 CPU 可用。  这就是为什么我感到如此奇怪的原因。

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

    您好、Andrew

    您是否解决了此问题? 或对其进行任何更新?

    此致

    Gary

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

    Gary、

    没有、我没有"解决"它。  我通过添加或更改代码来解决它。  当它正常工作时、所有代码都在足够的时间内运行、以便在下一个唤醒周期之前完成。  如果没有、CPU 永远不会进入休眠状态。

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

    在某种程度上、这就是执行静态调度的方式。 (在过去的日子里、我们计算了大量的 CPU 时钟。)

    我认为只要您有多个匿名唤醒源(UART 是否执行唤醒?) 您可能受困于静态调度、因为您需要始终知道接下来将关闭哪个中断。 我建议,通过识别唤醒,你可能会使事情变得更加稳健----"固化实时"。

    我不知道我有多少次发现自己写了一个小的跟踪工具--写一个“我得到了 "字节放入循环缓冲区--以找出意外的序列。 也许这样会有所帮助?

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

    唯一的唤醒源是 RTC、三个 ADC 读取。  I2C 不会唤醒、它只是完成中断、并且应该返回到睡眠状态、因为我 在中断中没有"__BIC_SR_REGISTER_ON_EXIT (LPM0_Bits);"。  我依靠 RTC 中断对 I2C 命令执行操作。  dBUG UART 仅传输、仅进行轮询。

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

    Bruce、

    您觉得这可以正常工作吗?  我添加了 interrupt_id 标志。

    #include "driverlib.h"
    #include 
    
    unsigned int interrupt_id = 0;
    //*
    main.c
    *
    / int main (void){
    //停止 WDT
    WDT_A_HOLD (WDT_A_base);
    initClockTo16MHz();
    inituart();
    
    /*初始化外设*/
    initGPIO();
    initrtc();
    
    _delay_cycles (10000);
    
    EUSCI_A_UART_ENABLE (EUSCI_A0_BASE);
    
    while (1){
    
    //由 RTC 中断唤醒
    
    P2OUT |= BIT3;//检查 CPU 使用率
    
    if (interrupt_id ==0)
    {
    
    adc1Sample ();
    ADC1_READING = ADC_Conversion_Result;
    }
    
    if (interrupt_id =1)
    {
    adc0Sample ();
    ADC0_READING = ADC_Conversion_Result;
    }
    
    
    if (interrupt_id =2)
    {ature_conversion (=
    
    tempid
    
    
    = 3
    
    
    );}interrupt_processing = ADC0_result (= ADC0_conversion);}(if);if (interrupt_conversion = temp_processing = tempid = ADC =
    
    
    P2OUT &=~BIT3;//检查 CPU 使用情况
    
    _bis_SR_register (LPM0_bits + GIE); //更改为 LPM0
    
    }
    
    
    
    void enable_ADC10 (uint8_t ADC_channel){
    //初始化 ADC 模块
    //
    * ADC 模块的基地址
    *使用内部 ADC 位作为采样/保持信号来启动转换
    *使用 MODOSC 5MHZ 数字振荡器作为时钟源
    *使用默认的1个时钟分频
    器*/
    ADC_init (ADC_base、 ADC_SAMPLEHOLDSOURCE_SC、ADC_CLOCKSOURCE_ADCOSC、ADC_CLOCKDIVIDER_1);
    
    
    ADC_ENABLE (ADC_BASE);
    
    ADC_setupSamplingTimer (ADC_base、ADC_CYCLEHOLD_1024_cycles、ADC_MULTIPLESAMPLESDISABLE);
    
    IF (ADC_CHANNEL = ADCINCH_12)
    {
    ADC_configureMemory (ADC_base、ADC_channel、ADC_VREFPS_INT、ADC_VREFNEG_AVSS);
    }
    否则
    {
    ADC_configureMemory (ADC_base、ADC_channel、ADC_VREFPOS_AVCC、ADC_VREFNEG_AVSS);
    }
    
    ADC_clearInterrupt (ADC_base、 ADC_completed_interrupt);
    
    //启用存储器缓冲器中断
    ADC_enableInterrupt (ADC_base、ADC_completed_interrupt);
    }
    
    void disable_ADC10 (void){
    ADC_disableConversions (ADC_base、0);
    ADC_disable (ADC_base);
    }
    
    void adc1Sample (void)
    {
    ENABLE_ADC10 (ADCINCH_1);
    
    _DELAY_CYCLES (15);
    
    //启用并开始转换
    //在单通道、单次转换模式中
    ADC_startConversion (ADC_base、ADC_SINGLECHANNEL);
    //LPM0、ADC 转换完成将强制退出
    INTERRUPT_ID = 1;
    _bis_SR_register (LPM0_bits + GIE);
    
    disable_ADC10 ();
    }
    
    void adc0Sample (void)
    {
    ENABLE_ADC10 (ADCINCH_0);//应为0
    
    _DELAY_CYCLES (15);
    
    //启用并开始转换
    //在单通道、单次转换模式中
    ADC_startConversion (ADC_base、ADC_SINGLECHANNEL);
    //LPM0、ADC 转换完成将强制 EXIT
    INTERRUPT_ID = 2;
    _bis_SR_register (LPM0_bits + GIE);
    
    disable_ADC10 ();
    }
    
    void tempSample (void)
    {
    ENABLE_ADC10 (ADCINCH_12);
    
    _DELAY_CYCLES (15);
    
    //启用并开始转换
    //在单通道、单次转换模式中
    ADC_startConversion (ADC_base、ADC_SINGLECHANNEL);
    
    //LPM0、ADC 转换完成将强制退出
    INTERRUPT_ID = 3;
    _bis_SR_register (LPM0_bits + GIE);
    
    disable_ADC10 ();
    }
    
    void initGPIO (void){
    
    P1DIR |= 0b01000000;
    
    P2DIR |= 0b00001111;// P0-P3所有输出
    P2OUT = 0x00;
    
    PMM_enableTempSensor ();//启用温度传感器
    PMM_enableInternalReference();
    
    P1SEL1 |= GPIO_PIN6;// PWM 模式
    
    P1SEL1 &=~(BIT7); // USCI_A0 UART 操作仅发送
    P1SEL0 |= BIT7;
    
    // I2C 引脚
    P1SEL0 |= BIT2 | BIT3;
    P1SEL1 &=~(BIT2 | BIT3);
    
    //ADC 引脚
    P1SEL0 |= BIT0 | BIT1;
    P1SEL1 |= BIT0 | BIT1;
    /*
    *禁用 GPIO 上电默认高阻抗模式以激活
    *先前配置的端口设置
    *
    PMM_unlockLPM5 ();
    }
    
    // ADC 中断服务例程
    #if defined (__TI_Compiler_version__)|| defined (__IAR_systems_ICC__)
    #pragma vector=ADC_vector
    __interrupt void ADC_ISR (void)
    #Elif defined (__GIC_)
    void ___attribute_isr (
    nc
    )(void)(nc) interrupt!
    #endif
    {
    ADC_Conversion_Result = ADCMEM0;// AP
    
    __ BIC_SR_register_ON_EXIT (LPM0_BITS); //退出 LPM0
    }
    
    void initClockTo16MHz()
    {
    //根据 MCLK 的器件数据表的要求配置一个 FRAM 等待状态
    //在配置时钟系统之前在8MHz 以上运行。
    FRCTL0 = FRCTLPW | NWAITS_1;
    
    _bis_SR_register (SCG0);//禁用 FLL
    CSCTL8 |= MODOSCREQEN;
    CSCTL3 |= SELREF_REFOCLK;//将 REFO 设置为 FLL 基准源
    CSCTL0 = 0; //清除 DCO 和 MOD 寄存器
    CSCTL1 &=~(DCORSEL_7); //首先清除 DCO 频率选择位
    CSCTL1 |= DCORSEL_5; //设置 DCO = 16MHz
    CSCTL2 = FLLD_0 + 487; //设置为 fDCOCLKDIV =(FLLN + 1)*(fFLLREFCLK/n)
    // =(487 + 1)*(32.768 kHz/1)
    // = 16MHz
    
    _DELAY_CYCLES (3);
    _BIC_SR_register (SCG0); //启用 FLL
    while (CSCTL7 &(FLLUNLOCK0 | FLLUNLOCK1)); // FLL 锁定
    
    CSCTL4 = SELMS_DCOCLKDIV | SELA_REFOCLK;
    }
    
    
    // RTC 中断服务例程
    #if defined (__TI_Compiler_version__)|| defined (__IAR_systems_ICC__)
    #pragma vector=RTC_vector
    __interrupt RTC_ISR (void)
    #Elif defined (__IAR_systems_ICC_)(void
    
    
    )(void)(void)(n_rtc)(void)(void)(void)
    #endif
    {
    interrupt_id = 0;
    _BIC_SR_REGISTER_ON_EXIT (LPM0_BITS); //睡眠定时器退出 LPM0
    
    开关(__evo_in_range (RTCIV、RTCIV_RTCIF)
    
    {
    案例 RTCIV_NONE:中断; //无中断
    案例 RTCIV_RTCIF: // RTC 溢出
    中断;
    默认值:break;
    }
    
    
    void initrtc()
    {
    RTCMOD = 16-1;//设置为256Hz
    SYSCFG2 |= RTCCKSEL; //选择 ACLK 作为 RTC 时钟
    RTCCTL = RTCSS_1 | RTCSR | RTCPS__16 | RTCIE;
    }
    
    

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

    看起来您已经引入了一个状态机、这可能是一种有趣的方法、但我认为它不会处于比赛状态。

    我所建议的只是:

    1) 1)引入2 ("易失性")变量:RTC_DONE 和 ADC_DONE。 每个都由相关 ISR 设置为1。

    2) 2)当您希望在开始调用之后等待 ADC 时、添加:

    > while (!ADC_DONE) LPM0; //等待完成事件

    >ADC_DONE = 0;  //确认事件

    因此、如果 RTC 中断反过来发生、程序将不会认为 ADC 已经完成。 RTC 中断(事件)将保持挂起状态、直到循环底部的模拟检查。

    (在获取 ADC_DONE 值和 LPM0之间仍有一小段距离。 现在这可能不是一个大问题。)

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

    Bruce、

    再次感谢您的宝贵见解。  我相信这正是您的建议?

    #include "driverlib.h"
    #include 
    
    unsigned int interrupt_id = 0;
    volatile unsigned int ADC_done = 0;
    volatile unsigned int RTC_done = 0;
    //
    * main.c
    *
    / int main (void){
    //停止 WDT
    WDT_A_HOLD (WDT_A_base);
    initClockTo16MHz();
    inituart();
    
    /*初始化外设*/
    initGPIO();
    initrtc();
    
    _delay_cycles (10000);
    
    EUSCI_A_UART_ENABLE (EUSCI_A0_BASE);
    
    while (1){
    
    //由 RTC 中断唤醒
    
    P2OUT |= BIT3;//检查 CPU 使用情况
    
    if (interrupt_id =0)
    {
    
    adc1Sample();
    ADC1_READING = ADC_Conversion_Result;
    }
    
    if (interrupt_id == 1)
    {
    adc0Sample();
    ADC0_READING = ADC_Conversion_Result;
    }
    
    
    if (interrupt_id == 2)
    {
    tempSample();
    Temperature 读取= ADC_Conversion_Result;
    }
    
    if (interrupt_id == 3)
    {
    
    DO 其他处理();
    }
    
    P2OUT &=~BIT3;//在
    
    (!RTC_DONE)
    {
    _bis_SR_register (LPM0_BITS + GIE)时检查 CPU 使用情况;//更改为 LPM0
    }
    
    RTC_DONE = 0;
    
    //_bis_SR_register (LPM0_Bits + GIE);//更改为 LPM0
    
    }
    
    }
    
    void enable_ADC10 (uint8_t adc_channel){
    //初始化 ADC 模块
    /*
    * ADC 模块的基地址
    *使用内部 ADC 位作为采样/保持信号来启动转换
    *使用 MODOSC 5MHZ 数字振荡器作为时钟源
    *使用默认的时钟分频器1
    *
    ADC_INIT (ADC_base、ADC_SAMPLEHOLDSOURCE_SC、ADC_CLOCKSOURCE_ADCOSC、ADC_CLOCKDIVIDER_1);
    
    
    ADC_ENABLE (ADC_base);
    
    ADC_setupSamplingTimer (ADC_base、ADC_CYCLEHOLD_1024_cycles、ADC_MULTIPLESAMPLESDISABLE);
    
    IF (ADC_CHANNEL = ADCINCH_12)
    {
    ADC_configureMemory (ADC_base、ADC_channel、ADC_VREFPS_INT、ADC_VREFNEG_AVSS);
    }
    其他
    {
    ADC_configureMemory (ADC_base、ADC_channel、ADC_VREFPS_AVCC、ADC_VREFNEG_AVSS);
    }
    
    ADC_clearInterrupt (ADC_base、ADC_completed_interrupt);
    
    //启用存储器缓冲器中断
    ADC_enableInterrupt (ADC_base、ADC_completed_interrupt);
    }
    
    void disable_ADC10 (void){
    ADC_DisableConversions (ADC_base、0);
    ADC_DISABLE (ADC_base);
    }
    
    void adc1Sample (void)
    {
    ENABLE_ADC10 (ADCINCH_1);
    
    _DELAY_CYCLES (15);
    
    //启用并开始转换
    //在单通道、单次转换模式中
    ADC_startConversion (ADC_base、ADC_SINGLECHANNEL);
    //LPM0、ADC 转换完成将强制退出
    
    //_bis_SR_register (LPM0_bits + GIE);
    
    while (!ADC_DONE)
    {
    _bis_SR_register (LPM0_bits + GIE);
    }
    
    ADC_DONE = 0;
    interrupt_id = 1;
    
    disable_ADC10 ();
    }
    
    void adc0Sample (void)
    {
    ENABLE_ADC10 (ADCINCH_0);//应为0
    
    _DELAY_CYCLES (15);
    
    //启用并开始转换
    //在单通道、单次转换模式中
    ADC_startConversion (ADC_base、ADC_SINGLECHANNEL);
    //LPM0、ADC 转换完成将强制退出
    
    //_bis_SR_register (LPM0_bits + GIE);
    
    while (!ADC_DONE)
    {
    _bis_SR_register (LPM0_bits + GIE);
    }
    
    ADC_DONE = 0;
    interrupt_id = 2;
    
    disable_ADC10 ();
    }
    
    void tempSample (void)
    {
    ENABLE_ADC10 (ADCINCH_12);
    
    _DELAY_CYCLES (15);
    
    //启用并开始转换
    //在单通道、单次转换模式中
    ADC_startConversion (ADC_base、ADC_SINGLECHANNEL);
    //LPM0、ADC 转换完成将强制退出
    
    //_bis_SR_register (LPM0_bits + GIE);
    
    while (!ADC_DONE)
    {
    _bis_SR_register (LPM0_bits + GIE);
    }
    
    ADC_DONE = 0;
    interrupt_id = 3;
    
    disable_ADC10 ();
    }
    
    void initGPIO (void){
    
    P1DIR |= 0b01000000;
    
    P2DIR |= 0b00001111;// P0-P3所有输出
    P2OUT = 0x00;
    
    PMM_enableTempSensor ();//启用温度传感器
    PMM_enableInternalReference();
    
    P1SEL1 |= GPIO_PIN6;// PWM 模式
    
    P1SEL1 &=~(BIT7); // USCI_A0 UART 操作仅发送
    P1SEL0 |= BIT7;
    
    // I2C 引脚
    P1SEL0 |= BIT2 | BIT3;
    P1SEL1 &=~(BIT2 | BIT3);
    
    //ADC 引脚
    P1SEL0 |= BIT0 | BIT1;
    P1SEL1 |= BIT0 | BIT1;
    /*
    *禁用 GPIO 上电默认高阻抗模式以激活
    *先前配置的端口设置
    *
    PMM_unlockLPM5 ();
    }
    
    // ADC 中断服务例程
    #if defined (__TI_Compiler_version__)|| defined (__IAR_systems_ICC__)
    #pragma vector=ADC_vector
    __interrupt void ADC_ISR (void)
    #Elif defined (__GIC_)
    void ___attribute_isr (
    nc
    )(void)(nc) interrupt!
    #endif
    {
    ADC_Conversion_Result = ADCMEM0;// AP
    
    ADC_DONE = 1;
    
    _BIC_SR_REGISTER_ON_EXIT (LPM0_BITS); //退出 LPM0
    }
    
    void initClockTo16MHz()
    {
    //根据 MCLK 的器件数据表的要求配置一个 FRAM 等待状态
    //在配置时钟系统之前在8MHz 以上运行。
    FRCTL0 = FRCTLPW | NWAITS_1;
    
    _bis_SR_register (SCG0);//禁用 FLL
    CSCTL8 |= MODOSCREQEN;
    CSCTL3 |= SELREF_REFOCLK;//将 REFO 设置为 FLL 基准源
    CSCTL0 = 0; //清除 DCO 和 MOD 寄存器
    CSCTL1 &=~(DCORSEL_7); //首先清除 DCO 频率选择位
    CSCTL1 |= DCORSEL_5; //设置 DCO = 16MHz
    CSCTL2 = FLLD_0 + 487; //设置为 fDCOCLKDIV =(FLLN + 1)*(fFLLREFCLK/n)
    // =(487 + 1)*(32.768 kHz/1)
    // = 16MHz
    
    _DELAY_CYCLES (3);
    _BIC_SR_register (SCG0); //启用 FLL
    while (CSCTL7 &(FLLUNLOCK0 | FLLUNLOCK1)); // FLL 锁定
    
    CSCTL4 = SELMS_DCOCLKDIV | SELA_REFOCLK;
    }
    
    
    // RTC 中断服务例程
    #if defined (__TI_Compiler_version__)|| defined (__IAR_systems_ICC__)
    #pragma vector=RTC_vector
    __interrupt RTC_ISR (void)
    #Elif defined (__IAR_systems_ICC_)(void
    
    
    )(void)(void)(n_rtc)(void)(void)(void)
    #endif
    {
    INTERRUPT_ID = 0;
    RTC_DONE = 1;
    _BIC_SR_REGISTER_ON_EXIT (LPM0_BITS); //睡眠定时器退出 LPM0
    
    开关(__evo_in_range (RTCIV、RTCIV_RTCIF)
    
    {
    案例 RTCIV_NONE:中断; //无中断
    案例 RTCIV_RTCIF: // RTC 溢出
    中断;
    默认值:break;
    }
    
    
    void initrtc()
    {
    RTCMOD = 16-1;//设置为256Hz
    SYSCFG2 |= RTCCKSEL; //选择 ACLK 作为 RTC 时钟
    RTCCTL = RTCSS_1 | RTCSR | RTCPS__16 | RTCIE;
    } 

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

    这基本上是我所想到的。 运行时它有什么作用?

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

    我实施了它、我不会看到任何不良影响。  很难判断它是否有任何改进、因为当我修改代码时、问题就会消失(需要喜欢这些类型的问题)。  我同意你的看法,认为它应该更强大。