用FPGA实现多路电压采集器:(1)在FPGA上实现异步串口通信

前几周微机课上布置了一个Project,要求用FPGA实现多路电压采集器,对多路模拟信号采集并显示其电压幅值。我们小组的设计思路是利用ADC芯片对模拟电压输入信号进行采集,转换为数字信号,然后交由FPGA进行处理,最后将处理结果通过串口传输给电脑并由串口助手显示读数。基本框图如下

经过好几天的努力,现在来做一个小小总结。

 

所谓多路电压采集器,指的是在同一时刻采集到的数据,虽然好多AD都能实现多路数据的采集,但大多是串行的,即采集完这一路,再采集下一路模拟信号,总是会有时间差,并非,Project的目的是用多片AD(每一片只用一路信号输入)同时采集,实现真正的多路信号同时采集,模拟量选用0~5v的电压

 

硬件:1.老师给发的DIGICUBE,XILINX SPARTAN3的FPGA,XC3S50,clk1=18.4320M,clk2=8M

   2.AD芯片是ADC0809,淘宝直接买的模块,后期有时间自己焊电路

     3.下载线,USB转串口线(用于串口通信)

软件:ISE13.3,串口助手

使用Verilog HDL

 

实现串口通信的代码是是学长们留下来的,稍作修改并增加注释

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date:     
// Design Name: 
// Module Name:   
// Project Name: 
// Target Devices: 
// Tool versions: 
// Description: 
//
// Dependencies: 
//
// Revision: 
// Revision 0.01 - File Created
// Additional Comments: 
//
//////////////////////////////////////////////////////////////////////////////////
//同济大学11级自动化
module uart(reset, clk, rx_in, tx_out);

//Port declaration
//clk, reset, rx, tx
input            reset;
input            clk;
input            rx_in;
output        tx_out;

//reg for tx
reg [7:0]    tx_reg;//发送数据寄存器,相当于buffer
wire [7:0]    tx_data;
reg [15:0]    tx_sample_cnt;//采样计数器
reg [3:0]    tx_cnt;
reg            tx_done;
reg            tx_out;
reg            tx_enable;

//reg for rx
reg [7:0]    rx_reg;
wire [7:0]    rx_data;
reg [15:0]    rx_sample_cnt;
reg [3:0]     rx_cnt;//接收到的数据位计数器
reg            rx_frame_err;//接收帧错误标记,未使用
reg            rx_done;
reg            rx_busy;
reg            rx_d;
reg            rx_enable;

assign    rx_data = (rx_done)?rx_reg:8'hzz;//zz为高阻状态
assign    tx_data = rx_data;


//uart rx logic
always@(posedge clk or posedge reset)
if(reset)
begin
    rx_sample_cnt <= 0;
    rx_cnt <= 0;
    rx_frame_err <= 0;
    rx_done <= 0;
    rx_busy <= 0;
    rx_d <= 0;
    rx_enable <= 1;
end

else
begin
    rx_d <= rx_in;//rx_in是从串口读入的数据,rx_d只有一位,数据帧开始的标志是0,结束是1(第9位)
    
    if(rx_done)
    begin
        rx_done <= 0;//接收完毕后,done标记位清零开始下一次接收
    end
    
    if(rx_enable)//若接收使能
    begin
        //Check if just received start of frame检查是否为一帧的开始
        if(!rx_busy && !rx_d)//busy为0时表示不忙,d为0表示一帧的开始
        begin//如果不忙...进入接收状态,使busy位置1,为了进行后面的处理
            rx_busy <= 1;//busy置1后要对接收的数据进行处理
            rx_sample_cnt <= 1;
            rx_cnt <= 0;
            rx_done <= 0;
        end
        
        //Start of frame detected, proceed with rest of data检测到一帧的开始
        if(rx_busy)//busy置1后要对接收的数据进行处理
        begin
            rx_sample_cnt <= rx_sample_cnt+1;//计数器每次+1
            if(rx_sample_cnt == 1920)//clk=18.432MHz,clk/1920=9600
            begin
                rx_sample_cnt <= 0;
            end
            
            //logic to sample at middle of data
            if(rx_sample_cnt == 960)//中间处采样
            begin
                if((rx_d==1) && (rx_cnt==0))
                begin
                    rx_busy <= 0;
                    rx_done <= 0;
                end
                
                else
                begin
                    rx_cnt <= rx_cnt+1;
                    rx_done <= 0;
                    
                    //start storing the rx data
                    if(rx_cnt>0 && rx_cnt<9)
                    begin
                        rx_reg[rx_cnt-1] <= rx_d;//reg=rx_buffer,rx_d是接收到的每一位
                    end
                    
                    if(rx_cnt == 9)
                    begin
                        rx_busy <= 0;//接收完毕后把busy位置0
                        
                        //check if end of frame received correctly
                        if(rx_d == 0)//第9位为停止位,若停止位为0则报错
                        begin
                            rx_frame_err <=1;
                        end
                        
                        else//否则接收完成
                        begin
                            rx_done <= 1;
                            rx_frame_err <= 0;
                        end
                    end
                end
            end
        end
    end
    
    if(!rx_enable)//若接收使能为0,即不能接收则
    begin
        rx_busy <= 0;
        rx_done <= 0;
    end
end


//uart tx logic,和rx类似
always@(posedge clk or posedge reset)
if(reset)
begin
    tx_reg <= 8'hff;
    tx_done <= 1;
    tx_out <= 1;
    tx_cnt <= 0;
    tx_sample_cnt <= 0;
    tx_enable <= 1;
end

else
begin
    if(rx_done && tx_done && !tx_cnt)
    begin
        tx_reg <= tx_data;
        tx_done <= 0;
        tx_out <= 0;
        tx_cnt <= 1;
        tx_sample_cnt <= 0;
    end
    
    else
    begin
        tx_sample_cnt <= tx_sample_cnt+1;
        
        if(tx_sample_cnt == 1920)
        begin
            tx_sample_cnt <= 0;
            
            if(tx_enable && !tx_done)
            begin
                tx_cnt <= tx_cnt+1;
                if(tx_cnt >0 && tx_cnt<9)
                begin
                    tx_out <= tx_reg[tx_cnt-1];
                end
                
                if(tx_cnt == 9)
                begin
                    tx_out <= 1;
                    tx_cnt <= 0;
                    tx_done <= 1;
                end
            end
            
            if(!tx_enable)
            begin
                tx_cnt <= 0;
                tx_sample_cnt <= 0;
                tx_reg <= 8'hff;
                tx_out <= 1;
                tx_done <= 1;
            end
            
            if(tx_done)
            begin
                tx_out <= 1;
            end
        end
    end
end
endmodule

 

实现的功能就是串口收发,把收到的数据再发回去

用usb转串口线脸上笔记本,打开选择相应端口号和9600的波特率即可测试

posted on 2013-11-28 21:20  _Ljj  阅读(1447)  评论(0编辑  收藏  举报