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.
您好!
我正在尝试同时运行两个计时器:用于生成 PWM 的 TimerA 和 TimerB。
定时器 A: 时钟源是使用16MHz 外部晶振的 TACLK (由另一个安装了 Y1的 msp430fr5969的引脚3.4提供16 MHz)
定时器 B:时钟源为 SMCLK、该时钟源映射到16MHz 的 MCLK (DCO 源)
我的最终目标是以高波特率生成2FSK 信号、为此、我将使用计时器 A 作为我的波特率源、并使用计时器 B 来生成 FSK 的2个频率
相关代码片段:
void set_cpu_freq () {
FRCTL0 = FRCTLPW | NWAITS_1;
CSCTL0_H = CSKEY >> 8;//解锁 CS 寄存器
CSCTL1 = DCORSEL | DCOFSEL_4;//将 DCO 设置为8MHz
CSCTL2 = SELM__VLOCLK | SELS__DCOCLK | SELM__DCOCLK;
CSCTL3 = DIVA_1 | DIVS__1 | DIVM_1;//将所有分频器设置为1
}
int main (void){
WDTCTL = WDTPW | WDTHOLD;//停止看门狗计时器
P1OUT &&~BIT3;//清除 P1.0输出锁存器以实现已定义的上电状态
P1DIR |= BIT3;//将 P1.0设置为输出方向
P1DIR &=~BIT2;
PM5CTL0 &=~μ A LOCKLPM5;//禁用 GPIO 上电默认高阻抗模式
//激活先前配置的端口设置
set_cpu_freq ();
while (1){
//消息生成代码:生成包含二进制信息的数组
__enable_interrupt ();
TA0CTL = TASSEL__TACLK | MC_1 | TACLR;// SMCLK、向上计数模式、无分频器
TA0CCR0 =(16000000/10000)- 1;//根据 SMCLK 频率设置周期
TA0CCTL0 = CCIE;//启用中断
TA0CCTL1 = OUTMOD_7;
TB0CTL = TBSSEL__SMCLK | TBCLR | MC_1;// SMCLK、向上计数模式、/8分频器
TB0CCTL1 = OUTMOD_7;
TB0CCTL0 = CCIE;//启用 CCR0中断
delay_ms (100);
}
}
#pragma vector=TIMER0_B0_vector
__interrupt void Timer0_B0 (void)
{
P1OUT ^= BIT3;//生成 FSK 频率
}
__attribute__((interrupt (TIMER0_A0_vector))//控制 FSK 信号的波特率
void timer_a0_isr (void){
if (TX_COUNTER < TXLEN){
如果(arr[TX_COUNTER]=0){
TB0CCR0 =(CPU_FREQ/(2*300000))-1;
}
否则为(arr[tx_counter]== 1){
TB0CCR0 =(CPU_FREQ/(2*400000))-1;
}
TX_COUNTER++;
}
否则{
TX_COUNTER = 0;
disable_signal ();
msp430_timer_stop ();
}
}
问题:
如下图所示、我观察到频率开关之间的延迟约为6-7微秒、最初我同时对计时器 A 和 B 使用 SMCLK、观察到同一个问题。 我假设这肯定是一个问题、原因是两个计时器都使用相同的源、即 SMCLK、我切换到了当前的设置、即为计时器 A 使用 TACLK、为计时器 B 使用 SMCLK、但同样的问题仍然存在、 导致波特率限制、因为6-7微秒间隙随着我增加波特率例如30kbps 变得更加显著。 我的目标是至少具有100Kbps 的波特率。
期待社区提出一些建议,以缓解这一问题。
此致!
1) 1)我完全不知道 TASSEL_TACLK 是如何工作的、因为我没有看到 TA0CLK (P1.2)的 P1SEL1设置。 我建议您对两个计时器都使用 SMCLK。
2) 2) 是否要求将 P1.3用作 FSK 时钟? 它看起来 P1.4可以输出 TB0.1、因此将 TB0CCTL1设置为 OUTMOD_4 (切换)将为您提供现在拥有的信号、但没有延迟。 我怀疑示波器跟踪中的这些差距源于此延迟(在 TA0CCR0 ISR 运行时)。
3) CCR0更新有非常严格的最后期限(20或26个计时器周期)。 您可能需要考虑使用 DMA 代替软件来更新 TB0CCR0。 [参考数据表(SLAS704G)表6-12]
我想(2)是您现在所看到的、(3)是您接下来将遇到的。
[编辑:我刚刚注意到 P1.3可以提供 TA1.2 [请参考数据表表表6-50],所以如果你不能切换引脚(上面的(2)),这是一个选项。]
1) 1) 我完全不知道 TASSEL_TACLK 是如何工作的、因为我没有看到 TA0CLK (P1.2)的 P1SEL1设置。
出错了。 我删除了线路
P1SEL1 |=(BIT2);//将 P1.2 SEL 设置为 TA0CLK
写入查询时。 TACLK 正常工作是因为从 P1.2上移除跳线会导致定时器 A 没有输出。
2) 2)我通过在代码中进行以下添加和更改、按照针对 FSK 输出的建议切换到了 P1.4:
int main (void){
P1SEL0 |= BIT4;//将引脚1.4设置为特殊功能输出
P1DIR |= BIT4;//设置通道1 PWM 的输出引脚1.4
}
TimerB 配置:
TB0CTL = TBSSEL__SMCLK | TBCLR | MC_1;// SMCLK、向上计数模式、/8分频器
TB0CCTL1 = OUTMOD_4;
TB0CCTL0 = CCIE;//启用 CCR0中断
删除了 TimerB 的 ISR
输出频率卡在500kHz 的单个频率上、它应根据以下代码进行更改
__attribute__(interrupt (TIMER0_A0_vector))
void timer_a0_isr (void){
if (TX_COUNTER < TXLEN){
如果(arr[TX_COUNTER]=0){
TB0CCR0 =(CPU_FREQ/(2*300000))-1;
}
否则为(arr[tx_counter]== 1){
TB0CCR0 =(CPU_FREQ/(2*500000))-1;
}
TX_COUNTER++;
}
否则{
TX_COUNTER = 0;
disable_signal ();
msp430_timer_stop ();
}
}
编辑:可能是因为我不熟悉编程 MSP430、所以我在第二点中以错误的方式实现了解决方案
2) 2)删除此行:
> TB0CCTL0 = CCIE;//启用 CCR0中断
因为您不需要中断。 此外,如果没有 ISR,CCIE 将会触发调用 ISR_Fault (或一些类似的名称),它将永久旋转,这将导致您的症状。
1)我不会与成功争辩,但使用 TACLK 不能获得任何东西。 我(仍)建议改用 SMCLK。
它解决了我所面临的问题,非常感谢您的帮助 布鲁斯·麦克肯纳伊47378!在过去的几天里,我一直在为这件事感到苦恼。
关于 TimerA ISR、我想再问一点、环路频率限制在100kHz 但不能指出为什么我要检查引脚1.3的输出来检查 ISR 环路的频率。
TimerA0配置:
TA0CTL = TASSEL__SMCLK | MC_1 | TACLR;// SMCLK、向上计数模式、无分频器
TA0CCR0 =(16000000/200000)- 1;//根据 SMCLK 频率设置周期
// TA0CCR0 = 1;
TA0CCTL0 = CCIE;//启用中断
TA0CCTL1 = OUTMOD_7;
TA0CTL |= MC_1;//启动计时器
__attribute__(interrupt (TIMER0_A0_vector))
void timer_a0_isr (void){
P1OUT ^= BIT3;
if (TX_COUNTER < TXLEN){
if (arr_dump[TX_COUNTER]== 0){
// TB0CCR0 =(CPU_FREQ/(2*2000000))-1;
TB0CCR0 = 3;
}
否则、if (arr_dump[tx_counter]== 1){
// TB0CCR0 =(CPU_FREQ/(2*2000000))-1;
TB0CCR0 = 2;
}
TX_COUNTER++;
}
否则{
TX_COUNTER = 0;
disable_signal ();
msp430_timer_stop ();
}
}
位周期(符号速率)受更新 TB0CCR0的速度限制、在本例中、更新 TB0CCR0 ISR 需要多长时间。 由于这也与您之前的时钟延迟有关、因此您测得的持续时间(6-7us)是对 ISR 时间的合理估算、相当于略高于100kHz 的时间。
修整基于软件的更新或许能够获得一点收益、但其结果却非常接近最小值。 此处的解决方案是 DMA (上述(3))。 在此模型中、arr_dump []数组将 包含 TB0CCR0值(长度为 TX_LEN),DMA 将在 TA0CCR0上触发以将连续值写入 TB0CCR0。 我在上面提到了 DMA 触发表;每次传输所需的时间在用户指南表11-3中、但这些都是非常快的、可供您使用。
这里有一个针对模拟应用的此方法演示:
细节不同、但原理是相同的。 那个会更新占空比(固定周期)、但它仍然使用计时器触发器来更新计时器寄存器。