用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的波特率即可测试

你可能感兴趣的:(FPGA)