3

我正在编写代码以使一组五个 LED 看起来像“Knight Rider”风格来回“反弹”。写入 PORTB 寄存器时,我注意到插入 LED 的方式不同,分别是 1、2、4、8、16。这些会打开相应的 LED。所以我想通过使用pow函数将寄存器设置为 2 的值循环到 LED 编号(0、1、2、3、4)。但它不能正常工作。

#include <avr/io.h>
#include <inttypes.h>
#include <math.h>

void delay(uint16_t x);
//void buttons(int b1, int b2);

int led = 0;
int inc = 1;
unsigned int ledpow = 0;

int main(void)
{
    DDRB |= (1<<PORTB0); //Set PORTB0 (pin 8) as an output
    DDRB |= (1<<PORTB1); //Set PORTB1 (pin 9) as an output
    DDRB |= (1<<PORTB2); //Set PORTB2 (pin 10) as an output
    DDRB |= (1<<PORTB3); //Set PORTB3 (pin 11) as an output
    DDRB |= (1<<PORTB4); //Set PORTB4 (pin 12) as an output
    DDRD &= ~(1<<PORTD3); //Set PORTD3 (pin 3) as an input
    DDRD &= ~(1<<PORTD4); //Set PORTD4 (pin 4) as an input
    PORTB = 0; //Disable Pull-up resistors for PORTB
    PORTD = 0; //Disable Pull-up resistors for PORTD

    while(1)
    {
        while((PIND & (1<<PORTD3)) != 0) {
            //Do nothing, just pause the program
        }

        ledpow = pow(2,led);
        PORTB = ledpow;

        led = led + inc;

        if ((led == 4) || (led==0)) {
            inc = -inc;
        }

        if((PIND & (1<<PORTD4)) != 0) {
            delay(50);
        }
        else {
            delay(100);
        }
    }
}

void delay(uint16_t x)
{
    uint16_t i,j;

    for(i=0;i<x;i++)
        for(j=0;j<1000;j++)
            ;
    return;
}

为什么这不起作用?我让它使用 switch/case 语句。我测试了该pow函数通过做PORTB = pow(2,0);以及变量“led”的其他权力来工作。那工作正常。

4

3 回答 3

1

因为 pow 函数返回一个浮点数,它不是它应该表示的值的精确表示(而且,数学函数使用近似值工作)。所以可能pow(2, 3)不返回 8 而是 7.99856 或 8.0000261 等。在前一种情况下,你搞砸了,因为当你将它分配给端口时,它会被截断为整数(端口保存整数,对吗?)并丢失它的小数部分,形成 7 来点亮所有 3 个第一个 LED。

对于整数运算, pow 函数也是过期的,你在浪费你的镜头。我想知道你为什么不PORTB = 1 << led;使用它来设置其他端口状态......

此外,您的延迟循环非常不便携。深入了解 AVR-libc 的文档,有两个延迟循环函数可以提供几乎精确的时间延迟。您可以在我的 AVR 实用程序库中查看如何使用它们:http: //github.com/H2CO3/libavrutil

于 2012-09-08T04:32:45.050 回答
1

你不应该使用pow(). 您可以pow()在 C++ 参考中找到有关信息。

但是,本质上,整数没有pow()签名:

     double pow (      double base,      double exponent );
long double pow ( long double base, long double exponent );
      float pow (       float base,       float exponent );
     double pow (      double base,         int exponent );
long double pow ( long double base,         int exponent );

这意味着在运行时,它可能不起作用,因为它会对结果进行四舍五入。它需要浮点库(在 AVR 上的软件中完全实现)——速度慢且占用空间。

PORTB = pow(2,0);可能会起作用,因为它是 a constexpr,因此可以在编译时进行评估。

相反,请尝试使用左移运算符,例如:

PORTB = 1 << led;
于 2012-09-08T04:33:48.517 回答
0

您最好的方法是完全避免 pow 。端口不进行操作,而是使用 digitalWrite 功能。

void setup() {
    for (uint8_t pin=0; pin<20; ++pin) {
        pinMode(pin, OUTPUT);
    }
}

void blink(const uint8_t pos) {
    digitalWrite(pos, HIGH);
    delay(200);
    digitalWrite(pos, LOW);
}

void loop() {
    for (uint8_t pos=0; pos<19; ++pos) {
        blink(pos);
    }
    for (uint8_t pos=19; pos>0; --pos) {
        blink(pos);
    }
}

更复杂的骑士版本可以在我的博客herehere中找到

于 2013-10-28T17:39:28.013 回答