<meter id="pryje"><nav id="pryje"><delect id="pryje"></delect></nav></meter>
          <label id="pryje"></label>

          新聞中心

          EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > 基于STEP FPGA的PCF8591的ADC(I2C)功能驅(qū)動(dòng)

          基于STEP FPGA的PCF8591的ADC(I2C)功能驅(qū)動(dòng)

          作者: 時(shí)間:2023-12-04 來源:電子森林 收藏

          硬件說明

          PCF8591是集成了4路ADC和1路DAC的芯片,使用I2C總線通信。
          I2C總線是由Philips公司開發(fā)的一種簡單、雙向二線制同步串行總線。它只需要兩根線即可在連接于總線上的器件之間傳送信息。主器件用于啟動(dòng)總線傳送數(shù)據(jù),并產(chǎn)生時(shí)鐘以開放傳送的器件,此時(shí)任何被尋址的器件均被認(rèn)為是從器件。如果主機(jī)要發(fā)送數(shù)據(jù)給從器件,則主機(jī)首先尋址從器件,然后主動(dòng)發(fā)送數(shù)據(jù)至從器件,最后由主機(jī)終止數(shù)據(jù)傳送;如果主機(jī)要接收從器件的數(shù)據(jù),首先由主器件尋址從器件,然后主機(jī)接收從器件發(fā)送的數(shù)據(jù),最后由主機(jī)終止接收過程。這里不做過多的講解,硬件連接如下:

          本文引用地址:http://www.ex-cimer.com/article/202312/453512.htm

          本設(shè)計(jì)的硬件連接如下

          本設(shè)計(jì)中FPGA作為I2C主設(shè)備,PCF8591作為I2C從設(shè)備,從設(shè)備的地址由固定地址和可編程地址組成,我們的外設(shè)底板已將可編程地址A0、A1、A2接地,所以7位地址為7'h48,加上最低位的讀寫控制,所以給PCF8591寫數(shù)據(jù)時(shí)的尋址地址為8'h90,對(duì)PCF8591讀數(shù)據(jù)時(shí)的尋址地址為8'h91。如下

          PCF8591集成了很多功能,當(dāng)需要不同的功能時(shí)要對(duì)PCF8591做相應(yīng)的配置,配置數(shù)據(jù)存儲(chǔ)在名為CONTROL BYTE的寄存器中,下圖展示了寄存器中部分bit的功能,詳細(xì)請(qǐng)參考PCF8591的datasheet,本設(shè)計(jì)中我們只使用通道1的ADC功能,配置數(shù)據(jù)為8'h01。

          本設(shè)計(jì)中我們需要兩次通信,

          • 第一次為配置數(shù)據(jù),具體為:開始–寫尋址–讀響應(yīng)–寫配置數(shù)據(jù)–讀響應(yīng)–結(jié)束
          • 第二次為讀ADC數(shù)據(jù),具體為:開始–讀尋址–讀響應(yīng)–[讀ADC數(shù)據(jù)–寫響應(yīng)–]循環(huán)讀

          第二次的時(shí)序如下圖:
          通過上面的介紹大家應(yīng)該對(duì)如何驅(qū)動(dòng)PCF8591進(jìn)行ADC采樣有了整體的概念,還有一些細(xì)節(jié)就是I2C通信的時(shí)序明細(xì),如下圖


          Verilog代碼

          // --------------------------------------------------------------------
          // >>>>>>>>>>>>>>>>>>>>>>>>> COPYRIGHT NOTICE <<<<<<<<<<<<<<<<<<<<<<<<<
          // --------------------------------------------------------------------
          // Module: ADC_I2C
          // 
          // Author: Step
          // 
          // Description: ADC_I2C
          // 
          // --------------------------------------------------------------------
          // Code Revision History :
          // --------------------------------------------------------------------
          // Version: |Mod. Date:   |Changes Made:
          // V1.1     |2016/10/30   |Initial ver
          // --------------------------------------------------------------------
          module ADC_I2C(
          	input				clk_in,		//系統(tǒng)時(shí)鐘
          	input				rst_n_in,	//系統(tǒng)復(fù)位,低有效
          	output				scl_out,	//I2C總線SCL
          	inout				sda_out,	//I2C總線SDA
          	output	reg			adc_done,	//ADC采樣完成標(biāo)志
          	output	reg	[7:0]	adc_data	//ADC采樣數(shù)據(jù)
          	)
          	; 	
          	parameter	CNT_NUM	=	15; 	
          	localparam	IDLE	=	3'd0;
          	localparam	MAIN	=	3'd1;
          	localparam	START	=	3'd2;
          	localparam	WRITE	=	3'd3;
          	localparam	READ	=	3'd4;
          	localparam	STOP	=	3'd5; 	//根據(jù)PCF8591的datasheet,I2C的頻率最高為100KHz,
          	//我們準(zhǔn)備使用4個(gè)節(jié)拍完成1bit數(shù)據(jù)的傳輸,所以需要400KHz的時(shí)鐘觸發(fā)完成該設(shè)計(jì)
          	//使用計(jì)數(shù)器分頻產(chǎn)生400KHz時(shí)鐘信號(hào)clk_400khz
          	reg					clk_400khz;
          	reg		[9:0]		cnt_400khz;
          	always@(posedge clk_in or negedge rst_n_in) begin
          		if(!rst_n_in) begin
          			cnt_400khz <= 10'd0;
          			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 	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; 	
          	always@(posedge clk_400khz or negedge rst_n_in) begin
          		if(!rst_n_in) begin	//如果按鍵復(fù)位,將相關(guān)數(shù)據(jù)初始化
          			scl_out_r <= 1'd1;
          			sda_out_r <= 1'd1;
          			cnt <= 1'b0;
          			cnt_main <= 4'd0;
          			cnt_start <= 3'd0;
          			cnt_write <= 3'd0;
          			cnt_read <= 5'd0;
          			cnt_stop <= 1'd0;
          			adc_done <= 1'b0;
          			adc_data <= 1'b0;
          			state <= IDLE;
          		end else begin
          			case(state)
          				IDLE:begin	//軟件自復(fù)位,主要用于程序跑飛后的處理
          						scl_out_r <= 1'd1;
          						sda_out_r <= 1'd1;
          						cnt <= 1'b0;
          						cnt_main <= 4'd0;
          						cnt_start <= 3'd0;
          						cnt_write <= 3'd0;
          						cnt_read <= 5'd0;
          						cnt_stop <= 1'd0;
          						adc_done <= 1'b0;
          						state <= MAIN;
          					end
          				MAIN:begin
          						if(cnt_main >= 4'd6) cnt_main <= 4'd6;  //對(duì)MAIN中的子狀態(tài)執(zhí)行控制cnt_main
          						else cnt_main <= cnt_main + 1'b1;
          						case(cnt_main)
          							4'd0:	begin state <= START; 
          							end	//I2C通信時(shí)序中的START
          							4'd1:	begin data_wr <= 8'h90; 
          							state <= WRITE; 
          							end	//A0,A1,A2都接了GND,寫地址為8'h90
          							4'd2:	begin data_wr <= 8'h00; 
          							state <= WRITE; 
          							end	//control byte為8'h00,采用4通道ADC中的通道0
          							4'd3:	begin state <= STOP; 
          							end	//I2C通信時(shí)序中的START
          							4'd4:	begin state <= START; 
          							end	//I2C通信時(shí)序中的STOP
          							4'd5:	begin data_wr <= 8'h91; 
          							state <= WRITE; 
          							end	//A0 A1 A2都接了GND,讀地址為8'h91
          							4'd6:	begin state <= READ; 
          							adc_done <= 1'b0; 
          							end	//讀取ADC的采樣數(shù)據(jù)
          							4'd7:	begin state <= STOP; 
          							adc_done <= 1'b1; 
          							end	//I2C通信時(shí)序中的STOP,讀取完成標(biāo)志
          							4'd8:	begin state <= MAIN; 
          							end	//預(yù)留狀態(tài),不執(zhí)行
          							default: state <= IDLE;	//如果程序失控,進(jìn)入IDLE自復(fù)位狀態(tài)
          						endcase
          					end
          				START:begin	//I2C通信時(shí)序中的起始START
          						if(cnt_start >= 3'd5) cnt_start <= 1'b0;	
          						//對(duì)START中的子狀態(tài)執(zhí)行控制cnt_start
          						else cnt_start <= cnt_start + 1'b1;
          						case(cnt_start)
          							3'd0:	begin sda_out_r <= 1'b1; 
          							scl_out_r <= 1'b1; 
          							end	//將SCL和SDA拉高,保持4.7us以上
          							3'd1:	begin sda_out_r <= 1'b1; 
          							scl_out_r <= 1'b1; 
          							end	//clk_400khz每個(gè)周期2.5us,需要兩個(gè)周期
          							3'd2:	begin sda_out_r <= 1'b0; 
          							end	//SDA拉低到SCL拉低,保持4.0us以上
          							3'd3:	begin sda_out_r <= 1'b0; 
          							end	//clk_400khz每個(gè)周期2.5us,需要兩個(gè)周期
          							3'd4:	begin scl_out_r <= 1'b0; 
          							end	//SCL拉低,保持4.7us以上
          							3'd5:	begin scl_out_r <= 1'b0; 
          							state <= MAIN; 
          							end	//clk_400khz每個(gè)周期2.5us,需要兩個(gè)周期,返回MAIN
          							default: state <= IDLE;	//如果程序失控,進(jìn)入IDLE自復(fù)位狀態(tài)
          						endcase
          					end
          				WRITE:begin	//I2C通信時(shí)序中的寫操作WRITE和相應(yīng)判斷操作ACK
          						if(cnt <= 3'd6) begin	//共需要發(fā)送8bit的數(shù)據(jù),這里控制循環(huán)的次數(shù)
          							if(cnt_write >= 3'd3) begin cnt_write <= 1'b0; 
          							cnt <= cnt + 1'b1; end
          							else begin cnt_write <= cnt_write + 1'b1; 
          							cnt <= cnt; end
          						end else begin
          							if(cnt_write >= 3'd7) begin cnt_write <= 1'b0; 
          							cnt <= 1'b0; end	//兩個(gè)變量都恢復(fù)初值
          							else begin cnt_write <= cnt_write + 1'b1; 
          							cnt <= cnt; end
          						end
          						case(cnt_write)
          							//按照I2C的時(shí)序傳輸數(shù)據(jù)
          							3'd0:	begin scl_out_r <= 1'b0; 
          							sda_out_r <= data_wr[7-cnt]; 
          							end	//SCL拉低,并控制SDA輸出對(duì)應(yīng)的位
          							3'd1:	begin scl_out_r <= 1'b1; 
          							end	//SCL拉高,保持4.0us以上
          							3'd2:	begin scl_out_r <= 1'b1; 
          							end	//clk_400khz每個(gè)周期2.5us,需要兩個(gè)周期
          							3'd3:	begin scl_out_r <= 1'b0; 
          							end	//SCL拉低,準(zhǔn)備發(fā)送下1bit的數(shù)據(jù)
          							//獲取從設(shè)備的響應(yīng)信號(hào)并判斷
          							3'd4:	begin sda_out_r <= 1'bz; 
          							end	//釋放SDA線,準(zhǔn)備接收從設(shè)備的響應(yīng)信號(hào)
          							3'd5:	begin scl_out_r <= 1'b1; 
          							end	//SCL拉高,保持4.0us以上
          							3'd6:	begin if(sda_out) state <= IDLE; 
          							else state <= state; 
          							end	//獲取從設(shè)備的響應(yīng)信號(hào)并判斷
          							3'd7:	begin scl_out_r <= 1'b0; 
          							state <= MAIN; 
          							end	//SCL拉低,返回MAIN狀態(tài)
          							default: state <= IDLE;	//如果程序失控,進(jìn)入IDLE自復(fù)位狀態(tài)
          						endcase
          					end
          				READ:begin	//I2C通信時(shí)序中的讀操作READ和返回ACK的操作
          						if(cnt <= 3'd6) begin	//共需要接收8bit的數(shù)據(jù),這里控制循環(huán)的次數(shù)
          							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	//兩個(gè)變量都恢復(fù)初值
          							else begin cnt_read <= cnt_read + 1'b1; 
          							cnt <= cnt; 
          							end
          						end
          						case(cnt_read)
          							//按照I2C的時(shí)序接收數(shù)據(jù)
          							3'd0:	begin scl_out_r <= 1'b0; 
          							sda_out_r <= 1'bz; 
          							end	//SCL拉低,釋放SDA線,準(zhǔn)備接收從設(shè)備數(shù)據(jù)
          							3'd1:	begin scl_out_r <= 1'b1; 
          							end	//SCL拉高,保持4.0us以上
          							3'd2:	begin adc_data_r[7-cnt] <= sda_out; 
          							end	//讀取從設(shè)備返回的數(shù)據(jù)
          							3'd3:	begin scl_out_r <= 1'b0; 
          							end	//SCL拉低,準(zhǔn)備接收下1bit的數(shù)據(jù)
          							//向從設(shè)備發(fā)送響應(yīng)信號(hào)
          							3'd4:	begin sda_out_r <= 1'b0; a
          							dc_done <= 1'b1; 
          							adc_data <= adc_data_r; 
          							end	//發(fā)送響應(yīng)信號(hào),將前面接收的數(shù)據(jù)鎖存
          							3'd5:	begin scl_out_r <= 1'b1; 
          							end	//SCL拉高,保持4.0us以上
          							3'd6:	begin scl_out_r <= 1'b1; 
          							adc_done <= 1'b0; 
          							end	//SCL拉高,保持4.0us以上
          							3'd7:	begin scl_out_r <= 1'b0; 
          							state <= MAIN; 
          							end	//SCL拉低,返回MAIN狀態(tài)
          							default: state <= IDLE;	//如果程序失控,進(jìn)入IDLE自復(fù)位狀態(tài)
          						endcase
          					end
          				STOP:begin	//I2C通信時(shí)序中的結(jié)束STOP
          						if(cnt_stop >= 3'd5) cnt_stop <= 1'b0;	//對(duì)STOP中的子狀態(tài)執(zhí)行控制cnt_stop
          						else cnt_stop <= cnt_stop + 1'b1;
          						case(cnt_stop)
          							3'd0:	begin sda_out_r <= 1'b0; 
          							end	//SDA拉低,準(zhǔn)備STOP
          							3'd1:	begin sda_out_r <= 1'b0; 
          							end	//SDA拉低,準(zhǔn)備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狀態(tài)
          							default: state <= IDLE;	//如果程序失控,進(jìn)入IDLE自復(fù)位狀態(tài)
          						endcase
          					end
          				default:;
          			endcase
          		end
          	end 	
          	assign	scl_out = scl_out_r;	//對(duì)SCL端口賦值
          	assign	sda_out = sda_out_r;	//對(duì)SDA端口賦值 
          	endmodule

          小結(jié)

          本節(jié)主要為大家講解了使用I2C驅(qū)動(dòng)PCF8591的ADC功能的原理及軟件設(shè)計(jì),需要大家掌握的同時(shí)自己創(chuàng)建工程,通過整個(gè)設(shè)計(jì)流程,生成FPGA配置文件加載測(cè)試。



          評(píng)論


          相關(guān)推薦

          技術(shù)專區(qū)

          關(guān)閉
          看屁屁www成人影院,亚洲人妻成人图片,亚洲精品成人午夜在线,日韩在线 欧美成人 (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })();