差别

这里会显示出您选择的修订版和当前版本之间的差别。

到此差别页面的链接

两侧同时换到之前的修订记录 前一修订版
后一修订版
前一修订版
adc数模转换模块 [2017/06/28 17:33]
anran [硬件说明]
adc数模转换模块 [2022/07/20 10:26] (当前版本)
zhijun [小结]
行 1: 行 1:
 ======基于STEP FPGA的PCF8591的ADC(I2C)功能驱动====== ======基于STEP FPGA的PCF8591的ADC(I2C)功能驱动======
  
-本节将和大家一起使用FPGA驱动底板上的PCF8591的ADC采样(I2C)功能。+本节将和大家一起使用[[FPGA]]驱动底板上的PCF8591的[[ADC]]采样([[I2C]])功能。
  
  
 ====硬件说明==== ====硬件说明====
 +
 ------- -------
-PCF8591是集成了4路ADC和1路DAC的芯片,使用I2C总线通信。+PCF8591是集成了4路[[ADC]]和1路[[DAC]]的芯片,使用[[I2C]]总线通信。
 \\ \\
-I2C总线是由Philips公司开发的一种简单、双向二线制同步串行总线。它只需要两根线即可在连接于总线上的器件之间传送信息。主器件用于启动总线传送数据,并产生时钟以开放传送的器件,此时任何被寻址的器件均被认为是从器件。如果主机要发送数据给从器件,则主机首先寻址从器件,然后主动发送数据至从器件,最后由主机终止数据传送;如果主机要接收从器件的数据,首先由主器件寻址从器件,然后主机接收从器件发送的数据,最后由主机终止接收过程。这里不做过多的讲解,硬件连接如下:+[[I2C]]总线是由Philips公司开发的一种简单、双向二线制同步串行总线。它只需要两根线即可在连接于总线上的器件之间传送信息。主器件用于启动总线传送数据,并产生时钟以开放传送的器件,此时任何被寻址的器件均被认为是从器件。如果主机要发送数据给从器件,则主机首先寻址从器件,然后主动发送数据至从器件,最后由主机终止数据传送;如果主机要接收从器件的数据,首先由主器件寻址从器件,然后主机接收从器件发送的数据,最后由主机终止接收过程。这里不做过多的讲解,硬件连接如下:
 {{ :​i2c总线框架.jpg?​800 |}} {{ :​i2c总线框架.jpg?​800 |}}
 \\ \\
行 14: 行 15:
 {{ :​pcf8591硬件连接.jpg?​1000 |}} {{ :​pcf8591硬件连接.jpg?​1000 |}}
 \\ \\
-本设计中FPGA作为I2C主设备,PCF8591作为I2C从设备,从设备的地址由固定地址和可编程地址组成,我们的外设底板已将可编程地址A0、A1、A2接地,所以7位地址为7'​h48,加上最低位的读写控制,所以给PCF8591写数据时的寻址地址为8'​h90,对PCF8591读数据时的寻址地址为8'​h91。如下+本设计中FPGA作为[[I2C]]主设备,PCF8591作为[[I2C]]从设备,从设备的地址由固定地址和可编程地址组成,我们的外设底板已将可编程地址A0、A1、A2接地,所以7位地址为7'​h48,加上最低位的读写控制,所以给PCF8591写数据时的寻址地址为8'​h90,对PCF8591读数据时的寻址地址为8'​h91。如下
 {{ :​pcf8591_i2c地址.jpg?​800 |}} {{ :​pcf8591_i2c地址.jpg?​800 |}}
 \\ \\
行 26: 行 27:
 {{ :​pcf8591_adc时序.jpg?​1000 |}} {{ :​pcf8591_adc时序.jpg?​1000 |}}
 \\ \\
-通过上面的介绍大家应该对如何驱动PCF8591进行ADC采样有了整体的概念,还有一些细节就是I2C通信的时序明细,如下图+通过上面的介绍大家应该对如何驱动PCF8591进行[[ADC]]采样有了整体的概念,还有一些细节就是[[I2C]]通信的时序明细,如下图
 {{ :​pcf8591_时序控制.jpg?​800 |}} {{ :​pcf8591_时序控制.jpg?​800 |}}
 {{ :​pcf8591_时序控制2.jpg?​800 |}} {{ :​pcf8591_时序控制2.jpg?​800 |}}
  
 ====Verilog代码==== ====Verilog代码====
 +
 ------ ------
 <code verilog> <code verilog>
行 36: 行 38:
 // >>>>>>>>>>>>>>>>>>>>>>>>>​ COPYRIGHT NOTICE <<<<<<<<<<<<<<<<<<<<<<<<<​ // >>>>>>>>>>>>>>>>>>>>>>>>>​ COPYRIGHT NOTICE <<<<<<<<<<<<<<<<<<<<<<<<<​
 // -------------------------------------------------------------------- // --------------------------------------------------------------------
-// Module: ​Uart_bus+// Module: ​ADC_I2C
 //  // 
 // Author: Step // Author: Step
 //  // 
-// Description: ​The module for uart communication +// Description: ​ADC_I2C
-//  +
-// Web: www.stepfapga.com+
 //  // 
 +// Web: www.stepfpga.com
 +//
 // -------------------------------------------------------------------- // --------------------------------------------------------------------
 // Code Revision History : // Code Revision History :
 // -------------------------------------------------------------------- // --------------------------------------------------------------------
 // Version: |Mod. Date:   ​|Changes Made: // Version: |Mod. Date:   ​|Changes Made:
-// V1.    |2016/04/20   |Initial ver+// V1.    |2016/10/30   |Initial ver
 // -------------------------------------------------------------------- // --------------------------------------------------------------------
-module ​Uart_Bus #+module ​ADC_I2C
 ( (
-parameter BPS_PARA = 1250 //​当使用12MHz时钟时波特率参数选择1250对应9600的波特率 + input clk_in, //​系统时钟 
-+ input rst_n_in,​ //​系统复位,低有效 
-+ output scl_out, //I2C总线SCL 
-input clk_in, //​系统时钟 + inout sda_out, //I2C总线SDA 
-input rst_n_in, //​系统复位,低有效 + output reg adc_done, //ADC采样完成标志 
-input rs232_rx,​ //​FPGA中UART接收端,分配给UART模块中的发送端TXD + output reg [7:​0] adc_data //ADC采样数据
-output rs232_tx //​FPGA中UART发送端,分配给UART模块中的接收端RXD +
-);  +
-  +
-/////////////////////////////////​UART接收功能模块例化////////////////////////////////////​ +
-wire bps_en_rx,​bps_clk_rx;​ +
-wire [7:​0] rx_data;​ +
- +
-//​UART接收波特率时钟控制模块 例化 +
-Baud # +
-+
-.BPS_PARA (BPS_PARA ) +
-+
-Baud_rx +
-(  +
-.clk_in (clk_in ), //系统时钟 +
-.rst_n_in (rst_n_in ), //系统复位,低有效 +
-.bps_en (bps_en_rx ),​ //​接收时钟使能 +
-.bps_clk (bps_clk_rx ) //​接收时钟输出 +
-); +
- +
-//​UART接收数据模块 例化 +
-Uart_Rx Uart_Rx_uut +
-+
-.clk_in (clk_in ), //系统时钟 +
-.rst_n_in (rst_n_in ),​ //​系统复位,低有效 +
-.bps_en (bps_en_rx ),​ //​接收时钟使能 +
-.bps_clk (bps_clk_rx ),​ //​接收时钟输入 +
-.rs232_rx (rs232_rx ),​ //​UART接收输入 +
-.rx_data (rx_data ) //接收到的数据+
 ); );
   
 + parameter CNT_NUM = 15;​
   
