OpenVINOTM,给你看得见的未来!>>
电子产品世界 » 论坛首页 » DIY与开源设计 » 电子DIY » 学号249 lhzh7的CPLD DIY(请教温度传感器驱动)(已贴代码)

共14条 1/2 1 2 跳转至

学号249 lhzh7的CPLD DIY(请教温度传感器驱动)(已贴代码)

助工
2013-06-28 17:06:15    评分

我选择第二(一)种方案:申请PCB板,购买组委会提供的元器件包 

实验名称:数字时钟数码管显示

对FPGA的基础知识和开发流程有了初步的了解,,但是对CPLD不是很了解,在进行FPGA开发时遇到很多问题,希望能够从更基础的地方开始学习好CPLD/FPGA。会进行简单的Verilog程序编写,能够使用Quartus ii的基本操作。


后面我将介绍一下做板子的过程以及实验过程。


1.《开发板焊接过程》....................................................................................2楼

2.《简易电子琴的设计——用CPLD演奏梁祝》......................................................8楼


——回复可见内容——liangzhu.rar


——回复可见内容——lm75a.rar




关键词: CPLD DIY 进程    

助工
2013-06-28 17:13:10    评分
2楼

1.《开发板焊接过程》

板子25号到的,28号焊好,并且下载了调试程序,调试好了板子。先谈谈焊板子中出现的问题吧,给焊板子没有经验的人分享点经验,我出现的问题大家引以为鉴。因为条件原因,我只有一个尖头的电烙铁、松香、镊子、锡丝。

     1.拿到元器件包和PCB板以后先看看每个元器件,对不熟悉的元器件最好上网查查资料,一定要弄清楚元器件的引脚。比如钽(tan)电容、肖特基二极管IN5822(实际是SS34)、注意LM75A的引脚,字朝下为正确的。

   2.焊板子的顺序最好先焊芯片、再焊小器件。我是按分包54321焊的,感觉焊起来还挺顺手的。

   3.由于没其他电烙铁,所以都是先在PCB板铜片上抹了一层松香然后滴上焊锡,压上贴片用电烙铁烫一下就粘住了。不知道这种方法科学不,大家最好看看焊接技术那个文档。

   4.第一次焊出来调试,有好多问题,数码管不亮,二极管也不亮。然后对着电路图用万用表一个一个测试,发现有的电容短路了,钽电容有一个焊反了。最后又把芯片的引脚都分开,然后显示结果正确了。调试的时候一定要耐心,每一个细节都不要放过。

   5.夏天了,使用电烙铁一定要注意安全,小心烫伤。如果烫伤了,擦点烫伤膏。

先抹松香焊锡

先抹松香焊锡(图片说明的文字去哪了?)

芯片贴上去

数码管显示0到7

led流水灯

LCD由于我的lcd屏幕有问题,就没有拍照,不过可以显示。

按键钢琴音也可以。


助工
2013-06-28 22:34:21    评分
3楼

助工
2013-06-29 13:45:17    评分
4楼
选中那一行字然后超级链接

助工
2013-06-29 13:45:50    评分
5楼
选中那一行然后超级链接

助工
2013-06-29 19:41:55    评分
6楼
谢谢你,搞定了。

院士
2013-06-30 17:34:43    评分
7楼
真心不错

助工
2013-07-01 22:05:17    评分
8楼

2.《简易电子琴的设计》

     用蜂鸣器演奏《梁祝》

     乐曲演奏的两个因素:音符发音频率和持续时间

音名

频率/Hz

音名

频率/Hz

音名

频率/Hz

低音1

262

中音1

523

高音1

1047

低音2

296

中音2

587

高音2

1175

低音3

330

中音3

659

高音3

1319

低音4

350

中音4

698

高音4

1397

低音5

392

中音5

784

高音5

1568

低音6

440

中音6

880

高音6

1760

低音7

494

中音7

988

高音7

