找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 3683|回复: 5
收起左侧

用stc单片机制作PC流光溢彩 源程序

  [复制链接]
ID:687694 发表于 2020-10-19 20:13 | 显示全部楼层 |阅读模式
近日在B站看到许多PC流光溢彩效果,如:https://www.bilibili.com/video/BV1fJ411B7bp?from=search&seid=16736407731500993634还有https://www.bilibili.com/video/BV1MC4y1h7iB?from=search&seid=16736407731500993634
效果是真不错,还有许多制作的视频帖子,但是。。。。。。都是基于arduino制作的,我手头上只有一块自制的arduino uno,个头有点大,洞洞板上还没有usb转串口,有点麻烦。正好上次制作rgb环形时钟的硬件符合条件,板上60颗灯珠,stc主控,带usb转串口,那么我们就用这个stc来做流光溢彩吧。
查了一下网上也没有stc的教程,就自己分析了一下运行过程。
首先由PC机运行AmbiBox软件抓取屏幕点,取得rgb颜色数据。
然后由串口发送至单片机解析。
解析后的数据刷新至rgbled显示。
过程貌似比较简单,但我们得分析其中的协议。
网查资料得到 Ada模式协议如下:
前三个字节分别是Ada,然后3个字节的前2个是led个数,最后一个是校验码,接着就是对应个数的rgb数据,每个led3字节,分别对应r,g,b。
有了这个就简单了。构建程序流程如下
单片机主频33.1776(为了配合串口波特率)
启动程序->初始化串口(定时器2,波特率115200,)->初始化led数组 ->检测显示(红,绿,蓝各显示一遍)->开启串口接收中断->主循环判断如果不允许中断则刷新rgbled,刷新完成后开启中断,如果允许中断则等待不允许中断。
中断函数中流程->依次判断接收字符是否对应,如果前3个字节对应则 接收电灯数据,并将数据保存至数组中,接收一组数据完毕,失能中断,这样不会因中断接收数据影响刷新。
图我也懒得拍照了,程序上传上来,大家想做的可以自己画个板子,烧上代码就行了,至于AmbiBox自行某度即可。

