SEGA星空投影仪太贵买不起?教你用STM32自制星空灯!

女神最近种草了一款星空投影仪——日本SEGA的Homestar。白柴看着少则几百,多则上千的价格,不禁感觉钱包一紧SEGA星空投影仪太贵买不起?教你用STM32自制星空灯!的图1

再看看某宝上几十块的星空灯,功能不少,但图案偏幼稚,一点都不浪漫。这样的东西,如何拿得出手送给女神呢?


看来只能自己动手DIY了。鲁迅曾说过:“如果没有你想要的星空灯,那么就自己做一个。”


SEGA星空投影仪太贵买不起?教你用STM32自制星空灯!的图2

事不宜迟,立马打电话给大Z老师,向他学习星空灯的制作。现在白柴就把整理好的制作方法分享给大家,感兴趣的粉丝们可以跟着一起做哟~


SEGA星空投影仪太贵买不起?教你用STM32自制星空灯!的图3
星空灯DIY报名征集

看完已心动,自己也想做?

现在报名参加EEPW星空灯DIY内测活动,满足你的愿望!

报名时间:4.23~4.30


参与名额:10名

*内测活动,活跃度高的粉丝更容易被选中


 亮点1

100元开发补贴 人人都有

放飞创意 费用我们报销


 亮点2

自己设计灯罩 我的灯 我做主

实现星空灯自由


 亮点3

记录过程 参与评比 得分最高者

我们将在520当天送上一份花束大礼(价值200元)

带上鲜花和星空灯,去和她告白吧!


如何报名?

添加小助手微信(ID:baichai1025),私信【星空灯报名】。

收到小助手回复后,即为报名成功。

SEGA星空投影仪太贵买不起?教你用STM32自制星空灯!的图4

扫一扫,添加小助手



星空灯成品展示

效果超nice!绝对能感动女神SEGA星空投影仪太贵买不起?教你用STM32自制星空灯!的图5

SEGA星空投影仪太贵买不起?教你用STM32自制星空灯!的图6
物料清单
SEGA星空投影仪太贵买不起?教你用STM32自制星空灯!的图7

本体:

  • STM32最小系统板(1个)

  • WS2812灯带(1个)

  • HC-06蓝牙模块(1个)

  • 杜邦线若干

SEGA星空投影仪太贵买不起?教你用STM32自制星空灯!的图8

星空灯本体

灯罩:

  • 裁好的亚克力板(1份)

  • 黑色墙纸(适量)

SEGA星空投影仪太贵买不起?教你用STM32自制星空灯!的图9

灯罩裁切图纸


SEGA星空投影仪太贵买不起?教你用STM32自制星空灯!的图10
制作详解
SEGA星空投影仪太贵买不起?教你用STM32自制星空灯!的图11

虽然叫星空灯,但本体实际是STM32点流水灯。硬件不复杂,属于入门级,有一点单片机和编程基础的朋友都可尝试制作。本文只给出了基础电灯程序,欢迎技术大神们开发添加新功能。

01

WS2812彩灯

先简单说下WS2812的工作过程:

  • 1)上电时,WS2812数据IO为低电平保持。

  • 2)空闲时,IO为低电平。

  • 3)数据发送完毕后,保持电平,超过规格书上定义的RESET时间(只有低电平时间超过280us,就可以认为是RESET)。

接下来,我们看下数据的时序,如图1。


SEGA星空投影仪太贵买不起?教你用STM32自制星空灯!的图12

图1 数据的时序

                         

如图2,是每24bit的组成。注意,顺序不是RGB888,而是GRB888。一般我们取颜色的数值,都是RGB顺序,所以这里在代码里实现的时候,会需要做一下移位。另外,需要注意的是,需要高位先发(MSB)。


SEGA星空投影仪太贵买不起?教你用STM32自制星空灯!的图13

图2 24bit数据结构

图3是时序波形图。关键在于用什么方法去表示Bit的波形,网络上的方法有很多。例如PWM,也有用SPI。今天我们就先用一种简单方法实行吧,IO口模拟是不错的选择。


SEGA星空投影仪太贵买不起?教你用STM32自制星空灯!的图14

图3 时序波形图 


现在我们开始配置工程吧。打开STM32CubeMX,新建一个工程,图4。


SEGA星空投影仪太贵买不起?教你用STM32自制星空灯!的图15

图4

在搜索框内,搜索我们的开发板型号,也就是STM32G070RB,图5。这样工程就新建好了。


SEGA星空投影仪太贵买不起?教你用STM32自制星空灯!的图16

图5

配置时钟树,如图6所示。


SEGA星空投影仪太贵买不起?教你用STM32自制星空灯!的图17

图6

