STM32F103 computer screen atmosphere light

Idea source: When I was visiting a treasure, I found a light strip attached to the computer screen, and the light strip will change with the color of the computer screen. At that time, I buried the idea of ​​DIY in my heart, until later helped The teacher did something and got some leftovers, so he made up his mind to do it!

software

Lower computer

The WS2812 light strip is used this time, so it is necessary to drive it to light up first.
So consult the data sheet of WS2812, its driving sequence is as follows.
Insert picture description here
There are many driving methods on the Internet, such as SPI, PWM, timers, etc., but this time the author uses the simplest IO flip to drive it. The other methods mentioned above are for readers to search and consult by themselves.

#ifndef __WS2812_H
#define __WS2812_H 			   
#include "sys.h"

#define LED_Nums 60

#define		RGB_LED_HIGH	PAout(8)=1
#define 	RGB_LED_LOW		PAout(8)=0

void RGB_LED_Init(void);
void RGB_LED_Write0(void);
void RGB_LED_Write1(void);
void RGB_LED_Reset(void);
void RGB_LED_Write_Byte(uint8_t byte);
void RGB_LED_Write_24Bits(uint8_t red, uint8_t green, uint8_t blue);
void RGB_LED_Show(uint8_t dat[]);

#endif

```c
#include "WS2812.h"
#include "delay.h"

void RGB_LED_Init(void)
{
    
    
	GPIO_InitTypeDef  GPIO_InitStructure;
 	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);	 
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;				 
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		 
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		
	GPIO_Init(GPIOA, &GPIO_InitStructure);					
	GPIO_SetBits(GPIOA, GPIO_Pin_8);						 
}

void RGB_LED_Write0(void)//WS2812写0码
{
    
    
	RGB_LED_HIGH;
	__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
	__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
    __nop();__nop();
	RGB_LED_LOW;
	__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
	__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
	__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
}


void RGB_LED_Write1(void)//WS2812写1码
{
    
    
	RGB_LED_HIGH;
	__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
	__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
	__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
	__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
	__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
	__nop();__nop();__nop();__nop();__nop();__nop();__nop();
	RGB_LED_LOW;
	__nop();__nop();
}

void RGB_LED_Reset(void)//WS2812复位操作
{
    
    
	RGB_LED_LOW;
	delay_us(80);
}

void RGB_LED_Write_Byte(uint8_t byte)//WS2812写1字节
{
    
    
	uint8_t i;
	for(i=0;i<8;i++)
	{
    
    
		if(byte&0x80)
		{
    
    
			RGB_LED_Write1();
		}
		else
		{
    
    
			RGB_LED_Write0();
		}
		byte <<= 1;
	}
}

void RGB_LED_Write_24Bits(uint8_t red, uint8_t green, uint8_t blue)//WS2812写1个像素点
{
    
    
    RGB_LED_Write_Byte(green);
    RGB_LED_Write_Byte(red);
	RGB_LED_Write_Byte(blue);
}

void RGB_LED_Show(uint8_t dat[])//WS2812写多个个像素点
{
    
    
	int16_t i;
	RGB_LED_Reset();
	for(i=0; i<LED_Nums; i++)
	{
    
    
		RGB_LED_Write_24Bits(dat[3*i], dat[3*i+1], dat[3*i+2]);
	}
	RGB_LED_HIGH;
}

In the source file, in order to improve the IO flip speed of STM32, bit-band output is used, and then _nop(); is used to adjust the delay to meet the requirements of the WS2812 drive signal. If possible, you can use a logic analyzer or oscilloscope to adjust the delay. The author adjusted the time for a while, so I need to be patient.
Insert picture description here
Insert picture description here

In this computer screen atmosphere light, the single-chip microcomputer uses a serial port to communicate with the PC.
Next is the serial port receiving program.

void USART1_IRQHandler(void)//串口1中断服务程序
	{
    
    
	static uint8_t k=0,i=0,rebuf[3*LED_Nums+2]={
    
    0};
	if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
		{
    
    
		 rebuf[k++] = USART_ReceiveData(USART1);//读取接收到的数据
		 if(!(rebuf[0]==0xaa))//如果帧头错误,清缓存
		 {
    
    
			 k = 0;
			 rebuf[0]=0;
			 printf("err!!!");
		 }
		 if(k == 3*LED_Nums + 2)//数据接收完毕
		 {
    
    
			if(rebuf[3*LED_Nums + 1] == 0x55)//判断帧尾
			{
    
    	
				for(i = 1; i<3*LED_Nums + 1; i++)
				{
    
    
					  LED_data[i-1] = rebuf[i];
						show_flag = 1;
				}	
			}
			k=0;//清缓存
		 }
    } 
} 

The serial port program is modified by casually finding a routine for receiving the serial port interrupt, and you only need to modify the serial port interrupt service function. As you can see, this time the author has customized a simple communication protocol, which is 0xaa,R,G,B,R,G,B...,0x55.

The main program is also very simple, as follows.

while(1)
{
    
    
	if(show_flag==1) 
	{
    
    
		RGB_LED_Show(LED_data);
		show_flag=0;
		printf("show ok!");
	}
}

Since then, the programming of the lower computer has been completed. Next, we only need to let the computer send the color value of the corresponding pixel to the microcontroller through the serial port.

Host computer

This time the host computer is developed using C#, and this time it is also a practice project for me to learn C# programming by myself. The author mainly wants to do the basic communication between the computer and the single-chip computer after finishing the study. When other things are needed, refer to the program of the boss, and modify it bit by bit to what you want.

The upper computer is mainly the serial port communication part and the screen color acquisition part.
The color acquisition procedure is as follows.

	int len = 60; //设置像素点
	Byte lightness = Convert.ToByte(textBox1.Text); //获取亮度设置
	int x = 0, y = 200; //截图起始点
	Bitmap RGB_Led = new Bitmap(1920, 1); 
	Graphics g = Graphics.FromImage(RGB_Led);
	
	Byte[] fram_data = new Byte[3];
	Byte[] GRB_data_last = new Byte[3 * len];
	Byte[] GRB_data_curr = new Byte[3 * len];
	Byte RGB_r = 0, RGB_g = 0, RGB_b = 0;
	fram_data[0] = 0xAA;
	fram_data[1] = lightness;
	fram_data[2] = 0x55;
	
	//g.CopyFromScreen(new Point(x, y), new Point(0, 0), new Size(1, 120));
	g.CopyFromScreen(x, y, 0, 0, new Size(1920, 1));//起始坐标想x,y,取一个1920*1的屏幕图像
	for (int i = 0; i < len; i++)
	{
    
    
		Color color_start = RGB_Led.GetPixel(16 * 2 * i, 0); //隔每16点取颜色
		RGB_r = color_start.R;
		RGB_g = color_start.G;
		RGB_b = color_start.B;
		GRB_data_last[3 * i] = RGB_r;
		GRB_data_last[3 * i + 1] = RGB_g;
		GRB_data_last[3 * i + 2] = RGB_b;
	}
	serialPort1.Write(fram_data, 0, 1);
	//serialPort1.Write(fram_data, 1, 1);
	serialPort1.Write(GRB_data_curr, 0, 3 * len);
	serialPort1.Write(fram_data, 2, 1);

The idea of ​​the program is very simple, that is, to obtain the RGB components of the color of the fixed pixels on the screen at regular intervals, and then send them to the single-chip microcomputer according to the previously designed communication protocol. I won’t go into details in detail. The host computer still has a lot of imperfections. For example, it is now possible to obtain a pixel. It is better to obtain the average color of the pixel in an area. In addition, for the light bar display effect to be smoother , It also needs some algorithms to process the acquired color data.
However, Prismatik, a special color picking software on the Internet. It was only seen after I finished this practice project. I also downloaded the software and tested it, and found that it is a bit unstable, and the serial port data is often interrupted. However, seeing other people working with Arduino to make it work well, I don't know where I have the problem.

The operating results of the host computer are as follows.
Insert picture description here

hardware

For the hardware part, I made a small driver board. By the way, it was also to verify some of my ideas, so that I could refer to it when designing the circuit in the future.
Insert picture description here
One is that the USB-to-serial chip uses CH340E, which does not require an external crystal oscillator and is small in size.
The second is that the serial port and the SWD download interface share the Type-C interface, which can be selected through the DIP switch.

Overall demonstration effect

Insert picture description here
To sum up, the final effect is not very satisfactory. The program algorithm still needs to be optimized. I will try Prismatik again if I have the opportunity, because its effect is really good.

Guess you like

Origin blog.csdn.net/weixin_44625313/article/details/113248494