激光投影POV(下)(2015-10-01)

文章字数限制,分成三篇:

激光投影POV(上)(2015-10-01)

激光投影POV(中)(2015-10-01)

激光投影POV(下)(2015-10-01)


程序源码

  • 完整代码下载:点击下载附件
  • 主程序展示(凑个字数哈)

      1 // ----------------------------------------------------------------------------
      2 // povLaser.ino
      3 //
      4 // Created 2015-08-26
      5 // By seesea <seesea2517#gmail#com>
      6 //
      7 // 激光POV
      8 //
      9 // - 由于需要用到外部中断,又想要端口整体操作,所以用了 mega2560
     10 // - A0 - A7 为 PORTK 端口,接到八个激光二极管正极,激光二极管负极接地(原用 pin22 - pin29 PORTA 端口,但焊接电路不方便就改 PORTK 了)
     11 // - pin21 为外部中断 2,作为 POV 起点的光敏电阻检测引脚
     12 // - pin20 为外部中断 3,作为 POV 终点的光敏电阻检测引脚
     13 // - 光敏电阻一端接 VCC,另一端通过 10K 的可变电阻接到 GND,相接处引出接到 pin20 和 pin21
     14 //   通过调整可变电阻达到调整检测灵敏度的目的,以便在不同的亮度的环境下使用
     15 // - pin3 输出 PWM 通过 PNP 三极管控制电机转动,通过调整 PWM 值控制电机以合适速度转动
     16 // - 电机控制一个镜子转动,镜子反射激光,达到偏转光线的作用
     17 //
     18 // 原打算在电机轴上使用光栅和红外对管来检测起止位置,后来发现镜子的转动造成光线 2 倍于镜子的转动角偏转,不好用
     19 // 所以给发射部分增加一个激光管做为光线位置指示,用光敏电阻来检测就完全吻合了
     20 //
     21 // ----------------------------------------------------------------------------
     22
     23 #include "asciiToDot.h"
     24 #include <avr/io.h>
     25
     26 #define PORT_LASER  PORTK                               // 控制八个激光二极管的端口寄存器
     27 #define DDR_LASER   DDRK                                // 控制八个激光二极管的端口方向寄存器
     28
     29 const char interruptNumStartSensor = 2;                 // 开始显示的光敏电阻的中断号
     30 const char interruptNumStopSensor  = 3;                 // 结束显示的光敏电阻的中断号
     31 volatile unsigned long ti          = 0;                 // 中断函数中用于记录时间的变量
     32 volatile unsigned long microDelay  = 0;                 // 扫描时激光二极管的点亮延时,在中断函数中更新值
     33 volatile bool flagDisplayOn        = false;             // 是否显示的标志,当开始光敏电阻检测到信号的时候置 true,结束光敏电阻检测到信号时置 false
     34
     35 const unsigned char pinPwmMotor    = 3;                 // 电机 pwm 控制引脚号
     36 const unsigned char pwmMotor       = 150;               // 电机 pwm 值
     37
     38 #define MAX_BUF_SIZE 50                                 // 串口接收最大字符数
     39 char bufStr[MAX_BUF_SIZE] = "seesea";                   // 默认显示字符
     40 byte *bufDot = stringToDot(bufStr);                     // 点阵缓冲区
     41 int  colNum  = strlen(bufStr) * asciiCharDotWidth;      // 点阵缓冲区大小
     42
     43 // 开始显示的中断处理函数
     44 void ISR_displayOn()
     45 {
     46     ti = millis();
     47     flagDisplayOn = true;
     48 }
     49
     50 // 结束显示的中断处理函数
     51 void ISR_displayOff()
     52 {
     53     microDelay = 1000 * (millis() - ti) / colNum;
     54     flagDisplayOn = false;
     55 }
     56
     57 void setup()
     58 {
     59     DDR_LASER = 0xFF;
     60
     61     pinMode(pinPwmMotor, OUTPUT);
     62     analogWrite(pinPwmMotor, pwmMotor);
     63
     64     attachInterrupt(interruptNumStartSensor, ISR_displayOn,  RISING);
     65     attachInterrupt(interruptNumStopSensor,  ISR_displayOff, RISING);
     66     interrupts();
     67
     68     Serial.begin(9600);
     69 }
     70
     71 void loop()
     72 {
     73     int i = 0;
     74
     75     if (! flagDisplayOn)
     76         return;
     77
     78     for (i = 0; i < colNum; ++i)
     79     {
     80         PORT_LASER = bufDot[i];
     81         delayMicroseconds(microDelay);
     82     }
     83 }
     84
     85 // 串口中断
     86 // 接收串口输入的字符串,更新显示缓冲区
     87 // 输入以 \n 为结束符,结束输入后更新点阵显示缓冲区从而更新显示内容
     88 // 注意:一次输入可能发生多次串口中断
     89 void serialEvent()
     90 {
     91     static int i = 0;
     92     while (Serial.available())
     93     {
     94         bufStr[i] = (char)Serial.read();
     95
     96         if (bufStr[i] == ‘\n‘)
     97         {
     98             bufStr[i] = ‘\0‘;
     99             delete [] bufDot;
    100             bufDot = stringToDot(bufStr);
    101             colNum = strlen(bufStr) * asciiCharDotWidth;
    102             i = 0;
    103             break;
    104         }
    105
    106         if (i >= MAX_BUF_SIZE)
    107             continue;
    108
    109         ++i;
    110     }
    111 }

