Operácie

Ovládanie RGB LED pásika

Z SensorWiki

Záverečný projekt predmetu MIPS / LS2023 - Dominik Illés


Zadanie

Ovládanie RGB led pásika pomocou jednoduchého menu v serial linke.

Arduino Nano.

Literatúra:


Analýza a opis riešenia

Zapojenie LED pasíka je jednoduché len tri vodiče a v data vstupom som dal resistor, aby náhodne veľké prúdy nepoškodili pása. Najťažšia časť bola nastavid pás aby poslané farby vykresloval, na to som použil asembler kód čo som našiel na internete. Na ovládanie som napísal malú menu s tromi zvláštnymi módmi, používaním numpadu môžme navigovať cez módy prednastavené, manuálna nastavenia celého pása a manuálna nastavenia hocijakeho LEDa. Aby nevykreslilo vždy pod sebou text a vyzeralo lepšie som použil terminalove ANSI ESC sekvencie: printf("\033[2J"); čo vymaže čo je na terminále a printf("\033[H"); aby kurzor bolo na začiatku.


Schéma zapojenia


Algoritmus a program

.

int main(void)
{
	char ReceivedChar;
	uart_init();
	stdout = &mystdout;
	uint16_t time = 0;
	int m = 0;	
		
while(1)
	{
		if(m==0){
		printf("Menu\n 1.Nastavene efeky\n 2.Nastavit cely pas\n 3.Nastavit LEDky");
		ReceivedChar = uart_getc();
		m=1;
		printf("\033[2J");
		printf("\033[H");
		}
//------------------------------------Predpisane effekty----------------------------------------------------------------
		if(ReceivedChar == '1')
		{
		//--------------------------------Effekty-----------------------------
		printf("Effekty\n 0.Vypnut\n 1.Red\n 2.Green\n 3.Blue\n 4.Rainbow-1\n 5.Rinbow-2\n 6.Breathing\n 7.Spat");
		while(m==1)
		{
		ReceivedChar = uart_getc();	
		switch(ReceivedChar)
		{
		//------------------------------Vypnut--------------------------------
	   	case '0':                          
			OffStrip();
			break;
		//------------------------------RED---------------------------------
		case '1':   
			RedStrip();	
			break;
	    //------------------------------Green---------------------------------	                     
		case '2':
			GreenStrip();
			break;  
	    //------------------------------Blue--------------------------------                            
		case '3':                          
			BlueStrip();
			break;
		//------------------------------------RainbowV1---------------------------------
	    case '4':                          
			Rainbow1();
			break;
		//-------------------------------------Rainbow-----------------------------------		
	    case '5':
			Rainbow2();
			break;
		//----------------------------Breathing------------------------------------
	    case '6':
			Breathing();
			break;
//---------------------------------------Spat---------------------------------------				
	    case '7':
			m=0;
			printf("\033[2J");
			printf("\033[H");
			break;
			}   
		}
	}						
//-------------------------------Nastavenie celej pasy-------------------------------------------------------
		if(ReceivedChar == '2')
		{
			fullLED(&m);		
		}
//-------------------------------Nastavenie zvlast ledky----------------------------------------------------------
		if(ReceivedChar == '3')
		{
			pieceLED(&m);
		}	   
	}

	return(0);
}
void __attribute__((noinline)) led_strip_write(rgb_color * colors, uint16_t count)
{
  // Set the pin to be an output driving low.
  LED_STRIP_PORT &= ~(1<<LED_STRIP_PIN);
  LED_STRIP_DDR |= (1<<LED_STRIP_PIN);

  cli();   // Disable interrupts temporarily because we don't want our pulse timing to be messed up.
  while (count--)
  {
    // Send a color to the LED strip.
    // The assembly below also increments the 'colors' pointer,
    // it will be pointing to the next color at the end of this loop.
    asm volatile (
        "ld __tmp_reg__, %a0+\n"
        "ld __tmp_reg__, %a0\n"
        "rcall send_led_strip_byte%=\n"  // Send red component.
        "ld __tmp_reg__, -%a0\n"
        "rcall send_led_strip_byte%=\n"  // Send green component.
        "ld __tmp_reg__, %a0+\n"
        "ld __tmp_reg__, %a0+\n"
        "ld __tmp_reg__, %a0+\n"
        "rcall send_led_strip_byte%=\n"  // Send blue component.
        "rjmp led_strip_asm_end%=\n"     // Jump past the assembly subroutines.

        // send_led_strip_byte subroutine:  Sends a byte to the LED strip.
        "send_led_strip_byte%=:\n"
        "rcall send_led_strip_bit%=\n"  // Send most-significant bit (bit 7).
        "rcall send_led_strip_bit%=\n"
        "rcall send_led_strip_bit%=\n"
        "rcall send_led_strip_bit%=\n"
        "rcall send_led_strip_bit%=\n"
        "rcall send_led_strip_bit%=\n"
        "rcall send_led_strip_bit%=\n"
        "rcall send_led_strip_bit%=\n"  // Send least-significant bit (bit 0).
        "ret\n"

        // send_led_strip_bit subroutine:  Sends single bit to the LED strip by driving the data line
        // high for some time.  The amount of time the line is high depends on whether the bit is 0 or 1,
        // but this function always takes the same time (2 us).
        "send_led_strip_bit%=:\n"
#if F_CPU == 8000000
        "rol __tmp_reg__\n"                      // Rotate left through carry.
#endif
        "sbi %2, %3\n"                           // Drive the line high.

#if F_CPU != 8000000
        "rol __tmp_reg__\n"                      // Rotate left through carry.
#endif

#if F_CPU == 16000000
        "nop\n" "nop\n"
#elif F_CPU == 20000000
        "nop\n" "nop\n" "nop\n" "nop\n"
#elif F_CPU != 8000000
#error "Unsupported F_CPU"
#endif

        "brcs .+2\n" "cbi %2, %3\n"              // If the bit to send is 0, drive the line low now.

#if F_CPU == 8000000
        "nop\n" "nop\n"
#elif F_CPU == 16000000
        "nop\n" "nop\n" "nop\n" "nop\n" "nop\n"
#elif F_CPU == 20000000
        "nop\n" "nop\n" "nop\n" "nop\n" "nop\n"
        "nop\n" "nop\n"
#endif

        "brcc .+2\n" "cbi %2, %3\n"              // If the bit to send is 1, drive the line low now.

        "ret\n"
        "led_strip_asm_end%=: "
        : "=b" (colors)
        : "0" (colors),         // %a0 points to the next color to display
          "I" (_SFR_IO_ADDR(LED_STRIP_PORT)),   // %2 is the port register (e.g. PORTC)
          "I" (LED_STRIP_PIN)     // %3 is the pin number (0-8)
    );

    // Uncomment the line below to temporarily enable interrupts between each color.
    //sei(); asm volatile("nop\n"); cli();
  }
  sei();          // Re-enable interrupts now that we are done.
  _delay_us(80);  // Send the reset signal.
}
#define F_CPU 16000000
#define BAUD 9600
#include <avr/io.h>
#include <util/setbaud.h>

