STC15W204S支持的雪花板亮灯实验
我进行的项目如下:
利用一个电子森林工程师设计好的雪花板以及其开源代码,进行修改和测试,了解雪花板的电路设计和单片机的引脚与通讯配置,以及点灯程序的实现。
雪花板使用CH340芯片实现USB串口通信的功能,可进行代码的烧录以及串口通信控制。
STC15W204S单片机的原理图如图。
图片来源:硬禾课程教参
其中:Vcc和GND为直流电源输入和电源/信号共地端,T2/TXD/P3.1为信号发送端,T2CKO/INT4/RXD/P3.0是信号接收端,以及时钟信号接受端。与芯片和主板有关的函数都封装在了头文件(.h)和其对应的.c文件里,一般不需要修改。只需要对主程序MAIN.c文件进行操作。
使用的LED器件为37个WS2812。在老师提供的教参中,图片描述了这些LED的连接,通信和供电方式。
LED芯片的四个引脚分别管控信号的输入,输出,电源的输入,以及接地。单片机的程序转化为电信号后传入LED芯片,前一个LED的Dout(信号输出)引脚连接到下一个LED的Din(信号输入)引脚,以实现每一圈的LED之间以及内外圈之间的通信,然而这一点的具体实现机制暂时没有理解得很明白,因为仅参照板子上的布线并不能很清晰地理解其中的关系。USB输入通过CH340转换后一部分作为5V电源给所有并联的LED供电。每一个LED都和一个电容并联,此电容作为旁路电容而过滤高频交流信号,推测其还具有滤波作用,因为LED的亮度需要通过PWM控制,需要以直流数字信号通过占空比输出模拟信号。
在进行程序烧录时,需要使用STC-ISP软件烧录。首先要设置输入程序时的IRC频率,使其等于33MHz,然后烧录,以使得MCU的内部晶振工作在33MHz. 若不设置,将出现雪花板LED灯点亮情况异常的现象。推测这是因为内部晶振频率与程序设置的频率无法匹配,灯的颜色和亮度都无法在时钟的信号周期内正确地以电平信号输出,因此产生了默认的白灯常亮情况。
流程如下:
我改变了源程序封装好的亮灯子函数的实现位置,取消了串口通信的控制,将其放在主程序内直接循环执行。效果如视频所示。创建并添加了burst(void)函数以实现涟漪效果,并将现成的几种灯效组合拼接。我还研究了彩虹流动效果的代码,但因为对C语言及单片机理解及时间有限,没有如愿实现。
主程序.c文件代码如下
/**************************************包含头文件*************************************/
#include "STC15W.h"
#include "ws2812.h" //包含LED驱动程序
#include "delay.h" //包含延时程序
#include "uart.h"
/**************************************子函数声明*************************************/
void WS2812_1_5Line_In(unsigned char *p,unsigned char line);//让其整圈一起点亮,内圈颜色保持不变,传递两个参数,第一个参数为显示颜色,第二个参数是让第几圈点亮,圈数1-5
void rainbow1(void);
void rainbow2(void);
void Flower_In(void);//一圈圈逐步点亮
void Water_lamp(unsigned char *p);//按1-37顺序点亮
void burst(void); //逐圈向外点亮,扩散效果(涟漪)
/***************************************全局变量**************************************/
unsigned char green[3]={50,0,0};//绿,红,蓝
unsigned char red[3]={0,50,0};//红
unsigned char blue[3]={10,10,50};//蓝
unsigned char white[3]={25,25,25};//白
unsigned char org[3]={10,80,0};//橘
unsigned char yellow[3]={50,50,0};
unsigned char cyan[3]={10,10,80};
unsigned char purple[3]={0,188,188};
unsigned char close[3]={0,0,0};
unsigned char color[7][3]={{0,5,0},{1,10,0},{10,25,0},{5,0,0},{0,0,5},{0,23,23},{5,5,5}};//红,橙,黄,绿,蓝,紫,白
xdata unsigned char buffer[64];
unsigned char buf_data=0x00;
unsigned char i;
unsigned char j;
void main()
{
DelayMs(1000); //上电延时
UartInit();
UART1_SendString("STC15W204S\r\nUart is ok !\r\n");//发送字符串检测是否初始化成功
DelayMs(1000);
ResetDataFlow();
WS2812_Close();
//主循环
while(1)
{
// UART1_SendData(buf_data);
// sovle(buf_data);
// Flash_WS2812(white);
WS2812_1_5Line_In(green,2);
DelayMs(2000);
rainbow2();
Water_lamp(red);
Flower_In();
burst();
/* rainbow2();
rainbow3();
rainbow4();
rainbow5(); */
/*DelayMs(1000);
for(i=1;i<=5;i++)
{
WS2812_1_5Line_In(color,i);
DelayMs(1000);
for(j=2;j<=6*(i-1)+1;j++)
{
SendOnePix(close);
}
}
WS2812_1_5Line_Single(blue,5);
DelayMs(1000);
for(i=1;i<=5;i++)
{
WS2812_1_5Line_In(color,i);
DelayMs(1000);
WS2812_Close();
}
WS2812_1_5Line_Single(green,5);
DelayMs(1000);
LED_Water(org);*/
/*for(i=0;i<6;i++)
{
WS2812_1_5Line_In(red,i);
DelayMs(1000);
} */
/*WS2812_1_5Line(color,2);
Water_lamp(green);
DelayMs(1000);
LED_Single_Flower();
DelayMs(1000);
LED_Water_Color(blue);
DelayMs(1000); */
}
}
//-------------------------------------------------------------------------------
//子程序名称:Flower_In(void)
//功能:一圈圈整体点亮,内部颜色不变
//参数:无
//说明:
//-------------------------------------------------------------------------------
void Flower_In(void)
{
WS2812_1_5Line_In(color,1);
Delay100Ms(5);
WS2812_1_5Line_In(color,2);
Delay100Ms(5);
WS2812_1_5Line_In(color,3);
Delay100Ms(5);
WS2812_1_5Line_In(color,4);
Delay100Ms(5);
WS2812_1_5Line_In(color,5);
Delay100Ms(5);
}
//-------------------------------------------------------------------------------
//子程序名称:rainbow1(void)
//功能:七色彩虹流动
//参数:无
//说明:
//-------------------------------------------------------------------------------
void rainbow1(void)
{
WS2812_1_5Line_In(red,1);
Delay100Ms(5);
WS2812_1_5Line_In(org,2);
Delay100Ms(5);
WS2812_1_5Line_In(yellow,3);
Delay100Ms(5);
WS2812_1_5Line_In(green,4);
Delay100Ms(5);
WS2812_1_5Line_In(blue,5);
Delay100Ms(15);
WS2812_1_5Line_In(purple,1);
WS2812_1_5Line_In(red,2);
WS2812_1_5Line_In(org,3);
WS2812_1_5Line_In(yellow,4);
WS2812_1_5Line_In(green,5);
Delay100Ms(15);
WS2812_1_5Line_In(cyan,1);
WS2812_1_5Line_In(purple,2);
WS2812_1_5Line_In(red,3);
WS2812_1_5Line_In(org,4);
}
void rainbow2(void)
{
WS2812_1_5Line_In(red,1);
WS2812_1_5Line_In(org,2);
WS2812_1_5Line_In(yellow,3);
WS2812_1_5Line_In(green,4);
WS2812_1_5Line_In(blue,5);
Delay100Ms(6);
WS2812_1_5Line_In(blue,1);
WS2812_1_5Line_In(red,2);
WS2812_1_5Line_In(org,3);
WS2812_1_5Line_In(yellow,4);
WS2812_1_5Line_In(green,5);
Delay100Ms(6);
WS2812_1_5Line_In(green,1);
WS2812_1_5Line_In(blue,2);
WS2812_1_5Line_In(red,3);
WS2812_1_5Line_In(org,4);
WS2812_1_5Line_In(yellow,5);
Delay100Ms(6);
}
//-------------------------------------------------------------------------------
//子程序名称:WS2812_1_5Line_In(unsigned char *p,unsigned char line)
//功能:让其整圈一起点亮,内圈颜色保持不变
//参数:指针参数是颜色的二维数组,line参数为第几圈(1-5)
//说明:
//-------------------------------------------------------------------------------
void WS2812_1_5Line_In(unsigned char *p,unsigned char line)
{
unsigned char count_sum;
unsigned char m=1;
unsigned char k=0;
switch(line)
{
case 1:
for(count_sum=0;count_sum<=36;count_sum++)//36个灯循环
{
if(count_sum==36)
{
SendOnePix(&p[(3*k)]);
}
else
SendOnePix(close);
}
ResetDataFlow();/*复位 为下一次发送做准备*/
break;
case 2:
for(count_sum=0;count_sum<36;count_sum++)//36个灯循环
{
k=1;
if(count_sum%6==0)
{
SendOnePix(&p[(3*k)]);
}
else
SendOnePix(close);
}
ResetDataFlow();
break;
case 3:
for(count_sum=0;count_sum<36;count_sum++)//36个灯循环
{
if(count_sum%6==1)
{
k=2;
SendOnePix(&p[(3*k)]);
}
else if(count_sum%6==0)
{
k=1;
SendOnePix(&p[(3*k)]);
}
else
SendOnePix(close);
}
ResetDataFlow();
break;
case 4:
for(count_sum=0;count_sum<36;count_sum++)//36个灯循环
{
if(count_sum%6==2)
{
k=3;
SendOnePix(&p[(3*k)]);
}
else if(count_sum%6==1)
{
k=2;
SendOnePix(&p[(3*k)]);
}
else if(count_sum%6==0)
{
k=1;
SendOnePix(&p[(3*k)]);
}
else
SendOnePix(close);
}
ResetDataFlow();
break;
case 5:
for(count_sum=0;count_sum<36;count_sum++)//36个灯循环
{
if(count_sum==3*m)
{
k=4;
SendOnePix(&p[(3*k)]);
}
else if(count_sum==(3*m)+1)
{
k=5;
SendOnePix(&p[(3*k)]);
}
else if(count_sum==(3*m)+2)
{
k=6;
SendOnePix(&p[(3*k)]);
m+=2;
}
else if(count_sum%6==2)
{
k=3;
SendOnePix(&p[(3*k)]);
}
else if(count_sum%6==1)
{
k=2;
SendOnePix(&p[(3*k)]);
}
else if(count_sum%6==0)
{
k=1;
SendOnePix(&p[(3*k)]);
}
else
SendOnePix(close);
}
m=1;
ResetDataFlow();
break;
}
}
//-------------------------------------------------------------------------------
//子程序名称:LED_Water(unsigned char *p)
//功能:由内而外流水点亮
//参数:指针参数是颜色的数组
//说明:
//-------------------------------------------------------------------------------
void LED_Water(unsigned char *p)//由内而外流水点亮
{
WS2812_1_5Line_Single(p,1);//37点不给新的数据,所以一直保持之前的状态
WS2812_1_5Line_Single(p,2);
// LED_3count(p);
// LED_4count(p);
// LED_5count(p);
WS2812_LineIn_Single(p,3);
WS2812_LineIn_Single(p,4);
WS2812_LineIn_Single(p,5);
}
自己构造的函数rainbow1(void)和rainbow2(void)本希望通过按规律改变每一圈灯的颜色以实现彩虹向外流动的效果(rainbow1为5圈7色,rainbow2为5圈5色),但实验中发现并不能使每一圈按需要的颜色亮起,甚至有些圈不亮,推测原因在于函数SendOnePix(unsigned char *ptr)的使用。void WS2812_1_5Line_In(unsigned char *p,unsigned char line)函数(使某一圈灯以某种颜色全部亮起)中调用了SendOnePix函数,其实现时传入的参数是&p[(3*k)],为颜色数组的地址,对其进行调试可能是可行的解决方案。
原本的构想包括使用串口通信函数和串口中断函数来实现使用上位机通过STC ISP软件发送数据来控制亮灯情况,但尚未实现。