通过74HC595移位寄存器改变LED亮度

Change LED intencity through 74HC595 shift register

我目前正在进行一个项目,我需要控制 13 个白色 LED 和一个 RGB LED,其中两个 shift registers 74HC595 级联。 我使用 SAMD21 XPLAINED PRO 电路板 (µC samd21j18a) 和 ATMEL Studio 作为 IDE.

windows 上工作

目前我基本上是使用 SPI 来完成的(我在 ATMEL Start 上定义了我项目的大部分参数)。

#include <atmel_start.h>

#define message_size    2

bool RgbColors[7][3] = {
    {1, 0, 0}, //Red
    {0, 1, 0}, //Green
    {0, 0, 1}, //Blue
    {1, 1, 0}, //Yellow
    {1, 0, 1}, //Pink
    {0, 1, 1}, //Cyan
    {1, 1, 1}, //White
};

uint8_t spi_transfer_array[message_size];
struct spi_xfer spi_driver_xfer;

// Send a 16 bits message through SPI
void spi_16bits_transfer(uint16_t data);
// Control a frame of 13 white LEDs and 1 RGB LED
void turn_led_model_on(uint8_t led, bool red, bool green, bool blue);


int main(void)
{
    atmel_start_init();
    spi_m_sync_enable(&SPI_0);
    
    uint8_t i = 0;
    bool red = 0;
    bool green = 0;
    bool blue = 0;
    
    while (1) {
        
        // Test
        for (uint8_t led = 0; led <= 13; led++){
            
            // RGB modulation
            if (i <= 6){
                red = RgbColors[i][0];
                green = RgbColors[i][1];
                blue = RgbColors[i][2];
                i++;
            }
            else {
                i = 0;
            }
            
            turn_led_model_on(led, red, green, blue);
            delay_ms(200);
        }
        
        for (uint8_t led = 0; led <= 13; led++){
            
            // RGB modulation
            if (i <= 6){
                red = RgbColors[i][0];
                green = RgbColors[i][1];
                blue = RgbColors[i][2];
                i++;
            }
            else {
                i = 0;
            }
            
            turn_led_model_on(13 - led, red, green, blue);
            delay_ms(200);
        }
    }
}


void spi_16bits_transfer(uint16_t data){
    spi_transfer_array[0] = ~data >> 8;
    spi_transfer_array[1] = ~data & 0xFF;
    
    spi_driver_xfer.txbuf = spi_transfer_array;
    spi_driver_xfer.size = message_size;
    
    gpio_set_pin_level(EN_pin, false);
    gpio_set_pin_level(SPI_SS, false);
    spi_m_sync_transfer(&SPI_0, &spi_driver_xfer);
    gpio_set_pin_level(SPI_SS, true);
    gpio_set_pin_level(EN_pin, true);
    delay_ms(1);
    gpio_set_pin_level(EN_pin, false);
}


void turn_led_model_on(uint8_t led, bool red, bool green, bool blue){
    if (led > 13) led = 13;
    
    uint16_t mask = 0;
    
    if (led > 0){
        for (uint8_t i = 1; i <= led; i++){
            mask |= (1 << (led - i));
        }
    }
    
    mask |= (red << 13);
    mask |= (green << 14);
    mask |= (blue << 15);
    
    spi_16bits_transfer(mask);
}

我目前面临的问题是我希望能够改变光强度,但我不知道如何使用 74HC595 并且我不知道我是否可以使用SPI。目标不仅是改变白色 LED 的强度,而且最重要的是获得更多选择 RGB LED 颜色的可能性(目前我只有 7 种可能性)。

我觉得可以创建一种 PWM 使用定时器来选择 LED 的发光频率,从而修改它们的强度,但我没能做到。

此外,我不知道是否可以独立改变每个 LED 的强度(这就是我需要的 RGB LED)。

谢谢

好的,我正在研究一个非常有效的软件解决方案。

我创建了一个“硬写”值table,这是一种固定 LED 频率的仪表。

我的仪表包含 26 个值(前 13 个值是“0”,后 13 个值是“1”)。根据我想要的强度,我用 13 个值的样本浏览了这个仪表(我的样本中的值从 gauge[intensity] 到 gauge[intensity + 12])。

(当强度为0时,我的样本只包含13次0。当强度为1时,我的样本只包含12次0和1次1。)。 根据这些值,我打开或关闭 LED 以调节强度。

#include <atmel_start.h>

#define message_size    2

uint8_t spi_transfer_array[message_size];
struct spi_xfer spi_driver_xfer;

void spi_16bits_transfer(uint16_t data);
void turn_led_model_on(uint8_t led, bool red, bool green, bool blue);

bool gauge[26] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};

int main(void)
{
    atmel_start_init();
    spi_m_sync_enable(&SPI_0);
    
    uint8_t intencity = 13; // The highest this value is, the brightest the light will be (from 0 to 13)
    uint8_t cycles = 3; 
    
    while (1) {
        
        // Test to create wave effect with LED
        // Increase
        for (uint8_t j = 0; j <= intencity; j++){
            for (uint8_t k = 0; k <= cycles; k++){
                for (uint8_t i = j; i < (j + 13); i++){
                    if (gauge[i]){
                        turn_led_model_on(13, 1, 0, 0);
                    }
                    else {
                        turn_led_model_on(0, 0, 0, 0);
                    }
                }
            }
        }
        
        // Decrease
        for (uint8_t j = 0; j <= intencity; j++){
            for (uint8_t k = 0; k <= cycles; k++){
                for (uint8_t i = j; i < (j + 13); i++){
                    if (!gauge[i]){
                        turn_led_model_on(13, 1, 0, 0);
                    }
                    else {
                        turn_led_model_on(0, 0, 0, 0);
                    }
                }
            }
        }
        
    }
    
}


void spi_16bits_transfer(uint16_t data){
    spi_transfer_array[0] = ~data >> 8;
    spi_transfer_array[1] = ~data & 0xFF;
    
    spi_driver_xfer.txbuf = spi_transfer_array;
    spi_driver_xfer.size = message_size;
    
    gpio_set_pin_level(EN_pin, false);
    gpio_set_pin_level(SPI_SS, false);
    spi_m_sync_transfer(&SPI_0, &spi_driver_xfer);
    gpio_set_pin_level(SPI_SS, true);
    gpio_set_pin_level(EN_pin, true);
    delay_ms(1);
    gpio_set_pin_level(EN_pin, false);
}


void turn_led_model_on(uint8_t led, bool red, bool green, bool blue){
    if (led > 13) led = 13;
    
    uint16_t mask = 0;
    
    if (led > 0){
        for (uint8_t i = 1; i <= led; i++){
            mask |= (1 << (led - i));
        }
    }
    
    mask |= (red << 13);
    mask |= (green << 14);
    mask |= (blue << 15);
    
    spi_16bits_transfer(mask);
}

我仍然需要努力将其用于 RGB 调制,但现在不应该那么复杂。