TCRT5000 反射式光传感器是一种集成的光电传感器, 内部包含一个红外发光二极管(IR LED) 和一个光电晶体管(Phototransistor)。 工作时, IR LED 发射波长为940 纳米的红外光, 当这些红外光照射到目标物体并被反射回来时, 光电晶体管会接收到反射光并根据其强度改变输出电压。 通过检测输出电压的变化, 可以判断目标物体的存在与否及其距离。
1、模块来源
2、参数
工作电压:3.3 - 5V
探测距离:1 ~ 15 mm
管脚数量:4 Pin
3、工作原理
原理图
TRCT5000 会通过红外反射,在内部通过运放,来判断物体是靠近还是远离,然后通过 D0 口输出 TTL 电平信号
模块具有4个管脚,分别是VCC、GND、A0、D0。
- VCC:电源线,连接单片机的3.3V-5V
- GND:地线,连接单片机的接地(GND)
- DO:TTL 开关信号输出
- AO:模拟信号输出(不同距离输出不同的电压,此引脚可以不接)
4、代码设计
v
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 编码(14 个字节)
parameter STR_leave = 112'hbc_ec_b2_e2_b5_bd_ce_ef_cc_e5_c0_eb_bf_aa;
// "检测到物体离开" 的 GB2312 编码(14 个字节)
//信号定义
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
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)
work_en <= 0;
else if (start_approach || start_leave)
work_en <= 1;
else if (tx_byte_cnt == 7'd15 && uart_tx_done) begin
work_en <= 0;
end
else
work_en <= work_en;
end
//byte counter
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
tx_byte_cnt <= 0;
end
else if (work_en) begin
if (tx_byte_cnt == 7'd15 && uart_tx_done) // 发完最后一个字节,归零
tx_byte_cnt <= 7'b0;
else if(uart_tx_done) // 每发完一个字节,计数器 +1
tx_byte_cnt <= tx_byte_cnt + 1'b1;
end
end
//将数据给串口后
// 串口发送数据控制
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
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;
uart_tx u_uart_tx(
.clk (clk ),
.rst_n (rst_n ),
.uart_tx_req (uart_tx_req&work_en ),// 发送使能请求
.tx_in_data (uart_tx_data ),// UART要发送的数据
.uart_txd (uart_txd ),// UART发送端口
.uart_tx_done (uart_tx_done ),//8bit数据发送完成
.uart_tx_busy (uart_tx_busy ) // 发送忙
);
endmodule1
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
121
122
123
124
125
126
127
128
129
130
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
121
122
123
124
125
126
127
128
129
130
verilog
`timescale 1ns / 1ps
//--------------------port----------------------------
module uart_tx (
input clk,
input rst_n,
input uart_tx_req,
input [7:0] tx_in_data,
output reg uart_txd,
output reg uart_tx_done,
output reg uart_tx_busy
);
//----------------------parameter-------------------
//串口有起始和停止位,还有波特率
parameter CLK_FREQ = 26'd50_000_000, // 系统时钟频率 50MHz
UART_BPS = 17'd115200; // UART 波特率 115200
parameter START_BIT = 1'b0; // 起始位
parameter END_BIT = 1'b1; // 停止位
localparam BAUD_CNT_MAX = CLK_FREQ / UART_BPS; //每434个时钟周期发一位数据
reg [12:0]baud_cnt; //434计数器
reg [3:0] bit_cnt; //8位计数器
reg [7:0] data_reg;
//使能信号锁存,发完一个字节(8位)清零
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
uart_tx_busy <= 0;
end
else if (uart_tx_req) begin
uart_tx_busy <= 1'd1;end
else if ((bit_cnt == 4'd09) && (baud_cnt == 'd1)) begin
uart_tx_busy <= 0;
end
else
uart_tx_busy <= uart_tx_busy;
end
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
baud_cnt <= 13'd0;
end
else if (baud_cnt == (BAUD_CNT_MAX-'d1)) begin
baud_cnt <= 0;
end
else if (uart_tx_busy) begin
baud_cnt <= baud_cnt + 'd1;
end
//baud_cnt <= baud_cnt?
end
//bit_cnt counter
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
bit_cnt <= 0;
end
else if(baud_cnt == 13'd1)begin
if ((bit_cnt == 4 'd9) )
bit_cnt <=0;
else if (uart_tx_busy )
bit_cnt <= bit_cnt +1;
end
//else
//bit_cnt <= bit_cnt;
end
//数据寄存器
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
data_reg<= 0;
end
else if(uart_tx_req)
data_reg <= tx_in_data;
end
//串口发送模块
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
uart_txd <= 1'd1; //空闲时为高电平
end
else if(baud_cnt == BAUD_CNT_MAX - 1)
case (bit_cnt)
4'd0: uart_txd <= START_BIT; // 起始位
4'd1: uart_txd <= data_reg[0]; // 数据最低位
4'd2: uart_txd <= data_reg[1];
4'd3: uart_txd <= data_reg[2];
4'd4: uart_txd <= data_reg[3];
4'd5: uart_txd <= data_reg[4];
4'd6: uart_txd <= data_reg[5];
4'd7: uart_txd <= data_reg[6];
4'd8: uart_txd <= data_reg[7]; // 数据最高位
4'd9: uart_txd <= END_BIT; // 停止位
default: uart_txd <= 1'b1; // 默认状态
endcase
end
// 发送就绪信号逻辑
always @(posedge clk or negedge rst_n) begin
if (!rst_n)
uart_tx_done <= 1'b0; // 初始化为未就绪
else if ( baud_cnt == 1'd1 && bit_cnt == 4'd9)
uart_tx_done <= 1'b1; // 发送完成,设置发送就绪信号为有效
else
uart_tx_done <= 1'b0; // 发送中
end
endmodule1
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
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
代码解释:
info
- 33~51 行:为了防止 D0 在时钟边沿变化这里我们要用一个三级的同步寄存器消除亚稳态,同时用 D3 和 D2 来对比判断上升/下降沿1
串口发送模块这里我们不再赘述,有需要学习可以去看串口回环那一章
5、仿真编写
由于TCRT5000模块的使用方法简单,主要是FPGA逻辑对TCRT5000模块传回的数据进行处理。
至于串口发送的逻辑相信读者已经很清楚了,我们可以将TCRT5000模块输入FPGA的信号D0_syn3(时钟同步后的信号)打上debug标记,分析TCRT5000模块的工作状态。
6、I/O 绑定
引脚图如下
7、程序下载
将程序烧录进开发板,移动传感器,然后我们可以在串口助手上查看具体的信息