-/////////////////////////////////​UART发送功能模块例化////////////////////////////////////​ + localparam IDLE = 3'​d0
-wire bps_en_tx,​bps_clk_tx;​ + localparam MAIN = 3'​d1
- + localparam START = 3'd2
-//​UART发送波特率时钟控制模块 例化 + localparam WRITE = 3'd3
-Baud # + localparam READ = 3'd4
-+ localparam STOP = 3'd5;
-.BPS_PARA (BPS_PARA +
-+
-Baud_tx +
-+
-.clk_in (clk_in ),​ //​系统时钟 +
-.rst_n_in (rst_n_in ),​ //​系统复位,低有效 +
-.bps_en (bps_en_tx ),​ //​发送时钟使能 +
-.bps_clk (bps_clk_tx ) //​发送时钟输出 +
-)+
- +
-//​UART发送数据模块 例化 +
-Uart_Tx Uart_Tx_uut +
-+
-.clk_in (clk_in ),​ //​系统时钟 +
-.rst_n_in (rst_n_in ),​ //​系统复位,低有效 +
-.bps_en (bps_en_tx ),​ //​发送时钟使能 +
-.bps_clk (bps_clk_tx ),​ //​发送时钟输入 +
-.rx_bps_en (bps_en_rx ),​ //​因需要自收自发,使用接收时钟使能判定:接收到新的数据,需要发送 +
-.tx_data (rx_data ),​ //​需要发出的数据 +
-.rs232_tx (rs232_tx ) //​UART发送输出 +
-)+
- +
-endmodule +
-</​code>​ +
-\\ +
-<code verilog>​ +
-// -------------------------------------------------------------------- +
-// >>>>>>>>>>>>>>>>>>>>>>>>>​ COPYRIGHT NOTICE <<<<<<<<<<<<<<<<<<<<<<<<<​ +
-// -------------------------------------------------------------------- +
-// Module: Baud +
-//  +
-// Author: Step +
-//  +
-// Description:​ Beat for uart transfer and receive baud rate +
-//  +
-// Web: www.stepfapga.com +
-//  +
-// -------------------------------------------------------------------- +
-// Code Revision History : +
-// -------------------------------------------------------------------- +
-// Version: |Mod. Date:   ​|Changes Made: +
-// V1.0     ​|2016/​04/​20 ​  ​|Initial ver +
-// -------------------------------------------------------------------- +
-module Baud # +
-+
-parameter BPS_PARA ​1250 //​当使用12MHz时钟时波特率参数选择1250对应9600的波特率 +
-+
-+
-input clk_in,​ //​系统时钟 +
-input rst_n_in,​ //​系统复位,低有效 +
-input bps_en,​ //​接收或发送时钟使能 +
-output reg bps_clk //​接收或发送时钟输出 +
-);  +
- +
-reg [12:​0] cnt;​ +
-//​计数器计数满足波特率时钟要求 +
-always @ (posedge clk_in or negedge rst_n_in) begin +
- if(!rst_n_in)  +
- cnt <1'b0+
- else if((cnt >BPS_PARA-1)||(!bps_en)) //​当时钟信号不使能(bps_en为低电平)时,计数器清零并停止计数 +
- cnt <= 1'b0; //​当时钟信号使能时,计数器对系统时钟计数,周期为BPS_PARA个系统时钟周期 +
- else  +
- cnt <cnt + 1'b1; +
-end+
   
-//产生相应波特率时钟节拍接收模块将以此节拍进行UART数据接收 + //根据PCF8591datasheetI2C的频率最高为100KHz, 
-always @ (posedge clk_in or negedge rst_n_in) + //​我们准备使用4个节拍完成1bit数据的传输,所以需要400KHz的时钟触发完成该设计 
- begin + //​使用计数器分频产生400KHz时钟信号clk_400khz 
- if(!rst_n_in)  + reg clk_400khz;​ 
- bps_clk ​<= 1'​b0;​ + reg [9:​0] cnt_400khz;​ 
- else if(cnt =(BPS_PARA>>​1)) //​BPS_PARA右移一位等于除2,因计数器终值BPS_PARA为数据更替时间点,所以计数器中值时为数据最稳定时间点 + always@(posedge clk_in or negedge rst_n_in) begin 
- bps_clk ​<= 1'b1;  + if(!rst_n_in) ​begin 
- else  + cnt_400khz <= 10'​d0;​ 
- bps_clk ​<= 1'b0;+ clk_400khz ​<= 1'​b0;​ 
 + end else if(cnt_400khz >CNT_NUM-1) begin 
 + cnt_400khz ​<= 10'd0; 
 + clk_400khz <= ~clk_400khz
 + end else begin 
 + cnt_400khz ​<= cnt_400khz + 1'b1; 
 + end
  end  end
 +
 + reg [7:​0] adc_data_r;​
 + reg scl_out_r;​
 + reg sda_out_r;​
 + reg [2:​0] cnt;​
 + reg [3:​0] cnt_main;​
 + reg [7:​0] data_wr;​
 + reg [2:​0] cnt_start;​
 + reg [2:​0] cnt_write;​
 + reg [4:​0] cnt_read;​
 + reg [2:​0] cnt_stop;​
 + reg [2:0] state;
  
