 
					
				15、TLC549AD转换时序详解(源代码注释)
       了解一个芯片的功能应该看它的参数,应用一个芯片你就得认真的去读懂它的时序图。
改进了上次的实验,加入了256的8位的缓存,并求平均。
          由图1、图2可知道 :
1、f(ioclk)max=1.1MHz。
2、t(su)min=1.4us。
3、t(wh)min=17us。
4、CS为低电平的时候读取数据;高电平的时候AD转换。
5、数据的读取需要8个ioclk,在ioclk上升沿的时候读取数据位。 
6、数据必须在CS置零1.4us后才能读取。 
  
                          图1: TLC549的信号时序图                                        

                                            图2: TLC549相关参数
在本次实验中参数如下选取
1、f(ioclk)=1MHz。
2、t(su)=1.5us。
3、t(wh)=17us。
因为FPGA的主时钟是50Mhz (t(sys)=0.02us)
所以t(ioclk)=50*t(sys);
       t(su)=1.5us=75*t(sys);
       t(wh)=17us=850*t(sys);
那么一次AD转换读取需要的时间为:
   t(su)+8*t(ioclk)+t(wh)=(75+8*50+850)*t(sys)=1325*t(sys)
module TLC549ADC
(
 input rst,
 input clk,
 input adc_data,
 output reg cs,
 output reg ioclk,
 output reg [7:0] led_out,
 output reg [3:0] V_H,
 output reg [3:0] V_L,
 output reg [3:0] Va_100,
 output reg [3:0] Va_10,
 output reg [3:0] Va_1
);
 integer k;
 reg signed [7:0] data_r [255:0]; //256个8位的数据缓存
  
 //clk计数器
 reg [11:0] clk_cnt;
 wire cs_n_read;
 wire cs_high;
 wire conover;
 
 //时钟计数器
 always @(posedge clk or negedge rst) begin
  if(!rst)
   clk_cnt <= 11'd0;
  else if(clk_cnt >=11'd1325)
   clk_cnt <= 11'b0;
  else
   clk_cnt <= clk_cnt + 1'b1;
 end
 // t(su)+8*t(ioclk)+t(wh)=(75+8*50+850)*t(sys)=1325*t(sys)
 assign cs_n_read = (clk_cnt > 11'd74)&&(clk_cnt <= 11'd475); //400个t(sys)
 assign cs_high  = (clk_cnt > 11'd475)&&(clk_cnt <= 11'd1325);//850个t(sys)
 assign conover = (clk_cnt == 11'd425) ? 1'b1 : 1'b0; //数据读取完后conover有一个上升沿
 
 //CS的时序;在AD转换的过程中CS为高电平,在数据读取的过程中CS为低电平。
 always @(posedge clk or negedge rst) begin
  if(!rst)
   cs <= 1'b1;
  else if(cs_high)
   cs <= 1'b1;
  else
   cs <= 1'b0;
 end
 
 //50分频;提供IOClk信号 
 reg [5:0] div_cnt;
 always @(posedge clk or negedge rst) begin
  if(!rst) begin
   div_cnt <= 6'd0;
   ioclk <= 1'b0;
   end
  else if(cs_n_read) begin   //从第75t(sys)到第475t(sys),这400个时钟里才有IOCLK信号,
             //才能读取数据,这样保证在0到第74t(sys)CS是低电平的。
   div_cnt <= div_cnt + 1'b1;  
   if(div_cnt < 6'd25)
    ioclk <= 1'b1;
   else if((div_cnt >= 6'd25)&&(div_cnt < 6'd50))
    ioclk <= 1'b0;
   else
    div_cnt <= 6'b0;
  end
 end
 
 //读取数据
 reg[7:0] radc_data;
 always @(posedge clk or negedge rst) begin
  if(!rst)
   radc_data <= 8'b0;
  else
  begin
   case(clk_cnt) //没50个t(sys)读取一个数据位
     11'd75: radc_data[7] <= adc_data;
     11'd125: radc_data[6] <= adc_data;
     11'd175: radc_data[5] <= adc_data;
     11'd225: radc_data[4] <= adc_data;
     11'd275: radc_data[3] <= adc_data;
     11'd325: radc_data[2] <= adc_data;
     11'd375: radc_data[1] <= adc_data;
     11'd425: radc_data[0] <= adc_data; 
     default: radc_data[0] <= 1'b0;
   endcase
  end
 end     
 
 //数据处理,conover
 reg [7:0] data_cnt;
 reg [15:0] Sum;
 always @(posedge conover or negedge rst) begin
  if(!rst)
  begin
   for(k=0;k<=255;k=k+1)
    data_r [k] = 8'b0;
    led_out <= 8'hx;
  end
  else 
  begin
   data_r[data_cnt] <= radc_data;
   data_cnt <= data_cnt + 1'b1; //单个数据放入缓存
   if(data_cnt == 8'd255) 
   begin      //写满256个缓存数据
    for(k=0;k<=255;k=k+1)
     Sum = Sum + data_r[k];
    Sum = Sum/255;   //求平均
    V_H = Sum[7:4];
    V_L = Sum[3:0];
    Sum = Sum*245/255; //换算成电压值
    led_out <= ~Sum[7:0];
    Va_100 <= Sum[7:0]/100;
    Va_10 <= Sum[7:0]/10%10;
    Va_1 <= Sum[7:0]%10; 
   end
  end
 end
  
endmodule
改进后效果明显比上次好一些

sof、pof下载:
时钟为Y1:——回复可见内容——
时钟为Y2:——回复可见内容——
回复
| 有奖活动 | |
|---|---|
| 硬核工程师专属补给计划——填盲盒 | |
| “我踩过的那些坑”主题活动——第002期 | |
| 【EEPW电子工程师创研计划】技术变现通道已开启~ | |
| 发原创文章 【每月瓜分千元赏金 凭实力攒钱买好礼~】 | |
| 【EEPW在线】E起听工程师的声音! | |
| 高校联络员开始招募啦!有惊喜!! | |
| 【工程师专属福利】每天30秒,积分轻松拿!EEPW宠粉打卡计划启动! | |
| 送您一块开发板,2025年“我要开发板活动”又开始了! | |

 
					
				 
			
			
			
						
			 
					
				 
					
				 
					
				 
					
				 
					
				 
					
				 我要赚赏金
 我要赚赏金 STM32
STM32 MCU
MCU 通讯及无线技术
通讯及无线技术 物联网技术
物联网技术 电子DIY
电子DIY 板卡试用
板卡试用 基础知识
基础知识 软件与操作系统
软件与操作系统 我爱生活
我爱生活 小e食堂
小e食堂

