本帖最后由 云天 于 2022-2-13 09:49 编辑
之前的一个项目,当时没有做成功。用 FireBeetle BLE4.1 低功耗蓝牙控制器 、霍尔传感器、电机和一排 LED 制作的视觉暂留POV显示器。什么是POV?
人眼在观察景物时,光信号传入大脑神经,需经过一段短暂的时间,光的作用结束后,视觉形象并不立即消失,这种残留的视觉称“后像”,也被称为是“视觉暂留”。 人眼每秒处理的图像不超过 10-12 个。当一系列图像很快的连续性的滚动时,就会让我们产生幻觉,感觉画面在动。这也是制作动画电影的基本原则。 项目制作过程:
【电机】
电机是从旧录音机上拆下来的,应该是用来转动磁带的。
根据上面的标识可知:
电机额定电压9V,转速2400rpm,逆时针方向旋转(CCW),可通过改变通电正负极,改变旋转方向。
【控制电机】
利用Arduino+编码器+L289N电机驱动板来控制电机转速。
编码器接在A0引脚,4,5号引脚接LED89N电机驱动板逻辑输入引脚,3号引脚接LED89N电机驱动板通道A使能引脚。
【POV控制器】
FireBeetle BLE4.1 低功耗蓝牙控制器 (Arduino Pro Mini 3.3V),支持锂电池接口:3.7 V锂电池。
D2——D9引脚接LED灯。
【霍尔传感器】
霍尔传感器接FireBeetle控制器的D10引脚。
调整好霍尔传感与磁铁的高度。
【安装 LED】
1、剪取一块洞洞板
2、安装 LED 灯,我使用八个白色的 LED 灯。
3、将所有 LED 灯的负极端口都焊接到洞洞板上。
4、添加电阻,防止 LED 灯因电压过高而烧坏。我使用 220ohm 的电阻,将每个电阻焊接到每个 LED 灯的正极。
5、将跳线电缆连接到电阻的另一个脚上。
电阻常识:
五色环电阻
五个色环电阻的识别:第一、二、三环分别代表三位有效数的阻值;第四环代表倍率;第五环代表误差。 如果第五条色环为黑色,一般用来表示为绕线电阻器,第五条色环如为白色,一般用来表示为保险丝电阻器。如果电阻体只有中间一条黑色的色环,则代表此电阻为零欧姆电阻。
例:红 红 黑 棕 金
其电阻为 220×10^1=2.2KΩ 误差为±5%
第一色环是百位数,第二色环是十位数,
第三色环是个位数,第四色环是应乘颜色次幂,
第五色环是误差率。
首先,从电阻的底端,找出代表公差精度的色环,金色的代表5%,银色的代表10%。上例中,最末端色环为金色,故误差率为5%。再从电阻的另一端,找出第一条、第二条色环,读取其相对应的数字,上例中,前三条色环都为红红黑,故其对应数字为红2、红2、黑0,其有效数是220。再读取第四条倍数色环,棕1。所以,我们得到的阻值是220×10^1=2.2KΩ。即阻值在2090-2310之间都是好的电阻。 如果第四条倍数色环为金色,则将有效数乘以0.1。如果第四条倍数色环为银色,则乘以0.01。
【测试程序】
程序代码中进行了详细注释
显示“HELLO WORLD”
-
- int asc;
- int letterSpace;
- int delayTime;
-
- void setup() {
- // initialize digital pin output.
- Serial.begin(9600);
- for(unsigned char i=2;i<10;i++){//定义2-9号,共8个引脚为输出
- pinMode(i, OUTPUT);
- }
- pinMode(10, INPUT);//10号引脚为输入,接霍尔传感器
- for(unsigned char i=2;i<10;i++){//初始化8个引脚为低电平
- digitalWrite(LED_BUILTIN, LOW);
- }
- asc=toascii('A');//获取大写字母A的Ascci值
- letterSpace=4;//定义字母之间的间距(毫秒)
- delayTime=500;//定义点出现的时间(微秒)
- }
- //字母十六进制点阵数组
- int Mychar[26][8]={
- {0xff,0xe7,0xe7,0xdb,0x81,0xbd,0x7e,0xff},//A
- {0xff,0xc1,0xbd,0xc1,0xbd,0x7d,0x81,0xff},//B
- {0xff,0xc3,0xbd,0xfd,0xfd,0x79,0x83,0xff},//C
- {0xff,0xc1,0x9d,0xbd,0xbd,0x9d,0xc1,0xff},//D
- {0xff,0x81,0xfd,0x81,0xfd,0xfd,0x81,0xff},//E
- {0xff,0x81,0xfd,0x81,0xfd,0xfd,0xfd,0xff},//F
- {0xff,0xc3,0xb9,0xfd,0x8d,0xb9,0x83,0xff},//G
- {0xff,0xbd,0xbd,0x81,0xbd,0xbd,0xbd,0xff},//H
- {0xff,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xff},//I
- {0xff,0xbf,0xbf,0xbf,0xbf,0xbd,0xc3,0xff},//J
- {0xff,0x9d,0xed,0xf5,0xe9,0xdd,0xbd,0xff},//k
- {0xff,0xfd,0xfd,0xfd,0xfd,0xfd,0x81,0xff},//L
- {0xff,0x99,0x99,0x99,0xa5,0xa5,0xa5,0xff},//M
- {0xff,0xb9,0xb9,0xb5,0xad,0x9d,0x9d,0xff},//N
- {0xff,0xc3,0x99,0xbd,0xbd,0x99,0xc3,0xff},//O
- {0xff,0xc1,0xbd,0xbd,0xc1,0xfd,0xfd,0xff},//P
- {0xff,0xc3,0x99,0xbd,0xbd,0xa9,0xc3,0xbf},//Q
- {0xff,0xc1,0xbd,0x81,0xbd,0xbd,0xbd,0xff},//R
- {0xff,0xc3,0xbd,0xc3,0x3f,0x7d,0x83,0xff},//S
- {0xff,0x80,0xf7,0xf7,0xf7,0xf7,0xf7,0xff},//T
- {0xff,0xbd,0xbd,0xbd,0xbd,0xbd,0xc3,0xff},//U
- {0xff,0x7e,0xbd,0xdd,0xdb,0xe3,0xf7,0xff},//V
- {0xff,0xff,0xff,0x66,0xa6,0x99,0x99,0xff},//W
- {0xff,0xdd,0xeb,0xf7,0xe3,0xd9,0xbc,0xff},//X
- {0xff,0xbc,0xd9,0xe3,0xf7,0xf7,0xf7,0xff},//Y
- {0xff,0x80,0xdf,0xe7,0xfb,0xfd,0x80,0xff} //Z
- };
- int pinState=0;
- void printLetter(String s){//显示字符串函数
-
- for(int m=0;m<s.length();m++){
- char s1=s.charAt(m); //取字符
- int xh=toascii(s1)-asc;//与字符'A'的Ascii码取差,获取在数组中的位置
-
- for(int k=0;k<8;k++){//8*8点阵
- for(int b=0;b<8;b++){
- pinState=!bitRead(Mychar[xh][k],b);//读取指定位的数据,因点阵码为暗码,读出的位要取反。
- digitalWrite(b+2, pinState); //按读取的位值点亮或熄灭对应的LED
- }
- delayMicroseconds(delayTime);//点间隔时间
- }
- delay(letterSpace);//字母间隔时间
- }
- }
-
- void loop() {
- boolean d=digitalRead(10);//获取霍尔传感器状态
-
- if(!d){//有磁时,为低电平
- printLetter("HELLOWORLD");
-
- }
-
-
- }
复制代码
【App Inventor2与FireBeetle BLE4.1低功耗蓝牙连接】
为获取POV旋转一周所需时间,花了一天时间,搞定了“App Inventor2与FireBeetle BLE4.1低功耗蓝牙连接”。
1、使用APP Inventor2 WxBit中自带的“低功耗蓝牙模块”。
2、获取蓝牙地址
扫描蓝牙设备,获取蓝牙地址
名称为:Bluno2
3、获取监听服务及特征UUID
UUID是“Universally Unique Identifier”的简称,通用唯一识别码的意思。对于蓝牙设备,每个服务都有通用、独立、唯一的UUID与之对应。也就是说,在同一时间、同一地点,不可能有两个相同的UUID标识的不同服务。
服务UUID有四个,FireBeetle BLE4.1低功耗蓝牙,监听服务使用“dfb0”。
特征UUID有16个,与服务“dfb0”对应的有3个,第一个为监听特征UUID(所有中第14个)。
收到信息后,在调试窗口显示。
4、FireBeetle BLE4.1低功耗蓝牙测试程序
Serial.begin(115200); 波特率一定要使用115200,我试了9600,APP Inventor2接收不到信息。
- char num_str[25];
- void setup() {
-
- Serial.begin(115200); //initial the Serial
- }
-
- void loop(){
-
- //if(Serial.available()){
- //Serial.write(Serial.read()); //send what has been received
- //Serial.println(); //print line feed character
- //}
- itoa(564,num_str,10);
- Serial.write(num_str);
-
- delay(2000);
- }
复制代码
【获取旋转一周时间】
当前程序使用micros();获取系统运行时间,为微秒,如电机旋转过慢,时间数据可能会溢出。后期改成millis();为毫秒。
-
- int asc;
- int letterSpace;
- int delayTime;
- char num_str[25];//保存转换后时间差的数字字符串
- int time_pre=0;
- void setup() {
- // initialize digital pin output.
- Serial.begin(115200);
- for(unsigned char i=2;i<10;i++){//定义2-9号,共8个引脚为输出
- pinMode(i, OUTPUT);
- }
- pinMode(10, INPUT);//10号引脚为输入,接霍尔传感器
- for(unsigned char i=2;i<10;i++){//初始化8个引脚为低电平
- digitalWrite(LED_BUILTIN, LOW);
- }
- asc=toascii('A');//获取大写字母A的Ascci值
- letterSpace=4;//定义字母之间的间距(毫秒)
- delayTime=500;//定义点出现的时间(微秒)
- time_pre=micros();
- }
- //字母十六进制点阵数组
- int Mychar[26][8]={
- {0xff,0xe7,0xe7,0xdb,0x81,0xbd,0x7e,0xff},//A
- {0xff,0xc1,0xbd,0xc1,0xbd,0x7d,0x81,0xff},//B
- {0xff,0xc3,0xbd,0xfd,0xfd,0x79,0x83,0xff},//C
- {0xff,0xc1,0x9d,0xbd,0xbd,0x9d,0xc1,0xff},//D
- {0xff,0x81,0xfd,0x81,0xfd,0xfd,0x81,0xff},//E
- {0xff,0x81,0xfd,0x81,0xfd,0xfd,0xfd,0xff},//F
- {0xff,0xc3,0xb9,0xfd,0x8d,0xb9,0x83,0xff},//G
- {0xff,0xbd,0xbd,0x81,0xbd,0xbd,0xbd,0xff},//H
- {0xff,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xff},//I
- {0xff,0xbf,0xbf,0xbf,0xbf,0xbd,0xc3,0xff},//J
- {0xff,0x9d,0xed,0xf5,0xe9,0xdd,0xbd,0xff},//k
- {0xff,0xfd,0xfd,0xfd,0xfd,0xfd,0x81,0xff},//L
- {0xff,0x99,0x99,0x99,0xa5,0xa5,0xa5,0xff},//M
- {0xff,0xb9,0xb9,0xb5,0xad,0x9d,0x9d,0xff},//N
- {0xff,0xc3,0x99,0xbd,0xbd,0x99,0xc3,0xff},//O
- {0xff,0xc1,0xbd,0xbd,0xc1,0xfd,0xfd,0xff},//P
- {0xff,0xc3,0x99,0xbd,0xbd,0xa9,0xc3,0xbf},//Q
- {0xff,0xc1,0xbd,0x81,0xbd,0xbd,0xbd,0xff},//R
- {0xff,0xc3,0xbd,0xc3,0x3f,0x7d,0x83,0xff},//S
- {0xff,0x80,0xf7,0xf7,0xf7,0xf7,0xf7,0xff},//T
- {0xff,0xbd,0xbd,0xbd,0xbd,0xbd,0xc3,0xff},//U
- {0xff,0x7e,0xbd,0xdd,0xdb,0xe3,0xf7,0xff},//V
- {0xff,0xff,0xff,0x66,0xa6,0x99,0x99,0xff},//W
- {0xff,0xdd,0xeb,0xf7,0xe3,0xd9,0xbc,0xff},//X
- {0xff,0xbc,0xd9,0xe3,0xf7,0xf7,0xf7,0xff},//Y
- {0xff,0x80,0xdf,0xe7,0xfb,0xfd,0x80,0xff} //Z
- };
- int pinState=0;
- void printLetter(String s){//显示字符串函数
-
- for(int m=0;m<s.length();m++){
- char s1=s.charAt(m); //取字符
- int xh=toascii(s1)-asc;//与字符'A'的Ascii码取差,获取在数组中的位置
-
- for(int k=0;k<8;k++){//8*8点阵
- for(int b=0;b<8;b++){
- pinState=!bitRead(Mychar[xh][k],b);//读取指定位的数据,因点阵码为暗码,读出的位要取反。
- digitalWrite(b+2, pinState); //按读取的位值点亮或熄灭对应的LED
- }
- delayMicroseconds(delayTime);//点间隔时间
- }
- delay(letterSpace);//字母间隔时间
- }
- }
-
- void loop() {
- boolean d=digitalRead(10);//获取霍尔传感器状态
-
- if(!d){//有磁时,为低电平
- itoa(micros()-time_pre,num_str,10);
- time_pre=micros();
- Serial.write(num_str);
- printLetter("HELLOWORLD");
-
- }
-
-
- }
复制代码
【发送显示内容】
通过APP发送显示内容
- String show_str;
- String comdata;
复制代码
- void loop() {
- boolean d=digitalRead(10);//获取霍尔传感器状态
- while(Serial.available()>0)
- {
- comdata+=char(Serial.read());
- delay(2);
- }
- if(comdata.length()>0)
- {
- show_str=comdata;
- comdata="";
- }
- if(!d){//有磁时,为低电平
- itoa(micros()-time_pre,num_str,10);
- time_pre=millis();//micros();为微秒,millis();为毫秒
- //Serial.write(num_str);
- printLetter(show_str);
-
- }
-
-
- }
复制代码
因字母编码和程序读取的顺序,显示的内容看着不太习惯。调整一下程序如下:
- void printLetter(String s){//显示字符串函数
-
- for(int m=s.length()-1;m>=0;m--){
- char s1=s.charAt(m); //取字符
- int xh=toascii(s1)-asc;//与字符'A'的Ascii码取差,获取在数组中的位置
-
- for(int k=7;k>=0;k--){//8*8点阵
- for(int b=0;b<8;b++){
- pinState=!bitRead(Mychar[xh][b],k);//读取指定位的数据,因点阵码为暗码,读出的位要取反。
- digitalWrite(b+2, pinState); //按读取的位值点亮或熄灭对应的LED
- }
- delayMicroseconds(delayTime);//点间隔时间
- }
- delay(letterSpace);//字母间隔时间
- }
- }
复制代码
读取顺序调整。
【显示时间】1、用电子表格画点阵图,再转换成16进制形式。
对应:0,1,2,3,4,5,6,7,8,9,:字符共11个
- {{0xE7,0xDB,0xDB,0xDB,0xDB,0xDB,0xDB,0xE7},//0
- {0xE7,0xF7,0xF7,0xF7,0xF7,0xF7,0xF7,0xE3},//1
- {0xE7,0xDB,0xFB,0xF7,0xEF,0xDF,0xDB,0xC3},//2
- {0xC7,0xFB,0xFB,0xC7,0xC7,0xFB,0xFB,0xC7},//3
- {0xF7,0xEF,0xDF,0xD7,0xC3,0xF7,0xF7,0xF7},//4
- {0xC3,0xDF,0xDF,0xC7,0xFB,0xFB,0xF7,0xCF},//5
- {0xF3,0xEF,0xDF,0xC7,0xDB,0xDB,0xDB,0xE7},//6
- {0xC3,0xFB,0xFB,0xFB,0xFB,0xFB,0xFB,0xFB},//7
- {0xE7,0xDB,0xDB,0xE7,0xE7,0xDB,0xDB,0xE7},//8
- {0xE7,0xDB,0xDB,0xDB,0xE3,0xFB,0xF7,0xCF},//9
- {0xC7,0xC7,0xC7,0xFF,0xFF,0xC7,0xC7,0xC7}};//:
复制代码
- void printTime(String s){//显示字符串函数
-
- for(int m=s.length()-1;m>=0;m--){
- char s1=s.charAt(m); //取字符
- int xh=0;
- if(s1==':'){
- xh=10;
- }
- else{
- xh=toascii(s1)-toascii('0');//与字符'0'的Ascii码取差,获取在数组中的位置
- }
-
-
- for(int k=0;k<8;k++){//8*8点阵
- for(int b=0;b<8;b++){
- pinState=!bitRead(Mychar[xh][b],k);//读取指定位的数据,因点阵码为暗码,读出的位要取反。
- digitalWrite(b+2, pinState); //按读取的位值点亮或熄灭对应的LED
- }
- delayMicroseconds(delayTime);//点间隔时间
- }
- delay(letterSpace);//字母间隔时间
- }
- }
复制代码
【显示视频】
【知识扩展】
测试小功率的LED灯珠工作电压: 1、需要使用的万用表,万用表选择二极管档。(其测试电流约1mA) 2、观测时,长脚为正。用表测时如图:若表有读数,则此时红表笔所测端为二极管的正极,同时发光二极管会发光。 3、若没有读数,则将表笔反过来再测一次;如果两次测量都没有示数,表示此发光二极管已经损坏。
|