原创 串口调试总结

2012-3-28 09:03 1060 7 7 分类: FPGA/CPLD

最近想跑个串口玩来着,找一些网上程序来用,没想到调了将近3周,要了亲命,终于调好,抽空总结一下吧。调试过程中对接口协议有了一定了解,对芯片max232了解还是比较深入的

最流行的串口程序,用了特权同学程序,直接用来跑,果断不行啊,然后仔细看了遍程序,发现一些问题,程序计数中算了校验位,却没有对校验位进行传输,上位机上自然还要设置校验位(odd奇,even偶);后面以为还有一个错误,后来发现是自己的问题,对阻塞,非阻塞理解不够啊,num<=num+1;case(num) ,num状态是从0开始啊(而不是1),又自己去写了一个,还是调不通。

又去找了一个  经验证版的,思想比上面的都简练很多,也很容易读懂,试了下,不行,换了个串口,发现重大突破了,竟让5个码能收对3个了,试着把上位机的停止位设成两位,OK了,好吧,把这个简练的程序各模块贴出来,各模块用原理图方式连接起来更方便,用语言写也可以的啦。本人是40M晶振,调了这么长时间,原来垃圾的坏串口真是坑爹死了。后来用新串口试了特权的程序,也跑通了。下面这个程序虽然长点,但是思想简单,没有绕太多。真心话,特权同学的程序绕太多了

总的来说,对于串口传输,主要还是按着时钟频率,计数,依次按bit接收和发送数据,用case语句控制较好,各大程序中,最大的差异还是在对波特率的书写上,发送阶段自然和上位机采用相同的波特率,接收阶段需要16*波特率,数据的中间点进行采样,相当于的到的数据还是以与上位机是相同的波特率(频率),好吧我承认这东西不难,是我太笨了,调了这长时间

  采样时钟模块:

module clkdiv(clk, clkout);

input clk;          //系统时钟

output clkout;      //采样时钟输出

reg clkout;

reg [15:0] cnt;

always @(posedge clk)   //分频进程

begin

