FPGA——PS/2驱动

编程入门 行业动态 更新时间:2024-10-22 17:36:46

<a href=https://www.elefans.com/category/jswz/34/1769628.html style=FPGA——PS/2驱动"/>

FPGA——PS/2驱动

概述

PS/2驱动框架分为四个部分:

1.预处理部分,用来同步ps/2_clk和ps/2_sda,从而进行边沿检测。

2.接收部分,当flag来了,接收sda的数据。

3.译码部分,根据ps/2数据手册对接收的数据进行转译。

4.显示部分,将转译过来的内容显示在数码管上。(因为我只做了数字0-9的显示,所以4位的data就足够了)

框架如下图所示:

预处理部分

首先对ps/2_clk进行上升沿寄存,因为时钟都是上升沿采样。通过寄存两拍(check_reg_clk)和寄存一拍的取反(~syn_reg_clk[1])相与得到flag_neg。正常采样的点为A点,但因为A点采不到,所以C作为A的近似点采样,寄存一拍(sda : C)后要采样的数据正好和flag_neg对齐。

预处理代码

module pre_handle (input    wire         clk,input    wire         ps2_clk,input    wire         ps2_sda,output   wire         flag_neg,output   wire         sda);reg            [1:0]  syn_reg_clk; //同步寄存ps2_clkreg            [1:0]  syn_reg_sda;//同步寄存ps2_sdareg                   check_reg_clk;	 always @ (posedge clk) syn_reg_clk <= {syn_reg_clk[0],ps2_clk};always @ (posedge clk) syn_reg_sda <= {syn_reg_sda[0],ps2_sda};assign sda = syn_reg_sda[1];always @ (posedge clk) check_reg_clk <= syn_reg_clk[1];assign flag_neg = check_reg_clk & (~syn_reg_clk[1]);	 endmodule 

接收部分

在接收部分定义了一个11位的捕获寄存器cap_reg,把每一次新接收到的sda都放在cap_reg的第一位,以此类推,接收11位后就是一个完整的数据,【停止位,校验位,8位数据位,起始位】

10

9

8

87

6

5

4

3

2

1

0

start

 

 

 

 

 

 

 

 

 

 

10

9

8

87

6

5

4

3

2

1

0

A0

start

 

 

 

 

 

 

 

 

 

10

9

8

87

6

5

4

3

2

1

0

A1

A0

start

 

 

 

 

 

 

 

 

10

9

8

87

6

5

4

3

2

1

0

A2

A1

A0

start

 

 

 

 

 

 

 

10

9

8

87

6

5

4

3

2

1

0

A3

A2

A1

A0

start

 

 

 

 

 

 

10

9

8

87

6

5

4

3

2

1

0

A4

A3

A2

A1

A0

start

 

 

 

 

 

10

9

8

87

6

5

4

3

2

1

0

A5

A4

A3

A2

A1

A0

start

 

 

 

 

10

9

8

87

6

5

4

3

2

1

0

A6

A5

A4

A3

A2

A1

A0

start

 

 

 

10

9

8

87

6

5

4

3

2

1

0

A7

A6

A5

A4

A3

A2

A1

A0

start

 

 

10

9

8

87

6

5

4

3

2

1

0

校验

A7

A6

A5

A4

A3

A2

A1

A0

start

 

10

9

8

87

6

5

4

3

2

1

0

Stop

校验

A7

A6

A5

A4

A3

A2

A1

A0

start

 

最开始接收起始位 start 放在第10,然后接收A0放在第10位,start位向右平移,处于第9位。此类推 当全部接收完,start位在第0位。

最后 第9位为检验位

[8:1]为数据位

把9-1为进行异或(^[9:1]),若异或结果为1,说明数据正确 把[8:1]输出给数码管。若不正确则不输出。

接收部分代码

