FPGA解析B码----连载2

前言

    调试昨天编写的程序,主要分成3个部分。

    第一部分:按键产生8ms,5ms,2ms的脉宽信号;

    第二部分:脉宽采集;

    第三部分:脉宽采集值变换电平信号,也就是0,1,标志电平(2);

第一部分:脉宽产生

    此部分采用STM32产生的,按键由FPGA产生,按一下产生一个脉冲,3个按键,分别产生3冲脉宽波形。

 第二部分:脉宽采集和电平信号变换

     这部分今天调试之后发现几个问题,更新程序如下:

//脉宽的上升沿和下降沿检测
reg        bpluse_en_d0; 
reg        bpluse_en_d1; 
wire       bpluse_falling_flag;
wire       bpluse_rasing_flag;
assign bpluse_falling_flag = (~bpluse_en_d0) & bpluse_en_d1;
assign bpluse_rasing_flag  = (~bpluse_en_d1) & bpluse_en_d0;
always @(posedge clk or negedge rst_n) begin         
    if (!rst_n) begin
        bpluse_en_d0 <= 1'b0;                                  
        bpluse_en_d1 <= 1'b0; 
    end                                                      
    else begin                                               
        bpluse_en_d0 <= bcodein;                               
        bpluse_en_d1 <= bpluse_en_d0;
        		  
    end
end

    先是上升沿下降沿检测。

//置位time是否开启
reg        timebeginflag; 
always@(posedge clk or negedge rst_n)
begin
	if (rst_n == 1'b0)
		timebeginflag <= 1'd0;                     
	else if (bpluse_rasing_flag == 1'b1)      
    	timebeginflag <= 1'd1;                      
	else if (bpluse_falling_flag == 1'b1)
		timebeginflag <= 1'd0; 
end

    然后time标志位的开启,这点昨天编写有点问题,改过来了,因为上升沿和下降沿标志仅仅是一个脉冲信号,执行一个机器周期就没了,所以去掉了else。

//上升沿之后计数器工作,下降沿之后计数器停止
reg [31:0]      timer;
always@(posedge clk or negedge rst_n)
begin
	if (rst_n == 1'b0)
		timer <= 32'd0;                     
	else if (timebeginflag == 1'b1)      
    	timer <= timer + 32'd1;                     
	else if (timebeginflag == 1'b0)
		timer <= 0;             
end

    上升沿开启计数器,下降沿将计数器归0。这个地方后面再说,为啥能直接归0。这个地方非常重要,关乎到FPGA的运行方式问题。

reg  [3:0]  bcodelevel;  /*synthesis noprune*/
always@(posedge clk or negedge rst_n)
begin
	if (rst_n == 1'b0)begin
		bcodelevel <= 0; 
   end		
	else if (bpluse_falling_flag == 1'b1)begin
		if(timer >= 32'd350000)begin
		   bcodelevel <= 4'd3; //P电平
	   end
      else if(timer >= 32'd200000)begin
		   bcodelevel <= 4'd2; //1电平
		end	
		else if(timer >= 32'd50000 )begin
		   bcodelevel <= 4'd1; //0电平
		end
	   else begin
		   bcodelevel <= bcodelevel; //0电平
		end
	end
	else begin
		bcodelevel <= bcodelevel; //0电平
	end

    下降沿来的时候将time转换成电平,为了后面编程方便,0 1 标志电平对应数值1 2 3,没有脉宽的时候对应数值0。这个程序else里面也做了修改,昨天编写的是等于0,今天是数值不变。

    教训:今天调试结果一直等于0,找了半天原因,原因出来了两个:

    (1)硬件连线没有连接好,插错了管脚,以至于脉冲信号进不来;

    (2)else里面给置0了,下降沿和上升沿标志仅仅是个脉冲,仅仅执行一次,如果else置0,结果就是仅仅有1次time的数据是对的,其他时间都是0。所以修改成了赋值不变。

第三部分:锁存问题

    来源:FPGA每个模块都是并行设计,也就是不存在先执行哪个,后执行哪个。所以改变变量的时候,必须考虑到时序问题。这点也是编写while(1)不适应FPGA的方面。思维方式必须变回来。

    bpluse_falling_flag来的时候,将time锁存,但是同时又将time置0。那么会不会锁存到错误的time的值。bpluse_falling_flag先改变timebeginflag的值,这步非常关键,这样就将锁存的时间提前置0一个周期。

     观察每个周期的图可以发现,锁存的值并且判断高低电平时,先由3变成1,也就是标志电平变为0电平,而time延后了一个周期,就是因为timebeginflag的问题。如果没有这个标志的话,两个同时进行,会出现不定值,这点非常重要。但是如果没有这个标志位怎么办?

    解决办法:加入bpluse_falling_flag后启动另一个定时器,我将这个定时器称为扫尾定时器。

(*noprune*)reg  resettimebeginflag;
always@(posedge clk or negedge rst_n)
begin
	if (rst_n == 1'b0)
		resettimebeginflag <= 1'd0;                                          
	else if (bpluse_falling_flag == 1'b1)
		resettimebeginflag <= 1'd1; 
   else if (resettimer == 8'd10)
		resettimebeginflag <= 1'd0; 
end 

    先是:bpluse_falling_flag脉宽下降沿时启动定时器flag,在resettime等于10时关闭定时器flag。

(*noprune*)reg [7:0]  resettimer;
always@(posedge clk or negedge rst_n)
begin
	if (rst_n == 1'b0)
		resettimer <= 0;                     
	else if (resettimebeginflag == 1'b1)      
    	resettimer <= resettimer + 8'd1; 
	else if (resettimebeginflag == 1'b0)      
    	resettimer <= 0; 		
end

    再是:flag启动定时器,flag等于0时,resettime置0。

    这里的FPGA的特殊之处就体现出来了:一个模块只能改变一个变量的值,不能在两个模块里改变一个变量的值,会报错。所以只能两个套在一起。这样就会出现一个问题:怎么执行?按照机器周期执行,里面time等于10的时候会停止,其实是等于11的时候停止。这个是因为下个周期才会改变值的问题,这点非常重要,如果对clk要求非常重要的话,这个自己必须弄好。

    然后:捕捉下降沿。

reg        resettime_en_d0; 
reg        resettime_en_d1; 
wire       resettime_falling_flag;
wire       resettime_rasing_flag;
assign resettime_falling_flag = (~resettime_en_d0) & resettime_en_d1;
assign resettime_rasing_flag  = (~resettime_en_d1) & resettime_en_d0;
always @(posedge clk or negedge rst_n) begin         
    if (!rst_n) begin
        resettime_en_d0 <= 1'b0;                                  
        resettime_en_d1 <= 1'b0; 
    end                                                      
    else begin                                               
        resettime_en_d0 <= resettimebeginflag;                               
        resettime_en_d1 <= resettime_en_d0;
        		  
    end
end

    就会在开始的下降沿之后再出现一个下降沿,这样就能处理其他置位或者没有解决的问题了。当然也可以用其他办法,这个办法是延迟多少个周期再处理,可以灵活应用。

第四部分:总结

    解决了脉宽产生和采集方面的问题,并且第一次观察到FPGA周期的并行机制。希望小伙伴也能解决类似的问题。程序是昨天调试的,今天早上来了之后才刚刚解决这个问题。下面继续编写之后的程序,解决捕捉两个标志电平的问题。需要程序的小伙伴等到程序编写完之后会放上百度网盘链接。

    需要的话可以关注公众号,里面的历史消息中只有QT的程序,等编写完B码的FPGA采集后会发布对应的程序,需要的小伙伴可以关注下。

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值