标题: 新年制作——激光投影POV [打印本页]
作者: 王朗的诱惑 时间: 2019-2-4 21:26
标题: 新年制作——激光投影POV
激光投影POV——不炫酷送黑币啊……

记得是2017年的一时兴起开了这个坑,当时做出来了显示效果,然后因为学习就一直搁置。过了2年又是我的一时兴起,这次总算是把它做完了。
这个制作用的材料:
1. 亚克力板
2. 亚克力镜子-没错,那个反光板是塑料的,买薄的,好加工而且非常轻
3. 笔芯-做支架用
4. CD机的光头-用了那个电机和塑料底座
5. 5V激光管
6. 单片机-STC15F2K16S2-直插28脚封装
7. 其他各种元器件-排针、三极管、电阻、电容、排线、洞洞板……
因为电路很简单,所以没画PCB,只有控制板的电路图,传感器就是红外对管,电机驱动就是一个NMOS加上一些滤波电路,后来还拆了个12V电机上的转速稳定电路装上了。
[电路图]单片机IO不是直接驱动激光管啊,都是有PNP三极管的!!这里偷懒没画……
工作原理:
电机带动反光镜(尽量)匀速旋转,红外对管检测镜面位置,检测到镜面位置给单片机外部中断信号,单片机开始计时。这个时间结束的时候就是镜面转到开始显示的位置,这时开始点亮激光管,从这里开始原理就和摇摇棒一样了。
还有个有意思的创新,这回我用上位机串口通信,直接传送点阵数据过来显示,这样就相当于用电脑上面的字库,解决了汉字字库的问题,只要上位机文本框里能显示,单片机就能把它投影出来。不过现在16个点还是有点捉鸡,大的东西显示不了……
[上位机界面]
程序结构:
占用资源:
外部中断0 红外对管
定时器0 反光镜旋转一圈计时
定时器1 激光点亮延时
定时器2 波特率发生器
串口1
CCP0 电机PWM
CCP1 串口接收定时器-用于判定数据帧
上位机用C#写的,VS2012编译,Debug模式。代码很简单,而且都是一些事件的触发,所以没写结构出来,直接看代码就可以,有注释很容易理解。
注意事项:
1. 单片机工作频率为27MHz 串口通信波特率默认9600 。基本参数的设置在各个头文件中。
2. 串口优先级已经调整为最高。
……剩下的想不起来了……等想起来再加吧……
最后……给自己发个广告:我的微博最近很冷清呀,欢迎捧场~ (其实我从没在上面发过电子相关的东西……

……)
作者: admin 时间: 2019-2-5 01:29
楼主的主程序如下:
- #include <STC15.h>
- #include <intrins.h>
- #include "main.h"
- #include "Uart.h"
- #include "U8_PWM.h"
- #include "display.h"
- #include "eeprom.h"
- typedef union
- {
- u8 time8[2];
- u16 time16;
- }TIME;
- volatile TIME t_speed; //记录定时器值
- volatile u16 speed; //反光镜转速 (调试用数据)
- volatile char t_count=0;//,d_count=0; //转速, 显示 定时器溢出计数
- volatile u16 d_time = 25000; //点亮激光延时 初始化值用于第一次写EEPROM
- u8 speed_pwm = 80; //反光镜转速 用于控制PWM占空比 初始化值用于第一次写EEPROM
- void delay_ms(unsigned char ms)
- {
- unsigned int i;
- do{
- i = MAIN_Fosc / 13000;
- while(--i) ;
- }while(--ms);
- }
- void Int0_Init(void)
- {
- // EA = 1;
- IT0 = 1;
- EX0 = 1;
- }
- void Timer0_Init(void) //计算转速作为延时参考
- {
- TMOD |= 0x01;
- TL0 = (65536-1000)%256;
- TH0 = (65536-1000) >> 8;
- // EA = 1;
- ET0 = 1;
- // TR0 = 1;
- }
- void Timer1_Init(void) //外部中断后点亮激光延时
- {
- TMOD |= 0x10;
- TL1 = (65536-1000)%256;
- TH1 = (65536-1000) >> 8;
- // EA = 1;
- ET1 = 1;
- // TR1 = 1;
- }
- u8 Verify_Sum(u8 *DataInput, u16 len)//累加校验计算
- {
- u8 sum=0;
- u16 i;
- for(i=0; i<len; i++) //数据累加
- sum += DataInput[i];
- return sum;
- }
- //整帧串口数据保存在UartRecvBuf[UARTRECVBUFSIZE]中
- //建议复制出来数据使用 防止处理过程中进串口接收中断丢失原始数据
- void UartDataRecv_Event(void)
- {
- u8 i,j;
- u16 Length;
- xdata u8 datBuf[UARTRECVBUFSIZE]; //临时数据存储
- xdata typePackage recvPackage; //接收数据包结构体
- code s8 AckBuf[] = {0x01, 0x10, 0x00, 0x00, 0x00, 0x00}; //Ack数据包
- s8 DatBuf[10] = {0x01, 0x03, 0x00, 0x00, 0x04}; //还有5个数据在下面赋值
-
- // Uart_SendByte(UartBytesToRead);
- // Uart_SendByte(0x49);
- for(Length=0; Length<UartBytesToRead; Length++) //复制数据
- {
- datBuf[Length] = UartRecvBuf[Length];
- }
-
- if(datBuf[0] != 0x01) return;
- Length = 6 + (u16)(datBuf[3]<<8 | datBuf[4]); //计算数据总长度
- if(Length != UartBytesToRead) //长度不对放弃数据
- {
- return;
- }
- //装载数据
- recvPackage.DeviceAddr = datBuf[0];
- recvPackage.Function = datBuf[1];
- recvPackage.Sequence = datBuf[2];
- recvPackage.DataLength = (u16)(datBuf[3]<<8 | datBuf[4]);
- recvPackage.Data = &datBuf[5];
- recvPackage.Sum = datBuf[5 + recvPackage.DataLength];
- if(recvPackage.Sum != Verify_Sum(recvPackage.Data, recvPackage.DataLength)) //数据校验
- return;
- //SendAck
- Uart_SendBuf(AckBuf, CountOfArray(AckBuf));
-
- // Uart_SendByte(recvPackage.Function);
- switch(recvPackage.Function) //帧功能判断
- {
- case 0x01:
- //Dis_WriteBuf("DataReceived!");
- for(i=0; i<STRINGLEN; i++) //写显存
- for(j=0; j<16; j++)
- DisBuf[i][j] = recvPackage.Data[j + i*16];
- break;
- case 0x02: //从机接收数据
- Dis_WriteBuf("Recv-Func-0x02");
- if(speed_pwm != recvPackage.Data[1])
- {
- speed_pwm = recvPackage.Data[1];
- Load_U8_PWM(speed_pwm); //转速
- IapEraseSector(IAP_ADDRESS_SPEED); //EEPROM存储数据
- IapProgramByte(IAP_ADDRESS_SPEED, speed_pwm);
- }
- if(d_time != (u16)(recvPackage.Data[2]<<8 | recvPackage.Data[3])) //点亮延时
- {
- d_time = (u16)(recvPackage.Data[2]<<8 | recvPackage.Data[3]);
- IapEraseSector(IAP_ADDRESS_DELAY); //EEPROM存储数据
- IapProgramByte(IAP_ADDRESS_DELAY, recvPackage.Data[2]);
- IapProgramByte(IAP_ADDRESS_DELAY+1, recvPackage.Data[3]);
- }
- // Uart_SendByte(0x33);
- break;
- case 0x03: //主机请求数据
- Dis_WriteBuf("Recv-Func-0x03");
- delay_ms(15); //隔断Ack和Dat两个数据包 避免上位机混淆
- DatBuf[5] = 0x00; //装载数据
- DatBuf[6] = speed_pwm;
- DatBuf[7] = (u8)(d_time>>8);
- DatBuf[8] = (u8)d_time;
- DatBuf[9] = Verify_Sum(&DatBuf[5], 4);
- Uart_SendBuf(DatBuf, CountOfArray(DatBuf));
- // Uart_SendByte(0x49);
- break;
- default: //未知功能帧
- return;
- }
- }
- void main(void)
- {
- u8 i;
-
- P1M0 = 0x00;
- P1M1 = 0x00;
- P2M0 = 0x00;
- P2M1 = 0x00;
- // UartFuncPtr = UartDataRecv_Event; //注册串口数据处理函数
-
- EA = 1;
-
- //第一次写EEPROM时使用此代码
- // IapEraseSector(IAP_ADDRESS_SPEED); //EEPROM存储数据
- // IapProgramByte(IAP_ADDRESS_SPEED, speed_pwm);
- // IapEraseSector(IAP_ADDRESS_DELAY); //EEPROM存储数据
- // IapProgramByte(IAP_ADDRESS_DELAY, d_time>>8);
- // IapProgramByte(IAP_ADDRESS_DELAY+1, d_time);
- speed_pwm = IapReadByte(IAP_ADDRESS_SPEED); //EEPROM数据读取
- d_time = (u16)(IapReadByte(IAP_ADDRESS_DELAY)<<8 | IapReadByte(IAP_ADDRESS_DELAY+1));
-
- U8_PWM_Init();
- for(i=5; i<=speed_pwm; i++) //电机加速
- {
- delay_ms(5);
- Load_U8_PWM(i);
- }
- // Load_U8_PWM(0);
- delay_ms(200); //等待转速稳定
-
- Int0_Init();
- Timer0_Init(); //计算转速作为延时参考
- Timer1_Init(); //外部中断后点亮激光延时
- Uart_Init();
- delay_ms(50);
- Uart_SendByte(0x98); //发送复位标识
- Dis_WriteBuf("蘑菇~"); //开机默认字幕
- WDT_CONTR = 0x07;
- WDT_CONTR |= 0x20; //EN_WDT
- while(1)
- {
- WDT_CONTR |= 0x10; //CLR_WDT
- if(DataProcFlag)
- {
- DataProcFlag = 0;
- //不知道为什么 调整串口优先级最高以后还是需要关闭外部中断
- EX0 = 0; //处理时间很长 关闭外部中断 不然会死机
- TR0 = 0;
- TR1 = 0;
- UartDataRecv_Event();
- EX0 = 1;
- TR0 = 1;
- TR1 = 1;
- }
- // delay_ms(200);
- // P40 = ~P40;
- // Uart_SendByte(0x49);
- }
- }
- void Int_Int0(void) interrupt 0
- {
- static char trig = 0;
- if(trig) //镜面不绝对对称 只使用其中一面
- {
- t_speed.time8[1] = TL0; //读取当前定时器值作为速度
- t_speed.time8[0] = TH0;
- TL0 = 0; //定时器重装
- TH0 = 0;
- TR0 = 1;
- speed = t_speed.time16;// + t_count*65536; //计算速度
- t_count = 0; //定时器溢出计数清零
- // d_time = 34000; //点亮激光延时
- TL1 = (65536-d_time)%256;
- TH1 = (65536-d_time) >> 8;
- TR1 = 1;
- }
- trig = ~trig;
- }
- void Int_Timer0(void) interrupt 1 //计算转速作为延时参考
- {
- t_count++; //定时器溢出计数
- }
- void Int_Timer1(void) interrupt 3 //外部中断后点亮激光延时
- {
- TR1 = 0; //停止计时
- EX0 = 0;
- // Display(0xFF, 0xFF);
- // Dis_WriteBuf("2019新年快乐!!!~");
- Dis_String();
- EX0 = 1;
- }
复制代码
作者: starwaver 时间: 2019-2-5 14:04
不错,很好,精彩。
作者: Tiansu_cxs 时间: 2019-2-8 17:40
感谢分享!
作者: Arvin0011 时间: 2019-2-15 17:16
东西感觉不错,不过我想说你真的很皮
作者: qzyhlf 时间: 2019-2-16 17:01
感谢分享!
作者: 王朗的诱惑 时间: 2019-2-17 09:35
Arvin0011 发表于 2019-2-15 17:16
东西感觉不错,不过我想说你真的很皮
啊哈哈哈哈哈哈~~~
作者: 快乐眼泪 时间: 2019-2-20 21:26
感谢楼主分享!
作者: 快乐眼泪 时间: 2019-2-20 21:31
只有反光镜旋转吗
作者: 王朗的诱惑 时间: 2019-2-21 11:20
对,能动的只有反光镜,光源不动。
作者: 864168613 时间: 2019-3-1 20:56
Rebuild target 'Target 1'
compiling main.c...
D:\Keil_v5\C51\Inc\STC\STC15.h(16): error C231: 'ACC': redefinition
D:\Keil_v5\C51\Inc\STC\STC15.h(17): error C231: 'B': redefinition
D:\Keil_v5\C51\Inc\STC\STC15.h(18): error C231: 'PSW': redefinition
D:\Keil_v5\C51\Inc\STC\STC15.h(19): error C231: 'CY': redefinition
D:\Keil_v5\C51\Inc\STC\STC15.h(20): error C231: 'AC': redefinition
D:\Keil_v5\C51\Inc\STC\STC15.h(21): error C231: 'F0': redefinition
D:\Keil_v5\C51\Inc\STC\STC15.h(22): error C231: 'RS1': redefinition
D:\Keil_v5\C51\Inc\STC\STC15.h(23): error C231: 'RS0': redefinition
D:\Keil_v5\C51\Inc\STC\STC15.h(24): error C231: 'OV': redefinition
D:\Keil_v5\C51\Inc\STC\STC15.h(25): error C231: 'P': redefinition
D:\Keil_v5\C51\Inc\STC\STC15.h(26): error C231: 'SP': redefinition
D:\Keil_v5\C51\Inc\STC\STC15.h(27): error C231: 'DPL': redefinition
D:\Keil_v5\C51\Inc\STC\STC15.h(28): error C231: 'DPH': redefinition
D:\Keil_v5\C51\Inc\STC\STC15.h(31): error C231: 'P0': redefinition
D:\Keil_v5\C51\Inc\STC\STC15.h(40): error C231: 'P1': redefinition
D:\Keil_v5\C51\Inc\STC\STC15.h(49): error C231: 'P2': redefinition
D:\Keil_v5\C51\Inc\STC\STC15.h(58): error C231: 'P3': redefinition
D:\Keil_v5\C51\Inc\STC\STC15.h(121): error C231: 'PCON': redefinition
D:\Keil_v5\C51\Inc\STC\STC15.h(131): error C231: 'IE': redefinition
D:\Keil_v5\C51\Inc\STC\STC15.h(132): error C231: 'EA': redefinition
D:\Keil_v5\C51\Inc\STC\STC15.h(135): error C231: 'ES': redefinition
D:\Keil_v5\C51\Inc\STC\STC15.h(136): error C231: 'ET1': redefinition
D:\Keil_v5\C51\Inc\STC\STC15.h(137): error C231: 'EX1': redefinition
D:\Keil_v5\C51\Inc\STC\STC15.h(138): error C231: 'ET0': redefinition
D:\Keil_v5\C51\Inc\STC\STC15.h(139): error C231: 'EX0': redefinition
D:\Keil_v5\C51\Inc\STC\STC15.h(140): error C231: 'IP': redefinition
D:\Keil_v5\C51\Inc\STC\STC15.h(144): error C231: 'PS': redefinition
D:\Keil_v5\C51\Inc\STC\STC15.h(145): error C231: 'PT1': redefinition
D:\Keil_v5\C51\Inc\STC\STC15.h(146): error C231: 'PX1': redefinition
D:\Keil_v5\C51\Inc\STC\STC15.h(147): error C231: 'PT0': redefinition
D:\Keil_v5\C51\Inc\STC\STC15.h(148): error C231: 'PX0': redefinition
D:\Keil_v5\C51\Inc\STC\STC15.h(154): error C231: 'TCON': redefinition
D:\Keil_v5\C51\Inc\STC\STC15.h(155): error C231: 'TF1': redefinition
D:\Keil_v5\C51\Inc\STC\STC15.h(156): error C231: 'TR1': redefinition
D:\Keil_v5\C51\Inc\STC\STC15.h(157): error C231: 'TF0': redefinition
D:\Keil_v5\C51\Inc\STC\STC15.h(158): error C231: 'TR0': redefinition
D:\Keil_v5\C51\Inc\STC\STC15.h(159): error C231: 'IE1': redefinition
D:\Keil_v5\C51\Inc\STC\STC15.h(160): error C231: 'IT1': redefinition
D:\Keil_v5\C51\Inc\STC\STC15.h(161): error C231: 'IE0': redefinition
D:\Keil_v5\C51\Inc\STC\STC15.h(162): error C231: 'IT0': redefinition
D:\Keil_v5\C51\Inc\STC\STC15.h(163): error C231: 'TMOD': redefinition
D:\Keil_v5\C51\Inc\STC\STC15.h(164): error C231: 'TL0': redefinition
D:\Keil_v5\C51\Inc\STC\STC15.h(165): error C231: 'TL1': redefinition
D:\Keil_v5\C51\Inc\STC\STC15.h(166): error C231: 'TH0': redefinition
D:\Keil_v5\C51\Inc\STC\STC15.h(167): error C231: 'TH1': redefinition
D:\Keil_v5\C51\Inc\STC\STC15.h(181): error C231: 'SCON': redefinition
D:\Keil_v5\C51\Inc\STC\STC15.h(182): error C231: 'SM0': redefinition
D:\Keil_v5\C51\Inc\STC\STC15.h(183): error C231: 'SM1': redefinition
D:\Keil_v5\C51\Inc\STC\STC15.h(184): error C231: 'SM2': redefinition
D:\Keil_v5\C51\Inc\STC\STC15.h(185): error C231: 'REN': redefinition
D:\Keil_v5\C51\Inc\STC\STC15.h(186): error C231: 'TB8': redefinition
D:\Keil_v5\C51\Inc\STC\STC15.h(187): error C231: 'RB8': redefinition
D:\Keil_v5\C51\Inc\STC\STC15.h(188): error C231: 'TI': redefinition
D:\Keil_v5\C51\Inc\STC\STC15.h(189): error C231: 'RI': redefinition
D:\Keil_v5\C51\Inc\STC\STC15.h(190): error C231: 'SBUF': redefinition
compiling U8_PWM.c...
compiling display.c...
compiling Uart.c...
compiling eeprom.c...
Target not created.
Build Time Elapsed: 00:00:00
一运行就错误
作者: 王朗的诱惑 时间: 2019-3-2 10:22
看样子是头文件重复的问题,可是我这没出问题诶……顺便上传下我用的STC15.H头文件……
-
QQ截图20190302101635.jpg
(33.09 KB, 下载次数: 128)
-
-
STC15Header.zip
2.84 KB, 下载次数: 12, 下载积分: 黑币 -5
STC15.H头文件
作者: 864168613 时间: 2019-3-2 13:06
能不能吧电路图画玩
作者: 565929732 时间: 2019-8-4 09:05
可以的
作者: youlianning 时间: 2019-8-4 10:20
还是有点不太理解原理呀,反光镜是如何做到将激光反射到正前方的墙上的呢?还是说是反射到激光背后的墙上。但如果是背后的墙,则必有一条竖线无法显示。若正前方的墙,则无法理解光路。才疏学浅,请不吝赐教
作者: 王朗的诱惑 时间: 2019-8-11 22:45
60度左右吧,不是正前,也不是正后。这个东西不能360度全显示的,确实会被挡住一部分竖线。
作者: liuhiong 时间: 2019-8-24 21:54
很好,有创新精神致得我好好学习。只是看不懂程序没办法。如果图片能长期显示和不间断更换图片(就是说当第一张图片转换到第二图片时,中间没有停止间隔),就更完美了。
作者: liuhiong 时间: 2019-8-24 22:08
镜子与激光不能在垂直线上,而是在上下直线上有一定的角度,而不是左右角度。横向直线的长短是由镜面的宽度决定的,而不是镜面的长度来决定的。
作者: 王朗的诱惑 时间: 2019-9-4 15:32
点阵数据是电脑通过串口传到单片机上的,传输速度不够,如果换用速度更快的通信方式或许可以做到。
作者: dj3365191 时间: 2020-8-29 12:23
楼主你好,你说检测镜面旋转速度的是红外对管,分别是什么型号的?你的原理图画的P3和P4是接对管的吧,请问怎样连接,我想既然是红外对管每管应该只有两个管脚,不知怎样与你图上的P3和P4对接呢?谢谢!
作者: 梁廷明 时间: 2020-8-31 17:29
上位机那个就是优秀
作者: 王朗的诱惑 时间: 2020-9-1 00:15
P3 接电机,P3 输出 PWM 方波,连电机驱动,这里其实就是一个 MOS 管;
P4 接对管,型号就是常见的 TCRT5000,类似的就行,原理都是一样的。红外对管电路可以参考 http://www.elecfans.com/d/1063734.html ,也是类似的都可以,输出方波到 P4 。
至于电路图……因为这个电路用洞洞板做的,所以我是先在纸上设计好,最后才补画的电路图,当时偷懒了,而且水平一般,画的也不规范,还省略了好多细节,还多包涵吧……
作者: 王朗的诱惑 时间: 2020-9-1 00:16
微博里乱七八糟东西一堆,用户体验极差,已弃用,请大家自动忽略……
作者: dj3365191 时间: 2020-9-2 12:13
感谢楼主的回复,明白了。
作者: zhuyaying 时间: 2021-2-25 22:41
楼主你的上位机代码可以发出来参考下吗
作者: 王朗的诱惑 时间: 2021-2-27 14:15
附件里有的
作者: hefq 时间: 2021-2-27 20:19
牛逼啊,大神,看到别人做的是有两个旋转的镜子啊,只有一个激光,
τ 宝上有一体的振镜模组,能在墙上扫出动画
作者: 王朗的诱惑 时间: 2021-2-28 01:09
害,过奖了,我这就是经费有限,只能被迫搞出来一个手工原型……我还是很向往那种高精度的更炫酷的产品的。如果网友想仿制,我强烈推荐3D打印之类的框架,难度会低很多。
另:两个旋转镜子的作品有链接吗?表示好奇
作者: exlies 时间: 2021-2-28 01:34
只有反光镜旋转吗
作者: hefq 时间: 2021-2-28 10:37
在τ 宝搜振镜
我搜到这个,只要一百多还有驱动,我没买啊,不知道能不能用,这个是简易的,贵的很贵
作者: hefq 时间: 2021-2-28 10:37
王朗的诱惑 发表于 2021-2-28 01:09
害,过奖了,我这就是经费有限,只能被迫搞出来一个手工原型……我还是很向往那种高精度的更炫酷的产品的 ...
https://item点taobao点com/item.htm?id=551252442809
刚才忘记链接了(自行替换.)
作者: 王朗的诱惑 时间: 2021-2-28 12:21
是的
欢迎光临 (http://www.51hei.com/bbs/) |
Powered by Discuz! X3.1 |