在线咨询
eetop公众号 创芯大讲堂 创芯人才网
切换到宽版

EETOP 创芯网论坛 (原名:电子顶级开发网)

手机号码,快捷登录

手机号码,快捷登录

找回密码

  登录   注册  

快捷导航
搜帖子
查看: 3479|回复: 2

串口接收机,状态机出了奇怪问题!

[复制链接]
发表于 2007-3-29 16:09:10 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?注册

x
串口接收机,状态机出了奇怪问题!

我的串口接收机是以《verilog 高级程序设计》一书中实例为参考,加上自己的需要改进的;
接收数据格式固定,1起始位,8位数据位,1位停止位
并为下一级提供时钟;
一直使用良好,最近发现状态机出问题了,而且很怪;下面是我的程序,我尽量注释,希望不要浪费大家过多时间;
在程序之前我先陈述一下我的问题,:
1:再没加 红色代码以前,程序在我的机子,可以无误运行,起码在我测试的时间内,大概8个多小时吧!!但是换了太终端设备,就会出问题;
2:问题是,过一段不确定的时间后,写时钟 wirte_clock 不再存在,只是个低电平,需要重新复位,要不然无法正常工作;
3:于是我断定flag_clock 为零,因为我检测sample_clock正常有输出;
4:既然flag_clock为零,所以肯定没有在 idle态,因为serial_signal_in为1,要是在idle态,那肯定falg_clock不为零;
5:所以我家了这句   assign         temp  = !(idle^state); 发现temp在出问题后,temp = 0;说明不在idle态;
6:于是assign         temp  = !(starting^state); 奇怪出现了,wirte_clock 正常了,错误再也出现不了;
7:assign         temp  = !(sending^state); 也没问题;
8:于是我又回到assign         temp  = !(idle^state); ,问题又回来了;
9:所以我断定,肯定是状态机跑乱了,但我又不知道是怎么跑乱的,我程序中加的红色部分对状态机有什么影响??
module portkUARR9_6k(serial_signal_in,
                                 sample_clock,
                                 reset,
                                 paraller_signal_out,
                                 write_clock,
                                 w_rst,
                                 temp                               //测试口
                                 );
                 
parameter     width_signal_out  =  8;                        //接收机并行输出8为数据
parameter     width_sample_count=  4;                    //控制采样时钟的寄存器宽度
parameter     width_bit_count   =  4;                       //控制输出位数的寄存器宽度
parameter     all_ones          =8'b11111111;
parameter     idle              =2'b00;
parameter     starting          =2'b01;
parameter     receving          =2'b10;
                     
input         serial_signal_in;              //串行输入信号
input         sample_clock;               //采样时钟
input         reset;                         //同步复位

           
output        [width_signal_out-1:0] paraller_signal_out;     //并行输出数据
output        write_clock;                                             //为下一级提供写时钟
output        w_rst;                                                     //为下一级提供写标志
output        temp;                                                     //测试端口

reg           [width_signal_out-1:0]  Rec_datareg; //数据寄存器,
reg           [width_signal_out-1:0]  Rec_shftreg;  //移位寄存器
reg           [width_sample_count-1:0]sample_counter;     //采样计数器
reg           [width_bit_count-1:0]   Bit_counter;      //输出位数计数器

                                      
reg            clr_Sample_counter,inc_Sample_counter;
reg            clr_Bit_counter,inc_Bit_counter;
reg            shift,load;  
reg            flag_wclk;
reg            w_rst,w_rst1;
reg            write_clock;
reg            [1:0]state,next_state;


assign         paraller_signal_out  =  Rec_datareg;     //把接收到的8位数据送出
assign         temp  = !(starting^state);     //这一句是后来加的,