接下来配置引脚 ,这里我们采用的是PWM+DMA的方式来驱动WS2812。通过WS2812的手册,可以得知驱动需要800KHZ的频率。现在我们来配置定时器,这里以定时器1为例来配置。如图7所示,图中的Pulse是指一个周期的脉冲数;计算方法79=(64M/800K)-1得出。


SEGA星空投影仪太贵买不起?教你用STM32自制星空灯!的图18

图7


下面我们开始配置DMA,如图8所示配置。


SEGA星空投影仪太贵买不起?教你用STM32自制星空灯!的图19

图8

到这里就可以生成代码了,图9。


SEGA星空投影仪太贵买不起?教你用STM32自制星空灯!的图20

图9


我们打开工程,将下面的代码,复制到图10所在位置:

#define ONE_PULSE        (59)                           //1 码计数个数#define ZERO_PULSE       (29)                           //0 码计数个数#define RESET_PULSE      (80)                           //80 复位电平个数(不能低于40)#define LED_NUMS         (12)                            //led 个数#define LED_DATA_LEN     (24)                           //led 长度,单个需要24个字节#define WS2812_DATA_LEN  (LED_NUMS*LED_DATA_LEN)        //ws2812灯条需要的数组长度
uint16_t static RGB_buffur[RESET_PULSE +WS2812_DATA_LEN] = { 0 };

SEGA星空投影仪太贵买不起?教你用STM32自制星空灯!的图21

图10

接下来就是DMA传输完成回调函数(根据你使用的定时器配置),以下函数都复制到main.c 的/* USER CODE BEGIN 4 */代码区:

voidHAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim){   HAL_TIM_PWM_Stop_DMA(&htim1,TIM_CHANNEL_1);}

下面就是WS2812的驱动函数了,该函数的作用是根据WS2812的数量将灯的GRB颜色数据写到需要DMA传送的数组中:

void WS281x_SetPixelColor(uint16_t n,uint32_t GRBColor){  uint8_ti;  if(n < LED_NUMS)  {    for(i = 0; i < 24; ++i)     RGB_buffur[24* n + i] = (((GRBColor << i) & 0X800000) ? ONE_PULSE : ZERO_PULSE);  }}

将三个颜色的数据合并成GRB数据:

uint32_t WS281x_Color(uint8_t red, uint8_tgreen, uint8_t blue){     returngreen << 16 | red << 8 | blue;}

这是一个简单的颜色渐变算法 ,感兴趣的可以研究研究:

uint32_t Wheel(uint8_t WheelPos){       WheelPos= 255 - WheelPos;       if(WheelPos < 85)       {              returnWS281x_Color(255 - WheelPos * 3, 0, WheelPos * 3);       }       if(WheelPos < 170)       {              WheelPos-= 85;              returnWS281x_Color(0, WheelPos * 3, 255 - WheelPos * 3);       }       WheelPos-= 170;       returnWS281x_Color(WheelPos * 3, 255 - WheelPos * 3, 0);}

这里简单的写了两个演示程序:

void Mode2_LED(uint8_t wait){       uint32_ttimestamp = HAL_GetTick();       uint16_ti;       staticuint8_t j;       staticuint32_t next_time = 0;       uint32_tflag = 0;       if(next_time < wait)       {              if((uint64_t)timestamp + wait - next_time > 0)                     flag= 1;       }       elseif (timestamp > next_time)       {              flag= 1;       }       if(flag)       {              j++;              next_time= timestamp + wait;              for(i = 0; i < LED_NUMS; i++)              {                     WS281x_SetPixelColor(i,Wheel((i + j) & 255));              }       }       HAL_TIM_PWM_Start_DMA(&htim1,TIM_CHANNEL_1,(uint32_t*)RGB_buffur,RESET_PULSE + WS2812_DATA_LEN);}
void Mode1_LED(uint8_t wait){       uint32_ttimestamp = HAL_GetTick();       uint16_ti;       staticuint8_t j;       staticuint32_t next_time = 0;
      staticuint8_t loop = 0;       if(loop == 0)              next_time= timestamp;       loop= 1; //首次调用初始化
      if((timestamp > next_time)) // && (timestamp - next_time < wait*5))       {              j++;              next_time= timestamp + wait;              for(i = 0; i < LED_NUMS; i++)              {                     WS281x_SetPixelColor(i,Wheel(((i * 256 / (LED_NUMS)) + j) & 255));              }       }       HAL_TIM_PWM_Start_DMA(&htim1,TIM_CHANNEL_1,(uint32_t*)RGB_buffur,RESET_PULSE + WS2812_DATA_LEN);}

在主函数中直接调用Mode1_LED和Mode2_LED函数即可。

 

OK,点亮之后相当炫酷。大家可以借鉴,修改出自己独特的风格。

02

按键模式切换

这里简单的写了几种模式,图11。

SEGA星空投影仪太贵买不起?教你用STM32自制星空灯!的图22

图11

                           

通过图12的原理图可以看出来,开发板上的按键连接的是PC13引脚。

SEGA星空投影仪太贵买不起?教你用STM32自制星空灯!的图23

图12

好的,知道了按键的引脚,我们打开STM32CubeMX软件来配置引脚,如图13所示。

SEGA星空投影仪太贵买不起?教你用STM32自制星空灯!的图24

图13

同时使能中断,如图14。

SEGA星空投影仪太贵买不起?教你用STM32自制星空灯!的图25

图14

生成代码,打开工程。

在/* USER CODE BEGIN 4 */

/* USER CODE END 4 */之间重写中断回调函数,代码如下。

void HAL_GPIO_EXTI_Rising_Callback(uint16_tGPIO_Pin){      switch(GPIO_Pin)       {              caseGPIO_PIN_13:Mode_Led++;       if(Mode_Led == 'I')           Mode_Led ='A';break;       }}

通过主函数判断当前的模式,并运行相对应的模式实现函数,如图15。

SEGA星空投影仪太贵买不起?教你用STM32自制星空灯!的图26

图15

 

通过按键进行模式选择就完成了。

03

蓝牙控制

接下来,用手机通过蓝牙来控制WS2812的模式和速度调节。

 

先打开STM32CubeMX配置我们要用到串口(这里以串口2为例,大家根据自己的喜好选择)。

因为蓝牙模块默认是9600Bits/s,所以我们配置时要与蓝牙的波特率一致,如下图16所示。

SEGA星空投影仪太贵买不起?教你用STM32自制星空灯!的图27

图16

同时我们使能下串口的收发中断,如图17。

SEGA星空投影仪太贵买不起?教你用STM32自制星空灯!的图28

图17

这样串口就配置好了,点击生成代码,打开工程。

SEGA星空投影仪太贵买不起?教你用STM32自制星空灯!的图29

图18

我们可以看到串口2的初始化程序,图18。

接下来添加代码,定义一个字符的数据接收,图19。

SEGA星空投影仪太贵买不起?教你用STM32自制星空灯!的图30

图19

添加以下代码,打开串口接收中断,图20。

SEGA星空投影仪太贵买不起?教你用STM32自制星空灯!的图31

图20

重写串口接收中断回调函数, 代码如下:

voidHAL_UART_RxCpltCallback(UART_HandleTypeDef *huart){   if(Buffer>='A' && Buffer <='H')    {       Mode_Led = Buffer;       printf("灯光模式:%c",Mode_Led);    }   if(Buffer == 'I')    {       Mode_wait  +=10;       if(Mode_wait==500)           Mode_wait=490;       printf("灯光速度:%d",500-Mode_wait);    }   if(Buffer == 'J')    {       Mode_wait  -=10;       if(Mode_wait==40)           Mode_wait=50;       printf("灯光速度:%d",500-Mode_wait);    }   HAL_UART_Receive_IT(&huart2,&Buffer, 1);}

这里的printf对串口发送函数进行了重定义,方法如下:

int fputc(int c, FILE *stream)    //重写fputc函数{ /*   huart1是工具生成代码定义的UART1结构体,    如果以后要使用其他串口打印,只需要把这个结构体改成其他UART结构体。*/   HAL_UART_Transmit(&huart2, (unsigned char *)&c, 1, 1000);     return 1;}

将代码复制到

/* USER CODE BEGIN 0 */

/* USER CODE END 0 */之间。

 

接下来点击Options for Target,把Use MicroLIB打上对勾,图21。

SEGA星空投影仪太贵买不起?教你用STM32自制星空灯!的图32

图21

至此就完成了对串口发送函数的重写,可以正常的使用printf函数了。我们可以通过输出一定的信息,显示出当前的状态。

连上蓝牙模块,发送模式对应的字符,就可以实现模式的切换,以及实现调速,图22。

SEGA星空投影仪太贵买不起?教你用STM32自制星空灯!的图33

图22

到这里,我们就实现了使用蓝牙控制的效果。

感兴趣粉丝们,欢迎报名参加我们的DIY活动哟~

SEGA星空投影仪太贵买不起?教你用STM32自制星空灯!的图34
SEGA星空投影仪太贵买不起?教你用STM32自制星空灯!的图35

扫码入群

扫码添加管理员微信

加入“电子产品世界”粉丝交流群


登录后免费查看全文
立即登录
App下载
技术邻APP
工程师必备
  • 项目客服
  • 培训客服
  • 平台客服

TOP

6
1