FPGA的串口接收程序

`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 21:56:42 10/11/2022
// Design Name:
// Module Name: uart_rx
// Project Name:
// Target Devices:
// Tool versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module uart_rx(
input clk, //clock input
input rst_n, //asynchronous reset input, low active
input [2:0] baud_set,
output reg finish_receive, //完成接收
input rs232_rx_pin,
output reg [7:0] now_rx_data
);

reg [2:0] r_data[7:0];//二维数组:8个3位r_data(最大是7) 对输入IO口信号多次采样,防止有偶尔的干扰造成的错误读数。
reg [2:0] sta_bit;    //起始位
reg [2:0] stp_bit;    //停止位 
 

reg   		rx232_rx0;
reg   		rx232_rx1;
reg   		start_receive;
reg   [8:0]	max_count_1_bit_div16;
wire  		start_rx_negedge; 


//波特率查找表 50M时钟的1个计数是20ns  //5207=9600、2603=19200、1301=38400、867=57600、433=115200
///*波特率设置,其中除以16的原因是将一个位周期划分成16段,来综合判断高低电平,防止只判断一两次会出现有掉电和升电的误判*/ 
//讲1个bit的时间段分成16份,则0,1,2,3,4认为是开头不进行采样,5,6,7,8,9,10,11是中间段进行采样,12,13,14,15,16是末尾段不进行采样。

//则1个采样点对应的最大计数脉冲个数是如下:
always@(*)
begin
case(baud_set)
3’d0: max_count_1_bit_div16 = (50_000_000/9600/16 - 1);
3’d1: max_count_1_bit_div16 = (50_000_000/19200/16 - 1);
3’d2: max_count_1_bit_div16 = (50_000_000/38400/16 - 1);
3’d3: max_count_1_bit_div16 = (50_000_000/57600/16 - 1);
3’d4: max_count_1_bit_div16 = (50_000_000/115200/16 - 1);
default: max_count_1_bit_div16 = (50_000_000/9600/16 - 1);
endcase

	end

always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
rx232_rx0 <= 1’b0;
rx232_rx1 <= 1’b0;
end
else
begin
rx232_rx0 <= rs232_rx_pin;
rx232_rx1 <= rx232_rx0;
end
end

assign start_rx_negedge = ((~rx232_rx0 ) & (rx232_rx1));//提取下降沿。2022年10月11日22:04:43

//设置启动接收标志。
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
start_receive <= 1’b0;
else if(start_rx_negedge)
start_receive <= 1’b1;
else if(finish_receive) //完成接收
start_receive <= 1’b0;
else if(sta_bit >= 4) //每个bit位会采样7次,即是在如下位置采样5,6,7,8,9,10,11是中间段进行采样
start_receive <= 1’b0;
else
start_receive <= start_receive;

	end

/--------------1/16个位时间循环---------------/
reg [8:0] cnt_of_one_bit_div16;
always @(posedge clk or negedge rst_n)
begin

	  if(!rst_n)
        cnt_of_one_bit_div16<=0;
    else if(start_receive)              //在工作情况下,判断div_cnt是否有1/16个位时间。到达则清零,否则递增
        begin
            if(cnt_of_one_bit_div16 < max_count_1_bit_div16)
                cnt_of_one_bit_div16 <= cnt_of_one_bit_div16 + 1'b1; 
            else
                cnt_of_one_bit_div16 <= 0;  
        end
    else
        cnt_of_one_bit_div16<=0;
 end			
			

wire   middle_count_of_one_bit_div16;
assign middle_count_of_one_bit_div16 = (cnt_of_one_bit_div16 == max_count_1_bit_div16/2);//一位周期分成16段,取每一段的中间时刻值来作为依据        

//1个起始位+8个数据位+1个停止位,一共10个bit位。1个bit位分成16段,则10个bit位分成160段。	

reg [7:0]bps_cnt;//160个bps_clk_16x需要8位数据来存储(一位有16个,总共有十位)
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
bps_cnt<=0;
else if(start_receive)
if(middle_count_of_one_bit_div16 == 1’b1)//16个分段中的中间。
begin
if(bps_cnt<159)
bps_cnt<=bps_cnt+1’b1;
else
bps_cnt<=0;
end
else
bps_cnt<=bps_cnt;

    else
        bps_cnt<=0;
 end			

always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
sta_bit<=0;
stp_bit<=0;

            r_data[0]<=0;//多位宽只能一个一个来,不能r_data[2:0][7:0]
            r_data[1]<=0;
            r_data[2]<=0;
            r_data[3]<=0;
            r_data[4]<=0;
            r_data[5]<=0;
            r_data[6]<=0;
            r_data[7]<=0;
        end
    else if(middle_count_of_one_bit_div16 ==1'b1)
        begin
            case(bps_cnt)
                1:begin
                        sta_bit<=0;
                        stp_bit<=0;
                        r_data[0]<=0;//多位宽只能一个一个来,不能r_data[2:0][7:0]
                        r_data[1]<=0;
                        r_data[2]<=0;
                        r_data[3]<=0;
                        r_data[4]<=0;
                        r_data[5]<=0;
                        r_data[6]<=0;
                        r_data[7]<=0;
                    end                    
                5, 6, 7, 8, 9, 10,11     			:		sta_bit  <=sta_bit   + rs232_rx_pin;//起始位判断
                21,22,23,24,25,26,27					:		r_data[0]<=r_data[0] + rs232_rx_pin;//分成16次,但是只取该16次中的中间其次来判断,下同。
                37,38,39,40,41,42,43					:		r_data[1]<=r_data[1] + rs232_rx_pin;
                53,54,55,56,57,58,59					:		r_data[2]<=r_data[2] + rs232_rx_pin;
                69,70,71,72,73,74,75					:		r_data[3]<=r_data[3] + rs232_rx_pin;
                85,86,87,88,89,90,91					:		r_data[4]<=r_data[4] + rs232_rx_pin;
                101,102,103,104,105,106,107			:		r_data[5]<=r_data[5] + rs232_rx_pin;
                117,118,119,120,121,122,123			:		r_data[6]<=r_data[6] + rs232_rx_pin;
                133,134,135,136,137,138,139			:		r_data[7]<=r_data[7] + rs232_rx_pin;
                149,150,151,152,153,154,155			:		stp_bit  <=stp_bit   + rs232_rx_pin;//结束位
                default                           :     ;
            endcase   
        end
		
end			
			
always @(posedge clk or negedge rst_n)
 begin
			if(!rst_n)
				now_rx_data <= 8'b0000_0000;
			else if(bps_cnt==159)//到159取数即可。
				   begin
						now_rx_data[0] <=  (r_data[0]>4)?  1'b1 :1'b0;
						now_rx_data[1] <=  (r_data[1]>4)?  1'b1 :1'b0;
						now_rx_data[2] <=  (r_data[2]>4)?  1'b1 :1'b0;
						now_rx_data[3] <=  (r_data[3]>4)?  1'b1 :1'b0;
						now_rx_data[4] <=  (r_data[4]>4)?  1'b1 :1'b0;
						now_rx_data[5] <=  (r_data[5]>4)?  1'b1 :1'b0;
						now_rx_data[6] <=  (r_data[6]>4)?  1'b1 :1'b0;
						now_rx_data[7] <=  (r_data[7]>4)?  1'b1 :1'b0;
					end
			else
          now_rx_data <= now_rx_data ; 

end

//finish_receive
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
finish_receive <= 1’b0;
else if(bps_cnt==159)//到159取数即可。
finish_receive <= 1’b1;
else if(start_rx_negedge)
finish_receive <= 1’b0;
else
finish_receive <= finish_receive ;
end
endmodule

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
协议说明: CCU向各个终端所发的数据格式有3种:查询,令牌,广播 查询:CCU向各个终端一对一发送一串数据,CCU在发送完后,终端在一定时间内拥有发言权。 令牌:CCU发出令牌命令后,各个终端收到自己的令牌帧后,拥有总线的发言权, 必须在一定时间内发出帧头,否则,CCU取消该终端的发言权。发言完或者没有发言, 把令牌在规定的时间内传给下一个终端 广播:CCU发出广播帧后,各个终端必须按照广播帧工作,不要回复CCU,也没有总线发言权 格式: 查询:7E, 命令,目标网络,地址,数据长度,数据,校验,7E 令牌:7E,命令,当前虚拟地址,令牌,校验,7E 广播; 7E, FF, FF, FF,数据长度,数据,校验,7E 数据格式说明: 1,7E为帧头,帧尾标志。如果在数据里面遇到有7E,将数据7E拆分为7F,80,如 果数据里面有7F,将7F拆分为7F,81.在接收时,将上面数据合成相应的数。 2,目标网络:为各个终端所在的网络。T/R0 为00,T/R 为01,T/R2 为02,T/R3 为03,T/R4为04,FF为全局广播。 3,地址:为各个受控设备物理地址。如果全局广播就为FF。 4,命令:00为CCU查询各个终端。01为各个终端回复CCU查询。02为令牌命令。 全局广播为FF。 5,数据长度,数据的长度。 6,数据,即要发送的数据。 7, 校验:两个7E之间除了校验的所有数据相加,0X55减去这个数得到的是校验值。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值