【问题标题】:click counter to light up LEDs using C code单击计数器以使用 C 代码点亮 LED
【发布时间】:2019-04-07 06:42:45
【问题描述】:

我正在为微控制器设计点击计数器,并使用 C 语言开发代码。

这里发生的情况是,当我单击第一个按钮时,它会计算按钮按下的次数。然后我必须按下第二个按钮以显示点亮 LED 的二进制计数。例如,如果我按第一个按钮 10 次,它将点亮第二个 LED 和第四个 LED。

由于有 8 个 LED,我使用了 2 个不同的端口。(来自 PORTB 的 6 位和来自 PORTD 的 2 位)。 为此,我使用 if/else 开发了一个代码。但我想在没有多个 if/else 操作的情况下实现此操作,因为这种方法似乎效率不高。

while(PIND & 0b00100000){                   //while PD5 switch is not pressed
        if(clickCount>=128){                //if click count>=128
            PORTB = PORTB | 0b00100000;     //set PB5 HIGH
            clickCount-=128;                //deduct 128 from clickCount
        }else if(clickCount>=64){
            PORTB = PORTB | 0b00010000;
            clickCount-=64;
        }else if(clickCount>=32){
            PORTB = PORTB | 0b00001000;
            clickCount-=32;
        }else if(clickCount>=16){
            PORTB = PORTB | 0b00000100;
            clickCount-=16;
        }else if(clickCount>=8){
            PORTB = PORTB | 0b00000010;
            clickCount-=8;
        }else if(clickCount>=4){
            PORTB = PORTB | 0b00000001;
            clickCount-=4;
        }else if(clickCount>=2){
            PORTD = PORTD | 0b10000000;
            clickCount-=2;
        }else if(clickCount==1){
            PORTD = PORTD | 0b01000000;
            clickCount = 0;
        }           
    }

而且我想用更少的字节数制作这段代码。那么有没有什么办法可以用for循环或者其他方法开发这段代码呢?

【问题讨论】:

  • 您应该更新您的问题,指出您实际上使用了 2 个端口 - 最后 2 位来自 portD。
  • 已经更新了。

标签: c arduino atmelstudio


【解决方案1】:

我不知道这是否会减少二进制文件的大小,并且未经测试。你仍然可以这样做:

 unsigned char mask[] = {
     0b01000000, 0b10000000, 0b00000001, 0b00000010,
     0b00000100, 0b00001000, 0b00010000, 0b00100000};
 while(PIND & 0b00100000) {
     for (int i = 7, v = 128; i > -1; --i, v /= 2) {
         if (clickCount >= v && clickCount > 0) {
             if (clickCount >= 4) {
               PORTB = PORTB | mask[i];
             } else {
               PORTD = PORTD | mask[i];
             }
             clickCount -= v;
             break;
         }
     }
 }

或者您可以使用单个循环:

int v = 128, i = 7;
while (v > 0 && (PIND & 0b00100000)) {
    if (clickCount >= v) {
         if (clickCount >= 4) {
           PORTB = PORTB | mask[i];
         } else {
           PORTD = PORTD | mask[i];
         }
        clickCount -= v;
    } else {
        --i;
        v /= 2;
    }
}

【讨论】:

  • 由于我使用中断来处理按钮点击,我将不得不更改您的代码。
  • 其实你不需要使用 if/else 或任何其他循环来实现这一点。我在下面的回答中提到了它。
【解决方案2】:

要处理输出,我会这样做:

clickCount %= 256; /* because the output is 8-bit */
PORTB = clickCount;

要使输出恰好长 1 条指令:

unsigned char clickCount = 0;

... /* do things, handle increment, handle 2nd button */

PORTB = clickCount; /* modulo 256 no longer needed, ClickCount cannot be more than 8 bits anyway */

我认为没有理由一点一点地这样做。

【讨论】:

  • 是的,您可以将值单独分配给您在此处提到的端口。
  • 然后你可以通过2个简单的操作来实现它,而不是无数的操作。当然,你需要另外处理conter和第二个按钮的增量。
  • 这里你只能使用1个端口。但在我的回答中,我们可以根据需要使用不同的端口。
  • 在做嵌入式工作时,总是最好优化所有可以优化的东西。当然你甚至可以使用 8 个端口,但这并不值得。改变硬件设计(在项目中足够早)比在软件中寻找灵活的解决方案更值得。
  • 是的,当然。但我已经将其他引脚用于其他几个目的。
【解决方案3】:

这可以通过将值分别分配给 PORTB 和 PORTD 来完成,因为您将点击次数存储在变量 clickCounter 中。

PORTB = PORTB | (clickCount & 0b00111111);
PORTD = PORTD | (clickCount & 0b11000000);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-06-16
    • 2010-11-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多