3

私は 5 つの LED のセットを「ナイト ライダー」スタイルで前後に「跳ね返る」ように見せるコードを書いています。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 ステートメントで動作させました。そして、変数「led」が持つ他の力を実行することでpow関数が機能することをテストしました。PORTB = pow(2,0);それは正しく機能しました。

4

3 に答える 3

1

pow 関数は浮動小数点数を返すため、それが表すはずの値の正確な表現ではありません (また、数学関数は近似値を使用して機能します)。したがって、おそらくpow(2, 3)8 ではなく 7.99856 または 8.0000261 などを返します。前者の場合、それをポートに割り当てると、整数に切り捨てられ (ポートは整数を保持しますよね?)、小数部が失われるため、失敗します。最初の 3 つの LED をすべて点灯させるために 7 を形成します。

整数演算の場合、 pow 関数も期限切れです。ショットを無駄にしています。他のポートの状態を設定するために使用しているのに、なぜ使用しないのだろうかPORTB = 1 << led;...

また、遅延ループは恐ろしく移植性がありません。AVR-libc のドキュメントに飛び込むと、ほぼ正確な時間遅延を提供する 2 つの遅延ループ関数があります。私の 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);であるため動作する可能性constexprがあり、コンパイル時に評価できます。

代わりに、左シフト演算子を使用してみてください。

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

あなたの最善のアプローチは、パウを完全に避けることです。ポートを操作する代わりに、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);
    }
}

より洗練されたナイト ライダー バージョンについては、私のブログのこちらこちらをご覧ください。

于 2013-10-28T17:39:28.013 に答える