软件字库的制作

  • 没有字库芯片,咱自力更生做软件字库
  • 制作步骤如下:
  1. 整理所需要的字符:整理了从空格到波浪号这一批常用ascii字符,它们的ascii码连续,方便编写程序
  2. 选择等宽字体,并且缩到最小显示效果也不错的字体,选择了“Courier New”字体,做成 8 个像素高的图片,可以发现每一个字符都是 7 个像素宽,这样就方便程序计算每一个字符的偏移量了
    其中有一些字符的位置需要手工调整:
    • g j p q y 上移两个像素
    • 所有的符号全体上移两个像素
    • j {} 还有微调(高度缩短了一个像素)
  3. 使用字模软件取模后,做成一个数组即可
  4. 编写函数根据输入的字符取得点阵信息
    根据每个字符宽 7 个像素,即在数组中占 7 个元素,首位是空格,ascii 值为 32,从而程序很容易计算任何一个字符的点阵数据在数组中的位置为: (字符的 ascii 值 - 空格的 ascii 值) * 7,连续 7 个元素
  5. 附上像素图(请准备好放大镜哦:D)

视频欣赏

时间: 2024-10-04 00:04:04

激光投影POV(下)(2015-10-01)的相关文章

HTML第一天学习笔记2015 10 01

如需在 HTML5 中显示视频,您所有需要的是: <video src="movie.ogg" controls="controls"> </video> <html> 与 </html> 之间的文本描述网页 <body> 与 </body> 之间的文本是可见的页面内容 <h1> 与 </h1> 之间的文本被显示为标题 <p> 与 </p> 之间的

激光投影POV(中)(2015-10-01)

Go将统治下一个10年?Go语言发展现状分析

"本文是国内Go语言大中华区首席布道师--许式伟,在QCon2015上海站上的分享.他预测Go语言10年内一定会超过C和java,并且统治这一个10年. Go语言语法及标准库变化 Go从1.0版本到现在(2015年)已经有三年多的时间,大的版本发布了五个,下面大家一起看看每个大版本分别都改了什么,当然这里不可能把所有的细节都提到,但我认为重要的会提出来. 首先是Go1.1,Go1.0于2012年4月发布,此后基本维持了每半年发布一个新版本的时间间隔.Go1.5比较例外,在Go1.5的拖累下,Go

第一金早评 - 2015年01月07日-晨早快訊

