2014-05-21 4 views
0

나는 하루 종일 붙어 있었고 두 개의 7 세그먼트 디스플레이를 사용하여 카운트 다운 타이머를 만들려고합니다. 나는 그것이 20에서 시작하여 0까지 카운트하기를 원한다. 1< 동안 나는 왼쪽 디스플레이 만 켜 놓고 싶습니다 (즉, 수십 자리에 0이 없음). Atmega 324A를 사용하고 있습니다. 모든 포트 C가 디스플레이 세그먼트에 연결되어 있고 PIND0을 사용하여 두 포트를 전환합니다. 여기까지 내가 지금까지 가지고있는 것이있다. 이가이 일을하는 동안에 나는 seven_seg [] 배열을 반복하는 루프에 대한 또 다른 필요 0하려면 모두 표시를 설정 않는 모든AVR에서 멀티플렉싱 7 세그먼트 디스플레이

#include <avr/io.h> 
#include<util/delay.h> 


int main(void) { 

    int prescale = (8000000/8)/1000-1; 
    int digit = 1; 
    uint8_t display; 
    int seven_seg = {0x3F,0X06,0X5B,0X4F,0X66,0X6D,0X7D,0C07,0X7F,0X6F}; 
    // Set OC1 to output 
    DDRD = (1<<0); 
    DDRC = 0xFF; 

    OCR1A = prescale; 
    //clear counter on compare match 
    TCCR1A = (0<<COM1A1) | (1<<COM1A0); 
    //Set Prescale and CTC Mode 
    TCCR1B = (0<<CS12) | (1<<CS11) | (0<<CS10) | (0<<WGM13) | (1<<WGM12); 


    while(1) { 

      display++; 
      if(display>50) display = 0; 
      for (i = 250; i>0; i--){   
      PORTD ^= 0<<PIND0; 
      PORTC = seven_seg[display%10];     
      PORTD ^= 1<<PIND0; 
      _delay_ms(100); 
      for (i = 250; i>0; i--){   
       PORTD ^= 1<<PIND0; 
       PORTC = seven_seg[display/10];     
       PORTD ^= 0<<PIND0; 
       _delay_ms(100); 
      } 
      } 
     while((TIFR1 & (1<<OCF1A)) == 0) {} 

     TIFR1 &= (1 << OCF1A); 

    } 
} 

? 이 문제를 다루는 방법을 정말로 모릅니다. 어떤 도움이라도 좋을 것입니다.

+1

코드가 올바르지 않습니다. 'seven_seg'는 단지'uint8_t' 일 때 어떻게 배열을 저장할 수 있습니까? 그리고 왜 16 진수 (또는 컴파일러가 해당 확장을 지원할 경우 바이너리)를 사용하지 않는가? 10 진수를 사용하여 세그먼트를 실현하는 것이 훨씬 더 어려울 것입니다. 들여 쓰기를 수정하십시오 –

+0

질문에 대해서는 MSD가 0이고 아무것도 표시하지 않는 이유는 무엇입니까? –

+0

컴파일러가'int seven_seg = {0x3F, 0X06,0X5B, 0X4F, 0X66,0X6D, 0X7D, 0C07,0X7F, 0X6F};'를 허용한다면, 새로운 컴파일러를 얻으십시오. 용의자 당신이 원하는'int seven_seg []/* add [] */= {0x3F, 0X06,0X5B, 0X4F, 0X66,0X6D, 0X7D, 0X07/* 0C07 */0X7F, 0X6F}; ' – chux

답변

2

당신은이 큰 오류를 만들 : 당신이

  • 당신이 가치 창출 로직에서 디스플레이 구동 로직을 분리해야 타이머를 사용하지 않는

    가장 좋은 것은 당신에게 것 작업을 분할하고이를 구현하는 방법을 계획하십시오.

    작업 하나를 디스플레이하기 쉬운 표현
    작업 3 데이터를 transfering :

    작업 하나가 쉽다는 것을 데이터를 표시하는 aktual 데이터를 제공하는 것이
    작업이를 표시합니다. 정수를 표시하고 세 개의 7-seg-disps가 있다고 가정합니다. 작업 중 하나는 표시 할 데이터를 제공하는 것입니다.

    int16_t numberToDisplay = 234; 
    

    작업 2도 그리 어렵지 않습니다. 디스플레이 친화적 표현은 디스플레이 요소 당 1 바이트가 될 것이다.

    #define NUM_7SEGS 3 
    volatile uint8_t dispData[NUM_7SEGS]; // volatile since it is be accassed by different contexts 
    

    해주기 표시 데이터
    void val2DispData(int16 val) 
    { 
        uint8_t i; 
        for(i=NUM_7SEGS; i; --i){ 
         uint8_t r = (uint8_t)(val%10); 
         val /= 10 
         dispData[i-1] = seven_seg[r]; 
        } 
    } 
    

    미세

    지금까지 입력 값을 전송하는 어떤 메커니즘이 필요?

    작업 3은 가장 어려운 작업입니다. 우리는 무엇을해야하는지 출력을 말하는 사람이 필요합니다.

    • 이 기다려 다음의 표시 소자를 활성화 외항으로 다음 숫자의 데이터를 배치
    • 현재 표시 소자를 비활성화 다음 원하므로 수단 3 디스플레이 소자를 다중화 비트.

    이 4 단계를 매우 빠르게 수행하여 한 번에 하나의 요소 만 활성화된다는 것을 관찰자가 인식하지 못하도록합니다. 이것은 다른 프로그램 논리와 완전히 독립적이므로 "백그라운드"에서이 작업을 수행해야합니다.

    메인 프로그램 흐름은 단순히 해당 기능을 호출하고 백그라운드 타이머 ISR은 표시에 대해 걱정합니다.

    타이머를 설정하고 인터럽트 서비스 루틴에서 요소 데이터를 전환해야합니다.당신은 하드웨어에 특정한 표시 요소의 활성화를 적응해야 물론

    // this have to be called cyclic from timer isr 
    // frequency is not that important but should be at 
    // least NUM_7SEGS * 200 Hz to not look ugly 
    void cyclicDisplayTask() 
    { 
        static uint8_t currentElement = 0; 
    
        // disable all elements 
        PORTD = 0; 
    
        // put data on the port 
        PORTC = dispData[currentElement]; // this is why the volatile is necessary. without the compiler would not notice that values may be changed by the main program flow 
    
        // enable next element 
        PORTD = (1<<currentElement); 
    
        ++currentElement; 
        if(currentElement>=NUM_7SEGS){ 
        currentElement = 0; 
        } 
    } 
    

    (타이머와 타이머 interrupts를 설정을위한 또 다른 튜토리얼을 참조하시기 바랍니다).

    트랜지스터를 사용하여 요소를 구동 할 수 있습니다. AVR 포트 핀은 단일 세그먼트를 구동하는 강한 엔포이지만 세그먼트의 공통 양극/음극을 구동하는 다른 쪽은 과부하 일 수 있습니다. 이것은 물론 세그먼트 내의 LED에 달려 있습니다. 이것이 낮은 전류 LED (~ 2mA)라면 괜찮습니다.

  • 관련 문제