广告

fpga学习日记14,实现UART发送

2013-8-28 09:45 880 0 分类: FPGA/CPLD 文集: 数电,FPGA学习

(注:如果本文有代码 则均搜索于网络或本人编写仅供学习之用)

UART是我们经常用到的通信方式之一,无论是RS232  RS485或者两机通信都离不开它


在使用单片机或者ARM时我们可以简单的通过配置寄存器或者调用API函数就能实现uart的
起始位,停止位,数据位数,奇偶校验,以及波特率控制

 

一般我们的操作流程是(不带FIFO的情况)
将数据放入一个寄存器假设为uart_buf 一个9位寄存器(或者更多)
假如需要奇偶校验那么状态寄存器中有一位状态位就是奇偶校验位直接给寄存器的第九位即可


单片机内部会根据波特率和起始位设置自动把数据一位一位的发出去
发送完成后会置标志并通知单片机发送完成
我们也可以随时查看发送缓冲区是否有数据 或者是否为空

 

当然目前的uart设计都预留了缓冲区以节省cpu的时间 提高了效率 底层自己处理

1.jpeg

 


起始位:先发出一个逻辑”0”的信号,表示传输字符的开始。
数据位:紧接着起始位之后。资料位的个数可以是4、5、6、7、8等,构成一个字符。通常采用

1.jpg

 

ASCII码。从最低位开始传送,靠时钟定位。
奇偶校验位:资料位加上这一位后,使得“1”的位数应为偶数(偶校验)或奇数(奇校验),以此

来校验资料传送的正确性。
停止位:它是一个字符数据的结束标志。可以是1位、1.5位、2位的高电平。
空闲:处于逻辑“1”状态,表示当前线路上没有资料传送
波特率:是衡量资料传送速率的指针。表示每秒钟传送的二进制位数。例如资料传送速率为120

字符/秒,而每一个字符为10位,则其传送的波特率为10×120=1200字符/秒=1200波特。

 

 

 

 

这里先设计一个最原始的UART发送器
波特率9600,奇偶校验无,数据位8,停止位1
这个设计比较重要的地方就是时钟和时序的问题  如何产生准确的9800bps的速率问题
设计思路 先计算发送一位的时间 然后用计数器对系统时钟计数到发送时间后 发送一位 然后继

续计数以此类推 算出发送一个字节的整个时间和时序

  以波特率9600为例子说明,波特率9600接收一个bit的时间为1s/9600=104us,即每隔104us发

送一个数据。
  104us = 104000ns 50M时钟的一个周期时间为20ns要远小于104000ns,所以可以用50M时钟

产生的计数器来计数,然后根据计数器来发送数据。
  
  新建一个计数器,50Mhz为时钟,那么计数器变化一次时间为20ns。
  由于一次完整数据接收需要有1144000ns时间,所以计数器必须记到1144000ns时间。
  1144000ns/20ns = 57200 ,所以需要16位计数器。
  
  Startbit(0)占据计数器的0   -104000ns/20ns = 5200
  D0           占据计数器的5200-208000ns/20ns = 10400
  D1           占据计数器的10400-312000ns/20ns = 15600
  D2           占据计数器的15600-416000ns/20ns = 20800
  D3           占据计数器的20800-520000ns/20ns = 26000
  D4           占据计数器的26000-624000ns/20ns = 31200
  D5           占据计数器的31200-728000ns/20ns = 36400
  D6           占据计数器的36400-832000ns/20ns = 41600
  D7           占据计数器的41600-936000ns/20ns = 46800 
  校验位       占据计数器的46800-1040000ns/20ns = 52000
  Endbit(1)  占据计数器的52000-1144000ns/20ns = 57200

3.jpg


也可以用类似的思路
比如每隔5200一个计数器加1则 
加到10后从0开始 
根据此计数器来判断要发送的位

大致代码流程

时钟上升沿计数 以产生波特率时钟
适当的时候获取要发送的数据data
然后按照上面的时间节点发送数据到uart输出口
计数到57200从0开始

verilog语言: verilog_uart_send
 
