这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » DIY与开源设计 » 电子DIY » 交一下PCF8563的作业

共7条 1/1 1 跳转至

交一下PCF8563的作业

助工
2014-09-29 13:09:01     打赏
PCF8563花费了我很长时间,在十几天内读不出任何数据,我都快绝望了。昨天突然发现SDA,SCL线上没有加上拉电阻,加上后一切正常了。这是实验现象(开发板上没有数码管,就用了LCD1602,顺便把世纪,年,月,日,星期也显示了。还有手机镜头摔坏了,效果有点渣,请大家见谅。):http://v.youku.com/v_show/id_XNzkzMjcxODIw.html



关键词: FPGA PCF8563    

助工
2014-09-29 13:11:18     打赏
2楼
/******************************************************************************
*Engineer: superdian   
*Create Date:  2014/9/7 
*Design Name:  
*Module Name:  		pcf8563_topd
*Project Name:  
*Target Devices: EP3CE5E144C8
*Tool versions: 
*Description: 
*
*Dependencies: 
*
*Revision:
*Revision 0.01 - File Created
*Additional Comments: 开发板晶振为20MHZ,工程中通过倍频50MH。
******************************************************************************/
module pcf8563_top(
                   input  sys_rstn,
                   input  sys_clk,
						 output scl,
				 		 inout  wire sda,
						 output lcd_rs     ,    //lcd的寄存器选择输出信号
                   output lcd_rw     ,    //lcd的读、写操作选择输出信号
                   output lcd_en     ,    //lcd使能信号
                   output [7:0] lcd_data  //lcd的数据总线(不进行读操作,故为输出)
                   );
						 
wire clk;					 
wire [7:0] data_trans;  //从相应寄存器读取的数据
wire       finish_bit;  //从单个寄存器读取数据完毕的标志
reg  [7:0] data_word;   //发送相应寄存器地址
reg  [7:0] sec;         //储存从秒寄存器读出的数据
reg  [7:0] mnt;         //储存从分寄存器读出的数据
reg  [7:0] hur;         //储存从小时寄存器读出的数据
reg  [7:0] week;        //储存从星期寄存器读出的数据
reg  [7:0] day;         //储存从日寄存器读出的数据
reg  [7:0] month;       //储存从月份寄存器读出的数据
reg  [7:0] year;        //储存从年寄存器读出的数据
reg  [7:0] code_ctl;    //状态机状态寄存器
parameter sec_time=8'd0;
parameter mnt_time=8'd1;
parameter hour_time=8'd2;
parameter day_time=8'd3;
parameter week_time=8'd4;
parameter month_time=8'd5;
parameter year_time=8'd6;


clk_pll clk_pll (
                 .inclk0(sys_clk),
	              .c0(clk)
					  );
 
 
