串口RS232通信程序(Verilog)

整理文档很辛苦,赏杯茶钱您下走!

免费阅读已结束,点击下载阅读编辑剩下 ...

阅读已结束,您可以下载文档离线阅读编辑

资源描述

串口RS232通信程序(Verilog)串口有9个管脚,其中只有三个是最重要的,分别是pin2:RxD(receivedata).接收数据pin3:TxD(transmitdata).发送数据pin5:GND(ground).地串行通信时序我们先来看看字节0x55的发送0x55的二进制代码是01010101,但发送时由低字节开始的,因此发送次序依次为1-0-1-0-1-0-1-0.串行通信电平·1issentusing-10V(orbetween-5Vand-15V).·0issentusing+10V(orbetween5Vand15V).由于计算机RS232的电平与电路板(通常+5V)之间电平的不同所以要用到转换芯片如果PCB板电源+-5V的话用MAX232如果PCB板(FPGA)电源是+-3.3V的话用MAX3232这个图的串口如果采用母头的话,要用交叉公母线,保证是PCB板上这边的RxD连计算机的TxD(3Pin),PCB板这边的TxD连计算机的RxD(2Pin).串行通信波特率这里要弄清楚波特率与比特率的差别:比特率是数字信号的传输速率,它用单位时间内传输的二进制代码的有效位(bit)数来表示,其单位为每秒比特数bit/s(bps)、每秒千比特数(Kbps)或每秒兆比特数(Mbps)来表示(此处K和M分别为1000和1000000,而不是涉及计算机存储器容量时的1024和1048576)。波特率指数据信号对载波的调制速率,它用单位时间内载波调制状态改变次数来表示,其单位为波特(Baud)。波特率与比特率的关系为:比特率=波特率X单个调制状态对应的二进制位数两相调制(单个调制状态对应1个二进制位)的比特率等于波特率;四相调制(单个调制状态对应2个二进制位)的比特率为波特率的两倍;八相调制(单个调制状态对应3个二进制位)的比特率为波特率的三倍;依次类推。对于串行通信来说,或者说是对于普通的数字电路来说,都是两相调制(单个调制状态对应1个二进制位),因此波特率=比特率(通常叫波特率)。PS:可以看看下面图就知道什么是四相调制。如果系统时钟是1.8432MHz,那16分频就得到115200Hzreg[3:0]BaudDivCnt;always@(posedgeclk)BaudDivCnt=BaudDivCnt+1;wireBaudTick=(BaudDivCnt==15);但通常系统的时钟不是刚刚好是波特率的整数倍,如果不采用DCM对系统进行倍频的话,可以采用下面程序进行处理,设系统时钟为2MHz=2000000Hz2000000/115200=17.361111024/59=17.3562000000/115200≈1024/59两个频率很接近,可以采用下面程序产生我们要的波特率。//10bitsfortheaccumulator([9:0]),andoneextrabitfortheaccumulatorcarry-out([10])reg[10:0]acc;//11bitstotal!always@(posedgeclk)acc=acc[9:0]+59;//useonly10bitsfromthepreviousresult,butsavethefull11bitswireBaudTick=acc[10];//sothatthe11thbitisthecarry-out当系统时钟为2MHz的时候,计算得到的波特率的值为115234,与115200只有0.03%的误差。我们怎么得到“59”呢,可以看下面的推导其中BaudBaudGeneratorAccWidth,Baud左移BaudGeneratorAccWidth位,相当于Baud乘以2的BaudGeneratorAccWidth次方。参照上面的程序与公式推导可以把程序修改如下:parameterClkFrequency=25000000;//25MHzparameterBaud=115200;parameterBaudGeneratorAccWidth=16;parameterBaudGeneratorInc=(BaudBaudGeneratorAccWidth)/ClkFrequency;reg[BaudGeneratorAccWidth:0]BaudGeneratorAcc;always@(posedgeclk)BaudGeneratorAcc=BaudGeneratorAcc[BaudGeneratorAccWidth-1:0]+BaudGeneratorInc;wireBaudTick=BaudGeneratorAcc[BaudGeneratorAccWidth];当要注意的是,上面程序中BaudGeneratorInc的计算公式出错,因为在Verilog语言中中间结果只能32位,而这个公式计算的结果超过了32位。所以要把这行改为parameterBaudGeneratorInc=((Baud(BaudGeneratorAccWidth-4))+(ClkFrequency5))/(ClkFrequency4);程序改变,得到的波特率不变。RS232发送接收模块RS-232发送模块下面是我们所想要实现的:它应该能像这样工作:发送器接收8位的数据,并将其串行输出。(TxD_start置位后开始传输).当有数传输的时候,使busy信号有效,此时“TxD_start”信号被忽略.RS-232模块的参数是固定的:8位数据,2个停止位,无奇偶校验.数据串行化假设我们已经有了一个115200波特的BaudTick信号.我们需要产生开始位、8位数据以及停止位。用状态机来实现看起来比较合适。reg[3:0]state;always@(posedgeclk)case(state)4'b0000:if(TxD_start)state=4'b0100;4'b0100:if(BaudTick)state=4'b1000;//开始位4'b1000:if(BaudTick)state=4'b1001;//bit04'b1001:if(BaudTick)state=4'b1010;//bit14'b1010:if(BaudTick)state=4'b1011;//bit24'b1011:if(BaudTick)state=4'b1100;//bit34'b1100:if(BaudTick)state=4'b1101;//bit44'b1101:if(BaudTick)state=4'b1110;//bit54'b1110:if(BaudTick)state=4'b1111;//bit64'b1111:if(BaudTick)state=4'b0001;//bit74'b0001:if(BaudTick)state=4'b0010;//停止位14'b0010:if(BaudTick)state=4'b0000;//停止位2default:if(BaudTick)state=4'b0000;endcase注意看这个状态机是怎样实现当TxD_start有效就开始,但只在BaudTick有效的时候才转换状态的。.现在,我们只需要产生TxD输出即可.regmuxbit;always@(state[2:0])case(state[2:0])0:muxbit=TxD_data[0];1:muxbit=TxD_data[1];2:muxbit=TxD_data[2];3:muxbit=TxD_data[3];4:muxbit=TxD_data[4];5:muxbit=TxD_data[5];6:muxbit=TxD_data[6];7:muxbit=TxD_data[7];endcase//将开始位、数据以及停止位结合起来assignTD=(state4)|(state[3]&muxbit);完整的代码在这里可以得到。RS232接收模块下面是我们想要实现的模块:我们的设计目的是这样的:1.当RxD线上有数据时,接收模块负责识别RxD线上的数据2.当收到一个字节的数据时,锁存接收到的数据到data总线,并使data_ready有效一个周期。注意:只有当data_ready有效时,data总线的数据才有效,其他的时间里不要使用data总线上的数据,因为新的数据可能已经改变了其中的部分数据。过采样异步接收机必须通过一定的机制与接收到的输入信号同步(接收端没有办法得到发送断的时钟)。这里采用如下办法。1.为了确定新数据的到来,即检测开始位,我们使用几倍于波特率的采样时钟对接收到的信号进行采样。2.一旦检测到开始位,再将采样时钟频率降为已知的发送端的波特率。典型的过采样时钟频率为接收到的信号的波特率的16倍,这里我们使用8倍的采样时钟。当波特率为115200时,采样时钟为921600Hz。假设我们已经有了一个8倍于波特率的时钟信号Baud8Tick,其频率为921600Hz。具体设计首先,接受到的RxD信号与我们的时钟没有任何关系,所以采用两个D触发器对其进行过采样,并且使之我我们的时钟同步。reg[1:0]RxD_sync;always@(posedgeclk)if(Baud8Tick)RxD_sync={RxD_sync[0],RxD};首先我们对接收到的数据进行滤波,这样可以防止毛刺信号被误认为是开始信号。reg[1:0]RxD_cnt;regRxD_bit;always@(posedgeclk)if(Baud8Tick)beginif(RxD_sync[1]&&RxD_cnt!=2'b11)RxD_cnt=RxD_cnt+1;elseif(~RxD_sync[1]&&RxD_cnt!=2'b00)RxD_cnt=RxD_cnt-1;if(RxD_cnt==2'b00)RxD_bit=0;elseif(RxD_cnt==2'b11)RxD_bit=1;end一旦检测到开始位,使用如下的状态机可以检测出接收到每一位数据。reg[3:0]state;always@(posedgeclk)if(Baud8Tick)case(state)4'b0000:if(~RxD_bit)state=4'b1000;//startbitfound?4'b1000:if(next_bit)state=4'b1001;//bit04'b1001:if(next_bit)state=4'b1010;//bit14'b1010:if(next_bit)state=4'b1011;//bit24'b1011:if(next_bit)state=4'b1100;//bit34'b1100:if(next_bit)state=4'b1101;//bit44'b1101:if(next_bit)state=4'b1110;//bit54'b1110:if(next_bit)state=4'b1111;//bit64'b1111:if(next_bit)state=4'b0001;//bit74'b0001:if(next_bit)state=4'b0000;//stopbitdefault:state=4'b0000;endcase注意,我们使用了next_bit来遍历所有数据位。reg[2:0]bit_spacing;always@(posedgeclk)if(state==0)bit_spacing=0;elseif(Baud8Tick)bit_spacing=bit_spacing+1;wirenext_bit=(bit_spacing==7);最后我们使用一个移位寄存器来存储接受到的数据。reg[7:0]RxD_data;always@(posedgeclk)if(Baud8Tick&&next_bit&&state[3])RxD_data={RxD_bit,RxD_data[7:1]};RS232接收模块(

1 / 11
下载文档,编辑使用

©2015-2020 m.777doc.com 三七文档.

备案号:鲁ICP备2024069028号-1 客服联系 QQ:2149211541

×
保存成功