043 assign sys_rst_n = 1'b1 ;
044
045 always @(posedge sys_clk or negedge sys_rst_n) begin
046        if (sys_rst_n ==1'b0)  
047            buff <= 8'b0;
048        else
049            buff  <= { key_data , key_data } ;
050 end
051        
052 assign LED = buff;
053
054 always @(posedge sys_clk or negedge sys_rst_n) begin
055        if (sys_rst_n ==1'b0)  
056            counter <= 16'b0;
057        else if (counter > 57200 )    
058            counter <= 16'b0;
059        else
060            counter  <= counter + 1'b1;
061 end
062
063 always @(*) begin
064    if ((counter > 0)         &&  (counter  <= 5200 ))  
065       txd  =  1'b0  ;                        
066    else if ((counter > 5200) &&  (counter  <= 10400))  
067       txd  =  buff[0]  ;                    
068    else if ((counter > 10400) && (counter  <= 15600))  
069       txd  =  buff[1]  ;                    
070    else if ((counter > 15600) && (counter  <= 20800))  
071       txd  =  buff[2]  ;                    
072    else if ((counter > 20800) && (counter  <= 26000))  
073       txd  =  buff[3]  ;                    
074    else if ((counter > 26000) && (counter  <= 31200))  
075       txd  =  buff[4]  ;                    
076    else if ((counter > 31200) && (counter  <= 36400))  
077       txd  =  buff[5]  ;                    
078    else if ((counter > 36400) && (counter  <= 41600))  
079       txd  =  buff[6]  ;                    
080    else if ((counter > 41600) && (counter  <= 46800))  
081       txd  =  buff[7]  ;                    
082    else if ((counter > 46800) && (counter  <= 52000))  
083       txd  =  1'b1     ;                    
084    else if ((counter > 52000) && (counter  <= 57200))
085       txd  =  1'b1     ;        
086    else            
087       txd  =  1'b1  ;  
088 end        
089
090
091 always @(posedge sys_clk or negedge sys_rst_n) begin
092        if (sys_rst_n ==1'b0)  
093           uart_txd <= 1'b1;        
094        else  
095           uart_txd  <= txd;        
096          
097 end
098
099 endmodule
100 //end of RTL code

 

网上有设计好的uart实例大家可以学习了 自己使用

http://bbs.ednchina.com/BLOG_ARTICLE_1904410.HTM 

http://www.cnblogs.com/loadomain/p/3237923.html

广告

文章评论 0条评论)

登录后参与讨论
相关推荐阅读
liang890319_284707880 2016-03-22 11:41
[博客大赛]我在搞嵌入式 我有罪
  我在搞嵌入式 我有罪 做嵌入式也有几年了 刚学习的时候书上说嵌入式的定义是以应用为中心,以计算机技术为基础,软硬件可裁剪,适应应用系统对功能、可靠性、成本、体积、功耗等严格要求的专用计...
liang890319_284707880 2015-10-22 11:57
帕萨特迈腾蒙迪欧哪个好
氵灬清风灬说:太小了,没法穿了,懒得换了 junyao00022说:............................... jd272475byp说:宝贝收到啦,衣服质量非常不错,...
liang890319_284707880 2015-10-22 11:56
二手荣威550和二手起亚k2哪个好
二手荣威550和二手起亚k2哪个好   风之乞说:衣服挺好的,就是偏小,已经更换了 梦里水乡0609说:不错 很好  不了不错  赞 四灵之首说:衣服质量不错,韵达快递不行~ ...
liang890319_284707880 2015-10-22 11:55
澳大利亚深海鱼油哪个牌子好
hgjfhgj说:不错  价格便宜  款式不错  开始买中码小了一点  免费给换的  好店家 小杰c子说:非常合适。也很有气质 天佑945说:还可以,性价比高。。。。。。。。。。 Ab...
liang890319_284707880 2015-10-19 11:03
常用DDR sdram和Flash型号
  以下是代码片段: http://blog.csdn.net/myarrow/article/details/7854863   主要是三星 现代 ...
liang890319_284707880 2013-09-29 17:00
ROM FLASH RAM
EPROM、EEPROM、FLASH的总结性区别   http://xdc0363.blog.163.com/blog/static/11546200220...
我要评论
0
0
广告