点击计数器使用C代码点亮LED灯

5
我正在为微控制器设计点击计数器,我正在使用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。 - virolino
已经更新了。 - dunu008
3个回答

3

我不确定这是否会减小二进制文件的大小,也没有进行过测试。但你仍可以尝试像这样做:

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

由于我正在使用中断来处理按钮点击,所以我必须更改您的代码。 - dunu008
实际上,您不需要使用if/else或任何其他循环来实现这个。我已在下面的答案中提到了它。 - dunu008

3

只需分别给PORTB和PORTD分配值即可完成此操作,因为您已经将点击次数存储在变量clickCounter中。

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

1
处理输出,我会做类似以下的事情:

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 */

我看不出逐个比特地执行它的理由。


是的,您可以按照您在这里提到的方式分别为端口分配值。 - dunu008
然后,您可以通过2个简单的操作来实现它,而不是无数的操作。当然,您还需要额外处理计数器的增量和第二个按钮。 - virolino
在这里,您只能使用一个端口。但是在我的答案中,我们可以根据需要使用不同的端口。 - dunu008
在进行嵌入式工作时,最好优化一切可以优化的内容。当然你甚至可以使用8个端口,但不值得。更值得的是在项目的早期修改硬件设计,而不是在软件中寻找灵活的解决方案。 - virolino
是的,当然可以。但我已经将其他引脚用于其他几个目的了。 - dunu008
为了使输出端口完整,更改引脚的使用对你最有利。否则,你的答案就是次优的。 - virolino

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接