1、顶层模块
写程序都一样,不能多有的程序都写在一个模块里,那样看起来很麻烦,出了错误也不好维护,对于一些小的程序我们可以写在一个模块里,但程序一旦复杂起来还是要懂得模块化编程的,对于顶层模块,最好是只写接口就好了,例如:
这段代码中,rx_232是我们的底层模块名,后面跟着的那个rx呢是我们自己取的名字,是任意的。后面的一大串呢就是接口,为了直观呢,建议大家采用我的这种写法,看上去比较清楚明白,括号里面的接口是我们顶层文件的接口,括号外面的是我们调用底层模块的接口,这些接口要一一对应正确才能保证数据之间的传输。
在顶层模块中,我们只定义了数据输入接口,用来接收数据,数据输出接口,用于发送数据,时钟接口,和复位接口。这四个接口是有输入输出关系的,对于其他的接口,是属于我们整个模块内部的接口,是模块与模块之间的接口,既非输入,也非输出,相当于一根导线一样,所以我们把他们定义成wire型变量
2、波特率选择模块
单片机或者计算机在串口通信时的传输速率用波特率表示,9600bps表示的就是每秒钟传送9600位的数据
这里之所以计数到5027,在这里算一下。
1秒传送9600位,那么传送一位的时间就可以算出,即1s=1000_000_000ns,所以传送一位数据需要1000_000_000/9600=
104166ns,而我们的时钟周期为20ns,因此需要计数到104166/20=5028个时钟周期
下面是串口通信时序图
我再来解释一下这个图吧,我当时学单片机的时候还真是没怎么重视这张图,只知道只要一个指令就可以发送,没有真正搞清楚是怎么发送和接受的,那就在这里复习一下吧
计算机和单片机之间进行通信,这里用的是rs232通信方式,即通信之前,计算机和单片机之前要设定好相同的波特率,只有波特率相同了才能进行通信。
其次,计算机发送数据时要先发送一个起始位,一般是低电平,后面跟着的是8位数据位,奇偶校验位,停止位等,当起始位低电平信号传送到我们的接收端口时,在接收模块中会发送一个命令给波特率时钟计数器,开始计时,计时到一半的时候会产生一个采样高脉冲信号,当接收模块检测到这个高脉冲之后就会将数据存到寄存器中,当检测到第11个脉冲信号时,也就是代表一帧的数据接收完毕,发送模块就给波特率选择模块发送一个停止信号告诉它停止计时。同时,当数据接收完毕之后也会产生一个信号告诉发送模块,信号已经接收完毕,准备发送,这个时候发送模块再给波特率计时模块发送一个信号开始计时,计数到某一位的中间时产生一个采样信号,当发送模块检测到采样信号之后就将寄存器里的数据送到发送端,每次只送一位,这样就实现了数据的接收与发送。
下面是波特率计时模块的主要程序部分
3、数据接收模块
在接收模块中,为了准确的检测计算机发送来的数据起始位的那个低电平信号,用到了边沿脉冲检测法,可以有效的避免毛刺现象带来的问题
下面是发送部分的主要程序段
4、数据发送模块
发送模块原理上和接受模块是一样的,不同点就是接收模块通过边沿检测法检测起始位低电平信号来启动接收数据,而发送模块是通过检测数据发送完毕后,我们认为的置一个低电平信号,发送模块通过检测这个低电平信号来启动发送。见下图
下面是生成的RTL视图
下面是测试结果