1976

     利用CPLD对开发板上的时钟进行分频,然后输出即可实现乐曲的演奏。

      音符的频率可以由上图中的speaker control部分获得。Speaker control是一个分频控制器,它由clk1输入一个较高的时钟频率(如12MHz,25MHz等),通过分频以后,有speakout输出,直接连接到蜂鸣器上面。
而音符的持续时间就要根据不同的乐曲的速度和音符持续的拍数来决定了,上图里面tone index是一个音符的查找表,输入的clk2是相对比较慢的时钟(8Hz或10Hz等),查找表就按照加一的顺序查找将要演奏的音符,并将它们送到tone maker 模块里面。这里的tone maker是一个八位二进制计数器(计数最大值是138),频率选择在4Hz,这样计一个数值的停留时间是0.25S,正好等于当全音符的持续时间设置为一秒的时候,四四拍的4分音符的持续时间。

分频器的设计:

(1):主频率6MHZ时钟和4HZ演奏频率的设计

  开发板时钟sys_clk 50MHZ,只需对50MHZ的频率进行8分频处理(实际8分频处理后频率为6.25MHZ)。

4hz的频率对50MHZ频率进行2的24次方分频(实际分频频率为约3HZ)

代码:reg[23:0] clk_cnt;

         always@(posedge sys_clk)

         clk_cnt<=clk_cnt+1'b1;

       

         wire clk_6mhz=clk_cnt[2];

         wire clk_4hz  =clk_cnt[23]

(2)任意频率时钟的设计

reg[13:0]divider,origin;
reg[7:0]counter;
reg sp;
wire carry;




assign carry=(divider==16383);


always @(posedge clk_6mhz)
begin  if(carry)divider=origin;
       else     divider=divider+1;
end


always@(posedge carry)
  begin
     sp =~sp;
  end
  
  
  always@(posedge clk_4hz)
   begin
     case({high ,med ,low})
     'b000000000011:   origin=7281;
     'b000000000101:   origin=8730;
     'b000000000110:   origin=9565;
     'b000000000111:   origin=10310;
     'b000000010000:   origin=10647;
     'b000000100000:   origin=11272;
     'b000000110000:   origin=11831;
     'b000001010000:   origin=12556;
     'b000001100000:   origin=12974;
     'b000100000000:   origin=13516;
     'b000000000000:   origin=16383;
     endcase
  end

(3)乐曲的演奏代码

always@(posedge clk_4hz)
     begin
       if(counter==50)      counter=0;
       else  counter=counter+1;
       case(counter)             
       0:  {high,med,low}='b000000000011;
       
 
  1:  {high,med,low}='b000000000011; 
  2:  {high,med,low}='b000000000011;   
  3:  {high,med,low}='b000000000011;
  4:  {high,med,low}='b000000000101;
  5:  {high,med,low}='b000000000101;
  6:  {high,med,low}='b000000000101;
  7:  {high,med,low}='b000000000110;
  8:  {high,med,low}='b000000010000;
  9:  {high,med,low}='b000000010000;
 10:  {high,med,low}='b000000010000;
 11:  {high,med,low}='b000000100000;
 12:  {high,med,low}='b000000000110;


ps:我编了48个音符,实际演奏用了差不多16s,证明前面确实是3hz,而不是4hz。

至于主频为什么用6Mhz,我在网上看到说是因为在6Mhz的时候,演奏效果最好,但是我还没有试验过。后期再试验一下。



视频地址:http://union.bokecc.com/flash/single/290666218ACBA694_36AC8561DB264B069C33DC5901307461_false_EEA982EE6B20F4D1_1/player.swf

助工
2013-07-03 15:50:47    评分
9楼
真心觉得楼主设计得不错,向楼主学习一下!

助工
2013-09-18 10:54:56    评分
10楼

大家有没有人做那个温度传感器那个实验?用cpld驱动lm75,在数码管上显示温度。我在网上下载了个代码,但是显示的有点问题,代码正在学习,但是有些地方还是看不懂,把代码贴出来大家帮我看看吧。

