串口调试总结

来源:本站
导读:目前正在解读《串口调试总结》的相关信息,《串口调试总结》是由用户自行发布的知识型内容!下面请观看由(电工技术网 - www.9ddd.net)用户发布《串口调试总结》的详细说明。
简介:最近想跑个串口玩来着,找一些网上程序来用,没想到调了将近3周,要了亲命,终于调好,抽空总结一下吧。

调试过程中对接口协议有了一定了解,对芯片max232了解还是比较深入的

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

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

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

采样时钟模块:

module clkp(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

提醒:《串口调试总结》最后刷新时间 2024-03-14 01:03:43,本站为公益型个人网站,仅供个人学习和记录信息,不进行任何商业性质的盈利。如果内容、图片资源失效或内容涉及侵权,请反馈至,我们会及时处理。本站只保证内容的可读性,无法保证真实性,《串口调试总结》该内容的真实性请自行鉴别。