【问题标题】:A macro gives a wrong value in C language宏在 C 语言中给出了错误的值
【发布时间】:2018-04-29 19:19:21
【问题描述】:

我正在尝试在带有 XC8 编译器的 MPLAB X IDE 中使用 PIC18F4321 的 Timer1 在 16 位模式下编写一个产生 1000 ms 延迟的子程序。利用此延迟来切换 LED。我的问题是我无法得到想要的延迟(1000 毫秒)。我尝试调试程序我观察到使用宏计算的“计数”值不正确。它给出的值是 0x4000 而不是 0x0F42。 不知道宏有什么问题:

#define count (((timeDelay) * 1000) / (timerPeriod) * 256)

// C-program using polled I/O:
#include <P18F4321.h>
#define timeDelay (1000) // 1000 ms
#define Fosc (4) // 4 MHz
#define timerPeriod (1 / ((Fosc) / 4)) // us
#define count (((timeDelay) * 1000) / (timerPeriod) * 256)
#define countInit ((0xFFFF - (count)) + 1)
#define countInitHigh ((countInit & 0xFF00) >> 8)
#define countInitLow (countInit & 0x00FF)

void T0Delay(); // A subroutine that generates a delay of 1000 ms

void main()
{
    OSCCON = 0x60; // 4MHz Internal Oscillator
    TRISC = 0x00; // Port C output
    T0CON = 0x07; // 16-bit, 1:256 prescaler, internal clock
    for(;;) // loop forever
    {
        PORTCbits.RC0 = 0; // turn LED OFF
        T0Delay(); // Wait 10 seconds
        PORTCbits.RC0 = 1; // turn LED ON
        T0Delay(); // Wait 10 seconds
    }
}

void T0Delay(void)
{
    TMR0H = countInitHigh;
    TMR0L = countInitLow;
    INTCONbits.TMR0IF = 0; // clear timer overflow flag
    T0CONbits.TMR0ON = 1; // start Timer0
    while(!INTCONbits.TMR0IF); //polling, wait until timer finishes counting
    T0CONbits.TMR0ON = 0; // Stop Timer0
}

【问题讨论】:

  • timerPeriod 真的应该扩展为 (1 / (((4)) / 4)),即 1 吗?
  • @zwol 是的,它是正确的
  • 如果您在 16 位 int 系统上,timeDelay * 1000 会导致未定义的行为
  • @M.M 是的,我使用的是 16 位系统。但是我该如何解决这个问题???
  • 一种方法是使用 32 位算法(将 1000 更改为 UINT32_C(1000)1000UL

标签: c embedded microcontroller mplab pic18


【解决方案1】:

我终于可以解决问题了,非常感谢你们。问题是在宏定义#define count (((timeDelay) * 1000) / ((timerPeriod) * 256)) 中,分子上的结果溢出超过 16 位。所以解决方案是通过将(1000) 更改为(1000UL) 来使用32 位算法。运行的最终代码将其更正如下:

// C-program using polled I/O:
#include <P18F4321.h>
#define timeDelay (1000UL) // 1000 ms
#define Fosc (4) // 4 MHz
#define timerPeriod (1 / ((Fosc) / 4)) // us  
#define count (((timeDelay) * 1000UL) / ((timerPeriod) * 256))
#define countInit ((0xFFFF - (count)) + 1)
#define countInitHigh ((countInit & 0xFF00) >> 8)
#define countInitLow (countInit & 0x00FF)

void T0Delay(); // A subroutine that generates a delay of 1000 ms

void main()
{
    OSCCON = 0x60; // 4MHz Internal Oscillator
    TRISC = 0x00; // Port C output
    T0CON = 0x07; // 16-bit, 1:256 prescaler, internal clock
    for(;;) // loop forever
    {
        PORTCbits.RC0 = 0; // turn LED OFF
        T0Delay(); // Wait 10 seconds
        PORTCbits.RC0 = 1; // turn LED ON
        T0Delay(); // Wait 10 seconds
    }
}

void T0Delay(void)
{
    TMR0H = countInitHigh;
    TMR0L = countInitLow;
    INTCONbits.TMR0IF = 0; // clear timer overflow flag
    T0CONbits.TMR0ON = 1; // start Timer0
    while(!INTCONbits.TMR0IF); //polling, wait until timer finishes counting
    T0CONbits.TMR0ON = 0; // Stop Timer0
}

【讨论】:

    【解决方案2】:

    如果你在(timerPeriod) * 256 周围加上括号,你会得到你想要的结果:

    #define count (((timeDelay) * 1000) / ((timerPeriod) * 256) /*<=parentheses here*/ )
    

    乘法和除法在 C 中具有相同的优先级(就像在数学中一样),所以如果你想除以 (timerPeriod) * 256,你需要用括号括起来。

    【讨论】:

    • 我刚刚尝试了您的提议,但仍然给出了错误的值!
    • @SamirFassak 重新定义后的值为0xf42。这是证据:ideone.com/zMX9FD
    • 是的,我在在线编译器上试过它给出了正确的值 (0x0f42) ideone.com/OtuCrf。它在 Visual C++ 2008 上也给出了正确的值。但是当我在 MPLAB X IDE 中的 XC8 编译器上尝试代码时,我得到一个错误的值 (0x0042)???
    • @SamirFassak (timeDelay) * 1000 在“16 位模式”下是否溢出?
    • @SamirFassak 抱歉,没有意识到您可以使用 16 位机器。好吧,在 16 位中您无法准确地进行计算,但也许您可以简单地将宏定义为 0xf42 或使用 c 预处理器以外的其他东西生成代码。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-04
    • 2015-07-04
    • 1970-01-01
    • 2017-11-14
    • 2020-09-03
    相关资源
    最近更新 更多