2012-09-08 5 views
3

5 개의 LED 세트가 앞뒤로 "기사 라이더 (Night Rider)"스타일로 "바운스 (bounce)"하는 코드를 작성하고 있습니다. PORTB 레지스터에 글을 쓸 때, LED를 꽂은 방식이 1, 2, 4, 8, 16 일 것이라고 인식했습니다. LED가 켜지면 LED가 켜집니다. 그래서 나는 pow 함수를 사용하여 레지스터를 2의 값으로 설정하여 LED 번호 (0, 1, 2, 3, 4)로 루핑하는 것으로 생각했습니다. 그래도 제대로 작동하지 않습니다.C 및 AVR pow 기능을 LED에 적용

#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"변수를 사용하여 작동한다는 것을 테스트했습니다. 그것은 올바르게 작동했습니다.

답변

1

pow 함수는 표현할 값의 정확한 표현이 아닌 부동 소수점 숫자를 반환하기 때문에 (또한 수학 함수는 근사법을 사용하여 작동합니다). 어쩌면 pow(2, 3)은 8을 반환하지만 7.99856이나 8.0000261 등입니다. 전자의 경우 포트에 할당하면 포트가 정수로 잘립니다 (포트는 정수를 보유하고 있습니까?). 분수 부분, 7을 형성하여 모든 3 개의 첫 번째 LED를 점등시킵니다.

정수 연산의 경우 pow 함수가 기한이 지나서 총을 낭비하고 있습니다. 나는 왜 당신이 다른 포트 상태를 설정하기 위해 그것을 사용합니까 PORTB = 1 << led;을 사용하지 않는지 궁금하네요 ...

또한, 귀하의 지연 루프는 몹시 unportable입니다. AVR-libc의 문서로 들어가면 거의 정확한 시간 지연을 제공하는 두 개의 지연 루프 기능이 있습니다. 내 AVR 유틸리티 라이브러리에서 사용하는 방법을 볼 수 있습니다. http://github.com/H2CO3/libavrutil

1

pow()을 사용하지 마십시오. pow() at C++ Reference에 대한 정보를 찾을 수 있습니다.

 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); 

는 결과를 반올림 때문에 실행시,이 작동하지 않을 수 있음을 의미합니다 :

그러나, 본질적으로, 정수에 대한 pow() 서명이 없습니다. 느린 속도와 공간을 차지하는 부동 소수점 라이브러리 (AVR의 소프트웨어에서 완벽하게 구현 됨)가 필요합니다.

PORTB = pow(2,0);constexpr이므로 컴파일 할 때 평가할 수 있습니다.

대신, 예를 들어, 왼쪽 시프트 연산자를 사용하려고 :

PORTB = 1 << led; 
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); 
    } 
} 

더 정교한 기사 라이더 버전 내 블로그 herehere

에서 찾을 수 있습니다