i2c_test i2c_test(
        
                   .clk(clk),
						 .scl(scl),
						 .sda(sda),
						 .data_read_wire(data_trans),
						 .sda_data_addr(8'ha2),
						 .sda_data_word(data_word),
						 .finish_bit(finish_bit)
						 );
lcd1602 lcd1602(
                   .sys_rstn(sys_rstn),
                   .lcd_rs(lcd_rs),
			          .lcd_rw(lcd_rw),
			          .lcd_en(lcd_en),
			          .lcd_data(lcd_data),
			          .sys_clk(clk),
			          .seg_sec(sec),
			          .seg_mnt(mnt),
			          .seg_hur(hur),
						 .seg_week(week),
				       .seg_day(day),
				       .seg_month(month),
				       .seg_year(year)   
			          );	

always@(posedge clk)
begin 
   case(code_ctl)
	sec_time:
	   begin 
		    if(finish_bit==1'b0)
			    begin 
				     data_word<=8'h02;//发送秒寄存器地址
					  sec<=data_trans;
				 end
		    else
	          begin
		          code_ctl<=mnt_time;
			    end 
		end 
	mnt_time:
       begin 
		     if(finish_bit==1'b0)
			     begin 
				      data_word<=8'h03;//发送分钟寄存器地址
					   mnt<=data_trans;
					end
			  else
			      begin 
					  code_ctl<=hour_time;
					end 
		 end
	hour_time:
       begin 
		    if(finish_bit==1'b0)
			     begin
				     data_word<=8'h04;//发送小时寄存器地址
					  hur<=data_trans;
					end
			 else
		        begin
				    code_ctl<=day_time; 
				  end  
		end 
	day_time:
      begin
		  if(finish_bit==1'b0)
		        begin
			       data_word<=8'h05;//发送日寄存器地址
			       day<=data_trans; 
			     end 
		  else
		        begin
			       code_ctl<=week_time;
		        end	 
	   end
	week_time:
      begin
	    if(finish_bit==1'b0)
		     begin 
		       data_word<=8'h6;//发送星期寄存器地址
		       week<=data_trans;
		     end 
		 else 
		     begin 
		       code_ctl<=month_time;
		     end  
	   end 
	month_time:
      begin
	   if(finish_bit==1'b0)
		    begin 
		      data_word<=8'h07;//发送月寄存器地址
		      month<=data_trans;
		    end 
		else 
          begin
		      code_ctl<=year_time; 
	       end 	 
	   end 
	year_time:
      begin
	    if(finish_bit==1'b0)
		 begin
		   data_word<=8'h08;//发送年寄存器地址 
			year<=data_trans;
		 end 
		 else 
		 begin
		   code_ctl<=sec_time;
		 end  
	   end 	
   endcase 
end 
endmodule 	
		 
				 
				

		
	
						 


			  
						 

 


助工
2014-09-29 13:12:48     打赏
3楼
/******************************************************************************
*Engineer: superdian   
*Create Date:  2014/9/7 
*Design Name:  
*Module Name:  		lcd1602
*Project Name:  
*Target Devices: EP3CE5E144C8
*Tool versions: 
*Description: 
*
*Dependencies: 
*
*Revision:
*Revision 0.01 - File Created
*Additional Comments: 开发板晶振为20MHZ,工程中通过倍频50MH。
******************************************************************************/
module lcd1602(sys_clk ,
			   sys_rstn   ,
			   lcd_rs     ,
			   lcd_rw     ,
			   lcd_en     ,
			   lcd_data   ,
			   seg_sec    ,
				seg_mnt    ,
				seg_hur    ,
				seg_week   ,
				seg_day    ,
				seg_month  ,
				seg_year   
				);
				
//输入输出信号定义
input [7:0] seg_sec;
input [7:0] seg_mnt;
input [7:0] seg_hur;
input [7:0]	seg_week;
input [7:0]	seg_day;
input [7:0]	seg_month;
input [7:0]	seg_year;  


input          sys_clk    ;//系统时钟输入
input          sys_rstn   ;//系统复位信号,低电平有效
output         lcd_rs     ;//lcd的寄存器选择输出信号
output         lcd_rw     ;//lcd的读、写操作选择输出信号
output         lcd_en     ;//lcd使能信号
output  [7:0]  lcd_data   ;//lcd的数据总线(不进行读操作,故为输出)
//寄存器定义
reg            lcd_rs     ;
reg            clk_div    ;
reg     [17:0] delay_cnt  ;
reg     [7:0]  lcd_data   ;
reg     [5:0]  char_cnt   ;		
reg     [7:0]  data_disp  ;
reg     [9:0]  state      ; 
/********************************
*********************************/
reg      [3:0] disp_dat;
reg      [25:0] g=0; 
reg      [3:0] shi1;
reg      [1:0] shi2;
reg      [3:0] fen1;
reg      [2:0] fen2;
reg      [3:0] miao1;
reg      [2:0] miao2;
reg      [7:0] shi11;
reg      [7:0] shi22;
reg      [7:0] fen11;
reg      [7:0] fen22;
reg      [7:0] miao11;
reg      [7:0] miao22;
reg      [2:0] week1;
reg      [3:0] day1;
reg      [2:0] day2;
reg      [3:0] month1;
reg      [3:0] month2; 
reg      [3:0] year1;
reg      [3:0] year2;
reg      [7:0] week11;
reg      [7:0] day11;
reg      [7:0] day22;
reg      [7:0] month11;
reg      [7:0] month22; 
reg      [7:0] year11;
reg      [7:0] year22;
reg      [7:0] centry1;
reg      [7:0] centry2;
reg      centry;

parameter	idle 		= 10'b000000000,	      //初始状态,下一个状态为CLEAR
			   clear		= 10'b000000001, 	      //清屏
			   set_function	= 10'b000000010, 	//功能设置:8位数据接口/2行显示/5*8点阵字符
			   switch_mode	= 10'b000000100, 	   //显示开关控制:开显示,光标和闪烁关闭
			   set_mode     = 10'b000001000, 	//输入方式设置:数据读写操作后,地址自动加一/画面不动
			   shift  		= 10'b000010000, 	   //光标、画面位移设置:光标向左平移一个字符位(光标显示是关闭的,所以实际上设置是看不出效果的)
			   set_ddram1   = 10'b000100000, 	//设置DDRAM的地址:第一行起始为0x00(注意输出时DB7一定要为1)
			   set_ddram2   = 10'b001000000, 	//设置DDRAM的地址:第二行为0x40(注意输出时DB7一定要为1)
			   write_ram1   = 10'b010000000, 	//数据写入DDRAM相应的地址
			   write_ram2   = 10'b100000000; 	//数据写入DDRAM相应的地址

assign lcd_rw = 1'b0;						//没有读操作,R/W信号始终为低电平
assign lcd_en = clk_div;	            //E信号出现高电平以及下降沿的时刻与LCD时钟相同
//时钟分频
always@(posedge sys_clk or negedge sys_rstn)
begin 
	if(!sys_rstn)
		begin
			delay_cnt<=18'd0;
			clk_div<=1'b0;
		end
	else if(delay_cnt==18'd249999)//原来50MHZ249999 
		begin
			delay_cnt<=18'd0;
			clk_div<=~clk_div;
		end
	else
		begin
			delay_cnt<=delay_cnt+1'b1;
			clk_div<=clk_div;
		end
end
always@(posedge clk_div or negedge sys_rstn)	//State Machine 
begin
	if(!sys_rstn)
		begin
			state 	 <= idle;
			lcd_data <= 8'bzzzzzzzz;
			char_cnt <= 5'd0;			
		end
	else
		begin
		case(state)
		idle:	begin						//初始状态
					state <= clear;
					lcd_data <= 8'bzzzzzzzz;
				end
		clear:	begin						//清屏
					state <= set_function;
					lcd_rs<=1'b0;
					lcd_data <= 8'b00000001;			
				end		
		set_function:						//功能设置(38H):8位数据接口/2行显示/5*8点阵字符
				begin
					state <= switch_mode;
					lcd_rs<=1'b0;
					lcd_data <= 8'b00111000;				
				end
		switch_mode:							//显示开关控制(0CH):开显示,光标和闪烁关闭
				begin
					state <= set_mode;
					lcd_rs<=1'b0;
					lcd_data <= 8'b00001100;
				end	
		set_mode:begin						//输入方式设置(06H):数据读写操作后,地址自动加一/画面不动
					state <= shift;	
					lcd_rs<=1'b0;
					lcd_data <= 8'b00000110;
				end
		shift:	begin						//光标、画面位移设置(10H):光标向左平移一个字符位(光标显示是关闭的,所以实际上设置是看不出效果的)
					state <= set_ddram1;
					lcd_rs<=1'b0;
					lcd_data <= 8'b0001_0000;			
				end		
		set_ddram1:						    //设置DDRAM的地址:第一行起始为00H(注意输出时DB7一定要为1)	
				begin
					state <= write_ram1; 
					lcd_rs<=1'b0;
					lcd_data <= 8'b1000_0000;//Line1
				end
		set_ddram2:							//设置DDRAM的地址:第二行为40H(注意输出时DB7一定要为1)
				begin
					state <= write_ram2;
					lcd_rs<=1'b0;
					lcd_data <= 8'b1100_0000;//Line2		
				end
		write_ram1:				
				begin									
					if(char_cnt <=5'd15)
						begin
							char_cnt <= char_cnt + 1'b1; 
							lcd_rs<=1'b1;
							lcd_data <= data_disp;
							state <= write_ram1;
						end
					else
						begin
							state <= set_ddram2;	
						end				
				end
		write_ram2:				
				begin									
					if(char_cnt <=5'd31)
						begin
							char_cnt <= char_cnt + 1'b1; 
							lcd_rs<=1'b1;
							lcd_data <= data_disp;
							state <= write_ram2;
						end
					else
						begin
							char_cnt <=5'd0;
							state <= shift;	
						end				
				end
		default: 	state <= idle;
		endcase
		end
end

always @(char_cnt)			//输出的字符
begin
	case (char_cnt)
	6'd0: data_disp  = "-";	
	6'd1: data_disp  = "-";	
	6'd2: data_disp  = "-";	
	6'd3: data_disp  = "-";	
	6'd4: data_disp  = centry2;	
	6'd5: data_disp  = centry1;	
	6'd6: data_disp  = year22;	
	6'd7: data_disp  = year11;	
	6'd8: data_disp  = "/";	
	6'd9: data_disp  = month22;	
	6'd10: data_disp = month11;	
	6'd11: data_disp = "/";	
	6'd12: data_disp = day22;	
	6'd13: data_disp = day11;	
	6'd14: data_disp = "/";	
	6'd15: data_disp = week11;	
	6'd16: data_disp = "E";	
	6'd17: data_disp = "E";	
	6'd18: data_disp = "P";	
	6'd19: data_disp = "W";	
	6'd20: data_disp = "-";	
	6'd21: data_disp = "-";	
	6'd22: data_disp = "-";	
	6'd23: data_disp = "-";	
	6'd24: data_disp = shi22;
	6'd25: data_disp = shi11;
	6'd26: data_disp = "/";
   6'd27: data_disp = fen22;	
	6'd28: data_disp = fen11;	
	6'd29: data_disp = "/";	
	6'd30: data_disp = miao22;	
	6'd31: data_disp = miao11;	



    default :   data_disp ="-";	
	endcase
end


/***************************************************
将从pcf8563读出的数据写入相应时,分,秒,年,月,日寄存器
*****************************************************/
always@(posedge sys_clk)
 begin 
    if(g==26'd2499999)
	     g<=26'd0;
	 else 
        g<=g+1'b1;
 end 
always@(posedge sys_clk)
    begin 
	   if(g==26'd2499999)
	     disp_dat<=disp_dat+1'b1;
		else 
        disp_dat<=disp_dat;
	 end


always@(disp_dat)
begin 
    case(disp_dat)
	 4'd0:
	        miao1=seg_sec[3:0];
	 4'd1:
	        miao2=seg_sec[6:4];
	 4'd2:
           fen1=seg_mnt[3:0];
	 4'd3:
	        fen2=seg_mnt[6:4];
	 4'd4:
           shi1=seg_hur[3:0];
	 4'd5:
           shi2=seg_hur[5:4];
	 4'd6:
           week1=seg_week[2:0];
	 4'd7:
           day1=seg_day[3:0];
	 4'd8:	
           day2=seg_day[5:4];	
	 4'd9:  
           month1=seg_month[3:0];
	 4'd10:
           month2=seg_month[5];
	 4'd11:
	        year1=seg_year[3:0];
	 4'd12:
	        year2=seg_year[7:4];	
	 4'd13:
           centry=seg_month[7];
	 

           

           
	endcase 
end

always@(posedge sys_clk)
begin
  if(centry == 1'b0)
    begin
      centry1 <= "0";
	   centry2 <= "2";
    end
  else 
    begin
      centry1 <= "9";
	   centry2 <= "1";
    end  
end 


/*************************************************
将相应寄存器的BCD码转换为ASCII码
**************************************************/

always@(week1)
begin
  case(week1)
   3'd0: week11 = "0";
   3'd1: week11 = "1";
	3'd2: week11 = "2";
	3'd3: week11 = "3";
	3'd4: week11 = "4";
	3'd5: week11 = "5";
	3'd6: week11 = "6";
	3'd7: week11 = "7";
	default : week11 = "0";
 endcase 	
   
end 


always@(day1)
begin
   case(day1)
	4'd0: day11 = "0";
   4'd1: day11 = "1";
   4'd2: day11 = "2";
   4'd3: day11 = "3";
   4'd4: day11 = "4";
   4'd5: day11 = "5";
   4'd6: day11 = "6";
	4'd7: day11 = "7";
	default: day11 = "0";
	endcase 
   	
end 

always@(day2)
begin
  case(day22)
  3'd0:day22 = "0";
  3'd1:day22 = "1";
  3'd2:day22 = "2";
  3'd3:day22 = "3";
  default: day22 ="0";
  endcase
  
end 



always@(month1)
begin
   case(month1)
	4'd0: month11 = "0";
   4'd1: month11 = "1";
   4'd2: month11 = "2";
   4'd3: month11 = "3";
   4'd4: month11 = "4";
   4'd5: month11 = "5";
   4'd6: month11 = "6";
   4'd7: month11 = "7";
	4'd8: month11 = "8";
	4'd9: month11 = "9";
	default : month11 = "0";
	endcase 
   	
end 

always@(month2)
begin
  case(month2)
  1'b0: month22 = "0";
  1'b1: month22 = "1";
  default : month22 = "0";
  endcase  
end 

always@(year1)
begin
  case(year1)
  4'd0: year11 = "0";
  4'd1: year11 = "1";
  4'd2: year11 = "2";
  4'd3: year11 = "3";
  4'd4: year11 = "4";
  4'd5: year11 = "5";
  4'd6: year11 = "6";
  4'd7: year11 = "7";
  4'd8: year11 = "8";
  4'd9: year11 = "9";
  default : year11 = "0";
 endcase 
end 

always@(year2)
begin
  case(year2)
  4'd0: year22 = "0";
  4'd1: year22 = "1";
  4'd2: year22 = "2";
  4'd3: year22 = "3";
  4'd4: year22 = "4";
  4'd5: year22 = "5";
  4'd6: year22 = "6";
  4'd7: year22 = "7";
  4'd8: year22 = "8";
  4'd9: year22 = "9";
  default : year22 = "0";
 endcase 
end 



always @(miao1)	
begin
	case (miao1)
	 4'd0: miao11 = "0";
    4'd1: miao11 = "1";
    4'd2: miao11 = "2";
    4'd3: miao11 = "3";
    4'd4: miao11 = "4";		
    4'd5: miao11 = "5";
    4'd6: miao11 = "6";
    4'd7: miao11 = "7";
    4'd8: miao11 = "8";
    4'd9: miao11 = "9";
    default :   miao11 ="0";
	endcase
end

always @(miao2)		
begin
	case (miao2)
	 3'd0: miao22 = "0";
    3'd1: miao22 = "1";
    3'd2: miao22 = "2";
    3'd3: miao22 = "3";
    3'd4: miao22 = "4";		
    3'd5: miao22 = "5";
    default :   miao22 ="0";
	endcase
end

always @(fen1)			
begin
	case (fen1)
	 4'd0: fen11 = "0";
    4'd1: fen11 = "1";
    4'd2: fen11 = "2";
    4'd3: fen11 = "3";
    4'd4: fen11 = "4";		
    4'd5: fen11 = "5";
    4'd6: fen11 = "6";
    4'd7: fen11 = "7";		
    4'd8: fen11 = "8";
    4'd9: fen11 = "9";
    
    default :   fen11 ="0";
	endcase
end

always @(fen2)			
begin
	case (fen2)
	 3'd0: fen22 = "0";
    3'd1: fen22 = "1";
    3'd2: fen22 = "2";
    3'd3: fen22 = "3";
    3'd4: fen22 = "4";		
    3'd5: fen22 = "5";
    default :   fen22 ="0";
	endcase
end

always @(shi1)		
begin
	case (shi1)
	 4'd0: shi11 = "0";
    4'd1: shi11 = "1";
    4'd2: shi11 = "2";
    4'd3: shi11 = "3";
    4'd4: shi11 = "4";		
    4'd5: shi11 = "5";
    4'd6: shi11 = "6";
    4'd7: shi11 = "7";		
    4'd8: shi11 = "8";
    4'd9: shi11 = "9";
    
    default :   shi11 ="0";
	endcase
end

always @(shi2)		
begin
	case (shi2)
	 2'd0: shi22 = "0";
    2'd1: shi22 = "1";
	 2'd2: shi22=  "2";
    default :   shi22 ="0";
	endcase
end
endmodule 

 


助工
2014-09-29 13:13:45     打赏
4楼
/******************************************************************************
*Engineer: superdian   
*Create Date:  2014/9/7 
*Design Name:  
*Module Name:  i2c_test 
*Project Name:  
*Target Devices: EP3CE5E144C8
*Tool versions: 
*Description: 
*
*Dependencies: 
*
*Revision:
*Revision 0.01 - File Created
*Additional Comments: 开发板晶振为20MHZ,工程中通过倍频50MHZ。
******************************************************************************/
module i2c_test(input clk,
               
                output scl,
					 inout wire sda,
					 output [7:0]data_read_wire,
					 input [7:0]sda_data_addr,
					 input [7:0]sda_data_word,
					 output reg finish_bit
					 );

reg sda_io_flag;      //sda输入输出状态寄存器
reg read_flag;        //主机读写状态
reg sda_r;            //数据寄存器
reg scl_r;            //时钟脉冲寄存器
reg [7:0] scl_ctr;    //scl分频参数寄存器
reg [7:0] scl_sts;
reg [7:0] i2c_sts;
reg [7:0] sda_data_a;
reg [3:0] data_bit;
reg [7:0] data_read;
reg [24:0] timer;

assign scl=scl_r;
assign sda=sda_io_flag?sda_r:1'bz; //sda输入输出状态选择

assign data_read_wire=data_read;

`define scl_pos  (scl_sts==3'd0)
`define scl_high (scl_sts==3'd1)
`define scl_neg  (scl_sts==3'd2)
`define scl_low  (scl_sts==3'd3)

parameter          idle     =4'd0;
parameter          start    =4'd1;
parameter			 send_a   =4'd2;
parameter			 slv_ack1 =4'd3;
parameter			 send_d   =4'd4;
parameter			 slv_ack2 =4'd5;
parameter			 send_dd  =4'd6;
parameter			 slv_ack3 =4'd7;
parameter			 read_byte =4'd8;
parameter			 master_ack =4'd9;
parameter			 stop    =4'd10;
//SCL分频250KHZ
always@(posedge clk)
 begin 
    if(scl_ctr ==8'd199)
	    scl_ctr<=8'd0;
	 else 
       scl_ctr<=scl_ctr+1'b1;	 

 end

always@(posedge clk)
  begin
     case(scl_ctr)
	     8'd49:  scl_sts<=3'd1;//处于高电平中间用于数据采样
		  8'd99:  scl_sts<=3'd2;//下降沿
		  8'd149: scl_sts<=3'd3;//处于低电平中间用于数据变化
		  8'd199: scl_sts<=3'd0;//上升沿
		 default: scl_sts<=3'd5; 
		endcase  
  end
 
always@(posedge clk)
  begin 
     if(scl_sts==3'd0)
	    scl_r<=1'b1;
	  if(scl_sts==3'd2)
	    scl_r<=1'b0;  
  end
  
always@(posedge clk)
begin 
   if(timer==0)
      begin 
		   i2c_sts<=idle;
			data_bit<=4'd0;
			sda_io_flag<=1'b1;
			sda_r<=1'b1;
			read_flag<=1'b0;
	   end
   case(i2c_sts)
     idle:
	      begin 
			    i2c_sts<=start;
				 if(read_flag==1'b1)//判断主机读写状态
				 
				    sda_data_a<=sda_data_addr+1'b1;//地址+1,即为读状态(A3)
				 else 
				    sda_data_a<=sda_data_addr;//地址不加一,即为写状态(A2)
			end 	 
	  start:
	       begin 
			     if(`scl_high)//启动I2C
				    begin
					    sda_io_flag<=1'b1;
						 sda_r<=1'b0;
						 i2c_sts<=send_a;//发送地址状态
					 end
				  else
				     begin  
					    i2c_sts<=start;
					  end
					
			 end
		send_a://发送地址状态
          begin 
		       if(`scl_low)
			        begin 
					      case(data_bit)//8位串行地址数据
							4'd0: sda_r<= sda_data_a[7];
							4'd1: sda_r<= sda_data_a[6];
							4'd2: sda_r<= sda_data_a[5];
							4'd3: sda_r<= sda_data_a[4];
							4'd4: sda_r<= sda_data_a[3];
							4'd5: sda_r<= sda_data_a[2];
							4'd6: sda_r<= sda_data_a[1];
							4'd7: sda_r<= sda_data_a[0];
							endcase 
							data_bit<=data_bit+1'b1;
							if(data_bit==4'd8)//发送地址完毕
							   begin
								    sda_io_flag<=1'b0;//SDA做输入口
									 i2c_sts<=slv_ack1;//读从机应答信号
									 data_bit<=4'd0;
								end 
					  end 
				 else 
		          i2c_sts<=send_a;
			  end 
		slv_ack1://从机应答
           begin
			     if(`scl_high)
				     begin 
					    sda_io_flag<=1'b0;
						 if(sda==0)
						     begin 
							    if(read_flag==1'b1)
								   begin 
									  i2c_sts<=read_byte;
									  sda_io_flag<=1'b0;
								   end 
							     else 
							       begin 
							         i2c_sts<=send_d;
							         sda_io_flag<=1'b1;
							         sda_r<=1'b0;
							         sda_data_a<=sda_data_word;
							       end 
						     end 
			         end 
	            else 
                  begin 
						   i2c_sts<=slv_ack1;
	                        
						 
						 end
	         end 
       send_d://发送数据
            begin   
	            if(`scl_low)
		            begin 
			            case(data_bit)
				            4'd0: sda_r<=sda_data_a[7];
					         4'd1: sda_r<=sda_data_a[6];
					         4'd2: sda_r<=sda_data_a[5];
					         4'd3: sda_r<=sda_data_a[4];
					         4'd4: sda_r<=sda_data_a[3];
					         4'd5: sda_r<=sda_data_a[2];
					         4'd6: sda_r<=sda_data_a[1]; 
                        4'd7: sda_r<=sda_data_a[0];
                      endcase
							 data_bit<=data_bit+1'b1;
							 if(data_bit==4'd8)
							   begin 
							     sda_io_flag<=1'b0;
								  i2c_sts<=slv_ack2;//发送数据完毕,进入应答状态
								  data_bit<=4'd0;
								end
								
						end
                     else
	                    i2c_sts<=send_d;
			     end 
        slv_ack2://应答状态
             begin
	              if(`scl_high)
					     begin 
						    sda_io_flag<=1'b0;
							 if(sda==0)
							    begin 
								     i2c_sts<=stop;
									  sda_io_flag<=1'b1;
									  sda_r<=1'b0;
							     end 
						   end 
			         else 
		               begin 
			               i2c_sts<=slv_ack2;
				         end 
			     end 
		  read_byte://读出数据
			    begin
				    if(`scl_high)
					    begin 
						    sda_io_flag<=1'b0;
							 data_read<=(data_read<<1)|sda;
							 data_bit<=data_bit+1'b1;
							 if(data_bit==4'd7)
							     begin
								    i2c_sts<=master_ack;
									 data_bit<=4'd0; 
								  end
						 end 
			     end 
		  master_ack://主机应答
		       begin
				    if(`scl_low)
					    begin 
						    sda_io_flag<=1'b1;
							 sda_r<=1'b0;
							 data_bit<=data_bit+1'b1;
							 if(data_bit==4'd1)
							    begin 
								   i2c_sts<=stop;
									data_bit<=4'd0;
							    end 
						 end 
				  end 
		  stop://停止I2C
             begin
			       if(`scl_high)
					     begin 
						     sda_r<=1'b1;
							  read_flag<=1'b1;
							  if(read_flag==1'b0)
							     i2c_sts<=idle;
							  else 
							     i2c_sts<=stop;
								
						  end 
			 
            end 
	   endcase	
  		
end  

always@(posedge clk)
begin 
    if(timer<=25'd12500000)
	    begin 
		    timer<=timer+1'b1;
			 if(timer==25'd12499999)
			   finish_bit<=1'b1;
		 end 
    else 
       begin 
           timer<=25'd0;
           finish_bit<=1'b0;
       end 
end 


endmodule 		  
 			
			
			
					 
              			
			           		  
								  
								  
                      							 
					  	 
									 
							
					      		
		
	        

  
 
 















 					 
					 

 


助工
2014-09-29 13:24:31     打赏
5楼

谈一下完成完成这次作业的感受吧。

1:讲师51fpga的设计值得借鉴,他的设计注意到了资源优化的问题,IIC作为一个模块多次被调用,减少了资源的使用。我的1602模块将BCD码转化为ASCII码的译码部分也可采用类似方式,我会继续尝试。

2:解决学习问题还得考虑周全,软硬件方面都要关注,并一步步排除。我一开始认为是设计的问题,借鉴了上次LM75A作业的代码也没解决,最后发现还是两个上拉电阻惹的祸。白白浪费了两个多星期时间,算是买个教训,不多加深了对IIC协议的理解。



助工
2014-09-29 13:26:56     打赏
6楼

院士
2014-09-29 13:44:48     打赏
7楼

审核通过,赞一个


共7条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]