module lm75a(clk,rst_n,scl,sda,cs,seg);
input clk,rst_n; //fu复位信号低电平有效,时钟50MHz;
output scl;  //I2C时钟,250KHz;时钟周期为4us;
inout sda;   //I2C数据端;
output[3:0] cs;  //数码管片选;
output[7:0] seg;  //数码管段选;
wire done;    // I2C读取一个数据完毕,更新数码管段选寄存器;
wire[15:0] data;//温度数据;
I2C_READ I2C_READ(
        .clk(clk),
 .rst_n(rst_n),
 .scl(scl),
 .sda(sda),
 .data(data)
              );
SEG_D  SEG_D(
       .clk(clk),
.rst_n(rst_n),
.cs(cs),
.seg(seg),
.data(data)
         );
endmodule 
//----------------------------------------------------//
//-----------------------I2C读温度数据-----------------//
//----------------------------------------------------//
module I2C_READ(
       clk,
rst_n,
scl,sda,data
              );
 
 
input clk; // 50MHz
input rst_n; //复位信号,低有效
output scl; // lm75的时钟端口
inout sda; // lm75的数据端口
output[15:0] data; //数码管显示的数据


//--------------------------------------------

reg[2:0] cnt; // cnt=0:scl上升沿,cnt=1:scl高电平中间,cnt=2:scl下降沿,cnt=3:scl低电平中间
reg[7:0] cnt_delay; //200循环计数,产生iic所需要的时钟,250Khz
reg scl_r; //时钟脉冲寄存器


