gpt4 book ai didi

c - 在 AVR Atmega324A 上多路复用七段显示器

转载 作者:太空宇宙 更新时间:2023-11-04 08:40:36 27 4
gpt4 key购买 nike

我一整天都被困在这个问题上,我正在尝试使用两个七段显示器创建一个倒数计时器。我希望它从 20 开始倒数到零。而 10< 我只想让左边显示(即十位没有 0)。我正在使用 Atmega 324A。我将所有端口 C 连接到显示段,并使用 PIND0 在两者之间切换。这是我目前所拥有的。

#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。在执行此操作时,我是否需要另一个 for 循环来遍历 seven_seg[] 数组?真的不知道如何解决这个问题。任何帮助都会很棒。

最佳答案

你犯了两个大错:

  1. 你不使用计时器
  2. 您应该将显示驱动逻辑与值(value)生成逻辑分开

最好的办法是拆分任务并计划如何实现。

任务一:提供要显示的数据
任务二:将该数据传输到显示友好的表示
任务三:数据的实际展示

任务一很简单。让我们假设你想显示整数并且你有三个 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 个显示元素,这意味着:

  • 停用当前显示元素
  • 将下一位的数据放到outport中
  • 激活下一个显示元素
  • 稍等一下。

而这 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;
}
}

当然,您必须使特定显示元素的启用适应您的硬件。

另请注意,您可以使用晶体管来驱动元件。 AVR 端口引脚足以驱动单个段,但驱动该段的公共(public)阳极/阴极的另一侧可能过载。这当然取决于段内的 LED。如果这是低电流 LED(~2mA)就没问题。

关于c - 在 AVR Atmega324A 上多路复用七段显示器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23784464/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com