1、实验目的
使用逻辑派Z1开发板(基于紫光同创 compa 系列 PGC4KD-6ILPG144 芯片)编写TCRT5000反射式光传感器模块验证代码,当传感器检测到物体接近时,板卡通过串口向上位机发送了“检测到物体接近”当物体离开时,板卡通过串口向上位机发送“检测到物体离开”。
2、TCRT5000反射式光传感器工作原理
TCRT5000反射式光传感器是一种集成的光电传感器,内部包含一个红外发光二极管(IR LED)和一个光电晶体管(Phototransistor)。工作时,IR LED发射波长为940纳米的红外光,当这些红外光照射到目标物体并被反射回来时,光电晶体管会接收到反射光并根据其强度改变输出电压。通过检测输出电压的变化,可以判断目标物体的存在与否及其距离。这种传感器常用于机器人避障、接近检测和物体检测等近距离应用,具有结构简单、成本低廉和响应快速的特点。模块图如下:
模块具有4个管脚,分别是VCC、GND、A0、D0。其中A0是模拟信号输出,D0是TTL电平输出。我们将D0接入开发板,当模块探测到物体时,D0会输出0,其他时候D0为高电平,我们根据这个原理设计代码。
3、代码设计
模块端口如下表:
模块代码如下:
`timescale 1ns / 1ps
module TCRT5000(
input clk ,
input rst_n ,
input D0 ,
output uart_txd
);
parameter STR_approach = 112'hbc_ec_b2_e2_b5_bd_ce_ef_cc_e5_bd_d3_bd_fc; // "检测到物体接近" 的 GB2312 编码
parameter STR_leave = 112'hbc_ec_b2_e2_b5_bd_ce_ef_cc_e5_c0_eb_bf_aa; // "检测到物体离开" 的 GB2312 编码
//信号定义
wire uart_tx_busy ;
wire uart_tx_done ;
wire start_approach/* synthesis PAP_MARK_DEBUG="true" */;
wire start_leave/* synthesis PAP_MARK_DEBUG="true" */;
reg [ 7: 0] uart_tx_data ;
reg uart_tx_req ;
reg work_en ;
reg [ 6: 0] tx_byte_cnt ;
reg [ 111: 0] str ;
reg D0_syn1;
reg D0_syn2;
reg D0_syn3/* synthesis PAP_MARK_DEBUG="true" */;
assign start_approach = ~D0_syn2 & D0_syn3;//下降沿//物体离开
assign start_leave = D0_syn2 & ~D0_syn3;//上升沿//物体接近
//时钟同步以及打拍
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
D0_syn1<= 1'b0;
D0_syn2<= 1'b0;
D0_syn3<= 1'b0;
end
else begin
D0_syn1<= D0;
D0_syn2<= D0_syn1;
D0_syn3<= D0_syn2;
end
end
always@(posedge clk or negedge rst_n)
if(rst_n == 1'b0)
work_en <= 1'b0;
else if(start_approach||start_leave)
work_en <= 1'b1;
else if(tx_byte_cnt== 7'd15&&uart_tx_done)
work_en <= 1'b0;
else
work_en <= work_en;
//串口发送逻辑
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
tx_byte_cnt <= 7'b0;
end else if (work_en) begin
if (tx_byte_cnt == 7'd15&&uart_tx_done) // 总共发送 16 字节
tx_byte_cnt <= 7'b0;
else if(uart_tx_done)
tx_byte_cnt <= tx_byte_cnt + 1'b1;
end
end
always @(posedge clk or negedge rst_n)
if (!rst_n)
str <= 112'b0;
else if(start_approach)
str <= STR_approach;
else if(start_leave)
str <= STR_leave;
else
str <= str;
// 串口发送数据控制
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
uart_tx_req <= 1'b0;
uart_tx_data <= 8'b0;
end else if (work_en && !uart_tx_busy) begin
case (tx_byte_cnt) // 根据当前字节计数器发送数据
7'd1: uart_tx_data <= str[111:104]; // "检"
7'd2: uart_tx_data <= str[103:96]; // "检"
7'd3: uart_tx_data <= str[95:88]; // "测"
7'd4: uart_tx_data <= str[87:80]; // "测"
7'd5: uart_tx_data <= str[79:72]; // "到"
7'd6: uart_tx_data <= str[71:64]; // "到"
7'd7: uart_tx_data <= str[63:56]; // "物"
7'd8: uart_tx_data <= str[55:48]; // "物"
7'd9: uart_tx_data <= str[47:40]; // "体"
7'd10: uart_tx_data <= str[39:32]; // "体"
7'd11: uart_tx_data <= str[31:24]; // "接"/"离"
7'd12: uart_tx_data <= str[23:16]; // "接"/"离"
7'd13: uart_tx_data <= str[15:8]; // "进"/"开"
7'd14: uart_tx_data <= str[7:0]; // "进"/"开"
7'd15: uart_tx_data <= 8'h0A; // 换行符
default: uart_tx_data <= 8'b0;
endcase
uart_tx_req <= 1'b1; // 拉高请求信号
end else begin
uart_tx_req <= 1'b0; // 请求信号拉高仅一个时钟周期
end
end
uart_tx u_uart_tx(
.clk (clk ),
.rst_n (rst_n ),
.uart_tx_req (uart_tx_req&work_en ),// 发送使能请求
.uart_tx_data (uart_tx_data ),// UART要发送的数据
.uart_txd (uart_txd ),// UART发送端口
.uart_tx_done (uart_tx_done ),//8bit数据发送完成
.uart_tx_busy (uart_tx_busy ) // 发送忙
);
endmodule
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
在这个模块中,由于模块输出的D0信号时钟与我们开发板的时钟不同步,我们使用D0_syn1、D0_syn2、D0_syn3寄存器对D0信号进行时钟同步,同时获取上升沿start_leave和下降沿start_approach。在之前的介绍中我们提到D0信号默认是高电平,当模块检测到有物体时,D0才会变成低电平。于是我们捕获D0信号的下降沿,作为触发信号,发送16字节的“检测到物体接近”,同样的捕获D0信号的上升沿作为触发信号发送“检测到物体离开”(汉字编码使用GB2312编码)。
对于串口发送模块的逻辑在“串口回环实验例程”章节已经介绍,若不熟悉请到对应章节进行了解。
约束文件如下:
define_attribute {p:uart_txd} {PAP_IO_DIRECTION} {OUTPUT}
define_attribute {p:uart_txd} {PAP_IO_LOC} {33}
define_attribute {p:uart_txd} {PAP_IO_VCCIO} {1.2}
define_attribute {p:uart_txd} {PAP_IO_STANDARD} {LVCMOS12}
define_attribute {p:uart_txd} {PAP_IO_DRIVE} {2}
define_attribute {p:uart_txd} {PAP_IO_NONE} {TRUE}
define_attribute {p:uart_txd} {PAP_IO_SLEW} {SLOW}
define_attribute {p:D0} {PAP_IO_DIRECTION} {INPUT}
define_attribute {p:D0} {PAP_IO_LOC} {92}
define_attribute {p:D0} {PAP_IO_VCCIO} {1.2}
define_attribute {p:D0} {PAP_IO_STANDARD} {LVCMOS12}
define_attribute {p:D0} {PAP_IO_PULLUP} {TRUE}
define_attribute {p:clk} {PAP_IO_DIRECTION} {INPUT}
define_attribute {p:clk} {PAP_IO_LOC} {5}
define_attribute {p:clk} {PAP_IO_VCCIO} {1.2}
define_attribute {p:clk} {PAP_IO_STANDARD} {LVCMOS12}
define_attribute {p:clk} {PAP_IO_PULLUP} {TRUE}
define_attribute {p:rst_n} {PAP_IO_DIRECTION} {INPUT}
define_attribute {p:rst_n} {PAP_IO_LOC} {19}
define_attribute {p:rst_n} {PAP_IO_VCCIO} {1.2}
define_attribute {p:rst_n} {PAP_IO_STANDARD} {LVCMOS12}
define_attribute {p:rst_n} {PAP_IO_PULLUP} {TRUE}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
4、代码仿真
由于TCRT5000模块的使用方法简单,主要是FPGA逻辑对TCRT5000模块传回的数据进行处理。至于串口发送的逻辑相信读者已经很清楚了,我们可以将TCRT5000模块输入FPGA的信号D0_syn3(时钟同步后的信号)打上debug标记,分析TCRT5000模块的工作状态。
当没有物体接近时模块输入的D0_syn3为高电平,如下图:
当有物体接近时模块输入的D0_syn3为低电平,如下图:
我们在代码中获取其下降沿start_approach与上升沿start_leave作为串口数据的发送标志,将物体离开或接近信息发送到上位机进行查看。
5、实验现象
将程序下载进入板卡,根据约束文件将板卡与TCTR5000模块连接。打开串口助手,设置波特率为115200,使用物体靠近和原理模块的发射管和接收管。可以观察到串口助手有如下信息: