这里写一个ask 的调制解调,首先是主要关于ASK在抽样判决的逻辑的撰写,
:首先在没有接收到数据的时候,我们的收到的信号肯定的是比较小的值(因为噪声应该是比较的值)。
所以我们这里要先设计一个开始逻辑,就是什么时候才是接收到数据,而不是空的噪声。
思路:这里是对接收到的值进行一个累加,然后取平均值,再设一个门限值,如果这个平均值大于前一个门限值,就是代表有数据进来的,而不是全是噪音了,接下来就可以进行符号判别了。当检测到有数据输入后,我们就要开始取样判决了。
这是一些自己画的波形:
下面给出代码并给与
// 实际只需要累加到8192,但是多加2个时钟周期,是为了后面累加与判决门限值
always @(posedge sclk) begin
if (rst_n == 1'b0) begin
work_cnt <='d0;
end else if(work_on == 1'b1) begin
work_cnt <= 'd0;
end else if (work_cnt == 'd8194) begin
work_cnt <= 'd0;
end else begin
work_cnt <= work_cnt + 1'b1;
end
end
//acc the din_data to acquire the gate
//
always@(posedge sclk )begin
if(rst_n == 1'b0)begin
work_sum <= 33'd0 ;
end else if(work_on == 1'b1)begin
work_sum <= 'd0;
end else if(work_cnt == 'd8194)begin //获得了一次门限值后清零
work_sum <= 'd0;
end else if(work_cnt == 'd8193)begin //保持
work_sum <= work_sum;
end else if(work_cnt == 'd8192) begin //输入值累加8192次,然偶除以8192,取平均值。
work_sum <= work_sum >> 13;
end else if(work_on == 1'b0)begin
work_sum <= work_sum + dina_t;
end
end
always@(posedge sclk )begin
if(rst_n == 1'b0)begin
work_gate <= 23'h7f_ffff; //23位的最大值
end else if(work_cnt == 'd8193) begin
work_gate <= {work_sum[20:0],2'b00}; //门限值是8192次数据的4倍
end //在8193时候进行更新wor_gate值,(所以万一没有检测到,下次这么大会开启?)
end
//
always@(posedge sclk )begin
if(rst_n == 1'b0)begin
work_on <= 1'b0;
end else if(byte_cnt > 1'b1 && byte_cnt == (data_len + 1) && byte_flag == 1'b1 )begin
work_on <= 1'b0;
end else if(detect_sync_cnt == 'd52000 && sync_flag == 1'b0) begin
//end else if(detect_sync_cnt == 'd52000 && sync_flag == 1'b1) begin
work_on <= 'd0;
end else if(work_cnt == 'd8193 && (work_sum > work_gate)) begin //当计数到8193,此时work_gate
work_on <= 1'b1; ///还是原来的值,上一个门限值
end //。
end
取样判决:首先符号的判断门限值选取,可以选择均值,但是均值门限值的选取肯定要大于一个符号周期,其次这样才能保证符号判决的正确,否则取均值长度过小导致判决门限值变化很快,导致判据出错。且如果连续发送多个 0 时,接收到的波形值都比较小,再取均值就可能导致判决门限过小,从而导致判决错误,所以对于符号周期比较长
的系统来说取均值的方法就不太适用了。这里是选取的5个符号周期的最大值的1/4的作为门限值。并且这个门限值也是5个符号周期更新一次,使用此统计门限值用于检测到同步头前的判决。检测到同步头之后更新的值小于旧的门限值的二分之一或更新的值大于旧的门限值的二倍,仍保持旧的门限值,等待下一次更新。这样能保证在一个符号周期内只有一个判决值,且发送多个 0 时,不会产生误判。
判断过程:由于我们的使用的设备是一个符号对应800个时钟周期,所以我们要设计一个计数器计数5个符号周期,然后设置一个标志位,每5个符号周期翻转一次,这样分别在标志位位0,1时分别找到5个符号周期的最大值,并且在一个启动了帧同步后才开始进行比较,在计数时到5个符号周期结束时开始与上一次的最大值2倍
牢记:在进行门限值赋值时,一定是等于上5个符号周期的最大值的1/4,这里要牢记(调试了2天,呜呜呜);这里一给出一些重要的逻辑波形图
下面也给出一些逻辑代码
//统计5个符号周期的平均功率作为平均功率作为符号判决标准
//由于我们的AD9361设置为了单通道模式,采样时钟为40M,
//由于两个时钟才能传,完一个 12 位的有效数据,
//所以实际的时钟频率为 80MHz,
//符号周期为 800 个时钟
//在 adc_valid 为低时
//数据保持,这样就当作有效数据被复制一次使用,也就是说数据频率为 100Kbps
//时,符号周期为 800 个时钟.
//所以我们这里统计5个符号周期的需要用计数器计数计数4000,即0到3999
//
//判决门限
always@(posedge sclk )begin
if(rst_n == 1'b0)begin
gate_cnt <= 'd0;
end else if(work_on == 1'b0) begin
gate_cnt <= 'd0;
end else if(work_on == 'd3999) begin
gate_cnt <= 'd0;
end else begin
gate_cnt <= gate_cnt + 1'b1;
end
end
//计数到4000,取5个符号周期,要取两个的值进行比较,所以要进行翻转
always@(posedge sclk )begin
if(rst_n == 1'b0)begin
gate_flag <= 1'b0;
end else if(work_on == 1'b0)begin
gate_flag <= 1'b0;
end else if(gate_cnt == 'd3999) begin
//gate_flag <= 1'b1;
gate_flag <= ~gate_flag;
end
end
// delay a clk
always@(posedge sclk )begin
gate_flag_t <= gate_flag;
end
//
always@(posedge sclk )begin
if(rst_n == 1'b0)begin
gate_a <= 'd0;
end else if(gate_flag_t == 1'b1 && gate_flag == 1'b0)begin //下降沿
gate_a <= 'd0; //将门限值的最大值清零
end else if(sync_flag == 1'b1 && gate_cnt == 'd3999 && gate_flag == 1'b0)begin //判断准则,若这个周期内的最大值大于
if(gate_a > (gate_b << 1) || gate_a < (gate_b >> 1))begin //大于上个周期的最大值的2倍或者小于其最小值
gate_a <= gate_b; //的1/2,就将gate_b赋值给gate_b
end
end else if(dina_tvalid == 1'b1 && gate_flag == 1'b0) begin //在5个符号周期内,比较其值
if(gate_a < dina_t)begin //找出输入数据的最大值,然后赋值给gate_a
gate_a <= dina_t;
end else begin
gate_a <= gate_a;
end
end
end
//
always@(posedge sclk )begin
if(rst_n == 1'b0)begin
gate_b <= 'd0;
end else if(gate_flag_t == 1'b0 && gate_flag == 1'b1)begin //上升沿 //gate_b 开始时计数
gate_b <= 'd0; // clear 0
end else if(sync_flag == 1'b1 && gate_cnt == 'd3999 && gate_flag == 1'b1)begin //判断准则,若这个周期内的最大值大于
if(gate_b > (gate_a << 1) || gate_b < (gate_a >> 1))begin //大于上个周期的最大值的2倍或者小于其最小值
gate_b <= gate_a; //的1/2,就将gate_b赋值给gate_b
end
//end else if(dina_tvalid == 1'b1 && gate_flag == 1'b0) begin //在下一个5个符号周期内,比较其值
end else if(dina_tvalid == 1'b1 && gate_flag == 1'b1) begin
if(gate_b < dina_t)begin //找出输入数据的最大值,然后赋值给gate_b
gate_b <= dina_t; //
end else begin
gate_b <= gate_b;
end
end
end
//用上述所取出来的值的1/4作为判决值,
//always@(posedge sclk )begin
// if(rst_n == 1'b0)begin
// gate_t <= 'd0;
// end else if(gate_flag == 1'b0) begin
// gate_t <= gate_a >> 2;
// gate_t <= gate_b >> 2;
//end
//用上述所取出来的值的1/4作为判决值,
//这里的门限值是与上一次比较,不是与现在的比较,切记,切记,这里调试了2天,一直没有找到问题
always@(posedge sclk )begin
if(rst_n == 1'b0)begin
gate_t <= 'd0;
end else if(gate_flag == 1'b1) begin
gate_t <= gate_a >> 2;
end else if(gate_flag == 1'b0) begin
gate_t <= gate_b >> 2;
end
end
/// 这里为判决
always@(posedge sclk )begin
if(rst_n == 1'b0)begin
bit_in<= 1'b0;
end else if(dina_t >= gate_t) begin
bit_in <= 1'b1;
end else begin
bit_in <= 1'b0;
end
end
重点:
符号采样:符号采样,我们应该在每个符号周期采样一次,并且尽可能的在一个符号周期的中间进行采样,因为我们的符号周期对应我们的800个时钟周期,所以我们需要一个符号的计数器,在计数到400就进行采样。但是在实际的过程的中,我们就收的数据并不是突变的,而是缓慢的变化,所以说所以判决出的每一个二进制数据并不是刚好等于400的,可能多也可能少,这就需要设计一个补偿的机制,来保证符号采样在判决后的二进制数据的正中间。
判决机制:对于判决出来的bit进行计数,只要变化,计数器就清零,重新开始计数,并且计数到800个时钟周期也清零,接下来进行。
(1)数据保持:就是出来的一直保持一个状态,比如连续的几个0或者1,这样就是前面我们的符号计数器计数到800,然后除以2(左移1位),就是一个符号的正中间,就可以进行判决
(2):当边沿变化时,计数值比较小时(小于400),我们可以将他认为是上一个bit的延展,
(3):当边沿变化时,计数值比较大(大于400小于799)时,要将此时的计数值除以二时,这个时刻为判决的时刻。
代码:
//利用fifo 来进行延拍,800个时钟周期
instance fifo /
// fifo wr: 1 x 1024
//
sfifo_wr1x1024 sfifo_wr1x1024_inst (
.clk(sclk), // input wire clk
.din(bit_in), // input wire [0 : 0] din
.wr_en(wr_fifo_en), // input wire wr_en
.rd_en(rd_fifo_en), // input wire rd_en
.dout(bit_delay), // output wire [0 : 0] dout
.full(full), // output wire full
.empty(empty) // output wire empty
);
//
always@(posedge sclk )begin
if(rd_fifo_en == 1'b1 )begin
bit_delay_t <= bit_delay;
end else begin
//bit_delay_t <=bit_delay_t;
bit_delay_t <='d0;
end
end
//当work on == 1 时,开始写FIFO
always@(posedge sclk )begin
if(rst_n == 1'b0)begin
wr_fifo_en <= 1'd0;
end else if(work_on == 1'b0) begin
wr_fifo_en <= 1'd0;
end else begin
wr_fifo_en <= 1'd1;
end
end
//------------------------
//从fifo里面读取出来的数据进行一个延拍
//--------------------------
always@(posedge sclk)begin
bit_in_t <= bit_in;
end
//判断数据的上升沿与下降沿
always@(posedge sclk )begin
//if(rst_n == 1'b0)begin
// rising <= 1'b0 ;
//end else
if(work_on == 1'b0) begin
rising <= 1'b0 ;
end else if(bit_in == 1'b1 && bit_in_t == 1'b0) begin
rising <= 1'b1 ;
end else begin
rising <= 1'b0;
end
end
///
always@(posedge sclk )begin
//if(rst_n == 1'b0)begin
// falling <= 1'b0 ;
// end else
if(work_on == 1'b0) begin
falling <= 1'b0 ;
end else if(bit_in == 1'b0 && bit_in_t == 1'b1) begin
falling <= 1'b1 ;
end else begin
falling <= 1'b0;
end
end
//判断两个沿之间的时钟数,取样时尽可能取一个数据的中间的那位
always@(posedge sclk )begin
if(rst_n == 1'b0)begin
count <= 'd0;
end else if(work_on == 1'b0) begin
count <= 'd0;
end else if(rising == 1'b1 || falling == 1'b1)begin
count <= 'd0;
end else if(count == 'd799) begin
count <= 'd0;
end else begin
count <= count +1'b1;
end
end
// 采样计数器,判决在何时取样
always@(posedge sclk )begin
if(rst_n == 1'b0)begin
samp_count <= 'd0;
end else if(work_on == 1'b0) begin
samp_count <= 'd0;
end else if(count == 'd799) begin
samp_count <= 'd399;
end else if(rising == 1'b1 ||falling == 1'b1)begin
if(count < 'd400) begin //超过了一个符号周期的长度
samp_count <= (800 + count ) >> 1;
end else if (count >= 'd400) begin
samp_count <= (count >>1); //不足一个符号周期的长度
end
end
end
//利用FIFO,将读使能延迟一个符号周期
always@(posedge sclk ) begin
if(rst_n == 1'b0)begin
rd_delay_cnt <= 'd0;
end else if(work_on == 1'b0)begin
rd_delay_cnt <= 'd0;
end else if(rd_delay_cnt == 'd800)begin
// rd_delay_cnt <= rd_delay_cnt;
rd_delay_cnt <= 'd800;
end else if(wr_fifo_en == 1'b1)begin
rd_delay_cnt <= rd_delay_cnt + 1'b1;
end
end
//写使能一个符号周期后,开启读使能
always@(posedge sclk )begin
if(rst_n == 1'b0)begin
rd_fifo_en <= 'd0 ;
end else if(empty == 1'b1)begin
rd_fifo_en <= 'd0 ;
end else if(rd_delay_cnt == 'd799) begin
rd_fifo_en <= 1'b1;
end
end
// fifo出来的数据,延迟了一个符号周期,判断其上升沿
always@(posedge sclk )begin
if(rst_n == 1'b0)begin
rising_delay <= 1'b0;
end else if(rd_fifo_en == 1'b0) begin
rising_delay <= 1'b0;
end else if(bit_delay == 1'b1 && bit_delay_t ==1'b0)begin
rising_delay <= 1'b1;
end else begin
rising_delay <= 1'b0;
end
end
always @(posedge sclk) begin
if(rd_fifo_en == 1'b1 ) begin
bit_delay_t <= bit_delay;
end
end
// fifo出来的数据,延迟了一个符号周期,判断其下降沿
always@(posedge sclk )begin
if(rst_n == 1'b0)begin
falling_delay <= 1'b0;
end else
if(rd_fifo_en == 1'b0) begin
falling_delay <= 1'b0;
end else if(bit_delay == 1'b0 && bit_delay_t ==1'b1)begin
falling_delay <= 1'b1;
end else begin
falling_delay <= 1'b0;
end
end
//这个没懂,为啥子要延迟
always@(posedge sclk )begin
if(rst_n == 1'b0)begin
count_delay <= 'd0;
end else if(rd_fifo_en == 1'b0) begin
count_delay <= 'd0;
end else if(falling_delay == 1'b1 || rising_delay == 1'b1) begin
count_delay <= 'd0;
end else if(count_delay == 'd799) begin
count_delay <= 'd0;
end else begin
count_delay <= count_delay + 1'b1;
end
end
//采样标志位
always@(posedge sclk )begin
if(rst_n == 1'b0)begin
samp_flag <= 1'd0;
end else if(rd_fifo_en == 1'b0) begin
samp_flag <= 1'd0;
end else if(rd_fifo_en == 1'b1 && count_delay == samp_count) begin
samp_flag <= 1'd1;
end else begin
samp_flag <= 1'd0;
end
end
由于我们发送的数据帧格式是7个巴克玛还有一个数据头(D5)(1101_0101),要检测到了之后才是真正的数据。
取样判决后我们进行数据头部巴克玛与数据头都直接用一个状态机检测,如果帧头部与数据头都检测完,下面就可以开启帧同步标志了,下面接收到的数据就是我们发送的数据了。
由于我们的数据是1帧数据8位,所以下面我们要进行判断数据的大小,只需要设计一个计数器,判决出8个数据拉高一个标志就行了
下面代码为检测巴克玛与数据头代码
always@(posedge sclk)begin
if(rst_n == 1'b0) begin
barker_state <= BS0;
end
if(rd_fifo_en == 1'b0 || sync_flag == 1'b1) begin
barker_state <= BS0;
end else begin //1110010 检测巴克玛
case(barker_state)
BS0:begin
if(samp_flag == 1'b1 && bit_delay_t == 1'b1)begin
barker_state <= BS1;
end else if(samp_flag == 1'b1 && bit_delay_t == 1'b0) begin
barker_state <= BS0;
end
end
BS1:begin
if(samp_flag == 1'b1 && bit_delay_t == 1'b1)begin
barker_state <= BS2;
end else if(samp_flag == 1'b1 && bit_delay_t == 1'b0) begin
barker_state <= BS0;
end
end
BS2:begin
if(samp_flag == 1'b1 && bit_delay_t == 1'b1)begin
barker_state <= BS3;
end else if(samp_flag == 1'b1 && bit_delay_t == 1'b0) begin
barker_state <= BS0;
end
end
BS3:begin
if(samp_flag == 1'b1 && bit_delay_t == 1'b0)begin
barker_state <= BS4;
end else if(samp_flag == 1'b1 && bit_delay_t == 1'b1) begin
barker_state <= BS0;
end
end
BS4:begin
if(samp_flag == 1'b1 && bit_delay_t == 1'b0)begin
barker_state <= BS5;
end else if(samp_flag == 1'b1 && bit_delay_t == 1'b1) begin
barker_state <= BS0;
end
end
BS5:begin
if(samp_flag == 1'b1 && bit_delay_t == 1'b1)begin
barker_state <= BS6;
end else if(samp_flag == 1'b1 && bit_delay_t == 1'b0) begin
barker_state <= BS0;
end
end
BS6:begin
if(samp_flag == 1'b1 && bit_delay_t == 1'b0)begin
barker_state <= BS7;
end else if(samp_flag == 1'b1 && bit_delay_t == 1'b1) begin
barker_state <= BS0;
end
end
BS7:begin
barker_state <= BS0;
end
default:barker_state <= BS0;
endcase
end
end
//sync
always@(posedge sclk )begin //1101_0101
if(rst_n == 1'b0)begin
sync_state <= SS0;
end else if(rd_fifo_en == 1'b0 || sync_flag == 1'b1) begin
sync_state <= SS0;
end else begin//d5:1101 0101
case(sync_state)
SS0:begin
if(samp_flag == 1'b1 && bit_delay_t == 1'b1)begin
sync_state <= SS1;
end else if(samp_flag == 1'b1 && bit_delay_t == 1'b0) begin
sync_state <= SS0;
end
end
SS1:begin
if(samp_flag == 1'b1 && bit_delay_t == 1'b1)begin
sync_state <= SS2;
end else if(samp_flag == 1'b1 && bit_delay_t == 1'b0) begin
sync_state <= SS0;
end
end
SS2:begin
if(samp_flag == 1'b1 && bit_delay_t == 1'b0)begin
sync_state <= SS3;
end else if(samp_flag == 1'b1 && bit_delay_t == 1'b1) begin
sync_state <= SS0;
end
end
SS3:begin
if(samp_flag == 1'b1 && bit_delay_t == 1'b1)begin
sync_state <= SS4;
end else if(samp_flag == 1'b1 && bit_delay_t == 1'b0) begin
sync_state <= SS0;
end
end
SS4:begin
if(samp_flag == 1'b1 && bit_delay_t == 1'b0)begin
sync_state <= SS5;
end else if(samp_flag == 1'b1 && bit_delay_t == 1'b1) begin
sync_state <= SS0;
end
end
SS5:begin
if(samp_flag == 1'b1 && bit_delay_t == 1'b1)begin
sync_state <= SS6;
end else if(samp_flag == 1'b1 && bit_delay_t == 1'b0) begin
sync_state <= SS0;
end
end
SS6:begin
if(samp_flag == 1'b1 && bit_delay_t == 1'b0)begin
sync_state <= SS7;
end else if(samp_flag == 1'b1 && bit_delay_t == 1'b1) begin
sync_state <= SS0;
end
end
SS7:begin
if(samp_flag == 1'b1 && bit_delay_t == 1'b1)begin
sync_state <= SS8;
end else if(samp_flag == 1'b1 && bit_delay_t == 1'b0) begin
sync_state <= SS0;
end
end
SS8:begin
sync_state <= SS0;
end
default:begin
sync_state <= SS0;
end
endcase
end
end