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.

[参考译文] MSP430G2955:引脚振荡器 CapSense 计数器未计数

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

https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/566478/msp430g2955-pin-oscillator-capsense-counter-not-counting

器件型号:MSP430G2955

大家好。 我在 MSP430G2955上有一个应用、用于测量连续6个元件的电容。 遗憾的是、在 WDT 栅极计时器期间、只有六个焊盘中的一个(焊盘0-5、只有焊盘1工作一致)会使 TA0R 计数。 当使用调试器在从 LPM3唤醒后检查 TA0R 的值时、对于焊盘1、TA0R 仅为非零、有时为 Pad2 (每5个读数)。 我的引脚映射已经过验证、此外、在使用示波器探测焊盘时、我可以在每个焊盘上看到正确的信号(每500ms 脉冲一次、其中每个脉冲的顶部由 RO 频率调制计数信号组成)。 振荡器似乎正常运行、但定时器没有计数。

以下是我的 CapSense 代码:

void TI_CTS_RO_PINOSC_TA0_WDTp_HAL (const 结构传感器*组、uint16_t *计数)
{
uint8_t i = 0;

//**上下文保存
//状态寄存器:
// WDTp:IE1、WDTCTL
// TIMERA0:TA0CTL、TA0CCTL1
//端口:PxSEL、PxSEL2
uint8_t contextSaveSR;
uint8_t contextSaveIE1;
uint16_t contextSaveWDTCTL;
uint16_t contextSaveTA0CTL、contextSaveTA0CCTL1、contextSaveTA0CCR1;
uint8_t contextSaveSel、contextSaveSel2;

contextSaveSR =__get_SR_register ();
contextSaveIE1 = IE1;
contextSaveWDTCTL = WDTCTL;
contextSaveWDTCTL &= 0x00FF;
contextSaveWDTCTL |= WDTPW;
contextSaveTA0CTL = TA0CTL;
contextSaveTA0CCTL1 = TA0CCTL1;
contextSaveTA0CCR1 = TA0CCR1;

//**设置测量计时器*********
//选项为 TA0、TA1、TB0、TB1、TD0、TD1这些选项被向上推入
//电容式触控层。

//配置和启动计时器
TA0CTL = tassel_3 + MC_2; // INCLK、CONT 模式//从 tassel_3中更改
TA0CCTL1 = CM_3 + CCIS_2 + CAP; //位置 Neg、GND、电容
IE1|= WDTIE; //启用 WDT 中断 
//循环所有6个焊盘 对于(i = 0;i <(group->numElements, i++) { //上下文保存 contextSaveSel =*((group->arrayPtr[i])->inputPxselRegister); contextSaveSel2 =*((group->arrayPtr[i])->inputPxsel2Register); //为张弛振荡器配置端口(英文... 启用电容式感应) *((group->arrayPtr[i])->inputPxselRegister )和=~((group->arrayPtr[i])->inputBits ); *((group->arrayPtr[i])->inputPxsel2Register)|=((group->arrayPtr[i])->inputBits ); //**设置门定时器******** //设置传感器测量的持续时间 WDTCTL =(WDTPW + WDTTMSEL +(group->measGateSource)+(group->accumulationCycles));// WDT 来自 aclk (栅极源)、aclk/512 ->使用 aclk 作为 CapSense TA0CTL |= TACLR; //清除 Timer_A TAR if (group->measGateSource == GATE _WDT_ACLK) { _bis_SR_register (LPM3_bits + GIE); //等待 WDT 中断 } 其他 { _bis_SR_register (LPM0_bits + GIE); //等待 WDT 中断 } //基准信号在 GND 和 VCC 之间交替(这会导致上升和下降触发事件) //这会导致一个转换、开始计算电容 TA0CCTL1 ^= CCIS0;//创建 CCR1的软件捕捉(设置比较源与 VCC) Counts[i]= TA0CCR1; //保存结果-此处的断点用于检查 TA0R 和 TA0CCR1 WDTCTL = WDTPW + WDTHOLD; //停止看门狗计时器 //上下文恢复 *((group->arrayPtr[i])->inputPxselRegister)= contextSaveSel; *((group->arrayPtr[i])->inputPxsel2Register)= contextSaveSel2; } //结束序列 //上下文恢复 _bis_SR_register (contextSaveSR); if (!(contextSaveSR & GIE)) { _BIC_SR_register (GIE); // } IE1 = contextSaveIE1; WDTCTL = contextSaveWDTCTL; TA0CTL = contextSaveTA0CTL; TA0CCTL1 = contextSaveTA0CCTL1; TA0CCR1 = contextSaveTA0CCR1; }

我们非常感谢您的任何帮助或想法。 您可以随时提出问题;我很乐意提供更多信息。

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

    提供 TI 自己的库(CTS_HAL.c)并不能提供很多线索、您如何设置主函数和按钮结构会更加有用。 我建议您参考 SLAC489代码包中提供的 RO_PINOSC_TA0_WDTp_Wheel_Button 示例以及通过 TI Resource Explorer 的电容式触控软件库示例。 这将使您更好地了解如何利用多个元素。

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

    Ryan、

    感谢你的帮助。 我已经阅读过您提到的示例、似乎我正在以与该示例相同的方式实施多个元素。 该示例中提供的 CTS_HAL.c 与我正在使用的 CTS_HAL.c 稍有不同(并在我的初始帖子中引用)、但进行这些微小的更改对我的系统没有任何影响。 (这些更改包括在进入看门狗 LPM 之前立即启用 TimerA0、以及不使用捕捉控制硬件寄存器 TA0CCTL1和 CCIS0软件捕捉)。

    正如我在最初的帖子中所说的、主要问题是连接到引脚振荡器的计数器仅对焊盘1 (和 pad2、但每20个焊盘采样一次)的脉冲进行计数。 也许这一附加代码将有助于发现问题的根源。

    这是我的主代码和按钮结构;此应用程序的主循环位于 sysExec 函数中。

    int main (void)
    {
    
    WDTCTL = WDTPW | WDTHOLD; //停止看门狗计时器
    
    //将初始化引脚设置为0
    P1DIR = 0xFF;
    P2DIR = 0xF9;// 2.1和2.2上的 CapSense 引脚
    P3DIR = 0xFE;// CapSense 3.0
    P4DIR = 0x8F;// CapSense 引脚4.5、4.6、4.7
    P1OUT = 0;
    P2OUT = 0;
    P3OUT = 0;
    P4OUT = 0;
    
    //执行硬件初始化
    clock_init();
    PIN_INIT();
    UART_INIT ();
    #ifdef direct_debug_UART
    DBG_UART_INIT ();
    #endif
    //调用 sys exec,从不返回。
    sysExec_exec();
    
    //系统永远不应达到执行的这一点。
    //但只是以防…
    disableGlobalInterrupt();
    //强制看门狗复位
    WDTCTL = 0xDEAD;
    
    while (1);
    
    }
    
    void clock_init (void)
    {
    DCOCTL = 0; //选择最低 DCOx 和 MODx 设置
    BCSCTL1 = CALBC1_1MHz; //设置 DCO
    DCOCTL = CALDCO_1MHz;
    
    BCSCTL1 |= DIV_0; // ACLK/1 [ACLK/(0:1、1:2、2:4、3:8)]
    BCSCTL2 = 0; // SMCLK [SMCLK/(0:1、1:2:4、3:8)]
    BCSCTL3 |= LFXT1S_0 | XCAP_2; // LFXT1上的 LFXT1S0 32768Hz 晶振
    }
    
    void PIN_INIT (void)
    {
    
    P1SEL |= GSM_INT + GSM_STATUS;//GSM_DCDC + GSM_INT + GSM_STATUS;Still TBD
    P1DIR |= VBAT_GND +_1V8_EN + GSM_DCDC;
    P1DIR &=~ GSM_INT_INT + GSM_INT_INT + GPT/ INT_INT 输入;P1DIR + GPT_0 + GPT_INT_INT_INT_INT + GPT/ INT_INT_INT_INT + INT_INT +
    // VBAT_GND 控制 VBAT 感应、默认关闭(低电平有效)
    // GSM_DCDC 控制(U4)默认关闭(高电平有效)
    //_1V8_EN 控制(U5)默认关闭(高电平有效)
    
    P2SEL |= BIT6 + BIT7;//为 P2.6
    P2DIR 配置晶振 XIN |= I2C_DRV + GSM_EN + BIT7;//为 BIT7; // I2C_DRV 是输出 GPIO (默认为 hi-z)控制引脚2.0上的 I2C // BIT0 = ACLK OUT
    //当 GPS 打开时,GSM_PWR 是输出 GPIO (默认为 OFF)打开
    //当调制解调器打开时,LS_VCC 为输出 GPIO (默认为关闭)
    // BIT7用于 P2.7
    
    P3SEL 上的晶振 XOUT |= I2C_SDA + I2C_SCL + TXD;
    P3SEL2 |= RXD;
    P3DIR |= VBAT_GND +_1V8_EN;
    
    P4DIR |= GPS_ON_OFF;
    }
    
    void UART_init (void)
    {
    // UART 的 ACLK 源
    UCA0CTL1 |= UCSSEL_1; // ACLK
    UCA0BR0 = 0x03; // 32 kHz 9600
    UCA0BR1 = 0x00; // 32 kHz 9600
    UCA0MCTL = UCBRS0 + UCBRS1; //调制 UCBRSx = 3.
    
    UCA0CTL1 &=~UCSWRST; //**初始化 USCI 状态机**
    UC0IE |= UCA0RXIE; //启用 USCI_A0 RX 中断
    }
    
    void dbg_UART_init (void)
    {
    uint8_t 垃圾;
    
    memset (isrCommBuf、0、ISR_BUF_SIZE);
    isrCommBufHead = 0;
    isrCommBufTail = ISR_BUF_SIZE - 1;
    memset (isrCommRecv、0xff、3);
    
    //清除接收缓冲区
    disable_UART_Rx ();
    垃圾= UCA0RXBUF;
    enable_UART_Rx();
    }
    
    void sysExec_exec(void)
    {
    uint32_t LOOP_COUNT;
    uint16_t NO_Water;
    uint8_t sample_period;
    
    //每秒启动计时器中断2x
    timerA1_init();
    
    //初始化2015年1月1日的日期
    // h、m、s、AM/pm
    settime (0x00、0x00、0x00、0x00);
    // y、m、d
    setdate (2015、1、1);
    
    WatersSense 初始化();//此函数不获取数据,它仅插入数据结构
    
    //启用全局中断
    enableGlobalInterrupt();
    LOOP_COUNT = 0;
    NO_Water 时间= 0;
    SAMPLE_PERIOD = 0;
    
    //主循环
    while (1)
    {
    
    //现在是取样的时候了
    WaterSense_TakeReading();//此函数最终调用 PIN 振荡器函数
    
    debug_sampProgress ();//向 UART 输入@
    
    LOOP_COUNT++;
    //每个 tICKS_PER_second (2)秒更新并报告统计信息
    如果(!(LOOP_COUNT % tICKS_PER_TREND)
    {
    uint8_t 级别;
    
    //水感应和存储
    Level = WaterSenseAnalyzeData ((loop_count * seconds_per_Trend)/ticks per_Trend);
    
    如果(!level)
    {
    如果(no_water _time < 0xFFFE)
    NO_Water Time += seconds_per_Trend;
    }
    其他
    NO_Water 时间= 0;
    
    
    如果(NO_Water 时间> NO_Water HF 到 LF Time in 秒)
    SAMPLE_PERIOD = 20秒_PER_TREND;
    其他
    SAMPLE_PERIOD = 0;
    
    #IF (PERIOD_TEMP_MEAS=1)
    //每分钟进行一次温度测量
    if (!(loop_count %(ticks per_Trend *(60/seconds_per_Trend))))
    WatersSenseReadInternalTemp ((loop_count * seconds_per_Trend)/ticks per_Trend);
    #endif
    } //现在是取样的时候了
    
    IF (SAMPLE_PERIOD)
    {
    #ifdef direct_debug_UART
    //即将入睡20秒
    while (!dbg_UART_txqempty ());//发送其余的调试数据
    while (dbg_UART_txpend ()); //等待最后一个字符被使用
    _delay_cycles (2000); //之后等待一个字符,以便终端不会被混淆
    #endif
    timera1_20sec_sleep();//将深度睡眠时间设置为20秒
    //此时禁用 UART TX ISR
    }
    
    //睡眠、Timer1A 中断时唤醒
    _bis_SR_register (LPM3_bits);
    
    
    IF (SAMPLE_PERIOD)
    {
    timerA1_inter_sample_sleep ();//将计时器设置回采样频率
    //此时启用 UART TX ISR
    SAMPLE_PERIOD = 0;
    LOOP_COUNT +=((20*TICKS_PER_TREND)/Seconds_PER_TREND);//我们睡眠了20秒(循环计数是样本滴答而不是秒)
    如果(no_water _time < 0xFFFE)
    NO_WASE_TIME += 20;//我们在20秒内也没有水(可能)
    }
    
    //如果接收到 OTA 复位器件消息、则重新启动活动
    //将为 true,等待延迟时间到期执行
    // MSP430重新启动
    。}
    }
    
    void waterscens_takeReading (void)
    {
    uint8_t pad_number;
    uint16_t padCounts[total_pad];
    
    //执行电容测量
    TI_CAPT_Raw (&PAD_SENSORS、&padCount[0]);//向 TI_CTS_RO_PINOSC_TA0_WDTp_HAL ()
    
    //每个焊盘的环路。
    
    对于(PAD_NUMBER = 0;PAD_NUMBER < NUM_PADS;PAD_NUMBER_++)
    {
    WaterDetect_add_sample, pad_number , padCounts[pad_number];
    }
    }
    
    void timerA1_init (void)
    {
    //#if ticks per_Trend = 3 && seconds_per_Trend = 2
    // TA1CCR0 = 21845-1;// 32786Hz/21845=1/1.5HZ
    //#elif (ticks per_Trend = 4 & seconds_per_Trend = 2+ ticks =
    1)= 1CCR384 (ticks = 1)|= 1 (ticks = 1)|= 1–1–1 (ticks = 1) // 32786Hz/16384=2Hz 这是当前使用的设置
    //#Elif TICKS_PER_Trend == 3 && Seconds_per_Trend == 1
    // TA1CCR0=10922-1;// 32786Hz/1/10922 =32786HZ/10922 = 3Hz
    // TA1Elif=1/tIC1Hz;/1=
    32786202Hz /1&tICK=1/tures=1/tures=1/tic4Hz;// tures=32786_1&ticf=1/tures=1/tic4Hz;// tures=1/tic1&tages=1/tic1&tic
    
    
    TA1CTL = tassel_1 + MC_1 + TACLR;
    TA1CCTL0 &=~CCIFG;
    TA1CCTL0 |= CCIE;
    TICKS_PER_second = 0;
    
    }
    
    //==== 下面的 structure.c 中的焊盘===
    //================================================================================
    //第一个元素(P4.7)
    const 结构元素 pad0 ={
    
    .inputPxselRegister =(unsigned char *)&P4SEL、
    .inputPxsel2Register =(unsigned char *)&P4SEL2、
    .inputBits = BIT7、
    .threshold = 500
    };
    
    
    //第二个元素(P2.1)
    const 结构元素 pad1 ={
    
    .inputPxselRegister =(unsigned char *)&P2SEL、
    .inputPxsel2Register =(unsigned char *)&P2SEL2、
    .inputBits = BIT1、
    .threshold = 100
    };
    
    
    //第三个元素(P4.6)
    const 结构元素 pad2 ={
    
    .inputPxselRegister =(unsigned char *)&P4SEL、
    .inputPxsel2Register =(unsigned char *)&P4SEL2、
    .inputBits = BIT6、
    .threshold = 100
    };
    
    //第四个元素(P2.2)
    const 结构元素 pad3 ={
    
    .inputPxselRegister =(unsigned char *)&P2SEL、
    .inputPxsel2Register =(unsigned char *)&P2SEL2、
    .inputBits = BIT2、
    .threshold = 100
    };
    
    
    //第五个元素(P4.5)
    const 结构元素 pad4 ={
    
    .inputPxselRegister =(unsigned char *)&P4SEL、
    .inputPxsel2Register =(unsigned char *)&P4SEL2、
    .inputBits = BIT5、
    .threshold = 100
    };
    
    //第六个元素(P3.0)
    const 结构元素 pad5 ={
    
    .inputPxselRegister =(unsigned char *)&P3SEL、
    .inputPxsel2Register =(unsigned char *)&P3SEL2、
    .inputBits = BIT0、
    .threshold = 100
    }; 

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

    您的代码和示例之间存在一些差异、但我对库资源的了解不够、无法提供任何有价值的建议。 您是否考虑移植特定按钮元素的示例、验证其是否正常运行、然后在 CapSense 正常工作后添加其他功能?

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

    Ryan、

    经过大量的故障诊断后、我发现了问题。

    在 MSP430G2955上、TIMERA1被连接至 PinOsc 电路而不是 TIMERA0。 通过切换哪个计时器运行我们的电容式感应引脚振荡、TAxR 计数正确、我们能够感应电容变化。

    器件数据表中的第14页让我了解了这一小细节。 此外、由于所有示例都配置为使用 TimerA0、包括其函数名、因此我被每个示例误导。 让 MSP430G2955的差异更清晰、或者在示例代码中添加注释可能会有所帮助。

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

    感谢您为其他社区成员提供此详细答案。 此反馈对 TI 来说是很有价值的信息。

    此致、
    Ryan