module ps2_rec ( input    wire         clk,input    wire         rst_n,input    wire         flag,input    wire         sda,output   reg   [7:0]  rec_code,output   reg          valid_flag,output   reg          error_flag
);reg            [3:0]  cnt;reg            [10:0] cap_reg;//捕获寄存器wire                  flag_recdone; //完成标志 always @ (posedge clk) beginif (rst_n == 0)cap_reg <= 0;elseif(flag)cap_reg <= {sda,cap_reg[10:1]};//脉冲来了 把每次新来的sda放在cap_reg的高位elsecap_reg <= cap_reg;endalways @ (posedge clk) beginif (rst_n == 0)cnt <= 0;elseif(cnt < 11)if (flag)cnt <= cnt + 1'b1;elsecnt <= cnt;elsecnt <= 0; //cnt == 11时直接清零 保持一个周期endassign flag_recdone = (cnt == 11); //cnt == 11这一个周期正好是脉冲完成的标志always @ (posedge clk) beginif (rst_n == 0)rec_code <= 0;elseif (flag_recdone && ^cap_reg[9:1] == 1)//接收完成且为奇校验rec_code <= cap_reg[8:1]; //认为cap_reg[8:1]是接收的信息elserec_code <= rec_code;endalways @ (posedge clk) beginif (rst_n == 0)valid_flag <= 0;elseif (flag_recdone && ^cap_reg[9:1] == 1) //接收完成且为奇校验valid_flag <= 1; //正确接收elsevalid_flag <= 0;endalways @ (posedge clk) beginif (rst_n == 0)error_flag <= 0;elseif (flag_recdone && ^cap_reg[9:1] == 0) //接收完成但不是奇校验error_flag <= 1; //有错误elseerror_flag <= 0;end
endmodule 

译码部分

定义一个16位的缓存数据,把新来的8位数据放在后8位。

0000

0000

0000

0000

显示为

0

0

1

C

A

1

C

1

C

A

1

C

1

C

A

                                                                                     .

A

                                                                                     .

A

                                                                                     .

A

1

C

1

C

A

1

C

F

0

0

F

0

1

C

0

1

C

3

2

B

3

2

3

2

B

                                                                                     .

B

                                                                                     .

B

                                                                                     .

B

3

2

3

2

B

3

2

F

0

0

F

0

3

2

0

 开始16bit数都为0 当A按下时 显示001C 持续按住A 显示1C1C,1CF0为瞬态(处于按下与松开之间的状态)  按键结束为F01C 这时再按下按键B 显示为1C32  持续按住B 显示3232,32F0为瞬态(处于按下与松开之间的状态)。按键结束为F032 。

总结:高8位为F0时,显示为零。高8为不为F0时,显示低8位对应的码值。

译码代码

module ps2_decoder (input    wire         clk,input    wire         rst_n,input    wire         flag,input    wire  [7:0]  code,output   reg   [3:0]  data	);reg            [15:0] buf_code;always @ (posedge clk) beginif (rst_n == 0)buf_code <= 0;elseif (flag)buf_code <= {buf_code[7:0],code};//新来的8位放后面elsebuf_code <= buf_code;endalways @ (posedge clk) beginif (rst_n == 0)data <= 0;elseif (buf_code[15:8] == 8'hf0)data <= 0;elsecase (buf_code[7:0])8'h45    :    data<=0;8'h16    :    data<=1;8'h1e    :    data<=2;8'h26    :    data<=3;8'h25    :    data<=4;8'h2e    :    data<=5;8'h36    :    data<=6;8'h3d    :    data<=7;8'h3e    :    data<=8;8'h46    :    data<=9;8'h1c    :    data<=10;8'h32    :    data<=11;8'h21    :    data<=12;8'h23    :    data<=13;8'h24    :    data<=14;8'h2b    :    data<=15;default  :    data<=0;endcaseend
endmodule 

 显示部分

显示部分就是把译码中的4位data显示在数码管上,这个根据数码管驱动不同略有区别。

总结

最后就是把4个模块实例化到一个总代码中,编译成功后如下图所示:

 最后的RTL级视图也和我们的框架图一致,ps/2驱动就完成了。

 

更多推荐

FPGA——PS/2驱动

本文发布于:2023-06-27 08:20:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/908689.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:FPGA   PS

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!