弄清楚我想做的基本事情但需要加PWM

问题描述

一个 Code 新手。我想创建标志性的 TV Knight Rider 扫描。我已经写了我的第一个代码并实现了基本功能。我知道有很多(已经)为此编写了代码,并且我查看了各种示例以了解我想要做什么。我在开始时添加一个全开序列,并在代码中找出了 GOTO。对你们大多数人来说很简单,但对我来说是一个构建块:) 这是我使用 MPLAB X IDE 5.45 和 XC8 的 16F88 的工作代码

    #include <stdio.h>
    #include <stdlib.h>
    #include "16F88_xc8_header.h"               // 16F88 CONfig BITS

    #define _XTAL_FREQ 4000000                  // 4 MHz clock

    int main(int argc,char** argv) 
{
    __CONfig(FOSC_INTRcclK&WDTE_OFF&MCLRE_OFF); 
    
        OSCCONbits.IRCF = 0b110;        // Binary value of the three ICRF bits to select 4 MHz internal oscillator
            
        TRISB = 0x00;
        PORTB = 0x00;
        
        { 
        PORTB = 0b00111111;             // ALL-ON EFFECT
        __delay_ms(400);
        PORTB = 0b00011111;
        __delay_ms(80);
        PORTB = 0b00001111;
        __delay_ms(80);
        PORTB = 0b00000111;
        __delay_ms(80);
        PORTB = 0b00000011;
        __delay_ms(80);
         }
     
        
        {
        kitt_scan:
        PORTB = 0b00000001;            // 6LED SCAN STARTS
        __delay_ms(400);
        PORTB = 0b00000010;
        __delay_ms(400);
        PORTB = 0b00000100;
        __delay_ms(400);
        PORTB = 0b00001000;
        __delay_ms(400);
        PORTB = 0b00010000;
        __delay_ms(400);
        PORTB = 0b00100000;
        __delay_ms(400);
        PORTB = 0b00010000;
        __delay_ms(400);
        PORTB = 0b00001000;
        __delay_ms(400);
        PORTB = 0b00000100;
        __delay_ms(400);
        PORTB = 0b00000010;
        __delay_ms(400);
        
        goto kitt_scan;
        
    return (EXIT_SUCCESS);
        }
  
}

接下来我要添加的是 PWM,以便在光图案左右移动时为 LED 提供拖尾效果。我当然用谷歌搜索过,但我发现的是如何让一个 LED 从低到高淡出。这不是我想要的,相反,我希望有一个可以在代码中分配的预定输出值的选项。

例如

0=LED OFF
1=LED at 30% Duty Cycle (very DIM LED)
2=LED at 70% Duty Cycle (somewhat DIM LED)
3=LED at 100% Duty Cycle (full bright LED)

我希望这样编码:

 PORTB = 0b00000003;           
    __delay_ms(400);
    PORTB = 0b00000032;
    __delay_ms(400);
    PORTB = 0b00000321;
    __delay_ms(400);

所以我的问题是,我从哪里开始甚至完成这项工作?欢迎提供任何见解。

谢谢 托尼

解决方法

电子产品

我只是将一个电容器与每个 LED 并联,这样当 LED 开启时,它也会为电容器充电,而当 LED 关闭时,LED 会在电容器放电时逐渐消失。 :-)

对于普通 C(或 C++)

警告:我没有测试过这些,所以我的示例代码中可能存在错误。学习修复错误和学习创建错误一样重要,所以如果有错误,你会学到更多!

假设您有一个从零开始并每 1 毫秒递增的计数器;当它达到 4 时,您将计数器重置为零;像这样:

    int counter = 0;
    
nextTick:
    __delay_ms(1);
    counter++;
    if(counter >= 4) {
        counter = 0;
    }

    goto nextTick;

如果您在计数器为零时打开 LED 并在计数器为 1 时关闭 LED,那么 LED 将亮起 25% 的时间并熄灭 75% 的时间。这可能看起来像:

    int counter = 0;
    
    PORTB = 0b00000001;