单片机源程序如下:
  1. #include "stc15.h"
  2. #include "ws2812.h"
  3. uchar xdata rgb[60][3];//led数组
  4. uchar sendrgb=0;//预发送rgb变量
  5. uchar h=0,l=0,o=0;
  6. uchar in=0;
  7. void delayms(int x)
  8. {
  9.         int i,j;
  10.         for(i=0;i<x;i++)
  11.         for(j=0;j<1000;j++);
  12. }

  13. void UartInit(void)                //115200bps@33.1776MHz
  14. {
  15.         SCON = 0x50;                //8位数据,可变波特率
  16.         AUXR |= 0x01;                //串口1选择定时器2为波特率发生器
  17.         AUXR |= 0x04;                //定时器2时钟为Fosc,即1T
  18.         T2L = 0xB8;                //设定定时初值
  19.         T2H = 0xFF;                //设定定时初值
  20.         AUXR |= 0x10;                //启动定时器2
  21.         ES = 1;              //使能串口1中断
  22. }
  23. void initrgb(uchar st,uchar sp,uchar rg0,uchar rg1,uchar rg2)//起始位,结束位,rgb1,2,3(初始化数组)
  24. {
  25. uchar i,j;
  26.         for(i=st;i<sp;i++)
  27.         {               
  28.                 for(j=0;j<3;j++)
  29.                 {
  30.                         switch(j)
  31.                         {
  32.                                 case 0:
  33.                         rgb[i][j]=rg0;
  34.                                 break;
  35.                                 case 1:
  36.                         rgb[i][j]=rg1;
  37.                                 break;
  38.                                 case 2:
  39.                         rgb[i][j]=rg2;
  40.                                 break;
  41.                         }
  42.                 }
  43.         }       
  44. }

  45. void display()     //刷新rebled输出函数
  46. {
  47. uchar i,j,k;
  48.         for(i=0;i<60;i++)
  49.         {
  50.                 for(j=0;j<3;j++)
  51.                 {
  52.                         sendrgb=rgb[i][j];
  53.                         for(k=0;k<8;k++)
  54.                         {
  55.                                 if(sendrgb&0x80)
  56.                                         st1();
  57.                                 else
  58.                                         st0();
  59.                                 sendrgb<<=1;
  60.                         }
  61.                 }
  62.         }
  63.         stop();
  64. }

  65. void main()
  66. {
  67. UartInit();//初始化串口
  68. initrgb(0,60,50,0,0);        //测试绿
  69. display();
  70. delayms(1000);
  71. initrgb(0,60,0,50,0);        //测试红
  72. display();
  73. delayms(1000);
  74. initrgb(0,60,0,0,50);        //测试蓝
  75. display();
  76. delayms(1000);
  77. initrgb(0,60,0,0,0);        //清屏
  78. display();
  79. delayms(1000);       
  80. EA = 1;   //开启中断,可接收数据
  81.        
  82.         while(1)
  83.                 {
  84.                 if(EA==0)//当中断关闭,表示一帧数据接收完毕
  85.                         {
  86.                                 display();//将当前数据刷新
  87.                                 EA=1;//开启中断,接收下一帧数据
  88.                         }
  89.                 }       
  90. }

  91. void Uart() interrupt 4   //串口中断
  92. {
  93.         uchar dat=0;
  94.     if (RI)
  95.     {
  96.                 dat=SBUF;
  97.         RI = 0;                 //清除RI位
  98.         if(dat==0x41&&in==0)
  99.                 {
  100.                         in=1;                                        //判断数据0位(A)
  101.                         SBUF=in;
  102.                         return;
  103.                 }
  104.                 if(dat==0x64&&in==1)                //判断数据1位(d)
  105.                 {
  106.                         in=2;
  107.                         SBUF=in;
  108.                         return;
  109.                 }
  110.                 else if(dat==0x61&&in==2)        //判断数据2位(a)
  111.                 {
  112.                         in=3;
  113.                         SBUF=in;
  114.                         return;
  115.                 }
  116.                 else if(in==3)                                //读取高位LED个数
  117.                 {
  118.                         h=dat;
  119.                         in++;
  120.                         return;
  121.                 }
  122.                 else if(in==4)                                //读取低位LED个数
  123.                 {
  124.                         l=dat;
  125.                         in++;
  126.                         return;
  127.                 }
  128.                 else if(in==5)                                //读取校验值
  129.                 {
  130.                         o=dat;
  131.                         if(o!=(h^l^0x55)) in=0;                //校验
  132.                         else in++;
  133.                         return;
  134.                 }
  135.                 else if(in>=6)                                //进入数据读取阶段
  136.                 {
  137.                         rgb[(in-6)/3][(in-6)%3]=dat;//将数据写入数组
  138.                         if((in-6)/3==l)                                //根据发来的led个数确定数据是否接收完毕
  139.                         {
  140.                                 in=0;
  141.                                 EA=0;
  142.                                 return;
  143.                         }
  144.                         else in++;
  145.                         return;
  146.                 }
  147.                         else                          //如果in小于6,且中途数据中断。则重新开始。
  148.                         {
  149.                                 in=0;
  150.                                 return;
  151.                         }
  152.         }
  153. }
复制代码

所有资料51hei提供下载:
流光溢彩.rar (35.49 KB, 下载次数: 34)

评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励!

查看全部评分

回复

使用道具 举报

ID:687694 发表于 2020-10-19 20:21 | 显示全部楼层
如果大家都想做一个玩玩,我就再出个详细的教程帖子。画好电路图,PCB。
回复

使用道具 举报

ID:820198 发表于 2021-4-12 10:52 | 显示全部楼层
不错啊,坐等详细教程
回复

使用道具 举报

ID:706724 发表于 2021-4-19 11:38 | 显示全部楼层
新手请教,程序中好像没有把中断的程序写出来?IN0=0;EA=1;.......直接实现用EA=1/0来实现总中断?
回复

使用道具 举报

ID:851858 发表于 2021-10-12 00:48 | 显示全部楼层
用89C52单片机烧上代码,P1.0接灯带数据端,不亮。
是89C52芯片不行,要stc15芯片? 还是要改代码的哪里?
换过Keil软件的器件为89C52,头文件试过stc15w.h和reg52.h。
不太懂望指教。
arduino点亮过
回复

使用道具 举报

ID:851858 发表于 2021-10-12 01:00 | 显示全部楼层
本帖最后由 ddwy43 于 2021-10-12 01:03 编辑

arduino的点亮过,灯带也就正常了
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表