串口接收机,状态机出了奇怪问题!
时间:10-02
整理:3721RD
点击:
串口接收机,状态机出了奇怪问题!
我的串口接收机是以《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:所以我家了这句assigntemp= !(idle^state); 发现temp在出问题后,temp = 0;说明不在idle态;
6:于是assigntemp= !(starting^state); 奇怪出现了,wirte_clock 正常了,错误再也出现不了;
7:assigntemp= !(sending^state); 也没问题;
8:于是我又回到assigntemp= !(idle^state); ,问题又回来了;
9:所以我断定,肯定是状态机跑乱了,但我又不知道是怎么跑乱的,我程序中加的红色部分对状态机有什么影响?
module portkUARR9_6k(serial_signal_in,
sample_clock,
reset,
paraller_signal_out,
write_clock,
w_rst,
temp//测试口
);
parameterwidth_signal_out=8;//接收机并行输出8为数据
parameterwidth_sample_count=4;//控制采样时钟的寄存器宽度
parameterwidth_bit_count=4;//控制输出位数的寄存器宽度
parameterall_ones=8'b11111111;
parameteridle=2'b00;
parameterstarting=2'b01;
parameterreceving=2'b10;
inputserial_signal_in;//串行输入信号
inputsample_clock;//采样时钟
inputreset;//同步复位
output[width_signal_out-1:0] paraller_signal_out;//并行输出数据
outputwrite_clock;//为下一级提供写时钟
outputw_rst;//为下一级提供写标志
outputtemp;//测试端口
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;//输出位数计数器
regclr_Sample_counter,inc_Sample_counter;
regclr_Bit_counter,inc_Bit_counter;
regshift,load;
regflag_wclk;
regw_rst,w_rst1;
regwrite_clock;
reg[1:0]state,next_state;
assignparaller_signal_out=Rec_datareg;//把接收到的8位数据送出
assigntemp= !(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;//校正采样寄存器,找到一个合适的采样起始时刻
endelse
begin
//next_state =idle;
if(sample_counter>7)//在没有数据输入的情况下,提供时钟,
begin
clr_Sample_counter = 1; //
flag_wclk= 1;//
w_rst1= 1;//
endelse
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 loador posedge w_rst1)//当采集到数据,即load == 1;
if(w_rst1)w_rst= 0;
else w_rst= 1;//写标志使能
always@(posedgesample_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
我的串口接收机是以《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:所以我家了这句assigntemp= !(idle^state); 发现temp在出问题后,temp = 0;说明不在idle态;
6:于是assigntemp= !(starting^state); 奇怪出现了,wirte_clock 正常了,错误再也出现不了;
7:assigntemp= !(sending^state); 也没问题;
8:于是我又回到assigntemp= !(idle^state); ,问题又回来了;
9:所以我断定,肯定是状态机跑乱了,但我又不知道是怎么跑乱的,我程序中加的红色部分对状态机有什么影响?
module portkUARR9_6k(serial_signal_in,
sample_clock,
reset,
paraller_signal_out,
write_clock,
w_rst,
temp//测试口
);
parameterwidth_signal_out=8;//接收机并行输出8为数据
parameterwidth_sample_count=4;//控制采样时钟的寄存器宽度
parameterwidth_bit_count=4;//控制输出位数的寄存器宽度
parameterall_ones=8'b11111111;
parameteridle=2'b00;
parameterstarting=2'b01;
parameterreceving=2'b10;
inputserial_signal_in;//串行输入信号
inputsample_clock;//采样时钟
inputreset;//同步复位
output[width_signal_out-1:0] paraller_signal_out;//并行输出数据
outputwrite_clock;//为下一级提供写时钟
outputw_rst;//为下一级提供写标志
outputtemp;//测试端口
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;//输出位数计数器
regclr_Sample_counter,inc_Sample_counter;
regclr_Bit_counter,inc_Bit_counter;
regshift,load;
regflag_wclk;
regw_rst,w_rst1;
regwrite_clock;
reg[1:0]state,next_state;
assignparaller_signal_out=Rec_datareg;//把接收到的8位数据送出
assigntemp= !(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;//校正采样寄存器,找到一个合适的采样起始时刻
endelse
begin
//next_state =idle;
if(sample_counter>7)//在没有数据输入的情况下,提供时钟,
begin
clr_Sample_counter = 1; //
flag_wclk= 1;//
w_rst1= 1;//
endelse
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 loador posedge w_rst1)//当采集到数据,即load == 1;
if(w_rst1)w_rst= 0;
else w_rst= 1;//写标志使能
always@(posedgesample_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
虽然处于无奈,贴了贴,但自己仍然不敢怠慢!
最近研究可以确定是,
state进入了亚稳态,再也出不来了,
但是assginstate^startting,如何让state逃离亚稳态,自己还不是很明白!
等待中!。
hehe,在这里又见面了。
看了一下,头都大了。
代码风格不大好,这是造成设计不稳定的主要原因。
如果你再换台机子,再换个终端,说不定加了红色的后,又不稳定了。
几点建议
1.serial_signal_in 通过本地时钟双ff寄存同步后再使用(这个信号是唯一的异步信号,如果出了亚稳态的问题,多半是由它引起的)。
2.把状态机编码方式改成gray码