2014-05-21 20 views
0

我一直在这一整天,我试图创建一个使用两个七段显示倒数计时器。我希望它从20开始倒数​​到零。虽然10 <我只想在左边显示(即在十位没有0)。我使用的是Atmega 324A。我已将端口C的所有端口连接到显示段,并使用PIND0在两者之间切换。这是我到目前为止。在AVR上多路复用七段显示Atmega324A

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

    } 
} 

这一切并设置两个显示器为0。我是否需要另一个用于遍历seven_seg []数组迭代它这样做的同时?真的不知道如何解决这个问题。任何帮助都会很棒。

+1

您的代码不正确。 'seven_seg'如何存储一个数组,而它只是'uint8_t'?为什么不使用十六进制(或者如果你的编译器支持该扩展则使用二进制)?使用十进制来实现这些段会更困难。请修正缩进 –

+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

你让2个大错误:

  1. 你不使用定时器
  2. ,则应该从价值创造逻辑分离显示驱动逻辑

最好的事情是你拆分任务并计划如何实现这一点。

任务一:提供要显示的数据
任务二:transfering该数据到显示友好表示
任务三:显示该数据

任务之一是容易的aktual。让我们假设你想显示整数,并且你有三个7-seg-disps。 所以任务之一是提供一些数据来显示。

int16_t numberToDisplay = 234; 

任务二也不那么难。显示友好的表示将是每个显示元素一个字节。

#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显示元件,这意味着:

  • 停用当前显示元件
  • 把下一个数字的数据到外港
  • 激活下一个显示元件
  • 等待一个位。

并且这4个步骤我们希望做得非常快,以便观察者无法识别一次只有一个元素处于活动状态。 因为这完全独立于其他程序逻辑,所以我们需要在“背景”中执行此操作。

您的主程序流只是简单地调用该函数,后台计时器ISR担心显示。

所以我们必须设置一个定时器并在其中断服务程序中调用元素数据的切换。(用于设置定时器和定时器interupts请参考其他教程)

// 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; 
    } 
} 
当然

你必须适应特定的显示元素,硬件的实现。

请注意,您可能需要一个晶体管来驱动元件。 AVR端口引脚强烈驱动单个段,但驱动段的公共阳极/阴极的另一侧可能会过载。这当然取决于细分市场中的LED。如果这是低电流LED(〜2mA),那就没问题。