always @ (posedge clk or negedge rst_n)
if(!rst_n) cnt_delay <= 8'd0;
else if(cnt_delay == 8'd199) cnt_delay <= 8'd0; //计数到4us为scl的周期,即250KHz
else cnt_delay <= cnt_delay+1'b1; //时钟计数


always @ (posedge clk or negedge rst_n) begin
if(!rst_n) cnt <= 3'd5;
else begin
case (cnt_delay)
9'd49: cnt <= 3'd1; //cnt=1:scl高电平中间,用于数据采样
9'd99: cnt <= 3'd2; //cnt=2:scl下降沿
9'd149: cnt <= 3'd3; //cnt=3:scl低电平中间,用于数据变化
9'd199: cnt <= 3'd0; //cnt=0:scl上升沿
default: cnt <= 3'd5;
endcase
end
end




`define SCL_POS (cnt==3'd0) //cnt=0:scl上升沿‘、|
`define SCL_HIG (cnt==3'd1) //cnt=1:scl高电平中间,用于数据采样
`define SCL_NEG (cnt==3'd2) //cnt=2:scl下降沿
`define SCL_LOW (cnt==3'd3) //cnt=3:scl低电平中间,用于数据变化
//`define `是非下边的按键


always @ (posedge clk or negedge rst_n)
if(!rst_n) scl_r <= 1'b0;
else if(cnt==3'd0) scl_r <= 1'b1; //scl信号上升沿
    else if(cnt==3'd2) scl_r <= 1'b0; //scl信号下降沿


assign scl = scl_r; //产生iic所需要的时钟
//---------------------------------------------
//需要写入24C02的地址和数据

`define DEVICE_READ 8'b1001_0001 //被寻址器件地址(读操作)
//`define DEVICE_WRITE   8'b1001_0000 //被寻址器件地址(写操作)
reg[7:0] db_r; //在IIC上传送的数据寄存器
reg[15:0] read_data; //读出LM75温度的数据寄存器


//---------------------------------------------
//读、写时序
parameter IDLE = 4'd0;
parameter START1 = 4'd1;
parameter ADD1 = 4'd2;
parameter ACK1 = 4'd3;
parameter DATA1  = 4'd4;
parameter ACK2 = 4'd5;
parameter DATA2 = 4'd6;
parameter NACK = 4'd7;
parameter STOP = 4'd8;


reg[3:0] cstate; //状态寄存器
reg sda_r; //输出数据寄存器
reg sda_link; //输出数据sda信号inout方向控制位
reg[3:0] num; //
reg[25:0] ti1;//每1.35s读一次温度值
always @ (posedge clk or negedge rst_n) 
if(!rst_n) ti1<=26'd0;
else ti1<=ti1+1'b1;


always @ (posedge clk or negedge rst_n) begin
if(!rst_n) begin
cstate <= IDLE;
sda_r <= 1'b1;
sda_link <= 1'b0;
num <= 4'd0;
read_data <= 16'd0;
end
else  
case (cstate)
IDLE: begin
sda_link <= 1'b1; //数据线sda为output
sda_r <= 1'b1;
if(ti1[25]) begin //计时时间到,读数据
db_r <= `DEVICE_READ; //送器件地址(读操作)
cstate <= START1;
end
else cstate <= IDLE; //时间没到
end
START1: begin
if(`SCL_HIG) begin //scl为高电平期间
sda_link <= 1'b1; //数据线sda为output
sda_r <= 1'b0; //拉低数据线sda,产生起始位信号
cstate <= ADD1;
num <= 4'd0; //num计数清零
end
else cstate <= START1; //等待scl高电平中间位置到来
end
ADD1: begin
if(`SCL_LOW) begin
if(num == 4'd8) begin
num <= 4'd0; //num计数清零
sda_r <= 1'b1;
sda_link <= 1'b0; //sda置为高阻态(input)
cstate <= ACK1;
end
else begin
cstate <= ADD1;
num <= num+1'b1;
case (num)
4'd0: sda_r <= db_r[7];
4'd1: sda_r <= db_r[6];
4'd2: sda_r <= db_r[5];
4'd3: sda_r <= db_r[4];
4'd4: sda_r <= db_r[3];
4'd5: sda_r <= db_r[2];
4'd6: sda_r <= db_r[1];
4'd7: sda_r <= db_r[0];
default: ;
endcase
//送器件地址,从高位开始
end
end
else cstate <= ADD1;
end
ACK1: begin
if(!sda_r && `SCL_HIG) begin //LM75产生应答信号

cstate <= DATA1; //dushuju 读数据
 
end
else if(`SCL_NEG)begin   //未产生应答信号,则忽略
cstate <= DATA1; //读数据
  end
else cstate <= ACK1; //等待从机响应
end

DATA1: begin
if(`SCL_HIG) begin
num <= num+1'b1;
case (num)
4'd0: read_data[15] <= sda;
4'd1: read_data[14] <= sda;  
4'd2: read_data[13] <= sda; 
4'd3: read_data[12] <= sda; 
4'd4: read_data[11] <= sda; 
4'd5: read_data[10] <= sda; 
4'd6: read_data[9]  <= sda; 
4'd7: read_data[8]  <= sda; 
default: ;
endcase //du读高字节
end

else if((`SCL_NEG) && (num==4'd8)) begin
num <= 4'd0; //num计数清零
sda_link <= 1'b1; //数据线sda为output
sda_r<=1'b1;// sda拉高,以便产生低电平
cstate <= ACK2;
end
else cstate <= DATA1;
end
 ACK2: begin
if(`SCL_LOW) begin
sda_r <= 1'b0; // 主机应答
end
else if(`SCL_NEG)begin 
  cstate <= DATA2;
sda_link <= 1'b0; //sda置为高阻态(input)
  sda_r<=1'b1;
  end
else cstate <= ACK2;
end
DATA2: begin
           
if(`SCL_HIG) begin
num <= num+1'b1;
case (num)
4'd0: read_data[7] <= sda;
4'd1: read_data[6] <= sda;  
4'd2: read_data[5] <= sda; 
4'd3: read_data[4] <= sda; 
4'd4: read_data[3] <= sda; 
4'd5: read_data[2] <= sda; 
4'd6: read_data[1] <= sda; 
4'd7: read_data[0] <= sda; 
default: ;
endcase //du读di字节
end
else if((`SCL_LOW) && (num==4'd8)) begin
num <= 4'd0; //num计数清零
sda_link <= 1'b1; //数据线sda为output
sda_r<=1'b1;           //产生非应答信号
cstate <= NACK;
end
else cstate <= DATA2;
end

NACK: begin
if(`SCL_LOW) begin
sda_r <= 1'b0; // 主机fei应答
cstate <= STOP;
end
else cstate <= NACK;
end
STOP: begin
     
if(`SCL_HIG) begin
sda_r <= 1'b1;
  cstate <= IDLE;
end
else cstate <= STOP;
end
default: cstate <= IDLE;
endcase
end


assign sda = sda_link ? sda_r:1'bz;
assign data = read_data;


endmodule
//--------------------------------------------------///
//------------------ 数码管显示----------------------///
//--------------------------------------------------///
module SEG_D(
clk,rst_n,
data,
cs,seg
);


input clk; // 50MHz
input rst_n; // 复位信号,低有效


input[15:0] data; //显示数据
output[3:0] cs; //数码管片选信号,低有效
output[7:0] seg; //8段数码管(包括小数点)


 reg[5:0] cnt;
always @ (posedge clk or negedge rst_n)
if(!rst_n) cnt <= 6'd0;
else if (cnt==6'd59) cnt <= 6'd0;
else cnt <= cnt+1'b1;



//-------------------------------------------------------------------------------
/* 共阳极 :不带小数点
              由0到f的编码为:
{
0xc0,0xf9,0xa4,0xb0,
0x99,0x92,0x82,0xf8,
0x80,0x90,0x88,0x83,
0xc6,0xa1,0x86,0x8e};
*/
parameter seg0 = 7'hc0,
seg1 = 7'hf9,
seg2 = 7'ha4,
seg3 = 7'hb0,
seg4 = 7'h99,
seg5 = 7'h92,
seg6 = 7'h82,
seg7 = 7'hf8,
seg8 = 7'h80,
seg9 = 7'h90,
sega = 7'h88,
segb = 7'h83,
segc = 7'hc6,
segd = 7'ha1,
sege = 7'h86,
segf = 7'h8e;


reg[7:0] sm_dbr; //7段数码管(不包括小数点)
reg[3:0] cs_r;       //片选寄存器
reg[3:0] num; //显示数据
always @ (posedge clk or negedge rst_n)
if(!rst_n) begin 
 num<=4'd0;
 cs_r<=4'b1111;
 end
else begin
    case (cnt)
   8'd59: begin
        cs_r<=4'b1110;
num<={data[8:5]};
         end
       8'd19: begin
        cs_r<=4'b1101;
num<={data[12:9]};
         end
8'd39: begin
        cs_r<=4'b1011;
num<={1'b0,data[15:13]};
end
default : ;
endcase
end  
assign cs=cs_r;
always @ (posedge clk or negedge rst_n)
    if(!rst_n) sm_dbr<=8'd0;
else begin
case (num) //温度值值显示在3个数码管上
4'h0: sm_dbr <= seg0;
4'h1: sm_dbr <= seg1;
4'h2: sm_dbr <= seg2;
4'h3: sm_dbr <= seg3;
4'h4: sm_dbr <= seg4;
4'h5: sm_dbr <= seg5;
4'h6: sm_dbr <= seg6;
4'h7: sm_dbr <= seg7;
4'h8: sm_dbr <= seg8;
4'h9: sm_dbr <= seg9;
4'ha: sm_dbr <= sega;
4'hb: sm_dbr <= segb;
4'hc: sm_dbr <= segc;
4'hd: sm_dbr <= segd;
4'he: sm_dbr <= sege;
4'hf: sm_dbr <= segf;
default: ;
endcase
     end
assign seg = sm_dbr;
 
endmodule  


源文件正在学习怎么上传


大家先帮我看看scl_r信号是什么样子的?


共14条 1/2 1 2 跳转至

回复

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