-endmodule + always@(posedge clk_400khz or negedge rst_n_in) begin 
-</code> + if(!rst_n_in) begin //​如果按键复位,将相关数据初始化 
-\\ + scl_out_r <= 1'd1; 
-<code verilog> + sda_out_r ​<= 1'd1; 
-// -------------------------------------------------------------------- + cnt <= 1'b0; 
-// >>>>>>>>>>>>>>>>>>>>>>>>>​ COPYRIGHT NOTICE <<<<<<<​<<<<<<<<<<<<<<<<<<​ + cnt_main ​<= 4'​d0;​ 
-// -------------------------------------------------------------------- + cnt_start ​<= 3'​d0;​ 
-// ModuleUart_Rx + cnt_write ​<= 3'​d0;​ 
-//  + cnt_read ​<= 5'​d0;​ 
-// Author: Step + cnt_stop ​<= 1'​d0;​ 
-//  + adc_done ​<= 1'​b0;​ 
-// Description:​ The receive module of uart interface + adc_data ​<= 1'​b0;​ 
-//  + state ​<= IDLE; 
-// Web: www.stepfapga.com + end else begin 
-//  + case(state) 
-// -------------------------------------------------------------------- + IDLE:​begin //​软件自复位,主要用于程序跑飞后的处理 
-// Code Revision History ​: + scl_out_r ​<= 1'​d1;​ 
-// -------------------------------------------------------------------- + sda_out_r ​<= 1'​d1;​ 
-// Version|Mod. Date:   ​|Changes Made: + cnt ​<= 1'​b0;​ 
-// V1.0     ​|2016/​04/​20 ​  ​|Initial ver + cnt_main ​<= 4'​d0;​ 
-// -------------------------------------------------------------------- + cnt_start ​<= 3'​d0;​ 
-module Uart_Rx + cnt_write ​<= 3'​d0;​ 
-+ cnt_read ​<= 5'​d0;​ 
-input clk_in,​ //系统时钟 + cnt_stop ​<= 1'​d0;​ 
-input rst_n_in,​ //系统复位低有效 + adc_done ​<= 1'​b0;​ 
- + state ​<= MAIN; 
-output reg bps_en,​ //接收时钟使能 + end 
-input bps_clk,​ //接收时钟输入 + MAIN:begin 
- + if(cnt_main >= 4'd6) cnt_main <= 4'​d6;  ​//对MAIN中的子状态执行控制cnt_main 
-input rs232_rx,​ //UART接收输入 + else cnt_main <= cnt_main + 1'​b1;​ 
-output reg [7:0] rx_data //接收到的数据 + case(cnt_main) 
-);  + 4'​d0:​ begin state <= START; end //I2C通信时序中的START 
- + 4'​d1:​ begin data_wr <= 8'h90; state <= WRITE; end //A0,​A1,​A2都接了GND,写地址为8'​h90 
-reg rs232_rx0,​rs232_rx1,​rs232_rx2;​  + 4'​d2:​ begin data_wr <= 8'h00; state <= WRITE; end //control byte为8'​h00,采用4通道ADC中的通道0 
-//多级延锁存去除亚稳态 + 4'​d3:​ begin state <= STOP; end //I2C通信时序中的START 
-always @ (posedge clk_in or negedge rst_n_in) begin + 4'​d4:​ begin state <= START; end //I2C通信时序中的STOP 
- if(!rst_n_in) begin + 4'​d5:​ begin data_wr <= 8'h91; state <= WRITE; end //A0 A1 A2都接了GND,读地址为8'​h91 
- rs232_rx0 ​<= 1'b0; + 4'​d6:​ begin state <= READ; adc_done <= 1'b0; end //读取ADC的采样数据 
- rs232_rx1 ​<= 1'b0+ 4'​d7:​ begin state <= STOP; adc_done <= 1'b1; end //I2C通信时序中的STOP,读取完成标志 
- rs232_rx2 ​<= 1'b0+ 4'​d8: begin state <= MAIN; end //预留状态,不执行 
- end else begin + default:​ state <= IDLE; //如果程序失控,进入IDLE自复位状态 
- rs232_rx0 ​<= rs232_rx; + endcase 
- rs232_rx1 ​<= rs232_rx0+ end 
- rs232_rx2 ​<= rs232_rx1; + START:begin //I2C通信时序中的起始START 
- end + if(cnt_start >= 3'd5) cnt_start <= 1'b0; //对START中的子状态执行控制cnt_start 
-end + else cnt_start <= cnt_start + 1'b1; 
- + case(cnt_start) 
-//检测UART接收入信号下降沿 + 3'​d0:​ begin sda_out_r <= 1'b1; scl_out_r <= 1'b1; end //将SCL和SDA拉高,保持4.7us以上 
-wire neg_rs232_rx ​rs232_rx2 & rs232_rx1 & (~rs232_rx0) & (~rs232_rx);  + 3'​d1:​ begin sda_out_r <= 1'b1; scl_out_r <= 1'b1; end //clk_400khz每个周期2.5us需要两个周期 
-  + 3'​d2:​ begin sda_out_r <= 1'b0; end //SDA拉低到SCL拉低,保持4.0us以上 
-reg [3:0] num;  + 3'​d3:​ begin sda_out_r <= 1'b0; end //clk_400khz每个周期2.5us,需要两个周期 
-//接收时钟使能信号的控制 + 3'​d4:​ begin scl_out_r <= 1'b0; end //SCL拉低,保持4.7us以上 
-always @ (posedge clk_in or negedge rst_n_in) ​begin + 3'​d5: begin scl_out_r <= 1'b0; state <= MAIN; end //clk_400khz每个周期2.5us,需要两个周期,返回MAIN 
- if(!rst_n_in+ default:​ state <= IDLE; //​如果程序失控,进入IDLE自复位状态 
- bps_en ​<= 1'b0; + endcase 
- else if(neg_rs232_rx && (!bps_en)) //当空闲状态(bps_en为低电平)时检测到UART接收信号下降沿,进入工作状态(bps_en为高电平),控制钟模块产生接收时钟 + end 
- bps_en ​<= 1'b1;  + WRITE:​begin //I2C通信序中的写操作WRITE和相应判断操作ACK 
- else if(num==4'd9)       //当完成一次UART接收操作后,退出工作状态,恢复空闲状态 + if(cnt <= 3'd6) begin //​共需要发送8bit的数据,这里控制循环的次数 
- bps_en ​<= 1'b0;  + if(cnt_write >= 3'd3) begin cnt_write ​<= 1'​b0; ​cnt <= cnt + 1'b1end 
-end + else begin cnt_write ​<= cnt_write + 1'b1cnt <= cnt; end 
- + end else begin 
-reg [7:0] rx_data_r+ if(cnt_write >= 3'd7) begin cnt_write ​<= 1'b0cnt <= 1'b0end //​两个变量都恢复初值 
-//当处于工作状态中时按照接收时钟节拍获取数据 + else begin cnt_write ​<= cnt_write + 1'b1; cnt <= cnt; end 
-always @ (posedge clk_in or negedge rst_n_in) begin + end 
- if(!rst_n_in) ​begin + case(cnt_write) 
- num <= 4'd0+ //按照I2C的时序传数据 
- rx_data ​<= 8'd0+ 3'​d0:​ begin scl_out_r <= 1'b0; sda_out_r <= data_wr[7-cnt];​ end //​SCL拉低,并控制SDA输出对应 
- rx_data_r ​<= 8'd0+ 3'​d1:​ begin scl_out_r <1'b1end //​SCL拉高,保持4.0us以上 
- end else if(bps_en) ​begin  + 3'​d2:​ begin scl_out_r <= 1'b1; end //​clk_400khz每个周期2.5us,需要两个周期 
- if(bps_clkbegin  + 3'd3: begin scl_out_r <= 1'b0end //​SCL拉低,准备发送下1bit的数据 
- num <= num+1'​b1;​ + //获取从设备的响应信号并判断 
- if(num<=4'd8) + 3'​d4:​ begin sda_out_r <= 1'bz; end //​释放SDA线,准备接收从设备的响应信号 
- rx_data_r[num-1]<=rs232_rx; //先接受位再接收高位8位有效数据 + 3'​d5:​ begin scl_out_r <= 1'b1; end //​SCL拉高,保持4.0us以上 
- end else if(num == 4'd9) begin //​完成一次UART接收操作将获取的数据输出 + 3'​d6:​ begin ​if(sda_outstate <= IDLE; else state <= state; end //​获取从设备的响应信号并判断 
- num <= 4'd0;  + 3'​d7:​ begin scl_out_r ​<= 1'​b0; ​state <= MAIN; end //SCL拉低,返回MAIN状态 
- rx_data <= rx_data_r; + default:​ state <= IDLE;​ //​如果程序失控,进入IDLE自复位状态 
 + endcase 
 + end 
 + READ:​begin //​I2C通信序中的读操作READ和返回ACK的操作 
 + if(cnt <= 3'd6) begin //​共需要接收8bit的数据,这里控制循环的次数 
 + if(cnt_read >= 3'd3) begin cnt_read ​<= 1'b0; cnt <= cnt + 1'​b1; ​end 
 + else begin cnt_read <= cnt_read + 1'b1; cnt <= cnt; end 
 + end else begin 
 + if(cnt_read >3'd7) begin cnt_read <1'b0; cnt <= 1'b0; end //​两个变量都恢复初值 
 + else begin cnt_read <= cnt_read + 1'b1; cnt <= cnt; end 
 + end 
 + case(cnt_read) 
 + //按照I2C的时序接收数据 
 + 3'​d0:​ begin scl_out_r ​<= 1'​b0; ​sda_out_r <= 1'bz; end //​SCL拉低,释放SDA线,准备接收从设备数据 
 + 3'​d1:​ begin scl_out_r <= 1'​b1; ​end //​SCL拉高,保持4.0us以上 
 + 3'​d2:​ begin adc_data_r[7-cnt<= sda_outend //​读取从设备返回的数据 
 + 3'​d3:​ begin scl_out_r <= 1'b0; end //SCL拉低准备接收下1bit的数据 
 + //​向从设备发送响应信号 
 + 3'​d4:​ begin sda_out_r <= 1'b0; adc_done <= 1'b1; adc_data <= adc_data_r; end //​发送响应信号,将前面接收的数据锁存 
 + 3'​d5:​ begin scl_out_r ​<= 1'b1end //​SCL拉高,保持4.0us以上 
 + 3'​d6:​ begin scl_out_r ​<= 1'b1adc_done <= 1'b0; end //​SCL拉高,保持4.0us以上 
 + 3'​d7:​ begin scl_out_r ​<= 1'b0state <= MAIN; end //​SCL拉低,返回MAIN状态 
 + default:​ state <= IDLE;​ //​如果程序失控,进入IDLE自复位状态 
 + endcase 
 + end 
 + STOP:begin //​I2C通信时序中的结束STOP 
 + if(cnt_stop >= 3'd5cnt_stop <= 1'​b0;​ //​对STOP中的子状态执行控制cnt_stop 
 + else cnt_stop ​<= cnt_stop ​+ 1'​b1;​ 
 + case(cnt_stop) 
 + 3'​d0:​ begin sda_out_r ​<= 1'b0; end //​SDA拉低,准备STOP 
 + 3'​d1:​ begin sda_out_r ​<= 1'b0end //SDA拉低,准备STOP 
 + 3'​d2:​ begin scl_out_r <= 1'​b1; ​end //​SCL提前SDA拉高4.0us 
 + 3'​d3:​ begin scl_out_r <1'b1; end //​SCL提前SDA拉高4.0us 
 + 3'd4: begin sda_out_r <= 1'b1; end //​SDA拉高 
 + 3'​d5:​ begin sda_out_r <= 1'b1; state <= MAIN; end //完成STOP操作,返回MAIN状态 
 + default:​ state <= IDLE; //​如果程序失控,进入IDLE自复位状态 
 + endcase 
 + end 
 + default:​; 
 + endcase
  end  end
  end  end
-end+  
 + assign scl_out = scl_out_r;​ //​对SCL端口赋值 
 + assign sda_out = sda_out_r;​ //​对SDA端口赋值
  
 endmodule endmodule
- 
 </​code>​ </​code>​
-\\ 
-<code verilog> 
-// -------------------------------------------------------------------- 
-// >>>>>>>>>>>>>>>>>>>>>>>>>​ COPYRIGHT NOTICE <<<<<<<<<<<<<<<<<<<<<<<<<​ 
-// -------------------------------------------------------------------- 
-// Module: Uart_Tx 
-//  
-// Author: Step 
-//  
-// Description:​ The transfer module of uart interface 
-//  
-// Web: www.stepfapga.com 
-//  
-// -------------------------------------------------------------------- 
-// Code Revision History : 
-// -------------------------------------------------------------------- 
-// Version: |Mod. Date:   ​|Changes Made: 
-// V1.0     ​|2016/​04/​20 ​  ​|Initial ver 
-// -------------------------------------------------------------------- 
-module Uart_Tx 
-( 
-input clk_in,​ //​系统时钟 
-input rst_n_in,​ //​系统复位,低有效 
-output reg bps_en,​ //​发送时钟使能 
-input bps_clk,​ //​发送时钟输入 
-input rx_bps_en,​ //​因需要自收自发,使用接收时钟使能判定:接收到新的数据,需要发送 
-input [7:​0] tx_data,​ //​需要发出的数据 
-output reg rs232_tx //​UART发送输出 
-); 
  
-reg rx_bps_en_r;​ 
-//​延时锁存接收时钟使能信号 
-always @ (posedge clk_in or negedge rst_n_in) begin 
- if(!rst_n_in) rx_bps_en_r <= 1'b0; 
- else rx_bps_en_r <= rx_bps_en; 
-end 
-  
-//​检测接收时钟使能信号的下降沿,因为下降沿代表接收数据的完成,以此作为发送信号的激励 
-wire neg_rx_bps_en = rx_bps_en_r & (~rx_bps_en);​ 
-  
-reg [3:​0] num;​ 
-reg [9:​0] tx_data_r;​  
-//​根据接收数据的完成,驱动发送数据操作 
-always @ (posedge clk_in or negedge rst_n_in) begin 
- if(!rst_n_in) begin 
- bps_en <= 1'b0; 
- tx_data_r <= 8'd0; 
- end else if(neg_rx_bps_en)begin  
- bps_en <= 1'​b1;​ //​当检测到接收时钟使能信号的下降沿,表明接收完成,需要发送数据,使能发送时钟使能信号 
- tx_data_r <= {1'​b1,​tx_data,​1'​b0};​  
- end else if(num==4'​d10) begin  
- bps_en <= 1'​b0;​ //​一次UART发送需要10个时钟信号,然后结束 
- end 
-end 
  
-//​当处于工作状态中时,按照发送时钟的节拍发送数据 +====小结====
-always @ (posedge clk_in or negedge rst_n_in) begin +
- if(!rst_n_in) begin +
- num <1'​b0;​ +
- rs232_tx <1'​b1;​ +
- end else if(bps_en) begin +
- if(bps_clk) begin +
- num <num + 1'​b1;​ +
- rs232_tx <tx_data_r[num];​ +
- end else if(num>=4'd10)  +
- num <4'​d0;​  +
- end +
-end+
  
-endmodule 
- 
-</​code>​ 
- 
-====小结==== 
 ------ ------
-本节主要为大家讲解了UART通信的原理及软件设计,需要大家掌握的同时自己创建工程,通过整个设计流程,生成FPGA配置文件加载测试。+本节主要为大家讲解了使用[[I2C]]驱动PCF8591的[[ADC]]功能的原理及软件设计,需要大家掌握的同时自己创建工程,通过整个设计流程,生成[[FPGA]]配置文件加载测试。
 \\ \\
-如果你对Diamond软件的使用不了解,请参考这里:[[lattice_diamond的使用|Diamond的使用]]。+如果你对Diamond软件的使用不了解,请参考这里:[[lattice_fpga|Diamond的使用]]。
  
 ====相关资料==== ====相关资料====
 +
 ------ ------
 \\ \\
-使用[[STEP-MXO2第二代]]的UART通信程序: ​ 后续会有下载连接 ​ 待更新+使用[[STEP-MXO2第二代]]的PCF8591的[[ADC]]驱动程序: ​ 后续会有下载连接 ​ 待更新
 \\ \\
-使用[[STEP-MAX10]]的UART通信程序: ​ 后续会有下载连接 ​ 待更新+使用[[STEP-MAX10]]的PCF8591的[[ADC]]驱动程序: ​ 后续会有下载连接 ​ 待更新
 \\ \\