要和可莉一起去炸鱼吗?虽然被抓住就是一整天的禁闭,但鱼很好吃,所以值得!|

羽小兮

园龄:3年4个月粉丝:9关注:33

FPGA ise项目 实现点亮led灯,串口收发


前言

FPGA verilog项目学习


一、FPGA开发板使用

1.D1闪烁 间隔1s

代码如下:

module D1
#(
 parameter CNT_MAX = 26'd49_999_999
)
(
input wire sys_clk , //系统时钟 50Mh
input wire sys_rst_n , //全局复位
 
output reg led1_out //输出控制 led 灯
);

//reg define
reg [25:0] cnt ; //经计算得需要 26 位宽的寄存器才够 1s
reg cnt_flag;

//cnt:计数器计数,当计数到 CNT_MAX 的值时清零
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt <= 26'b0;
else if(cnt == CNT_MAX)
cnt <= 26'b0;
else
 cnt <= cnt + 1'b1;
 
//cnt_flag:计数到最大值产生的标志信号,每当计数满标志信号有效时取反
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_flag <= 1'b0;
else if(cnt == CNT_MAX)
cnt_flag <= 1'b1;
 else
 cnt_flag <= 1'b0;
 
//led_out:输出控制一个 LED 灯
 always@(posedge sys_clk or negedge sys_rst_n)
 if(sys_rst_n == 1'b0)
 led1_out <= 1'b0;
 else if(cnt_flag == 1'b1)
 led1_out <= ~led1_out;
 
 endmodule

2.D2闪烁,间隔1s,按下key1,key2,实现D2的闪烁时间加长/减少

代码如下(示例):

module D2
(
	 output reg led1_out, //输出控制 led 灯
	 output reg led2_out, //输出控制 led 灯
    input wire sys_clk , //系统时钟 50Mh
    input wire sys_rst_n , //全局复位
	 input   key1_flag,
	 input   key2_flag

);


//reg define
reg [26:0] cnt; //经计算得需要 27 位宽的寄存器才够 1s,29位宽10s
reg [25:0] cnt1; //经计算得需要 27 位宽的寄存器才够 1s,29位宽10s
reg [26:0] CNT_MAX ; //计数到一秒
reg [26:0] CNT1_MAX ;

initial 
begin
CNT_MAX <= 27'd50_000_000; //计数到一秒
CNT1_MAX <= 27'd50_000_000; //计数到一秒
end


 
//cnt:计数器计数,当计数到 CNT_MAX 的值时清零
always@(posedge sys_clk or negedge sys_rst_n)
begin
    if(sys_rst_n == 1'b0)
    cnt <= 27'd0;
    else if(cnt == CNT_MAX)
    cnt <= 27'd0;
    else
    cnt <= cnt + 27'd1;
 end
 
//cnt1:计数器计数,当计数到 CNT1_MAX 的值时清零
always@(posedge sys_clk or negedge sys_rst_n)
begin
    if(sys_rst_n == 1'b0)
    cnt1 <= 0;
    else if(cnt1 == CNT1_MAX)
    cnt1 <= 0;
    else
    cnt1 <= cnt1 + 26'd1;
 end
 
 
 //led1_out:输出控制一个 LED 灯的闪烁
always@(posedge sys_clk or negedge sys_rst_n)
begin
if(sys_rst_n == 1'b0)
 led1_out <= 1'b1;
else if(cnt1 == CNT1_MAX )
led1_out <= ~led1_out;
//led1_out <= 1;
end



always@(posedge sys_clk )
begin
    if(key1_flag==1 )
	 begin
	      
         CNT_MAX <= CNT_MAX + 27'd25_000_000;//key1按下一次,闪烁时间加长0.5s
	 end
	 else if(CNT_MAX >= 27'd49_000_001)
	 begin
	       if(key2_flag==1)
			 begin
			      CNT_MAX <= CNT_MAX - 27'd25_000_000;//key2按下一次,闪烁时间减小0.5s
			 end
	 end
end


//led2_out:输出控制一个 LED 灯的闪烁
always@(posedge sys_clk or negedge sys_rst_n)
begin
if(sys_rst_n == 1'b0)
 led2_out <= 1'b1;
else if(cnt == CNT_MAX )
led2_out <= ~led2_out;
//led2_out <= 1;
//else if(key1_flag==1 )
//led2_out <= ~led2_out;
end

 
endmodule

二、串口通信

key3作为串口驱动信号,向mcu发送数据,反复发送,key4按下,mcu发送信号给FPGA,FPGA发送反馈数据给mcu

发送代码如下(示例):

module uart(
    input  sys_clk,
    input  sys_rst_n,
    output  reg uart_txd,
    input  key3_flag,//key3_flag 为 1 时表示消抖后检测到按键被按下
	 input  key4_flag,
    input  [7:0] uart_data,
	 input [7:0] uart_data1,
	 input uart_done,
	  output reg led3_out

    );


			 
/*//............按键检测............//
//按键消抖
reg [19:0] cnt_20ms ; //计数器
parameter CNT_MAX = 20'd999_999; //计数器计数最大值
//cnt_20ms:如果时钟的上升沿检测到外部按键输入的值为低电平时,计数器开始计数
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_20ms <= 20'b0;
else if(key3_in == 1'b1)
cnt_20ms <= 20'b0;
else if(cnt_20ms == CNT_MAX && key3_in == 1'b0)
cnt_20ms <= cnt_20ms;
else
cnt_20ms <= cnt_20ms + 1'b1;
 
//key3_flag:当计数满 20ms 后产生按键有效标志位
//且 key3_flag 在 999_999 时拉高,维持一个时钟的高电平
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
  key3_flag <= 1'b0;
else if(cnt_20ms == CNT_MAX - 1'b1)
  key3_flag <= 1'b1;
else
  key3_flag <= 1'b0;*/



//.........串口...........//
parameter BPS = 5208; 		
reg [7:0] data_buf;
reg tx_start;
reg tx1_start;
reg[3:0] tx_cnt;
reg[12:0] clk_cnt;
//reg[3:0] state;
reg tx_flag;
reg tx1_flag;

always @ (posedge sys_clk or negedge sys_rst_n)
		if(!sys_rst_n)
		begin
         tx_start <= 1'b0;
			tx1_start <= 1'b0;
		end
		else begin
		if(key3_flag==1)
		  begin tx_start <= ~tx_start;end
		if(key4_flag==1)
         begin tx1_start <= ~tx1_start;end
      end
//发送55 aa 66 99 01 23 45 67//
always @ (posedge sys_clk or negedge sys_rst_n)
		if(!sys_rst_n)
			tx_flag <=0;
		else if(tx_start)
			tx_flag <=1'b1;
		else if((tx_cnt == 4'd9)&&(clk_cnt ==BPS/2))
			      tx_flag <= 1'b0;	
		
//发送mcu的反馈数据的标志位//
always @ (posedge sys_clk or negedge sys_rst_n)
		if(!sys_rst_n)
			tx1_flag <=0;
		else if(tx1_start)
			tx1_flag <=1'b1;
		else if((tx_cnt == 4'd9)&&(clk_cnt ==BPS/2))
			      tx1_flag <= 1'b0;
		
always @ (posedge sys_clk or negedge sys_rst_n)
		begin
			if(!sys_rst_n)
				begin
				clk_cnt<=13'd0;tx_cnt <= 4'd0;
				end
			else if(tx_flag||tx1_flag)
			begin
				if(clk_cnt == BPS-1)
				begin
				   clk_cnt <= 13'd0;
					tx_cnt <= tx_cnt +1'b1;
					if(tx_cnt == 4'd9)tx_cnt <=0;
				end
				else
				begin
				clk_cnt <= clk_cnt +1'b1;tx_cnt<=tx_cnt;		
            end				
			end
		end

	
		


 
       /*
always @ (posedge sys_clk or negedge sys_rst_n)
		begin
			if(!sys_rst_n)
				begin
				state<=IDLE;
	         //data_buf=8'h55;
				end
			else 
				case(state)
				IDLE:if(key3_flag==1)
					begin
					tx_cnt<=0;
					clk_cnt<=0;
						if(tx_start==1 )
							state<=SEND;
					end
				SEND:
					begin
					if(tx_cnt==4'd9&&clk_cnt==BPS/2)
						begin
						tx_cnt<=4'd10;
						state<=END;
						end
					else if(clk_cnt==BPS-1)
						begin
						clk_cnt<=0;
						tx_cnt<=tx_cnt+1'b1;
						end
					else
						begin
						clk_cnt<=clk_cnt+1'b1;
						tx_cnt<=tx_cnt;
						end
					end
				END:
				begin
				if(tx_start==1)
					begin
					state<=END;
					end
				else
					state<=IDLE;
				end
				default:state<=IDLE;
			endcase
		end
*/		
		//2s发送一次数据
		reg [26:0] cnt_2s;
		always @ (posedge sys_clk or negedge sys_rst_n)
		if(!sys_rst_n)			
			cnt_2s<=0;
		else if(cnt_2s==27'd100_000_000)//2s
			cnt_2s<=0;
		else
			cnt_2s<=cnt_2s+27'd1;

		//1.5s发送一次数据
		reg [27:0] cnt_15s;
		always @ (posedge sys_clk or negedge sys_rst_n)
		if(!sys_rst_n)			
			cnt_15s<=0;
		else if(cnt_15s==28'd75_000_000-1)//1.5s
			cnt_15s<=0;
		else
			cnt_15s<=cnt_15s+28'd1;
      //八位数据轮流
		reg [3:0] cnt_8;
		always @ (posedge sys_clk or negedge sys_rst_n)
		if(!sys_rst_n)
			cnt_8<=4'd0;
		else if(cnt_2s==27'd100_000_000)//2s
			cnt_8<=cnt_8+4'd1;
		else if(cnt_8 == 4'd8)
			cnt_8<=4'd0;
			
		//两位数据轮流	
		reg [3:0] cnt1_2;
		always @ (posedge sys_clk or negedge sys_rst_n)
		if(!sys_rst_n)
			cnt1_2<=4'd0;
		else if(cnt_15s==27'd75_000_000-1)//1.5s
			cnt1_2<=cnt1_2+4'd1;
		else if(cnt1_2 == 4'd2)//
			cnt1_2<=4'd0;
//两位数据轮流	
		reg [3:0] cnt1_8;
		always @ (posedge sys_clk or negedge sys_rst_n)
		if(!sys_rst_n)
			cnt1_8<=4'd0;
		else if(cnt_15s==27'd75_000_000-1)//1.5s
			cnt1_8<=cnt1_8+4'd1;
		else if(cnt1_8 == 4'd8)//
			cnt1_8<=4'd0;
		
		always @ (posedge sys_clk or negedge sys_rst_n)
		begin
		if(!sys_rst_n)
			data_buf<=8'h00;
//		else if(tx1_flag == 1) begin  
//		   data_buf <= 8'h11;

      else if(tx1_flag ==1)begin//key4按下,发送数据11
//		   else if(uart_done==1)//数据传输完成的标志位,发送反馈数据
		     /*if(uart_data == 8'h89)
			  data_buf <= uart_data;
           if(uart_data == 8'hAB)
			  data_buf <= uart_data;
           if(uart_data == 8'hCD)
			  data_buf <= uart_data;*/
			 if(uart_data == 8'h11)
			  data_buf <= uart_data;
//          //if(uart_done==1)begin
//			 if(cnt_15s<=28'd75_000_000 && uart_done==1)
//			  data_buf <=  uart_data;
//			 if(cnt_15s>28'd75_000_000 && uart_done==1)
//			  data_buf <= ~uart_data;	   
//			  end 
			  //end 
			  if(uart_data == uart_data )
            case(cnt1_2)
				4'd0:data_buf <= uart_data;
				4'd1:data_buf <= uart_data1;
				default:;
			   endcase	
//            case(cnt1_8)
//				4'd0:data_buf <= array[0];//55
//				4'd1:data_buf <=~array[0];//aa
//				4'd2:data_buf <= array[1];//66
//				4'd3:data_buf <=~array[1];//99
//				4'd4:data_buf <= array[2];//01
//				4'd5:data_buf <=~array[2];//23
//				4'd6:data_buf <= array[3];//45
//				4'd7:data_buf <=~array[3];//67
//				default:;//00
//			endcase 
		end	
		else if(tx_flag ==1)//发送的两帧数据
			case(cnt_8)
				4'd0:data_buf <= 8'h55;//55
				4'd1:data_buf <= 8'hAA;//aa
				4'd2:data_buf <= 8'h66;//66
				4'd3:data_buf <= 8'h99;//99
				4'd4:data_buf <= 8'h01;//01
				4'd5:data_buf <= 8'h23;//23
				4'd6:data_buf <= 8'h45;//45
				4'd7:data_buf <= 8'h67;//67
				default:data_buf <= 8'h00;//00
			endcase
		end
		
		always @ (posedge sys_clk or negedge sys_rst_n)
		begin
			if(!sys_rst_n)
				uart_txd <= 8'b1;
			else 
				case(tx_cnt)
					4'd0:uart_txd <= 8'b0;
					4'd1:uart_txd <= data_buf[0];
					4'd2:uart_txd <= data_buf[1];
					4'd3:uart_txd <= data_buf[2];
					4'd4:uart_txd <= data_buf[3];
					4'd5:uart_txd <= data_buf[4];
					4'd6:uart_txd <= data_buf[5];
					4'd7:uart_txd <= data_buf[6];
					4'd8:uart_txd <= data_buf[7];
					4'd9:uart_txd <= 8'b1;
					default:uart_txd <= 8'b1;
				endcase

				
		end
reg [7:0] array [0:3];
reg [3:0]	i;	
//检测是否接收到数据uart_data == 8'h89 || uart_data == 8'hAB || uart_data == 8'hCD || uart_data == 8'hEF
always@(posedge sys_clk or negedge sys_rst_n)
if(!sys_rst_n)
    begin
        led3_out<=1;
    end
else if(uart_done == 1'b1)
    begin i<=0;array[i]<=uart_data;i<=i+1;end
else if(uart_data1 == 8'h32)
    begin led3_out <= 0 ; end	
else if(uart_data1 == 8'h10)
    begin led3_out <= 1 ; end
else if(uart_data1 == 8'h76)
    begin led3_out <= 0 ; end	
else if(uart_data1 == 8'h54)
    begin led3_out <= 1 ; end	 
endmodule

接收代码如下(示例):

module rx(
    input  sys_clk,
    input  sys_rst_n,
	 input  key4_flag,
	 input  uart_rxd,
    output   reg[7:0] uart_data,
	 output   reg[7:0] uart_data1,
	 output   reg      uart_done
//	 output reg led3_out

    );

//.........串口...........//
parameter BPS = 5208;

reg         rx_start;
reg         rx_flag;//数据有效段的标志,拉高为有效
reg [3:0]   rx_cnt;//波特率周期的计数器
reg [12:0]  clk_cnt;//系统时钟的计数器
reg [7:0]   rxdata;//输出数据的寄存器
reg         uart_rxd_reg0;
reg         uart_rxd_reg1;
wire        start_flag;
initial uart_data <= 8'h11;

//initial begin uart_data <= 8'h11; end
//边缘检测的功能,检测数据的低电平,开始位,数据传输开始就拉高start_flag
always@(posedge sys_clk or negedge sys_rst_n)begin
    if(!sys_rst_n)begin
        uart_rxd_reg0 <= 1'b1;
        uart_rxd_reg1 <= 1'b1;
    end
    else begin
        uart_rxd_reg0 <= uart_rxd;
        uart_rxd_reg1 <= uart_rxd_reg0;     
    end
end
assign start_flag = (uart_rxd_reg1)&(~uart_rxd_reg0);

/*//key4按下,mcu开始发送数据,FPGA接收数据传输开始位拉高,数据接收标志位rx_start就拉高
always @ (posedge sys_clk or negedge sys_rst_n)
		if(!sys_rst_n)
         rx_start <= 1'b0;
		else if(key4_flag && start_flag)
         rx_start <= 1;*/

//根据rx_start传输开始的标志,设置传输的有效段的范围, 即从开始位到结束位都拉高rx_flag,至于为甚后面是波特率周期的一办,是为了给一帧数据留一个缓冲的时间;
always@(posedge sys_clk or negedge sys_rst_n)begin
    if(!sys_rst_n)
        rx_flag <= 0;
    else 
	 begin
        //if(rx_start)
		  if(start_flag)
            rx_flag <= 1'b1;
        else if(rx_cnt == 4'd9 && clk_cnt == BPS/2)
            rx_flag <= 1'b0;
        else
            rx_flag <= rx_flag;        
    end 
end
//系统时钟的计数器
always@(posedge sys_clk or negedge sys_rst_n)begin
    if(!sys_rst_n)
        clk_cnt <= 0;
    else begin
        if(rx_flag)begin
            if(clk_cnt < BPS - 1)
                clk_cnt <= clk_cnt + 1'b1;
            else
                clk_cnt <= 0;    
        end
        else
            clk_cnt <= 0;    
    end 
end
//波特率周期计数器,每当系统时钟计数器计数到一个波特率周期时,波特率周期计数器就加一
always@(posedge sys_clk or negedge sys_rst_n)begin
    if(!sys_rst_n)
        rx_cnt <= 0;
    else begin
        if(rx_flag)begin
            if(clk_cnt == BPS - 1)
                rx_cnt <= rx_cnt + 1'b1;
            else
                rx_cnt <= rx_cnt;    
        end
        else
            rx_cnt <= 0;
    end 
end
//串行数据转换为并行数据,至于为什么是计数到波特率周期的一半,是为了采样中间的值,这样采样的正确性高
always@(posedge sys_clk or negedge sys_rst_n)begin
    if(!sys_rst_n)
        rxdata <= 0;
    else begin
        if(rx_flag)begin
            if(clk_cnt == BPS/2)begin
                case(rx_cnt)
                    4'd1:   rxdata[0] <= uart_rxd;      
                    4'd2:   rxdata[1] <= uart_rxd; 
                    4'd3:   rxdata[2] <= uart_rxd; 
                    4'd4:   rxdata[3] <= uart_rxd; 
                    4'd5:   rxdata[4] <= uart_rxd; 
                    4'd6:   rxdata[5] <= uart_rxd; 
                    4'd7:   rxdata[6] <= uart_rxd; 
                    4'd8:   rxdata[7] <= uart_rxd; 
                    default:;
                endcase       
            end
            else
                rxdata <= rxdata;    
        end
        else
            rxdata <= 0;
    end
end
//最后将寄存的输出数据传给输出,并拉高输出完的标志位uart_done
always@(posedge sys_clk or negedge sys_rst_n)begin
    if(!sys_rst_n)begin
        uart_data <= uart_data;
		  uart_data1 <= 0;
        uart_done <= 0;
    end
    else begin
        if(rx_cnt == 4'd9)begin
            uart_data <= rxdata;
				uart_data1 <= ~rxdata;
            uart_done <= 1'b1; 
        end
        else begin
//            uart_data <= 0;
//				uart_data1 <= 0;
            uart_done <= 0;
        end
    end
end

检测是否接收到数据
//always@(posedge sys_clk or negedge sys_rst_n)
//if(!sys_rst_n)
//    begin
//        led3_out<=1;
//    end
else if(uart_done == 1'b1)
//else if(uart_data == 8'h89)
//    begin led3_out <= ~led3_out ; end

	
endmodule




 

按键检测模块

module key1_filter
#(
parameter CNT_MAX = 20'd999_999 //计数器计数最大值
)
(
input wire sys_clk , //系统时钟 50MHz
input wire sys_rst_n , //全局复位
input wire key1_in , //按键输入信号

output reg key1_flag //key1_flag 为 1 时表示消抖后检测到按键被按下
                       //key1_flag 为 0 时表示没有检测到按键被按下

 );


//按键消抖
reg [19:0] cnt_20ms ; //计数器

//cnt_20ms:如果时钟的上升沿检测到外部按键输入的值为低电平时,计数器开始计数
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_20ms <= 20'b0;
else if(key1_in == 1'b1)
cnt_20ms <= 20'b0;
else if(cnt_20ms == CNT_MAX && key1_in == 1'b0)
cnt_20ms <= cnt_20ms;
else
cnt_20ms <= cnt_20ms + 1'b1;
 
//key1_flag:当计数满 20ms 后产生按键有效标志位
//且 key1_flag 在 999_999 时拉高,维持一个时钟的高电平
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
  key1_flag <= 1'b0;
else if(cnt_20ms == CNT_MAX - 1'b1)
  key1_flag <= 1'b1;
else
  key1_flag <= 1'b0;


按键按的次数
//always@(posedge sys_clk or negedge sys_rst_n)
//if(sys_rst_n == 1'b0)
//  key1_value <= 4'd0;
//else if(key1_flag == 1'b1)
//  key1_value <= key1_value + 4'd1;
//else
//  key1_value <= 4'd0;
 
endmodule

总结

串口通信收发数据。

本文作者:cloud-sword

本文链接:https://www.cnblogs.com/cloud-sword/p/16407492.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   羽小兮  阅读(352)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起
  1. 1 404 not found REOL
404 not found - REOL
00:00 / 00:00
An audio error has occurred.

作曲 : Reol

作词 : Reol

fade away...do over again...

fade away...do over again...

歌い始めの一文字目 いつも迷ってる

歌い始めの一文字目 いつも迷ってる

どうせとりとめのないことだけど

伝わらなきゃもっと意味がない

どうしたってこんなに複雑なのに

どうしたってこんなに複雑なのに

噛み砕いてやらなきゃ伝わらない

ほら結局歌詞なんかどうだっていい

僕の音楽なんかこの世になくたっていいんだよ

Everybody don't know why.

Everybody don't know why.

Everybody don't know much.

僕は気にしない 君は気付かない

何処にももういないいない

Everybody don't know why.

Everybody don't know why.

Everybody don't know much.

忘れていく 忘れられていく

We don't know,We don't know.

目の前 広がる現実世界がまた歪んだ

目の前 広がる現実世界がまた歪んだ

何度リセットしても

僕は僕以外の誰かには生まれ変われない

「そんなの知ってるよ」

気になるあの子の噂話も

シニカル標的は次の速報

麻痺しちゃってるこっからエスケープ

麻痺しちゃってるこっからエスケープ

遠く遠くまで行けるよ

安定なんてない 不安定な世界

安定なんてない 不安定な世界

安定なんてない きっと明日には忘れるよ

fade away...do over again...

fade away...do over again...

そうだ世界はどこかがいつも嘘くさい

そうだ世界はどこかがいつも嘘くさい

綺麗事だけじゃ大事な人たちすら守れない

くだらない 僕らみんなどこか狂ってるみたい

本当のことなんか全部神様も知らない

Everybody don't know why.

Everybody don't know why.

Everybody don't know much.

僕は気にしない 君は気付かない

何処にももういないいない

Everybody don't know why.

Everybody don't know why.

Everybody don't know much.

忘れていく 忘れられていく

We don't know,We don't know.