c语言 - 弄清楚了我想做的基本事情.但需要添加PWM



有一个代码新手。我想创建标志性的电视骑士扫描。我已经编写了我的第一个代码并实现了基本功能。我知道有很多(已经)为此编写的代码,我已经查看了各种示例以了解我想做什么。我在开始时添加了一个全能序列,并在代码中找出了 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变得0b11111101nextPortBvalue &= ~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, 1, 2, 3, 4, 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, 0, 0, 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, 0, 0, 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;

相关内容

  • 没有找到相关文章

最新更新