每日金市速遞 (2015年01月07日) 谢权东 先生 上日9999 金粒賣出價每両 HKD 12590 金粒賣出價資料參考周生生,周大福 即日投資策略: 黃金日線圖上分析,日線收3連陽,K線沿布林帶中軌和上軌之間運行,金價日內大漲,布林帶有向上開口跡象,布林中軌向上翹頭,短週期均線指標金叉向上,MACD快慢線死叉於0軸下方金叉,有上穿0軸趨勢,紅柱放量. 從4小時來看,布林帶向上開口,金價處於布林上軌1220與MA5-1215之間震盪往上,短週期均線指標金叉向上,MACD快慢線於0軸附近形成金

Clover KextsToPatch 使用方法 2015.10.21

Clover KextsToPatch 使用方法 2015.10.21 前些天,因为 Thinkpad X230 BIOS 白名单限制,给她换了一块 ar9285 无线网卡,只是因为这块网卡正好可以被 Mac OS X 驱动,也正好在 Thinkpad X230 BIOS 白名单之中.给 Clover 配置的时候,为了防止忘记,便记录下来. 因为灵活使用 Clover 成为黑苹果用户的必修课,否则你就只能漫天寻找 kext,寄希望与运气能正确驱动你的硬件了.Clover 中有一个强大的功能 Ke

4分钟apache自带ab压力测试工具使用: 2015.10.4

2015.10.44分钟apache自带ab压力测试工具使用:win8.1 wampserver2.5 -Apache-2.4.9-Mysql-5.6.17-php5.5.12-64b 可以参考一下部分讲解有图,我就是打开cmd窗口,进入apache的安装目录(ab一般是apache自带测试工具,所以然后就可以执行需要测试的命令就好了),我的在F:\wamp\bin\apach\apache2.4.9\bin目录下:两种执行方式,1.进入上面说的目录后执行以下命令,如 .\ab -n5000 -

[OpenStack 存储] 说说RAID0 1 2 3 4 5 6 10 01 30 50, 软RAID, 硬RAID

最近在思考一种廉价方便的cinder集成LVM driver的方式,那就是cinder+LVM+多块盘组成的RAID硬盘.这样的情况下就要根据读写需求和可用资源考虑采用什么样的RAID,以及怎样选择实现raid的方式,有两种分别为硬件RAID和软件RAID,为了温习一下,就顺便画些图(图中使用的硬盘数都是该RAID下需要的最少硬盘数)总结下各个RAID技术. 软RAID与硬RAID 硬RAID可以理解为需要RAID卡,通过RAID卡实现对多块盘的管理, 把多块盘组成RAID冗余阵列,如何组合成R

Delphi下OpenGL2d绘图(01)-初始化

一.前言: Delphi默认支持OpenGl,可以uses OpenGL单元进行引用,便可以使用OpenGL的函数.OpenGl是跨平台的,而且Windows很早就支持并集成在系统中,存在于system32中的opengl32.dll,不需要额外安装.虽然windows本身有d3d,但能力有限,还没去学习怎么用. 引用别人的话:OpenGL仅仅支持以下几种基本几何图形:点,线和多边形.没有表面或者更高级的图形(比如球状图形)能被作为基本图形元素绘制.但是它们能够用多边形完美的模仿出来.随意看看现

【网络】高性能网络编程--下一个10年,是时候考虑C10M并发问题了

转载:http://www.52im.net/thread-568-1-1.html 1.前言 在本系列文章的上篇中我们回顾了过云的10年里,高性能网络编程领域著名的C10K问题及其成功的解决方案(上篇请见:<高性能网络编程(二):上一个10年,著名的C10K并发连接问题>).本文将讨论单机服务器实现C10M(即单机千万并发连接)的可能性及其思路. 截至目前,40gpbs.32-cores.256G RAM的X86服务器在Newegg网站上的报价是几千美元.实际上以这样的硬件配置来看,它完全可