网站制作有什么好的介绍,个人wordpress 手机,大学生app开发经费预算表,免费网站应用一、UART相关介绍
UART是我们常用的全双工异步串行总线#xff0c;常用TTL电平标准#xff0c;由TXD和RXD两根收发数据线组成。
那么#xff0c;利用硬件描述语言实现UART对应的电路和51单片机内部配合寄存器实现的电路到底有何区别呢#xff1f;接下来我们对照看一下。 …一、UART相关介绍
UART是我们常用的全双工异步串行总线常用TTL电平标准由TXD和RXD两根收发数据线组成。
那么利用硬件描述语言实现UART对应的电路和51单片机内部配合寄存器实现的电路到底有何区别呢接下来我们对照看一下。
二、FPGA实现UART异步串行收发方式
对于FPGA而言利用verilog实现这个过程其实最重要的就是安排好对应的计数器并配合移位寄存器串并转换即可完成。
FPGA发送端对应的代码如下
module uart_tx(input wire clk ,input wire rst_n ,input wire [7:0] pi_data ,input wire pi_flag ,output reg tx );reg [7:0] pi_data_reg;//用于寄存传进来的数据reg tx_flag ;reg [12:0] cnt_baud ;reg bit_flag1;reg [3:0] bit_cnt ;//在接收到pi_flag为高电平的时候寄存输入数?always(posedge clk or negedge rst_n)beginif(!rst_n)pi_data_reg d0;else if(pi_flag 1b1)pi_data_reg pi_data ;endalways(posedge clk or negedge rst_n)beginif(!rst_n)tx_flag 1b0;else if(bit_flag1 1b1 bit_cnt d8)tx_flag 1b0;else if(pi_flag 1b1)tx_flag 1b1;end always(posedge clk or negedge rst_n)beginif(!rst_n)cnt_baud d0;else if(tx_flag 1b0)cnt_baud d0;else if(cnt_baud d5207 tx_flag 1b1)cnt_baud d0;else if(tx_flag 1b1)cnt_baud cnt_baud 1b1;endalways(posedge clk or negedge rst_n)beginif(!rst_n)bit_flag1 1b0;else if(cnt_baud 5206)bit_flag1 1b1;else bit_flag1 1b0;endalways(posedge clk or negedge rst_n)beginif(!rst_n)bit_cnt d0;else if(bit_cnt d8 bit_flag1 1b1)bit_cnt d0;else if(bit_flag1 1b1)bit_cnt bit_cnt 1b1;end always(posedge clk or negedge rst_n)beginif(!rst_n)tx 1b1;//空闲状态else if(pi_flag 1b1)tx 1b0;//起始?else if(bit_flag1 1b1 bit_cnt d7)tx pi_data_reg[bit_cnt];//8位数?else if(bit_cnt d8 bit_flag1 1b1)tx 1b1;//空闲?end
endmoduleFPGA接收端对应的代码如下module uart_rx(input wire clk ,input wire rst_n ,input wire rx ,output reg [7:0] po_data ,output reg po_flag);//用于打拍的寄存器reg rx1;reg rx2;reg rx2_reg ;reg rx_flag ;reg [12:0] cnt_baud ;reg bit_flag ;reg [3:0] bit_cnt ;//对接收到的外部信号进行打拍寄存always(posedge clk)beginrx1 rx ;rx2 rx1 ;rx2_reg rx2 ;end//检测下降沿拉高rx_flagalways (posedge clk or negedge rst_n) beginif (!rst_n) beginrx_flag 1b0;endelse if (rx2 1b0 rx2_reg 1b1) beginrx_flag 1b1;endelse if(bit_flag 1b1 bit_cnt d8)rx_flag 1b0;endalways (posedge clk or negedge rst_n) beginif (!rst_n) cnt_baud d0;else if(rx_flag 1b0)cnt_baud d0;else if(cnt_baud d5207 rx_flag 1b1)//5207为波特率是9600时对应的计数值cnt_baud d0;else if(rx_flag 1b1)cnt_baud cnt_baud 1b1;endalways (posedge clk or negedge rst_n) beginif (!rst_n) bit_flag 1b0;else if(cnt_baud d2603 rx_flag 1b1)bit_flag 1b1;else bit_flag 1b0;end always (posedge clk or negedge rst_n) beginif (!rst_n) bit_cnt d0;else if(bit_cnt d8 bit_flag 1b1)bit_cnt d0;else if(bit_flag 1b1 rx_flag 1b1)bit_cnt bit_cnt 1b1;endalways (posedge clk or negedge rst_n) beginif (!rst_n) po_data d0;else if(bit_flag 1b1 bit_cnt d1)po_data {rx2_reg,po_data[7:1]};end always (posedge clk or negedge rst_n) beginif (!rst_n) po_flag 1b0 ;else if(bit_flag 1b1 bit_cnt d8)po_flag 1b1 ;else po_flag 1b0;endendmodule顶层代码如下module top_uart(input wire clk ,input wire rst_n ,input wire rx ,output wire tx);wire [7:0] po_data ;wire po_flag ;uart_rx inst_uart_rx (.clk(clk), .rst_n(rst_n), .rx(rx), .po_data(po_data), .po_flag(po_flag));uart_tx inst_uart_tx (.clk(clk), .rst_n(rst_n), .pi_data(po_data), .pi_flag(po_flag), .tx(tx));endmodule经过综合后生成的对应原理图如下顶层 tx:可以发现这里其实每一位寄存器都对应着一个D触发器剩余的逻辑由LUT实现。 rx接收端同理。 三、单片机内部UART异步串行收发实现方式
对于51单片机而言它内部是CPU控制一些在物理层面已经连接好寄存器通过对寄存器的控制配合电路的改变完成整个任务。
对于串口通信这个任务而言它的整个实现过程总结如下
整个实现可分为三大部分定时器、中断系统及对应的缓冲寄存器完成三大部分配合内部CPU便可完成收发任务具体示意图如下
红色区域是定时器部分它外部连接着晶振通过对TH1和TL1寄存器写入初始值可实现具体溢出频率的控制假设晶振频率位12MHz12T模式下1us计数一次,TH1和TL1填入0xF3(对应十进制243一共256则每隔256-24313个数就会溢出一次则溢出率为1/13us0.07692MHz,当SMOD1时频率只经过➗16也就对应4800Hz,就会对应波特率4800Baud。配合控制器即可完成对波特率的控制。
蓝色部分是用于发送和接收数据的缓冲区
黄色部分是串口中断器这个中断器在接收数据的时候需要使用TI和RI是中断标志。 在使用方式上对涉及的寄存器进行初始化后将数据写入SBUF或通过中断读取SBUF内的数据即可完成发送接收任务。
对应配置代码如下
#include REGX51.H/*** brief 串口初始化4800bps11.0592MHz* param 无 * retval 无*/
void UART_Init()
{//对串行寄存器配置SCON0x50; //串行控制寄存器涉及模式选择PCON 0x7F; //电源控制寄存器包括波特率//对定时器0进行配置#11.0592MTMOD 0x0F; //设置定时器模式低4位保持不变TMOD | 0x20; //设置定时器模式串口对应的模式需要是双8位模式TL1 0xFA; //设定定时初值TH1 0xFA; //设定定时器重装值ET1 0; //禁止定时器1中断TR1 1; //启动定定时器1//串口中断配置EA1;//启动所有中断ES1;//启动串口中断
}
/*** brief 串口发送1个字节数据4800bps11.0592MHz* param Byte 要发送的一个字节数据* retval 无*/
void UART_SendByte(unsigned char Byte)
{SBUFByte;//将数据写入发送缓冲器即可while(TI0);//是否有中断请求位TI0;//软件置0
}//串口中断函数的模板需要用的时候复制到主函数中
/*
//注意一个函数不能既在主函数中出现又在中断函数中出现
void UART_Routine() interrupt 4 //串口中断对应的中断号
{if(RI1)//接收到了串口中断{P2~SBUF;UART_SendByte(SBUF);RI0;//需要由软件清0}}
*/
主函数代码如下
#include REGX51.H
#include Delay.h
#include UART.hvoid main()
{UART_Init();while(1){}
}//注意一个函数不能既在主函数中出现又在中断函数中出现
void UART_Routine() interrupt 4 //串口中断对应的中断号
{if(RI1)//接收到了串口中断{P2~SBUF;UART_SendByte(SBUF);RI0;//需要由软件清0}}
四、总结
均由寄存器加逻辑电路组成只不过二者工作模式及灵活性差别很大单片机依赖冯诺依曼架构需要控制器控制且电路固定使得定时器、寄存器等资源有限FPGA的并行及灵活性在这里体现的淋漓尽致。