void uart_init( void ) 
{
    UBRR0H = UBRRH_VALUE;
    UBRR0L = UBRRL_VALUE;

#if USE_2X
    UCSR0A |= _BV(U2X0);
#else
    UCSR0A &= ~(_BV(U2X0));
#endif

    UCSR0C = _BV(UCSZ01) | _BV(UCSZ00); /* 8-bit data */
    UCSR0B = _BV(RXEN0) | _BV(TXEN0);   /* Enable RX and TX */
}

//------------------------------------Uart Prikazy-------------------------------------------------
void uart_putc(char c) 
{
   if (c == '\n') 
    {
       uart_putc('\r');
    }
   loop_until_bit_is_set(UCSR0A, UDRE0); /* Wait until data register empty. */
   UDR0 = c;
}

void uart_puts(const char *str) {
    // Transmit a null-terminated string via UART
    while (*str) {
        // Wait for the UART data register to be ready for transmission
        while (!(UCSR0A & (1 << UDRE0)));
        // Transmit the character
        UDR0 = *str++;
    }
}

char uart_getc(void) {
    loop_until_bit_is_set(UCSR0A, RXC0); /* Wait until data exists. */
    return UDR0;
}

void uart_gets(char *buffer, uint8_t max_length) {
    uint8_t count = 0;
    char received_char;

    while (1) {
        received_char = uart_getc();

        // Check for newline or carriage return
        if (received_char == '\n' || received_char == '\r') {
            break;
        }

        // Append received character to the buffer
        if (count < max_length - 1) {
            buffer[count++] = received_char;
        }
    }

    // Null-terminate the buffer
    buffer[count] = '\0';
}
	void RedStrip()
	{
		for (uint16_t i = 0; i < LED_COUNT; i++)
		{
		colors[i] = (rgb_color){ 100, 0, 0 };
		}
		led_strip_write(colors, LED_COUNT);
		_delay_ms(20);
	}
	void GreenStrip()
	{
		for (uint16_t i = 0; i < LED_COUNT; i++)
		{
		 colors[i] = (rgb_color){ 0, 100, 0 };
		}
		led_strip_write(colors, LED_COUNT);

		_delay_ms(20); 
	}
	void BlueStrip()
	{
		for (uint16_t i = 0; i < LED_COUNT; i++)
		{
		 colors[i] = (rgb_color){ 0, 0, 100 };
		}
		led_strip_write(colors, LED_COUNT);

		_delay_ms(20); 
	}
	void OffStrip()
	{
		for (uint16_t i = 0; i < LED_COUNT; i++)
		{
		 colors[i] = (rgb_color){ 0, 0, 0 };
		}
		led_strip_write(colors, LED_COUNT);
		_delay_ms(20);
	}	
	void Rainbow1()
	{
		uint16_t time = 0;
		 while (UDR0=='4')
		 {
		for (uint16_t i = 0; i < LED_COUNT; i++)
		{
		 uint8_t x = (time >> 2) - 8 * i;
		 colors[i] = (rgb_color){ x, 255-x, x };
		}
		led_strip_write(colors, LED_COUNT);
		_delay_ms(20);
		time += 20;  
		}	
	}
	
	void Rainbow2()
	{
	uint8_t hue = 1; // Initialize hue value
    while (UDR0 == '5') {
        for (uint16_t i = 0; i < LED_COUNT; i++) {
            // Calculate hue-modified colors
            colors[i] = hsv_to_rgb(hue);
            // Increment hue for the next LED
        }
		hue += 1;
		if(hue==255){hue=1;}
        // Write colors to LED strip
        led_strip_write(colors, LED_COUNT);
        // Delay for color transition
        _delay_ms(50);
		}
	}
	
	void Breathing()
	{
		int c = 0;
		 uint8_t r = 0;
		 uint8_t g = 0;
		 uint8_t b = 0;
		 while (UDR0=='6')
		 {
			for (uint16_t i = 0; i < LED_COUNT; i++)
			{
			colors[i] = (rgb_color){ r, g, b };
			}	 
					 if(c==0)
					 {
						r++;
						if(r==150)
						{c=1;}
					 }
					 if(c==1)
					 {
						 r--;
						 if(r==0)
						{c=0;}
					 }			
		led_strip_write(colors, LED_COUNT);
		_delay_ms(20);    
			}
	}
	
	void fullLED(int* m)
	{
			char red[MAX_BUFFER_SIZE];
			char green[MAX_BUFFER_SIZE];
			char blue[MAX_BUFFER_SIZE];
			while(*m==1)
			{
				printf("RGB(0-255)-- Set blue to 300 to go back\n");
				printf("Red brightness: ");
				uart_gets(red, MAX_BUFFER_SIZE);
				int num1 = atoi(red);
				printf("%d \n",num1);
				printf("Green brightness: ");
				uart_gets(green, MAX_BUFFER_SIZE);
				int num2 = atoi(green);
				printf("%d \n",num2);
				printf("Blue brightness: ");
				uart_gets(blue, MAX_BUFFER_SIZE);
				int num3 = atoi(blue);
				printf("%d \n",num3);
				
				if(num1>255 || num2>255 || num3>255)
				{*m=0;
				printf("\033[2J");
				printf("\033[H");
				break;
				}
				for (uint16_t i = 0; i < LED_COUNT; i++)
				{
					colors[i] = (rgb_color){ num1, num2, num3 };
				}

				led_strip_write(colors, LED_COUNT);
				_delay_ms(20);
				printf("\033[2J");
				printf("\033[H");	
				}			
		}
			
	void pieceLED(int* m)
		{
			char red[MAX_BUFFER_SIZE];
			char green[MAX_BUFFER_SIZE];
			char blue[MAX_BUFFER_SIZE];
			char lednumber[MAX_BUFFER_SIZE];
			
			while(*m==1)
			{
				printf("CHoose the LED: -Set blue to 300 to go back\nLED:");
				uart_gets(lednumber, MAX_BUFFER_SIZE);
				int led = atoi(lednumber);
				printf("%d \n",led);				
				
				printf("Red brightness: ");
				uart_gets(red, MAX_BUFFER_SIZE);
				int num1 = atoi(red);
				printf("%d \n",num1);
				printf("Green brightness: ");
				uart_gets(green, MAX_BUFFER_SIZE);
				int num2 = atoi(green);
				printf("%d \n",num2);
				printf("Blue brightness: ");
				uart_gets(blue, MAX_BUFFER_SIZE);
				int num3 = atoi(blue);
				printf("%d \n",num3);
				
				if(num1>255 || num2>255 || num3>255)
				{*m=0;
				printf("\033[2J");
				printf("\033[H");
				break;
				}
				colors[led] = (rgb_color){ num1, num2, num3 };

				led_strip_write(colors, LED_COUNT);
				_delay_ms(20);
				printf("\033[2J");
				printf("\033[H");	
			}			
		}