if(cnt == 16'd130)

begin

clkout <= 1'b1;

cnt <= cnt + 16'd1;

end

else if(cnt == 16'd260)

begin

clkout <= 1'b0;

cnt <= 16'd0;

end

else

begin

cnt <= cnt + 16'd1;

end

end

endmodule

 

发送模块:

module uarttx(clk, datain, wrsig, idle, tx);

input clk;          //UART时钟

input [7:0] datain; //需要发送的数据

input wrsig;        //发送命令,上升沿有效

output idle;        //线路状态指示,高为线路忙,低为线路空闲

output tx;          //发送数据信号

reg idle, tx;

reg send;

reg wrsigbuf, wrsigrise;

reg presult;

reg[7:0] cnt;       //计数器

parameter paritymode = 1'b0;

//检测发送命令是否有效

always @(posedge clk)

begin

wrsigbuf <= wrsig;

wrsigrise <= (~wrsigbuf) & wrsig;

end

always @(posedge clk)

begin

if (wrsigrise &&  (~idle))  //当发送命令有效且线路为空闲时,启动新的数据发送进程

begin

send <= 1'b1;

end

else if(cnt == 8'd176)      //一帧资料发送结束

begin

send <= 1'b0;

end

end

always @(posedge clk)

begin

if(send == 1'b1)

begin

case(cnt)       //产生起始位

8'd0:

begin

tx <= 1'b0;

idle <= 1'b1;

cnt <= cnt + 8'd1;

end

8'd16:

begin

tx <= datain[0];    //发送数据0位

presult <= datain[0]^paritymode;

idle <= 1'b1;

cnt <= cnt + 8'd1;

end

8'd32:

begin

tx <= datain[1];    //发送数据1位

presult <= datain[1]^presult;

idle <= 1'b1;

cnt <= cnt + 8'd1;

end

8'd48:

begin

tx <= datain[2];    //发送数据2位

presult <= datain[2]^presult;

idle <= 1'b1;

cnt <= cnt + 8'd1;

end

8'd64:

begin

tx <= datain[3];    //发送数据3位

presult <= datain[3]^presult;

idle <= 1'b1;

cnt <= cnt + 8'd1;

end

8'd80:

begin

tx <= datain[4];    //发送数据4位

presult <= datain[4]^presult;

idle <= 1'b1;

cnt <= cnt + 8'd1;

end

8'd96:

begin

tx <= datain[5];    //发送数据5位

presult <= datain[5]^presult;

idle <= 1'b1;

cnt <= cnt + 8'd1;

end

8'd112:

begin

tx <= datain[6];    //发送数据6位

presult <= datain[6]^presult;

idle <= 1'b1;

cnt <= cnt + 8'd1;

end

8'd128:

begin

tx <= datain[7];    //发送数据7位

presult <= datain[7]^presult;

idle <= 1'b1;

cnt <= cnt + 8'd1;

end

8'd144:

begin

tx <= presult;      //发送奇偶校验位

presult <= datain[0]^paritymode;

idle <= 1'b1;

cnt <= cnt + 8'd1;

end

8'd160:

begin

tx <= 1'b1;     //发送停止位            

idle <= 1'b1;

cnt <= cnt + 8'd1;

end

8'd176:

begin

tx <= 1'b1;            

idle <= 1'b0;   //一帧资料发送结束

cnt <= cnt + 8'd1;

end

default:

begin

cnt <= cnt + 8'd1;

end

endcase

end

else

begin

tx <= 1'b1;

cnt <= 8'd0;

idle <= 1'b0;

end

end

endmodule

接受模块:

UART的接收数据时序为:当检测到数据的下降沿时,表明线路上有数据进行传输,这时计数器CNT开始计数,当计数器为24=16+8时,采样的值为第0位数据;当计数器的值为40时,采样的值为第1位数据,依此类推,进行后面6个数据的采样

module uartrx(clk, rx, dataout, rdsig, dataerror, frameerror);

input clk;          //采样时钟

input rx;           //UART数据输入

output dataout;     //接收数据输出

output rdsig;

output dataerror;   //资料出错指示

output frameerror;  //帧出错指示

reg[7:0] dataout;

reg rdsig, dataerror;

reg frameerror;

reg [7:0] cnt;

reg rxbuf, rxfall, receive;

parameter paritymode = 1'b0;

reg presult, idle;

always @(posedge clk)   //检测线路的下降沿

begin

rxbuf <= rx;

rxfall <= rxbuf & (~rx);

end

always @(posedge clk)

begin

if (rxfall && (~idle))  //检测到线路的下降沿并且原先线路为空闲,启动接收数据进程

begin

receive <= 1'b1;

end

else if(cnt == 8'd175)  //接收数据完成

begin

receive <= 1'b0;

end

end

always @(posedge clk)

begin

if(receive == 1'b1)

begin

case (cnt)

8'd0:

begin

idle <= 1'b1;

cnt <= cnt + 8'd1;

rdsig <= 1'b0;

end

8'd24:  //接收第0位数据

begin

idle <= 1'b1;

dataout[0] <= rx;

presult <= paritymode^rx;

cnt <= cnt + 8'd1;

rdsig <= 1'b0;

end

8'd40: //接收第1位数据

begin

idle <= 1'b1;

dataout[1] <= rx;

presult <= presult^rx;

cnt <= cnt + 8'd1;

rdsig <= 1'b0;

end

8'd56: //接收第2位数据

begin

idle <= 1'b1;

dataout[2] <= rx;

presult <= presult^rx;

cnt <= cnt + 8'd1;

rdsig <= 1'b0;

end

8'd72: //接收第3位数据

begin

idle <= 1'b1;

dataout[3] <= rx;

presult <= presult^rx;

cnt <= cnt + 8'd1;

rdsig <= 1'b0;

end

8'd88: //接收第4位数据

begin

idle <= 1'b1;

dataout[4] <= rx;

presult <= presult^rx;

cnt <= cnt + 8'd1;

rdsig <= 1'b0;

end

8'd104: //接收第5位数据

begin

idle <= 1'b1;

dataout[5] <= rx;

presult <= presult^rx;

cnt <= cnt + 8'd1;

rdsig <= 1'b0;

end

8'd120:     //接收第6位数据

begin

idle <= 1'b1;

dataout[6] <= rx;

presult <= presult^rx;

cnt <= cnt + 8'd1;

rdsig <= 1'b0;

end

8'd136:     //接收第7位数据

begin

idle <= 1'b1;

dataout[7] <= rx;

presult <= presult^rx;

cnt <= cnt + 8'd1;

rdsig <= 1'b1;

end

8'd152:     //接收奇偶校验位

begin

idle <= 1'b1;

if(presult == rx)

dataerror <= 1'b0;

else

dataerror <= 1'b1;  //如果奇偶校验位不对,表示数据出错  

cnt <= cnt + 8'd1;

rdsig <= 1'b1;

end

8'd168:

begin

idle <= 1'b1;

if(1'b1 == rx)

frameerror <= 1'b0;

else

frameerror <= 1'b1;     //如果没有接收到停止位,表示帧出错

cnt <= cnt + 8'd1;

rdsig <= 1'b1;

end

default:

begin

cnt <= cnt + 8'd1;

end

endcase

end

else

begin

cnt <= 8'd0;

idle <= 1'b0;

rdsig <= 1'b0;

end

end

endmodule

PARTNER CONTENT

文章评论0条评论)

登录后参与讨论
EE直播间
更多
我要评论
0
7
关闭 站长推荐上一条 /3 下一条