アイデアの出典:宝物を訪ねていたときに、コンピューターの画面に取り付けられたライトストリップを見つけました。ライトストリップはコンピューターの画面の色によって変化します。そのとき、私はDIYのアイデアを心に埋めました。 、後で助けられるまで先生は何かをして残り物を手に入れたので、彼はそれをする決心をしました!
ソフトウェア
下のコンピューター
今回はWS2812ライトストリップを使用しているので、先に駆動して点灯させる必要があります。
したがって、WS2812のデータシートを参照してください。その駆動シーケンスは次のとおりです。
インターネット上にはSPI、PWM、タイマーなど多くの駆動方法がありますが、今回は最も単純なIOフリップを使用して駆動します。上記の他の方法は、読者が自分で検索して参照するためのものです。
#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;
}
ソースファイルでは、STM32のIOフリップ速度を向上させるために、ビットバンド出力が使用され、次に_nop();が使用されて、WS2812ドライブ信号の要件を満たすように遅延が調整されます。可能であれば、ロジックアナライザまたはオシロスコープを使用して遅延を調整できます。作者はしばらく時間を調整したので、我慢する必要があります。
このコンピュータ画面の大気光では、シングルチップマイクロコンピュータはシリアルポートを使用してPCと通信します。
次はシリアルポート受信プログラムです。
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;//清缓存
}
}
}
シリアルポートプログラムは、シリアルポート割り込みを受信するためのルーチンを何気なく見つけることによって変更され、シリアルポート割り込みサービス機能を変更するだけで済みます。ご覧のとおり、今回、作成者は0xaa、R、G、B、R、G、B ...、0x55という単純な通信プロトコルをカスタマイズしました。
メインプログラムも次のように非常にシンプルです。
while(1)
{
if(show_flag==1)
{
RGB_LED_Show(LED_data);
show_flag=0;
printf("show ok!");
}
}
それ以来、下のコンピュータのプログラミングは完了しました。次に、コンピュータに対応するピクセルのカラー値をシリアルポートを介してマイクロコントローラに送信させるだけです。
ホストコンピューター
今回はホストコンピューターをC#を使って開発しましたが、今回は自分でC#プログラミングを学ぶ練習プロジェクトでもあります。作者は、研究終了後、主にコンピューターとシングルチップコンピューター間の基本的なコミュニケーションを行いたいと考えています。他に必要な場合は、上司のプログラムを参考にして、少しずつ修正していきます。
上位コンピュータは主にシリアルポート通信部と画面色取得部です。
色の取得手順は次のとおりです。
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);
プログラムのアイデアは非常に単純です。つまり、画面上の固定ピクセルの色のRGBコンポーネントを一定の間隔で取得し、以前に設計された通信プロトコルに従ってシングルチップマイクロコンピューターに送信します。詳細については触れませんが、ホストコンピュータにはまだ多くの欠陥があります。たとえば、ピクセルを取得できるようになりました。領域内のピクセルの平均色を取得することをお勧めします。さらに、ライトバーの表示効果はよりスムーズです。また、取得したカラーデータを処理するためにいくつかのアルゴリズムが必要です。
ただし、インターネット上の特別なカラーピッキングソフトウェアであるPrismatik。それは私がこの練習プロジェクトを終えた後にのみ見られました。また、ソフトウェアをダウンロードしてテストしたところ、少し不安定で、シリアルポートのデータが頻繁に中断されることがわかりました。しかし、Arduinoをうまく機能させるために他の人が働いているのを見ると、どこに問題があるのかわかりません。
ホストコンピュータの動作結果は以下のとおりです。
ハードウェア
ハードウェア部分は小さなドライバーボードを作りましたが、ちなみに、将来の回路設計時に参考にできるように、アイデアを検証することもありました。
まず、USB-シリアルチップは、外部水晶発振器を必要とせず、サイズが小さいCH340Eを採用しています。
2つ目は、シリアルポートとSWDダウンロードインターフェイスがType-Cインターフェイスを共有していることです。これは、DIPスイッチを介して選択できます。
全体的なデモンストレーション効果
要約すると、最終的な効果はあまり満足のいくものではありません。プログラムアルゴリズムを最適化する必要があります。効果が非常に良いので、機会があればもう一度Prismatikソフトウェアを試してみます。