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

如何解决弄清楚我想做的基本事情但需要加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;

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-