zoukankan      html  css  js  c++  java
  • 基于FPGA的电压表与串口通信(上)

    实验原理

        该实验主要为利用TLC549采集模拟信号,然后将模拟信号的数字量通过串口发送到PC上上位机进行显示,使用到的TLC549驱动模块在进阶实验已经使用到了,串口模块在基础实验也已经使用到了,本实验主要是做一个综合,将数据流进行一个整合。

    硬件原理图

    实验代码

    顶层文件

    TLC549驱动

    /*******************************************************************************

    **----------------------------文件信息--------------------------

    ** 文件名称:ADC_TLC549.v

    ** 功能描述:使用AD芯片TLC549采集模拟信号

    ** 操作过程:将模拟信号接到TLC549的输入管脚上

    *******************************************************************************/

    module ADC_TLC549

    (

        clk,//系统50MHZ时钟

    reset_n,//复位

        ioclk,//AD TLC549的时钟

        data,//AD TLC549的数据口

        cs,//AD TLC549的片选择

    segcs,//数码管的为选择

    segdata,//数码管的7段码

    send_finish,//发送完成标志

        start,//开始采集信号

    data_cnt,//数据位标志

        voltage_data1,//采集的电压数据

        voltage_data2,//采集的电压数据

        voltage_data3,//采集的电压数据

        voltage_data4 //采集的电压数据

    );

    input clk;//系统50MHZ时钟

    input reset_n;//复位

    input data;//AD TLC549的数据口

    input send_finish;//发送完成标志

    output cs;//AD TLC549的数据口

    output ioclk;//AD TLC549的时钟

    output start;//开始采集信号

    output[7:0] voltage_data1;//采集的电压数据

    output[7:0] voltage_data2;//采集的电压数据

    output[7:0] voltage_data3;//采集的电压数据

    output[7:0] voltage_data4;//采集的电压数据

    output[3:0] data_cnt;//数据位标志

    output[7:0]segdata;

    output[3:0]segcs;

    reg[7:0] voltage_data1;//采集的电压数据

    reg[7:0] voltage_data2;//采集的电压数据

    reg[7:0] voltage_data3;//采集的电压数据

    reg[7:0] voltage_data4;//采集的电压数据

    reg[3:0] data_cnt;

    // reg[7:0] voltage_data;

    reg[3:0] segcs;

    reg[7:0]segdata;

    reg start;

    reg cs,ioclk,clk1k,clk1ms;

    reg[15:0] count;

    reg[24:0] count1ms;

    reg[3:0] cnt;

    reg[2:0] number;

    reg[1:0] state;

    reg[7:0] dataout;

    reg[16:0] tenvalue;

    parameter sample=2'b00,

    display=2'b01;

    /**********产生100k的采集时钟信号*********/

    always@(posedge clk)

    begin

    if(count<=250)

    count<=count+1'b1;

    else

    begin

    count<=0;

    ioclk<=~ioclk;

    end

    end

    /*******产生周期为1ms1kHz的信号*********/

    always@(posedge clk)

    begin

    if(count1ms>25'd25000)

    begin

    clk1ms<=~clk1ms;

    count1ms<=0;

    end

    else

    count1ms<=count1ms+1'b1;

    end

    /*********AD采样程序**************/

    always@(negedge ioclk ornegedge reset_n)

    begin

    if(reset_n ==1'b0)

    begin

    start<=1'b0;

    state<=sample;

    cs<=1;//AD片选

    cnt<=0;

    tenvalue<=0;

    dataout<=0;

    end

    else

    begin

    case(state)

    sample:

    begin

    cs<=0;

    start<=1'b0;

    dataout[7:0]<={dataout[6:0],data};

    if(cnt>4'd7)

    begin

    cnt<=0;

    state<=display;

    end

    else

    begin

    cnt<=cnt+1'b1;

    state<=sample;

    end

    end

    display:

    begin

    cs<=1;//AD片选

    tenvalue<=(tendata((dataout>>4)&8'b0000_1111)*16+ tendata(dataout &8'b0000_1111))*129;//

    //得到采集的数据

    start<=1'b1;

    voltage_data1<=((tenvalue/10)%10)+8'd48;//个位

    voltage_data2<=((tenvalue/100)%10)+8'd48;//十位

    voltage_data3<=((tenvalue/1000)%10)+8'd48;//百位

    voltage_data4<=(tenvalue/10000)+8'd48;//千位

    if(send_finish ==1'b1)

    state<=sample;

    else

    state<=display;

    end

    default: state<=display;

    endcase

    end

    end

    /***********2进制转十进制函数*************/

    function[7:0] tendata;//返回一个4位的数字

    input[7:0] datain;

    begin

    case(datain)

    4'b00000000: tendata=4'd0;//0

    4'b00000001: tendata=4'd1;//1

    4'b00000010: tendata=4'd2;//2

    4'b00000011: tendata=4'd3;//3

    4'b00000100: tendata=4'd4;//4

    4'b00000101: tendata=4'd5;//5

    4'b00000110: tendata=4'd6;//6

    4'b00000111: tendata=4'd7;//7

    4'b00001000: tendata=4'd8;//8

    4'b00001001: tendata=4'd9;//9

    4'b00001010: tendata=4'd10;//

    4'b00001011: tendata=4'd11;//

    4'b00001100: tendata=4'd12;

    4'b00001101: tendata=4'd13;

    4'b00001110: tendata=4'd14;

    4'b00001111: tendata=4'd15;

    default:tendata=8'bzzzz_zzzz;

    endcase

    end

    endfunction

    /*********十进制转LED段选函数*********/

    function[7:0] leddata;//返回一个8位的数字

    input[3:0] datain;

    begin

    case(datain)

    4'd0: leddata=8'b11000000;//0

    4'd1: leddata=8'b11111001;//1

    4'd2: leddata=8'b10100100;//2

    4'd3: leddata=8'b10110000;//3

    4'd4: leddata=8'b10011001;//4

    4'd5: leddata=8'b10010010;//5

    4'd6: leddata=8'b10000010;//6

    4'd7: leddata=8'b11111000;//7

    4'd8: leddata=8'b10000000;//8

    4'd9: leddata=8'b10010000;//9

    4'd10: leddata=8'b10111111;//-

    4'd11: leddata=8'b01111111;//.

    default:leddata=8'bzzzz_zzzz;

    endcase

    end

    endfunction

    /********数码管扫描函数*************/

    always@(posedge clk1ms)

    begin

    if(number==5) number<=0;

    else

    begin

         number<=number+1;

         case(number)

         4'd0:

         begin

         segdata<=leddata((tenvalue/10)%10);//个位

         segcs<=4'b1110;

         end

         4'd1:

         begin

         segdata<=leddata((tenvalue/100)%10);//十位

         segcs<=4'b1101;

         end

         4'd2:

         begin

         segdata<=leddata((tenvalue/1000)%10);//百位

         segcs<=4'b1011;

         end

         4'd3:

         begin

         segdata<=leddata(tenvalue/10000);//千位

         segcs<=4'b0111;

         end

         4'd4:

         begin

         segdata<=leddata(4'd11);//. 显示小数点

         segcs<=4'b0111;

         end

            endcase

        end

    end

    endmodule

    UART通信

    /*******************************************************************************

    ** 文件名称:uart.v

    ** 功能描述:串口通信__FPGA和上位机通信(波特率:9600bps,10bit1位起始位,8个数据位,1个结束)

    *******************************************************************************/

    module uart(

    clk,

    rst,

    rxd,

    txd,

    start,

    data_cnt,

        voltage_data1,

        voltage_data2,

        voltage_data3,

        voltage_data4,

    send_finish

    );

    input clk;//系统50MHZ时钟

    input rst;//复位

    input rxd;//串行数据接收端

    output txd;//串行数据发送端

    input start;//开始采集信号

    input[3:0] data_cnt;//数据位标志

    input[7:0] voltage_data1;//采集的电压数据

    input[7:0] voltage_data2;//采集的电压数据

    input[7:0] voltage_data3;//采集的电压数据

    input[7:0] voltage_data4;//采集的电压数据

    output send_finish;//发送完成标志

    reg[15:0] div_reg;//分频计数器,分频值由波特率决定。分频后得到频率8倍波特率的时钟

    reg[2:0] div8_tras_reg;//该寄存器的计数值对应发送时当前位于的时隙数

    reg[3:0] state_tras;//发送状态寄存器

    reg clkbaud_tras;//以波特率为频率的发送使能信号

    reg clkbaud8x;//8倍波特率为频率的时钟,它的作用是将发送或接受一个bit的时钟周期分为8个时隙

    reg trasstart;//开始发送标志

    reg            send_finish;

    reg txd_reg;//发送寄存器

    reg[7:0] rxd_buf;//接受数据缓存

    reg[7:0] txd_buf;//发送数据缓存

    reg[3:0] send_state;//发送状态寄存器

    parameter div_par=16'h145;

    //分频参数,其值由对应的波特率计算而得,按此参数分频的时钟频率是波倍特率的8    

    //倍,此处值对应9600的波特率,即分频出的时钟频率是9600*8 (CLK50M)

    assign txd = txd_reg;

    // assign send_state=data_cnt;

    /*******分频得到8倍波特率的时钟*********/

    always@(posedge clk )

    begin

        if(!rst)

            div_reg<=0;

        elsebegin

            if(div_reg==div_par-1'b1)

                div_reg<=0;

            else

                div_reg<=div_reg+1'b1;

         end

    end

    always@(posedge clk)

    begin

        if(!rst)

            clkbaud8x<=0;

        elseif(div_reg==div_par-1'b1)

            clkbaud8x<=~clkbaud8x;//分频得到8倍波特率的时钟:clkbaud8x

    end

    // *******************************/

    always@(posedge clkbaud8x ornegedge rst)//clkbaud8x

    begin

        if(!rst)

            div8_tras_reg<=0;

        elseif(trasstart)

            div8_tras_reg<=div8_tras_reg+1'b1;//发送开始后,时隙数在8倍波特率的时钟下加1循环

    end

    always@(div8_tras_reg)

    begin

        if(div8_tras_reg==7)

            clkbaud_tras=1;//在第7个时隙,发送使能信号有效,将数据发出

        else

            clkbaud_tras=0;

    end

    // *********发送数据模块***************/

    always@(posedge clkbaud8x ornegedge rst)//clkbaud8x

    begin

        if(!rst)

    begin

            txd_reg<=1;//发送寄存器置高

            trasstart<=0;//开始发送标志置低

            txd_buf<=8'h00;//发送缓存器清零

            state_tras<=0;//发送状态寄存器清零

    send_finish <=1'b0;

    send_state<=4'd0;

        end

        else

    if(start ==1'b1)

    case(state_tras)

    4'b0000:begin//发送起始位

    send_finish <=1'b0;

    if(!trasstart&&send_state<4'd7)

    trasstart<=1;

    elseif(send_state<4'd7)begin

    if(clkbaud_tras)begin

    txd_reg<=0;

    state_tras<=state_tras+1'b1;

    end

    end

    elsebegin

    state_tras<=0;

    end                    

    end        

    4'b0001:begin//发送第1

    if(clkbaud_tras)begin

    txd_reg<=txd_buf[0];

    txd_buf[6:0]<=txd_buf[7:1];

    state_tras<=state_tras+1'b1;

    end

    end

    4'b0010:begin//发送第2

    if(clkbaud_tras)begin

    txd_reg<=txd_buf[0];

    txd_buf[6:0]<=txd_buf[7:1];

    state_tras<=state_tras+1'b1;

    end

    end

    4'b0011:begin//发送第3

    if(clkbaud_tras)begin

    txd_reg<=txd_buf[0];

    txd_buf[6:0]<=txd_buf[7:1];

    state_tras<=state_tras+1'b1;

    end

    end

    4'b0100:begin//发送第4

    if(clkbaud_tras)begin

    txd_reg<=txd_buf[0];

    txd_buf[6:0]<=txd_buf[7:1];

    state_tras<=state_tras+1'b1;

    end

    end

    4'b0101:begin//发送第5

    if(clkbaud_tras)begin

    txd_reg<=txd_buf[0];

    txd_buf[6:0]<=txd_buf[7:1];

    state_tras<=state_tras+1'b1;

    end

    end

    4'b0110:begin//发送第6

    if(clkbaud_tras)begin

    txd_reg<=txd_buf[0];

    txd_buf[6:0]<=txd_buf[7:1];

    state_tras<=state_tras+1'b1;

    end

    end

    4'b0111:begin//发送第7

    if(clkbaud_tras)begin

    txd_reg<=txd_buf[0];

    txd_buf[6:0]<=txd_buf[7:1];

    state_tras<=state_tras+1'b1;

    end

    end

    4'b1000:begin//发送第8

    if(clkbaud_tras)begin

    txd_reg<=txd_buf[0];

    txd_buf[6:0]<=txd_buf[7:1];

    state_tras<=state_tras+1'b1;

    end

    end

    4'b1001:begin//发送停止位

    if(clkbaud_tras)begin

    txd_reg<=1;

    txd_buf<=8'h00;

    state_tras<=state_tras+1'b1;

    end

    end

    4'b1111:begin

    if(clkbaud_tras)begin

    state_tras<=state_tras+1'b1;

    send_state<=send_state+1'b1;

    trasstart<=0;

    case(send_state)

    4'b0000:

    txd_buf<=voltage_data4;//个位

    4'b0001:

    txd_buf<=8'd46;//小数点

    4'b0010:

    txd_buf<=voltage_data3;//十位

    4'b0011:

    txd_buf<=voltage_data2;//百位

    4'b0100:

    txd_buf<=voltage_data1;//千位

    4'b0101:

    txd_buf<=8'd86;//"V"

    4'b0110:

    begin

    txd_buf<=8'd10;//换行符

    send_finish <=1'b1;

    send_state<=4'b0000;

    end

    default:

    txd_buf<=8'd0;

    endcase

    end

    end

    default:begin

    if(clkbaud_tras)begin

    state_tras<=state_tras+1'b1;

    trasstart<=1;

    end

    end

    endcase

    end

    endmodule

    大西瓜FPGA-->https://daxiguafpga.taobao.com

    博客资料、代码、图片、文字等属大西瓜FPGA所有,切勿用于商业! 若引用资料、代码、图片、文字等等请注明出处,谢谢!

    每日推送不同科技解读,原创深耕解读当下科技,敬请关注微信公众号“科乎”。

  • 相关阅读:
    python上传阿里云oss
    python调用百度图片识别api
    python实现sm2和sm4国密(国家商用密码)算法
    python坐标获取经纬度或经纬度获取坐标免费模块--geopy
    剑指 Offer 36. 二叉搜索树与双向链表
    vs code中终端中的命令不能使用的解决方法
    VS Code切换默认终端(cmd、powershell)
    剑指 Offer 35. 复杂链表的复制
    剑指 Offer 33. 二叉搜索树的后序遍历序列
    剑指 Offer 32
  • 原文地址:https://www.cnblogs.com/logic3/p/5303609.html
Copyright © 2011-2022 走看看