always  @(state or serial_signal_in or sample_counter or Bit_counter)                              //为每一次数据的流动提供状态
        begin                     //所有状态赋 0 值
                        clr_Sample_counter = 0;
                         shift       = 0;
                          load        = 0;
                           flag_wclk   = 0;
                         //w_rst              = 0;
                          inc_Sample_counter = 0;
                          clr_Bit_counter    = 0;
                          inc_Bit_counter    = 0;
                          w_rst1             = 0;
                          next_state         = state;
      case(state)
         idle:    if(serial_signal_in == 0)
                 begin
                     next_state = starting;
                     clr_Sample_counter = 1;             //校正采样寄存器,找到一个合适的采样起始时刻
                 end  else
                     begin
                         //next_state =  idle;
                         if(sample_counter>7)            //在没有数据输入的情况下,提供时钟,
                             begin
                                clr_Sample_counter = 1; //
                                flag_wclk          = 1;      //
                                w_rst1             = 1;     //
                      end  else
                             inc_Sample_counter = 1;//  以上几段其实相当于分频
                      end
           
          starting:if(serial_signal_in == 1)begin
                     next_state = idle;
                      clr_Sample_counter = 1;
                    end else
                          begin
                               next_state = receving;
                               clr_Sample_counter = 1;        
                           end
          receving:if(sample_counter<7) //  
                              inc_Sample_counter = 1;
                      else begin
                             clr_Sample_counter = 1;
                            //shift              = 1;
                             if(Bit_counter!= 8)begin
                             inc_Bit_counter    = 1;
                             shift              = 1;
                     end else
                            begin
                                clr_Bit_counter    = 1;
                                next_state         = idle;
                                load               = 1;
                                flag_wclk          = 1;
                           end
                      end
      default:next_state = idle;
     endcase
   
   end
                 

always  @(posedge load  or posedge w_rst1)   //当采集到数据,即load == 1;
  if(w_rst1)w_rst              = 0;
         else w_rst              = 1;                      //写标志使能

always  @(posedge  sample_clock)
        begin
         if(reset==0)                                      //复位时完成的操作
               begin
                     Rec_shftreg<=all_ones;
                     Rec_datareg<=all_ones;
                     sample_counter<=0;
                     Bit_counter <=0;
                     state<=idle;
                     write_clock <= 0;
               end else
                   begin
           
                          state<=next_state;
                          if(clr_Sample_counter) sample_counter <= 0;
                          else if(inc_Sample_counter==1) sample_counter<=sample_counter+1;   //采样时钟计数
                            if(clr_Bit_counter==1)     Bit_counter <= 0;      
                            else if(inc_Bit_counter == 1)  Bit_counter <= Bit_counter+1;           //采样到的数据 计数,
                             if(shift==1)  Rec_shftreg <= {serial_signal_in,Rec_shftreg[width_signal_out-1:1]}; //采样
                             if(load ==1)  Rec_datareg <= Rec_shftreg;//取数
                  
                             if(flag_wclk ==1)   write_clock <= 1; //时钟
                             else write_clock <= 0;
                  end                     
   end
                                    
endmodule
 楼主| 发表于 2007-3-31 13:05:02 | 显示全部楼层
虽然处于无奈,贴了贴,但自己仍然不敢怠慢!
最近研究可以确定是,
state进入了亚稳态,再也出不来了,
但是  assgin  state^startting,如何让state逃离亚稳态,自己还不是很明白!

等待中!。。。。。
发表于 2007-4-2 12:51:30 | 显示全部楼层
hehe,在这里又见面了。

看了一下,头都大了。。
代码风格不大好,这是造成设计不稳定的主要原因。
如果你再换台机子,再换个终端,说不定加了红色的后,又不稳定了。

几点建议
1.serial_signal_in 通过本地时钟双ff寄存同步后再使用(这个信号是唯一的异步信号,如果出了亚稳态的问题,多半是由它引起的)。
2.把状态机编码方式改成gray码

[ 本帖最后由 wice3 于 2007-4-2 13:39 编辑 ]
您需要登录后才可以回帖 登录 | 注册

本版积分规则

关闭

站长推荐 上一条 /2 下一条


小黑屋| 手机版| 关于我们| 联系我们| 在线咨询| 隐私声明| EETOP 创芯网
( 京ICP备:10050787号 京公网安备:11010502037710 )

GMT+8, 2024-11-22 09:50 , Processed in 0.017921 second(s), 6 queries , Gzip On, Redis On.

eetop公众号 创芯大讲堂 创芯人才网
快速回复 返回顶部 返回列表