nextTick:
    __delay_ms(1);
    counter++;
    if(counter >= 4) {
        counter = 0;
        PORTB = 0b00000001;
    }

    if(counter == 1) {
        PORTB = 0b00000000;
    }

    goto nextTick;

如果您在计数器为 2 时关闭 LED,则 LED 将亮起 50% 的时间;如果您在计数器为 3 时关闭 LED,则 LED 将亮起 75% 的时间;如果您在计数器大于或等于 4 时关闭 LED(这永远不会发生,因为它首先重置为零)LED 将在 100% 的时间内亮起;如果您在计数器为零时关闭 LED,那么 LED 将在“几乎 0%”的时间内亮起。

您可以使用变量来控制“LED 应该亮多少”,例如:

    int counter = 0;
    int LED0_timeOn = 2;
    
    PORTB = 0b00000001;

nextTick:
    __delay_ms(1);
    counter++;
    if(counter >= 4) {
        counter = 0;
        PORTB = 0b00000001;
    }

    if(counter == LED0_timeOn) {
        PORTB = 0b00000000;
    }

    goto nextTick;

这有点笨拙,因为当 LED 应该在 0% 的时间内打开时,您会先打开它,然后再将其关闭。您可以通过使用变量并且每个刻度只设置一次 PORTB 来避免这种情况,如下所示:

    int counter = 0;
    int nextPortBvalue = 0b00000001;
    int LED0_timeOn = 2;
    

nextTick:
    PORTB = nextPortBvalue;
    __delay_ms(1);
    counter++;
    if(counter >= 4) {
        counter = 0;
        nextPortBvalue = 0b00000001;
    }

    if(counter == LED0_timeOn) {
        nextPortBvalue = 0b00000000;
    }

    goto nextTick;

如果你有 6 个变量,你可以有 6 个 LED,每个 LED 都有不同的“花费时间”;喜欢:

    int counter = 0;
    int nextPortBvalue = 0b00111111;
    int LED0_timeOn = 0;
    int LED1_timeOn = 1;
    int LED2_timeOn = 2;
    int LED3_timeOn = 3;
    int LED4_timeOn = 4;
    int LED5_timeOn = 0;
    
nextTick:
    PORTB = nextPortBvalue;
    __delay_ms(1);
    counter++;
    if(counter >= 4) {
        counter = 0;
        nextPortBvalue = 0b00111111;
    }

    if(counter == LED0_timeOn) {
        nextPortBvalue &= ~0b00000001;
    }
    if(counter == LED1_timeOn) {
        nextPortBvalue &= ~0b00000010;
    }
    if(counter == LED2_timeOn) {
        nextPortBvalue &= ~0b00000100;
    }
    if(counter == LED3_timeOn) {
        nextPortBvalue &= ~0b00001000;
    }
    if(counter == LED4_timeOn) {
        nextPortBvalue &= ~0b00010000;
    }
    if(counter == LED5_timeOn) {
        nextPortBvalue &= ~0b00100000;
    }

    goto nextTick;

这有点棘手 - 关闭一位(或一个 LED)而不弄乱它需要使用的其他位,并关闭除一位之外的所有其他位。 ~0b00000010 表示“反转这些位”,因此 ~0b00000010 变为 0b11111101,而 nextPortBvalue &= ~0b00000010; 表示“nextPortBvalue 的新值与旧值相同AND 0b11111101"(导致第二位关闭,而其他所有位保持不变)。

虽然这有点混乱 - 它复制了 6 次逻辑(每个 LED 一次)。您可以通过使用数组和循环来解决该问题,例如:

    int counter = 0;
    int nextPortBvalue = 0b00111111;
    int LED_timeOn[6] = { 0,1,2,3,4,0 };
    
nextTick:
    PORTB = nextPortBvalue;
    __delay_ms(1);
    counter++;
    if(counter >= 4) {
        counter = 0;
        nextPortBvalue = 0b00111111;
    }
    for(int bit = 0; bit < 6; bit++) {
        if(counter == LED_timeOn[bit]) {
            nextPortBvalue &= ~(0b00000001 << bit);
        }
    }

    goto nextTick;

现在您可以控制每个 LED 开启(或关闭)的时间;你会想要改变 LED_timeOn 数组中的值的东西(并改变每个 LED 花费的时间)。您每 400 毫秒执行一次此操作,因此让我们添加第二个计数器来测量 400 毫秒:

    int counter1 = 0;
    int counter2 = 0;
    int nextPortBvalue = 0b00111111;
    int LED_timeOn[6] = { 0,0 };
    
nextTick:
    PORTB = nextPortBvalue;
    __delay_ms(1);
    counter1++;
    counter2++;
    if(counter1 >= 4) {
        counter1 = 0;
        nextPortBvalue = 0b00111111;
    }
    if(counter2 >= 400) {
        counter2 = 0;
    }

    for(int bit = 0; bit < 6; bit++) {
        if(counter1 == LED_timeOn[bit]) {
            nextPortBvalue &= ~(0b00000001 << bit);
        }
    }

    goto nextTick;

每 400 毫秒,您希望所有现有的“LED 花费的时间”减少(因此 LED 会变暗),然后设置一个新的“100% 开启”LED。您需要另一个变量来跟踪哪个 LED 是下一个“100% 亮”的 LED。结果是这样的:

    int counter1 = 0;
    int counter2 = 0;
    int nextPortBvalue = 0b00111111;
    int LED_timeOn[6] = { 0,0 };
    int nextOnLED = 0;
    
nextTick:
    PORTB = nextPortBvalue;
    __delay_ms(1);
    counter1++;
    counter2++;
    if(counter1 >= 4) {
        counter1 = 0;
        nextPortBvalue = 0b00111111;
    }
    if(counter2 >= 400) {
        counter2 = 0;
        /* Make all the LEDs fade */
        for(int bit = 0; bit < 6; bit++) {
            if(LED_timeOn[bit] > 0) {
                LED_timeOn[bit]--;
            }
        }
        /* Change the value for the next "100% on" LED to 4 */
        LED_timeOn[nextOnLED] = 4;
    }

    for(int bit = 0; bit < 6; bit++) {
        if(counter1 == LED_timeOn[bit]) {
            nextPortBvalue &= ~(0b00000001 << bit);
        }
    }

    goto nextTick;

最后一个问题是您还想更改哪个 LED 是下一个“100% 亮”的 LED;但有时是左边的下一个 LED,有时是右边的下一个 LED。一种处理方法是假装中间有 4 个假 LED;这样在打开第 6 个 LED 后,您将打开第 7 个“假 LED”(实际上又是第 5 个 LED!)。这可能是这样的:

    int counter1 = 0;
    int counter2 = 0;
    int nextPortBvalue = 0b00111111;
    int LED_timeOn[6] = { 0,0 };
    int nextOnLED = 0;
    
nextTick:
    PORTB = nextPortBvalue;
    __delay_ms(1);
    counter1++;
    counter2++;
    if(counter1 >= 4) {
        counter1 = 0;
        nextPortBvalue = 0b00111111;
    }
    if(counter2 >= 400) {
        counter2 = 0;
        /* Make all the LEDs fade */
        for(int bit = 0; bit < 6; bit++) {
            if(LED_timeOn[bit] > 0) {
                LED_timeOn[bit]--;
            }
        }
        /* Change the value for the next "100% on" LED to 4 */
        if(nextOnLED < 6) {
            LED_timeOn[nextOnLED] = 4;       /* A real LED */
        } else {
            LED_timeOn[10 - nextOnLED] = 4;  /* A fake LED */
        }
        /* Update the next 100% on LED */
        nextOnLED++;
        if(nextOnLED >= 10) {
            nextOnLED = 0;
        }
    }

    for(int bit = 0; bit < 6; bit++) {
        if(counter1 == LED_timeOn[bit]) {
            nextPortBvalue &= ~(0b00000001 << bit);
        }
    }

    goto nextTick;

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...