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.
使用 CCS v10、并且当前在定制 SBC 上运行 MSP430F5638。 使用 TB0创建用于 LED 调光的 PWM。 TB0工作正常、在示波器上获得所需的频率和占空比。 但我有很多问题。 我包含了与完整版相同的简化版部分。 完整程序会将大量数据发送到所连接的 LCD 以进行测试和开发-为清晰起见、删除了该代码。
void main(void) { WDTCTL = WDTPW | WDTHOLD; // stop watchdog timer // setup functions // setup_430_ports(); setup_430_clocks(); // use XT2 @ 20 MHz // setup testing for LED PWM Dimmer set_LED_TB0_dim(); // no code accessible after LED function runs // LCD_put_string_4_cc(170, 20, "AFTER LED TB0 CALL", red, white); }
void set_LED_TB0_dim(void) { float xt2 = 20e6, frequency, dutycycle; WDTCTL = WDTPW+WDTHOLD; // Stop WDT P4SEL |= BIT6; // P4.6 peripheral option select P4DIR |= BIT6; // P4.6 output // left most 0 not required since only 1 TB TBCCR0 = 100; // set CCR0 cycle period register TBCCTL6 = OUTMOD_7; // set CCR6 Output mode, reset/set TBCCR6 = 50; // set CCR6 PWM duty cycle TBEX0 = 0; // has no effect, 0 = '/1' by default // enable CCR6 interrupt - required for ISR to run // but disables TB0, no PWM out //TBCCTL6 = CCIE; // ID_0 = /1 by default // add enable interrupt - not necessary (+ TBIE), removed TBCTL = TBSSEL_2 + MC_1 + ID_0 + TBCLR; // SMCLK, up mode to CCR0, /1, TB clear // compute frequency & duty cycle for LCD diagnostics frequency = xt2/TBCCR0; // not accurate for > 50% and < 100%, need to cast int as float dutycycle = (float)TBCCR0/TBCCR6; // no timer output without this? __bis_SR_register(LPM0_bits + GIE); // enter LPM0 with interrupts enabled, CPU off, runs in regular routines //__bis_SR_register(GIE); // interrupts enabled, runs in regular routines //__bic_SR_register_on_exit(LPM0_bits); // exit LPM0 - can only run from ISR's } // ISR from msp430f66xx_tb_03.c and modified // Timer_B0 CCR6 Interrupt Vector (TBIV) handler // changed from B1 to B0 - BOTH MUST BE B1 TO WORK???? #pragma vector=TIMERB1_VECTOR __interrupt void TIMERB1_ISR(void) { switch( __even_in_range(TBIV,14) ) { case 0: break; // No interrupt case 2: break; // CCR1 not used case 4: break; // CCR2 not used case 6: break; // CCR3 not used case 8: break; // CCR4 not used case 10: break; // CCR5 not used case 12: // CCR6 overflow { __bic_SR_register_on_exit(LPM0_bits); // exit LPM0, can only run from ISR LCD_put_string_4_cc(170, 40, "IN TB0 ISR CASE 12", red, white); break; } case 14: break; // CCR7 not used default: { LCD_put_string_4_cc(190, 0, "IN TB0 ISR DEFAULT CASE", white, red); break; // no default } } }
main()问题
1.在调用 SET_LED_TB0_DIM ()后,为什么 main()中的任何代码都不运行?
Set_LED_TB0_DIM ()问题
我真的不希望 TB0将 CPU 放入 LPM 中、但没有它、代码就无法运行。
ISR 问题
为什么 ISR 名称在矢量和函数名称中要求 B1、而不要求 B0? 这是 TB0、但不适用于 B0。
我看到两个问题。
第一个是注释掉启用定时器中断的代码。 这意味着当您设置 LPM0时、没有 ISR 导致退出。 当然、您启用中断的代码也会对该寄存器中先前的设置进行削减、这就是 PWM 停止的原因。 "|="可能是您的意思。
但是、如果启用了中断、您没有太多时间为 ISR 提供服务。 我怀疑大约100个 SMCLK 周期与 MCLK 相同。 LCD 字串调用很容易会消耗更多的电量。 这意味着在 ISR 返回之前会触发另一个计时器中断。 一种启动时钟周期主程序的可靠方法。
main() 1:正如 David 指出的,你没有设置 TB0CCTL6:CCIE,所以 LPM 永远不会被吵醒。
SET_LED 1:TB0是规范名称。 如果您将代码移动到具有2个 Tb/s 的器件、则会有"TB"和"TB1"、这将很难读取。
Set_LED 3: 请描述您的症状。
SET_LED 5:请描述您的症状。
ISR 1: TIMERB1_Vector 正式为 TIMER0_B1_VECTOR、其中 B0_VECTOR (仅限)应用于 CCR0、B1_VECTOR 应用于所有其他对象。 [参考用户指南(SLAU208Q)第18.2.6节]
主动:正如 David 指出的、您的计时器运行速度非常快。 如果不使 CPU 饱和、ISR 中就无法执行其他操作。 (您也无法读取每5微秒变化一次的 LCD。)
感谢 Bruce、
主要() 1 ----------------------------------------------
我现在将 通过 TB0CCTL6 = OUTMOD_7 + CCIE 来设置 CCIE;
我的 ISR 案例是这样的
案例12:// CCR6溢出
{
_BIC_SR_REGISTER_ON_EXIT (LPM0_BITS);//退出 LPM0,只能从 ISR 运行
LCD_PUT_STRING_4_cc (170、20、"在 TB0 ISR 案例12中"、红色、白色);
中断;
}
LCD 语句运行、如果我将其注释掉、我仍然有问题。 main 中没有任何内容、在调用 SET_LED 运行后、我仍然对此执行错误操作。
SET_LED 3和5 --------------------------------------------------
此仪器将在 RTC 设置的2秒周期运行。 它会启动、读取数据、执行它的操作、更新 LCD 并返回到睡眠状态。 有几个按钮、每个按钮都有自己的 ISR、大多数按钮只是设置一个全局变量、主第二个循环会处理该全局变量。 但是、一个开关将通过连续按来设置功率级别来打开 LED 闪光灯、最后将其关闭。 这就是我不希望 SET_LED 函数进入 LPM 的原因。 但没有它、函数就无法运行。 还有其他选项吗?
定时器运行得很快-------
TB0必须生成100KHz 至1MHz 的方波信号才能驱动 LED 驱动器 IC。 ACLK 太慢、但我可以将 SMCLK 除以8、并且仍然会从100KHz 到800KHz 获取脉冲、或/4以准确地达到范围。 这应该有所帮助。
让计时器以200kHz (甚至1MHz)的频率生成 PWM 是可以的。 以200kHz (或400kHz、如果您仍在设置 TBIE)中断是另一种情况、因为每个 ISR 需要大约30个 CPU 时钟才能进入和退出。 由于 您的所有 CPU 都专用于 ISR 调用、因此未执行 main()。
如果该 LCD 调用正在更新(人类可读)显示、则每秒更新200、000次没有任何价值、因为人类可能无法这么快地读取它。
我建议您采用另一个计时器(您有4x+RTC 可供使用)并以人机速度运行该计时器、例如每秒1-2次中断、以更新显示。 让 TB0在后台独立运行(无中断)。
在从中断连接到 CPU 上的情况下、这是可以的。
我最初的问题之一是:如何在不创建任何中断的情况下将 TB0用作 PWM 发生器。 我从不需要 TB0 ISR。 我想使用 TB0作为自打开时起的哑铃脉冲发生器、直到我决定将其关闭。
LCD 每2秒更新一次。 我只在 ISR 中卡住了一个调用、以查看它是否实际到达那里-它是这样的。
我用于 TB0的两个 TI 示例是:msp430f66xx_TB_03.c 和 msp430f66xx_10.c、10个示例调用_ bis_SR_register (LPM0_bits + GIE);为什么它会调用它呢?
----------------------------------------------------
我想知道:如何将 TB0用作单调 PWM 而不使用 ISR!
请勿设置 CCIE 或 TBIE、并注释掉_bis_SR 调用、程序流正常、但 TB0不执行任何操作。 嗯、不是真的、在 main 结束前、示波器上有一个非常短的脉冲闪存(如果我在正确的微秒时间内查看示波器)并关闭所有外设。 向该测试代码添加了一个循环、以查看脉冲稳定状态。
许多示例在 main()末尾进入 LPM,只是因为它们没有执行什么操作。 在示例10中、它间接用作演示、演示一旦启动、PWM 就会自动运行、您不必执行任何操作。
您的代码是否仍然与您在上面发布的代码类似? 该代码在调用 SET_LED_TB0_DIM 后从 main 返回、因此 它最终会进入启用的循环(在 ABORT()中)。 我认为没有任何东西会停止计时器、因此 PWM 将永远继续。 我怀疑它是停止 PWM 的其他东西。
如上所示:LCD 调用现在正在工作-它被过多的中断调用所困扰-正如您指出的那样。 TB0只创建一个单一脉冲序列、然后关闭。 如果我在 LCD 调用之后添加一个无限循环、脉冲将永远运行。
在 SET_LED_()中,我刚刚注释掉了对__bis_SR_register()的调用。 ISR 未运行。
那么问题是:一旦 main 结束、内部外设是关闭还是保持运行? 在我看来、它们被关闭(至少 TB0)。 主停止后、SBC 的功耗大约下降4mA、而不是在环路中运行。 这只是平均电流、看不到与时间相关的电流。
在嵌入式系统中,不应让 main()退出,因为没有任何地方可以退出。 C 运行时库通常会在 main()退出时放置一些内容。 通常只是一个无限循环、但它可能会进入低功耗模式。 如果不检查目标代码、就无法确定。
感谢 David 和 Bruce
这是一个非常有启发性的问题、有很多细微差别。 我将关闭它。