// Function to convert HSV to RGB
rgb_color hsv_to_rgb(uint8_t hue) {
    uint8_t sector = hue / 42; // Divide the hue into 6 sectors (42 degrees each)
    uint8_t remainder = (hue % 42) * 6; // Get the remainder and scale it to fit in a 8-bit range

    uint8_t red = 0, green = 0, blue = 0;

    switch (sector) {
        case 0:
            red = 255;
            green = remainder;
            break;
        case 1:
            red = 255 - remainder;
            green = 255;
            break;
        case 2:
            green = 255;
            blue = remainder;
            break;
        case 3:
            green = 255 - remainder;
            blue = 255;
            break;
        case 4:
            red = remainder;
            blue = 255;
            break;
        case 5:
            red = 255;
            blue = 255 - remainder;
            break;
    }

    rgb_color rgb = { red, green, blue };
    return rgb;
}

Funkcia led_strip_write používa C a AVR assembler kód na nastavenie LED pasíka a na to aby vykreslilo jednotlivé farby a effekty. Assembler kód je na odosielanie jedného bájtu do LED pásu(jednotlivé farebé zložky). Assembly kód sa zabezpečí, že načasovanie prenosu bitov je presné a konzistentné, bez ohľadu na frekvenciu mikroprocesora. Kód používa na dosiahnutie tohto cieľa kombináciu inštrukcií nop (bez operácie) a inštrukcií podmienenej vetvy. Funkcie RedStrip, BlueStrip, a GreenStrip slúžia, na to aby celý pás svietil vo zvolených farbách, OffStrip vypína, Rainbow1 sa posiela zelený had a za tým sa objavý fialové a bielé pozadie, Rainbow2 ide cez HSV škálu, a breathing sa plinule odymí a zasvieti pás na červeno. FullLED nám povolí nastaviť celý pás na samo zvoliteľnú farbu pomocou RGB hodnoty, a pomocou PieceLED môžme nastaviť jednotlivé ledky na zvolenú farbu pomocou RGB hodnoty.

Zdrojový kód: LEDovlad.c


Overenie

Aplikácia.

Video:

Kľúčové slová 'Category', ktoré sú na konci stránky nemeňte.