焊接stepfpga and 调试 and 总体功能实现 and 总结

1.硬件设计及调试结果

在这里插入图片描述

在这里插入图片描述
焊接与调试的感悟:一定要考虑焊接的顺序。在原理图,pcb设计以及打板完成之后,首先要解决的是有关一些基本元器件的(如阻值,电容值的选取)。焊接时,要先焊接贴片式的电阻和电容,先焊接小型的贴片元器件,然后焊接一些直插式的元器件,然后焊接usb以及ch340等。最后加入排针将核心板插入。
在后期调试每一个模块并验证其设计的正确性时,对于10路的DA,一定要满足R2R的关系,这对于后期调出波形发生器有很重要的影响。如果不满足此关系。对于后期正弦波信号,调试过程中,如果不满足此关系。波形就会不平滑甚至出现错误。

2.蜂鸣器发出音乐的设计流程

1.设计的代码

module Beeper
		(
		input					clk_in,		//系统时钟
		input					rst_n_in,	//系统复位,低有效
		//input					tone_en,	//蜂鸣器使能信号
		//input			[4:0]	tone,		//蜂鸣器音节控制
		output	reg				piano_out	//蜂鸣器控制输出
		);
		wire clk2;
		reg [2:0] jishu;
		reg [4:0] tone;
		reg [5:0] cnt;
		reg [15:0] time_end;
		parameter t1=1;
		parameter t2=2;
		parameter t3=3;
		parameter t4=4;
		 divide #(.WIDTH(24),.N(3000000)) u1
		 (	
		 .clk(clk_in),
			.rst_n(rst_n_in),
			.clkout(clk2)
			);
always@(tone) begin
	case(tone)
		5'd1:	time_end =	16'd22935;	//L1,
		5'd2:	time_end =	16'd20428;	//L2,
		5'd3:	time_end =	16'd18203;	//L3,
		5'd4:	time_end =	16'd17181;	//L4,
		5'd5:	time_end =	16'd15305;	//L5,
		5'd6:	time_end =	16'd13635;	//L6,
		5'd7:	time_end =	16'd12147;	//L7,
		5'd8:	time_end =	16'd11464;	//M1,
		5'd9:	time_end =	16'd10215;	//M2,
		5'd10:	time_end =	16'd9100;	//M3,
		5'd11:	time_end =	16'd8589;	//M4,
		5'd12:	time_end =	16'd7652;	//M5,
		5'd13:	time_end =	16'd6817;	//M6,
		5'd14:	time_end =	16'd6073;	//M7,
		5'd15:	time_end =	16'd5740;	//H1,
		5'd16:	time_end =	16'd5107;	//H2,
		5'd17:	time_end =	16'd4549;	//H3,
		5'd18:	time_end =	16'd4294;	//H4,
		5'd19:	time_end =	16'd3825;	//H5,
		5'd20:	time_end =	16'd3408;	//H6,
		5'd21:	time_end =	16'd3036;	//H7,
		default:time_end =	16'd65535;	
	endcase
end
 
reg [17:0] time_cnt;
//当蜂鸣器,计数器按照计数终值(分频系数)计数
always@(posedge clk_in or negedge rst_n_in)
		begin
			if(!rst_n_in) 
				begin
			  time_cnt <= 1'b0;
			   end
			else 
				 if(time_cnt>=time_end) 
						begin
						time_cnt <= 1'b0;
						end 
					else 
						begin
						time_cnt <= time_cnt + 1'b1;
						end
		end
 
//根据计数器的周期,翻转蜂鸣器控制信号
always@(posedge clk_in or negedge rst_n_in) 
begin
	if(!rst_n_in) 
		begin
		piano_out <= 1'b0;
		end 
	else if(time_cnt==time_end) 
		begin
		piano_out <= ~piano_out;	//蜂鸣器控制输出翻转,两次翻转为1Hz
		end
		else begin
		piano_out <= piano_out;
	end
end

always @ (posedge clk2,negedge rst_n_in)
	begin
		if(!rst_n_in)
			begin
			tone<=5'd0;
            cnt<=6'h0;
            end
        else
			begin
			if(cnt==6'd42)
				cnt<=6'h0;
			else
			cnt<=cnt+1'b1;
            case(cnt)
            6'd1:tone<=5'd5;
            6'd2:tone<=5'd5;
            6'd3:tone<=5'd6;
            6'd4:tone<=5'd6;
            6'd5:tone<=5'd5;
            6'd6:tone<=5'd5;
            6'd7:tone<=5'd8;
            6'd8:tone<=5'd8;
            6'd9:tone<=5'd7;
            6'd10:tone<=5'd7;
            6'd11:tone<=5'd5;
            6'd12:tone<=5'd5;
            6'd13:tone<=5'd6;
            6'd14:tone<=5'd6;
            6'd15:tone<=5'd5;
            6'd16:tone<=5'd5;
            6'd17:tone<=5'd9;
            6'd18:tone<=5'd9;
            6'd19:tone<=5'd8;
            6'd20:tone<=5'd8;
            6'd21:tone<=5'd5;
            6'd22:tone<=5'd5;
            6'd23:tone<=5'd12;
            6'd24:tone<=5'd12;
            6'd25:tone<=5'd10;
            6'd26:tone<=5'd10;
            6'd27:tone<=5'd8;
            6'd28:tone<=5'd8;
            6'd29:tone<=5'd7;
            6'd30:tone<=5'd7;
            6'd31:tone<=5'd6;
            6'd32:tone<=5'd6;
            6'd33:tone<=5'd11;
            6'd34:tone<=5'd11;
            6'd35:tone<=5'd10;
            6'd36:tone<=5'd10;
            6'd37:tone<=5'd8;
            6'd38:tone<=5'd8;
            6'd39:tone<=5'd9;
            6'd40:tone<=5'd9;
            6'd41:tone<=5'd8;
            6'd42:tone<=5'd8;
			endcase
			end
	end
endmodule

always @ (posedge clk2,negedge rst_n_in)
	begin
		if(!rst_n_in)
			begin
			tone=5'd1;
			end
		else
			if (tone==5'd21)
				begin
				tone=5'd1;
				end
			else
				begin
				tone=tone+1;
				end
		end
endmodule

2.调试结果
由于蜂鸣器能产生特定的音调,是由输入的pwm波的频率变化来控制其音调,于是设定21种频率来区分。分成三组,每一组对应七个音,分别是1,2,3,4,5,6,7。这三个组,分别是低音,中音和高音。通过计数器产生延时来翻转高低电平来产生不同频率的信号,最终通过滤波电路以及放大电路驱动蜂鸣器发声。
上面的verilog程序中自己根据乐谱设计了一首小的音乐,验证自己对于蜂鸣器这条支路设计正确。

3.温度传感器的实现的设计流程

1.代码实现
1)总模块

  module Uart_Bus #
    (
    parameter				BPS_PARA = 1250 //当使用12MHz时钟时波特率参数选择1250对应9600的波特率
    )
    (
    input					clk_in,			//系统时钟
    input					rst_n_in,		//系统复位,低有效
    input					rs232_rx,		//FPGA中UART接收端,分配给UART模块中的发送端TXD
    output					rs232_tx,		//FPGA中UART发送端,分配给UART模块中的接收端RXD
    output [8:0]          seg_led_1,
    output [8:0]         seg_led_2,
    inout                 onewire
    );	
    wire [15:0]  data_out;
    wire [11:0] bcd;
    
    DS18B20Z  u1
    	(
    		.clk_in(clk_in),			
    		.rst_n_in(rst_n_in),		
    		.one_wire(onewire),		
    		.data_out(data_out)		
    	);
    	bcd  u2
    	(
    		.rst_n(rst_n_in),
    		.binary(data_out[10:4]),
    		.bcd(bcd)
    		);
    		//assign bcd1=bcd;
    		//assign bcd2=bcd1;
    	 LED u3
    	 (
    		.seg_data_1(bcd[3:0]),
    		.seg_data_2(bcd[7:4]),
    		.seg_led_1(seg_led_1),
    		.seg_led_2(seg_led_2)
    		);
    /UART接收功能模块例化
    wire					bps_en_rx,bps_clk_rx;
    wire			[7:0]	rx_data;
    
     assign rx_data=bcd[7:0];
     
     /*
    //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		)	//接收到的数据
    );
    
     */
    /UART发送功能模块例化
    wire					bps_en_tx,bps_clk_tx;
     
    //UART发送波特率时钟控制模块 例化
    Baud #
    (
    .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

2)分模块
二进制数转BCD码

module bcd(rst_n,binary,bcd);   //rst_n为使能端,binary为待转换的二进制数,bcd为转换后的BCD码      
parameter B_SIZE=7;				//B_SIZE为二进制数所占的位数,可根据需要进行扩展 
 
input       rst_n;                 	//rst_n高电平有效,低电平时
input  		[B_SIZE-1:0] binary;
output reg  [B_SIZE+4:0] bcd;
 
reg  [B_SIZE-1:0] bin;   
//reg  [B_SIZE+3:0] bcd;    //bcd的长度应根据实际情况进行修改   
reg  [B_SIZE+4:0] result;   //result的长度=bcd的长度 
  
always@(binary or rst_n)
   begin      
      bin= binary;     
	  result = 0;         
   if(rst_n == 0) 
	  bcd <= 0;      
else    
	begin         
repeat(B_SIZE-1)//使用repeat语句进行循环计算      
   begin            
	result[0] = bin[B_SIZE-1];                     
   if(result[3:0] > 4)            
    result[3:0]=result[3:0]+ 4'd3;      
   if(result[7:4] > 4)            
    result[7:4]=result[7:4]+4'd3;  
   if(result[11:8] > 4)   	   
	result[11:8] = result[11:8]+4'd3; //扩展时应参照此三条if语句续写   
   //if(result[15:12] > 4)   	   
	//result[15:12]= result[15:12]+ 4'd3;  
	result=result<<1;
	bin=bin<<1; end         
	result[0]= bin[B_SIZE-1]; 
	bcd<=result;   
   end  
   end   
endmodule

产生稳定的波特率

 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数据接收
    always @ (posedge clk_in or negedge rst_n_in)
    	begin
    		if(!rst_n_in) 
    			bps_clk <= 1'b0;
    		else if(cnt == (BPS_PARA>>1)) 	//BPS_PARA右移一位等于除2,因计数器终值BPS_PARA为数据更替时间点,所以计数器中值时为数据最稳定时间点
    			bps_clk <= 1'b1;	
    		else 
    			bps_clk <= 1'b0;
    	end
     
    endmodule

温度传感器采集数据

  module DS18B20Z
    (
    	input				clk_in,			//系统时钟
    	input				rst_n_in,		//系统复位,低有效
    	inout				one_wire,		//DS18B20Z传感器单总线,双向管脚
    	output	reg	[15:0]	data_out		//DS18B20Z有效温度数据输出
    );
     
    	/*
    	本设计通过驱动DS18B20Z芯片获取温度数据,
    	需要了解inout类型的接口如何实现双向通信,
    	中间涉及各种不同的延时和寄存器指令操作,注释部分以作简要说明
    	*/
    	//wire	[15:0]	data_out
    	localparam	IDLE	=	3'd0;
    	localparam	MAIN	=	3'd1;
    	localparam	INIT	=	3'd2;
    	localparam	WRITE	=	3'd3;
    	localparam	READ	=	3'd4;
    	localparam	DELAY	=	3'd5;
     
    	//计数器分频产生1MHz的时钟信号
    	reg					clk_1mhz;
    	reg		[2:0]		cnt_1mhz;
    	always@(posedge clk_in or negedge rst_n_in) begin
    		if(!rst_n_in) begin
    			cnt_1mhz <= 3'd0;
    			clk_1mhz <= 1'b0;
    		end else if(cnt_1mhz >= 3'd5) begin
    			cnt_1mhz <= 3'd0;
    			clk_1mhz <= ~clk_1mhz;	//产生1MHz分频
    		end else begin
    			cnt_1mhz <= cnt_1mhz + 1'b1;
    		end
    	end
     
    	reg		[2:0]		cnt;
    	reg					one_wire_buffer;
    	reg		[3:0]		cnt_main;
    	reg		[7:0]		data_wr;
    	reg		[7:0]		data_wr_buffer;
    	reg		[2:0]		cnt_init;
    	reg		[19:0]		cnt_delay;
    	reg		[19:0]		num_delay;
    	reg		[3:0]		cnt_write;
    	reg		[2:0]		cnt_read;
    	reg		[15:0]		temperature;
    	reg		[7:0]		temperature_buffer;
    	reg		[2:0] 		state = IDLE;
    	reg		[2:0] 		state_back = IDLE;
    	//使用1MHz时钟信号做触发完成下面状态机的功能
    	always@(posedge clk_1mhz or negedge rst_n_in) begin
    		if(!rst_n_in) begin
    			state <= IDLE;
    			state_back <= IDLE;
    			cnt <= 1'b0;
    			cnt_main <= 1'b0;
    			cnt_init <= 1'b0;
    			cnt_write <= 1'b0;
    			cnt_read <= 1'b0;
    			cnt_delay <= 1'b0;
    			one_wire_buffer <= 1'bz;
    			temperature <= 16'h0;
    		end else begin
    			case(state)
    				IDLE:begin		//IDLE状态,程序设计的软复位功能,各状态异常都会跳转到此状态
    						state <= MAIN;	//软复位完成,跳转之MAIN状态重新工作
    						state_back <= MAIN;
    						cnt <= 1'b0;
    						cnt_main <= 1'b0;
    						cnt_init <= 1'b0;
    						cnt_write <= 1'b0;
    						cnt_read <= 1'b0;
    						cnt_delay <= 1'b0;
    						one_wire_buffer <= 1'bz;
    					end
    				MAIN:begin		//MAIN状态控制状态机在不同状态间跳转,实现完整的温度数据采集
    						if(cnt_main >= 4'd11) cnt_main <= 1'b0;
    						else cnt_main <= cnt_main + 1'b1;
    						case(cnt_main)
    							4'd0: begin state <= INIT; end	//跳转至INIT状态进行芯片的复位及验证
    							4'd1: begin data_wr <= 8'hcc;state <= WRITE; end	//主设备发出跳转ROM指令
    							4'd2: begin data_wr <= 8'h44;state <= WRITE; end	//主设备发出温度转换指令
    							4'd3: begin num_delay <= 20'd750000;state <= DELAY;state_back <= MAIN; end	//延时750ms等待转换完成
     
    							4'd4: begin state <= INIT; end	//跳转至INIT状态进行芯片的复位及验证
    							4'd5: begin data_wr <= 8'hcc;state <= WRITE; end	//主设备发出跳转ROM指令
    							4'd6: begin data_wr <= 8'hbe;state <= WRITE; end	//主设备发出读取温度指令
     
    							4'd7: begin state <= READ; end	//跳转至READ状态进行单总线数据读取
    							4'd8: begin temperature[7:0] <= temperature_buffer; end	//先读取的为低8位数据
     
    							4'd9: begin state <= READ; end	//跳转至READ状态进行单总线数据读取
    							4'd10: begin temperature[15:8] <= temperature_buffer; end	//后读取的为高8为数据
     
    							4'd11: begin state <= IDLE;data_out <= temperature; end	//将完整的温度数据输出并重复以上所有操作
    							default: state <= IDLE;
    						endcase
    					end
    				INIT:begin		//INIT状态完成DS18B20Z芯片的复位及验证功能
    						if(cnt_init >= 3'd6) cnt_init <= 1'b0;
    						else cnt_init <= cnt_init + 1'b1;
    						case(cnt_init)
    							3'd0: begin one_wire_buffer <= 1'b0; end	//单总线复位脉冲拉低
    							3'd1: begin num_delay <= 20'd500;state <= DELAY;state_back <= INIT; end	//复位脉冲保持拉低500us时间
    							3'd2: begin one_wire_buffer <= 1'bz; end	//单总线复位脉冲释放,自动上拉
    							3'd3: begin num_delay <= 20'd100;state <= DELAY;state_back <= INIT; end	//复位脉冲保持释放100us时间
    							3'd4: begin if(one_wire) state <= IDLE; else state <= INIT; end	//根据单总线的存在检测结果判定是否继续
    							3'd5: begin num_delay <= 20'd400;state <= DELAY;state_back <= INIT; end	//如果检测正常继续保持释放400us时间
    							3'd6: begin state <= MAIN; end	//INIT状态操作完成,返回MAIN状态
    							default: state <= IDLE;
    						endcase
    					end
    				WRITE:begin		//按照DS18B20Z芯片单总线时序进行写操作
    						if(cnt <= 3'd6) begin	//共需要发送8bit的数据,这里控制循环的次数
    							if(cnt_write >= 4'd6) begin cnt_write <= 1'b1; cnt <= cnt + 1'b1; end
    							else begin cnt_write <= cnt_write + 1'b1; cnt <= cnt; end
    						end else begin
    							if(cnt_write >= 4'd8) begin cnt_write <= 1'b0; cnt <= 1'b0; end	//两个变量都恢复初值
    							else begin cnt_write <= cnt_write + 1'b1; cnt <= cnt; end
    						end
    						//对于WRITE状态中cnt_write来讲,执行过程为:0;[1~6]*8;7;8;
    						case(cnt_write)
    							//lock data_wr
    							4'd0: begin data_wr_buffer <= data_wr; end	//将需要写出的数据缓存
    							//发送 1bit 数据的用时在60~120us之间,参考数据手册
    							4'd1: begin one_wire_buffer <= 1'b0; end	//总线拉低
    							4'd2: begin num_delay <= 20'd2;state <= DELAY;state_back <= WRITE; end	//延时2us时间,保证15us以内
    							4'd3: begin one_wire_buffer <= data_wr_buffer[cnt]; end	//先发送数据最低位
    							4'd4: begin num_delay <= 20'd80;state <= DELAY;state_back <= WRITE; end	//延时80us时间
    							4'd5: begin one_wire_buffer <= 1'bz; end	//总线释放
    							4'd6: begin num_delay <= 20'd2;state <= DELAY;state_back <= WRITE; end	//延时2us时间
    							//back to main
    							4'd7: begin num_delay <= 20'd80;state <= DELAY;state_back <= WRITE; end	//延时80us时间
    							4'd8: begin state <= MAIN; end	//返回MAIN状态
    							default: state <= IDLE;
    						endcase
    					end
    				READ:begin		//按照DS18B20Z芯片单总线时序进行读操作
    						if(cnt <= 3'd6) begin	//共需要接收8bit的数据,这里控制循环的次数
    							if(cnt_read >= 3'd5) 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'd6) begin cnt_read <= 1'b0; cnt <= 1'b0; end	//两个变量都恢复初值
    							else begin cnt_read <= cnt_read + 1'b1; cnt <= cnt; end
    						end
    						case(cnt_read)
    							//读取 1bit 数据的用时在60~120us之间,总线拉低后15us时间内读取数据,参考数据手册
    							3'd0: begin one_wire_buffer <= 1'b0; end	//总线拉低
    							3'd1: begin num_delay <= 20'd2;state <= DELAY;state_back <= READ; end	//延时2us时间
    							3'd2: begin one_wire_buffer <= 1'bz; end	//总线释放
    							3'd3: begin num_delay <= 20'd5;state <= DELAY;state_back <= READ; end	//延时5us时间
    							3'd4: begin temperature_buffer[cnt] <= one_wire; end	//读取DS18B20Z返回的总线数据,先收最低位
    							3'd5: begin num_delay <= 20'd60;state <= DELAY;state_back <= READ; end	//延时60us时间
    							//back to main
    							3'd6: begin state <= MAIN; end	//返回MAIN状态
    							default: state <= IDLE;
    						endcase
    					end
    				DELAY:begin		//延时控制
    						if(cnt_delay >= num_delay) begin	//延时控制,延时时间由num_delay指定
    							cnt_delay <= 1'b0;
    							state <= state_back; 	//很多状态都需要延时,延时后返回哪个状态由state_back指定
    						end else cnt_delay <= cnt_delay + 1'b1;
    					end
    			endcase
    		end
    	end
     
    	assign	one_wire = one_wire_buffer;
     
    endmodule

串口发送模块

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  [7:0]  seg_led_1,seg_led_2;
	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 <= 1;
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(1)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

数码管显示

 module LED (seg_data_1,seg_data_2,seg_led_1,seg_led_2);
     
    	input [3:0] seg_data_1;						//数码管需要显示0~9十个数字,所以最少需要4位输入做译码
    	input [3:0] seg_data_2;						//小脚丫上第二个数码管
    	output [8:0] seg_led_1;						//在小脚丫上控制一个数码管需要9个信号 MSB~LSB=DIG、DP、G、F、E、D、C、B、A
    	output [8:0] seg_led_2;						//在小脚丫上第二个数码管的控制信号  MSB~LSB=DIG、DP、G、F、E、D、C、B、A
     
            reg [8:0] seg [9:0];                                            //定义了一个reg型的数组变量,相当于一个10*9的存储器,存储器一共有10个数,每个数有9位宽
     
            initial                                                         //在过程块中只能给reg型变量赋值,Verilog中有两种过程块always和initial
                                                                            //initial和always不同,其中语句只执行一次
    	    begin
                  seg[0] = 9'h3f;                                           //对存储器中第一个数赋值9'b00_0011_1111,相当于共阴极接地,DP点变低不亮,7段显示数字  0
    	      seg[1] = 9'h06;                                           //7段显示数字  1
    	      seg[2] = 9'h5b;                                           //7段显示数字  2
    	      seg[3] = 9'h4f;                                           //7段显示数字  3
    	      seg[4] = 9'h66;                                           //7段显示数字  4
    	      seg[5] = 9'h6d;                                           //7段显示数字  5
    	      seg[6] = 9'h7d;                                           //7段显示数字  6
    	      seg[7] = 9'h07;                                           //7段显示数字  7
    	      seg[8] = 9'h7f;                                           //7段显示数字  8
    	      seg[9] = 9'h6f;                                           //7段显示数字  9
                end
     
            assign seg_led_1 = seg[seg_data_1];                         //连续赋值,这样输入不同四位数,就能输出对于译码的9位输出
            assign seg_led_2 = seg[seg_data_2];
     
    endmodule

设计结果与感悟
通过查看 DS18B20Z温度传感器的手册,了解内部不同状态切换,以及控制命令数据命令的时序逻辑,实现温度的采集。对于该设计,时序的要求特别高,如果没有 按照手册的时序编写程序,就会导致各种功能的出错。整体设计是利用温度传感器来采集温度并将温度通过串口发送并通过上位机实时的串口助手实时显示温度,除此之外将温度的整数部分显示的两位数码管上。在显示的过程中,由于存在十进制数与bcd码之间的转换,根据其转化原理设计其转化程序。
对于转化过程中,程序设计不能利用除法和取余,这种会导致生成电路时,产生大量的触发器和门电路,大量消耗内部资源,导致资源利用率降低。

4.信号发生器的实现

1)波形产生的总模块程序设计

module Uart_Bus #
(
parameter				BPS_PARA = 1250 //当使用12MHz时钟时波特率参数选择1250对应9600的波特率
)
(
input					clk_in,			//系统时钟
input					rst_n_in,		//系统复位,低有效
input					rs232_rx,		//FPGA中UART接收端,分配给UART模块中的发送端TXD
output					rs232_tx,		//FPGA中UART发送端,分配给UART模块中的接收端RXD
output  	[7:0]			seg_led_1,
output      [7:0]           seg_led_2,
output [9:0] dac_data_out
//output     [7:0]       led
);		
 
 reg [9:0] dac_data_out;
 
 
 parameter  s1=2'b00;
 parameter  s2=2'b01;
 parameter  s3=2'b10;
 
 
LED u1(
	.seg_data_1( segdata1),
	.seg_data_2(segdata2),
	.seg_led_1(seg_led_1),
	.seg_led_2(seg_led_2)
	); 
 
 reg [1:0]  leixing;
 reg [5:0]  pinlv;
 reg [3:0]  segdata1,segdata2;
 wire [9:0]   dac_data_out1,dac_data_out2,dac_data_out3;
//reg     [7:0]       led;
 
 reg  dds_en_in;
 reg   state1,state2,state3,state4;
 
 
/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		)	//接收到的数据
);
 
 always @(posedge clk_in)
	 begin
		leixing = rx_data[7:6];
		pinlv=rx_data[5:0];
		segdata1=rx_data[6];
		segdata2=rx_data[7];
		end

	 DDS  u10
	(
	 .clk_in(clk_in),  
	 .rst_n_in(1),  
	 .dds_en_in(state1),  
	 .f_increment(pinlv),  
	 .p_increment(0),  
	 .dac_data_out(dac_data_out1)  
	);	
	
	sanjiaobo  u11
	(
	 .clk_in(clk_in),  
	 .rst_n_in(1),  
	 .dds_en_in(state2),  
	 .f_increment(pinlv),  
	 .p_increment(0),  
	 .dac_data_out(dac_data_out2)  
	);

	 fangbom  u12
	(
	 .clk_in(clk_in),  
	 .rst_n_in(1),  
	 .dds_en_in(state3),  
	 .f_increment(pinlv),  
	 .p_increment(0),  
	// .dac_clk_out(clk_in),  
	 .dac_data_out(dac_data_out3)  
	);	
	
	//assign dac_data_out=dac_data_out1;
	
	always @(posedge  clk_in)
	begin
		case(leixing)
		s1:	dac_data_out=dac_data_out1;
		s2:	dac_data_out=dac_data_out2;
		s3:	dac_data_out=dac_data_out3;
		endcase
	end
 always @(posedge  clk_in)
	 case (leixing)
		s1:
			begin
			state1=1;
			state2=0;
			state3=0;
			//state4=0;
			end
			
		s2:
			begin
			state1=0;
			state2=1;
			state3=0;
			//state4=0;
			end
			
		s3:
			begin
				state1=0;
				state2=0;
				state3=1;
				//state4=0;
				end
	 endcase
	
	 
	// always @(posedge  clk_in)
		// begin
		//led=dac_data_out1[9:2];
		//end
/UART发送功能模块例化
wire					bps_en_tx,bps_clk_tx;
 
//UART发送波特率时钟控制模块 例化
Baud #
(
.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

2)正弦波的产生
**

module DDS
(
input clk_in,  //clock in
input rst_n_in,  //reset, active low
input dds_en_in,  //dds work enable
input [23:0] f_increment,  //frequency increment
input [23:0] p_increment,  //phase increment
output dac_clk_out,  //clock out
output [9:0] dac_data_out  //data out
);
reg [23:0] phase_accumulator;
wire [23:0] phase;
//wire [9:0] dac_data_out;
assign dac_clk_out = clk_in;
//next_phase = phase_accumulator + f_increment;
always @(posedge clk_in or negedge rst_n_in)
begin
	if(!rst_n_in) phase_accumulator <= 23'b0;
	else if(dds_en_in) phase_accumulator <= phase_accumulator + f_increment;
end
assign phase = phase_accumulator + p_increment; // phase is the high 8 bits
lookup_table lookup_table_uut
(
.phase(phase[23:16]), 
.dac_data_out(dac_data_out)
);
endmodule
/**************************************************
module: lookup_table
**************************************************/
module lookup_table
(
input [7:0] phase, 
output reg [9:0] dac_data_out
);
wire [5:0] address = phase[5:0];
wire [1:0] sel = phase[7:6];
wire [9:0] sine;
always@(sel or sine)
	case (sel)
		2'b00 : dac_data_out = {1'b1, sine[9:1]};
		2'b01 : dac_data_out = {1'b1, sine[9:1]};
		2'b10 : dac_data_out = {1'b0, 9'h1ff-sine[9:1]};
		2'b11 : dac_data_out = {1'b0, 9'h1ff-sine[9:1]};
	endcase
sine_table sine_table_uut
(
.sel(sel),
.address(address),
.sine(sine)
);
	
endmodule
/**************************************************
module: sine_table
**************************************************/
module sine_table
(
input [1:0] sel,
input [5:0] address,
output reg [9:0] sine
);
reg    [5:0] table_addr;
always @(sel or address)
	case (sel)
		2'b00: table_addr = address;
		2'b01: table_addr = 6'h3f - address;
		2'b10: table_addr = address;
		2'b11: table_addr = 6'h3f - address;
	endcase
always @(table_addr)
	case(table_addr)	
		6'h0: sine=10'h000;
		6'h1: sine=10'h019;
		6'h2: sine=10'h032;
		6'h3: sine=10'h04B;
		6'h4: sine=10'h064;
		6'h5: sine=10'h07D;
		6'h6: sine=10'h096;
		6'h7: sine=10'h0AF;
		6'h8: sine=10'h0C4;
		6'h9: sine=10'h0E0;
		6'ha: sine=10'h0F9;
		6'hb: sine=10'h111;
		6'hc: sine=10'h128;
		6'hd: sine=10'h141;
		6'he: sine=10'h159;
		6'hf: sine=10'h170;
		6'h10: sine=10'h187;
		6'h11: sine=10'h19F;
		6'h12: sine=10'h1B5;
		6'h13: sine=10'h1CC;
		6'h14: sine=10'h1E2;
		6'h15: sine=10'h1F8;
		6'h16: sine=10'h20E;
		6'h17: sine=10'h223;
		6'h18: sine=10'h238;
		6'h19: sine=10'h24D;
		6'h1a: sine=10'h261;
		6'h1b: sine=10'h275;
		6'h1c: sine=10'h289;
		6'h1d: sine=10'h29C;
		6'h1e: sine=10'h2AF;
		6'h1f: sine=10'h2C1;
		6'h20: sine=10'h2D3;
		6'h21: sine=10'h2E5;
		6'h22: sine=10'h2F6;
		6'h23: sine=10'h307;
		6'h24: sine=10'h317;
		6'h25: sine=10'h326;
		6'h26: sine=10'h336;
		6'h27: sine=10'h344;
		6'h28: sine=10'h353;
		6'h29: sine=10'h360;
		6'h2a: sine=10'h36D;
		6'h2b: sine=10'h37A;
		6'h2c: sine=10'h386;
		6'h2d: sine=10'h392;
		6'h2e: sine=10'h39C;
		6'h2f: sine=10'h3A7;
		6'h30: sine=10'h3B1;
		6'h31: sine=10'h3BA;
		6'h32: sine=10'h3C3;
		6'h33: sine=10'h3CB;
		6'h34: sine=10'h3D3;
		6'h35: sine=10'h3DA;
		6'h36: sine=10'h3E0;
		6'h37: sine=10'h3E6;
		6'h38: sine=10'h3EB;
		6'h39: sine=10'h3F0;
		6'h3a: sine=10'h3F3;
		6'h3b: sine=10'h3F7;
		6'h3c: sine=10'h3FA;
		6'h3d: sine=10'h3FC;
		6'h3e: sine=10'h3FE;
		6'h3f: sine=10'h3FF;
	endcase
endmodule

3)三角波的实现
module sanjiaobo
(
input clk_in, //clock in
input rst_n_in, //reset, active low
input dds_en_in, //dds work enable
input [23:0] f_increment, //frequency increment
input [23:0] p_increment, //phase increment
output dac_clk_out, //clock out
output [9:0] dac_data_out //data out
);

reg [23:0] phase_accumulator;
wire [23:0] phase;
//wire [9:0] dac_data_out;
assign dac_clk_out = clk_in;

//next_phase = phase_accumulator + f_increment;
always @(posedge clk_in or negedge rst_n_in)
begin
if(!rst_n_in) phase_accumulator <= 23’b0;
else if(dds_en_in) phase_accumulator <= phase_accumulator + f_increment;
end

assign phase = phase_accumulator + p_increment; // phase is the high 8 bits
a lookup_table_uut
(
.phase(phase[23:16]),
.dac_data_out(dac_data_out)
);

endmodule

/**************************************************
module: a
**************************************************/
module a
(
input [7:0] phase,
output reg [9:0] dac_data_out
);

wire [5:0] address = phase[5:0];
wire [1:0] sel = phase[7:6];
wire [9:0] sine;

always@(sel or sine)
case (sel)
2’b00 : dac_data_out = {1’b1, sine[9:1]};
2’b01 : dac_data_out = {1’b1, sine[9:1]};
2’b10 : dac_data_out = {1’b0, 9’h1ff-sine[9:1]};
2’b11 : dac_data_out = {1’b0, 9’h1ff-sine[9:1]};
endcase

b sine_table_uut
(
.sel(sel),
.address(address),
.sine(sine)
);

endmodule

/**************************************************
module: b
**************************************************/
module b
(
input [1:0] sel,
input [5:0] address,
output reg [9:0] sine
);

reg [5:0] table_addr;

always @(sel or address)
case (sel)
2’b00: table_addr = address;
2’b01: table_addr = 6’h3f - address;
2’b10: table_addr = address;
2’b11: table_addr = 6’h3f - address;
endcase

always @(table_addr)
case(table_addr)
6’h0: sine=10’h000;
6’h1: sine=10’h010;
6’h2: sine=10’h020;
6’h3: sine=10’h030;
6’h4: sine=10’h040;
6’h5: sine=10’h050;
6’h6: sine=10’h060;
6’h7: sine=10’h070;
6’h8: sine=10’h080;
6’h9: sine=10’h090;
6’ha: sine=10’h0a0;
6’hb: sine=10’h0b0;
6’hc: sine=10’h0c0;
6’hd: sine=10’h0d0;
6’he: sine=10’h0e0;
6’hf: sine=10’h0f0;
6’h10: sine=10’h100;
6’h11: sine=10’h110;
6’h12: sine=10’h120;
6’h13: sine=10’h130;
6’h14: sine=10’h140;
6’h15: sine=10’h150;
6’h16: sine=10’h160;
6’h17: sine=10’h170;
6’h18: sine=10’h180;
6’h19: sine=10’h190;
6’h1a: sine=10’h1a0;
6’h1b: sine=10’h1b0;
6’h1c: sine=10’h1c0;
6’h1d: sine=10’h1d0;
6’h1e: sine=10’h1e0;
6’h1f: sine=10’h1f0;
6’h20: sine=10’h200;
6’h21: sine=10’h210;
6’h22: sine=10’h220;
6’h23: sine=10’h230;
6’h24: sine=10’h240;
6’h25: sine=10’h250;
6’h26: sine=10’h260;
6’h27: sine=10’h270;
6’h28: sine=10’h280;
6’h29: sine=10’h290;
6’h2a: sine=10’h2a0;
6’h2b: sine=10’h2b0;
6’h2c: sine=10’h2c0;
6’h2d: sine=10’h2d0;
6’h2e: sine=10’h2e0;
6’h2f: sine=10’h2f0;
6’h30: sine=10’h300;
6’h31: sine=10’h310;
6’h32: sine=10’h320;
6’h33: sine=10’h330;
6’h34: sine=10’h340;
6’h35: sine=10’h350;
6’h36: sine=10’h360;
6’h37: sine=10’h370;
6’h38: sine=10’h380;
6’h39: sine=10’h390;
6’h3a: sine=10’h3a0;
6’h3b: sine=10’h3b0;
6’h3c: sine=10’h3c0;
6’h3d: sine=10’h3d0;
6’h3e: sine=10’h3e0;
6’h3f: sine=10’h3F0;
endcase
endmodule
4)方波的实现

module fangbom
(
input clk_in,  //clock in
input rst_n_in,  //reset, active low
input dds_en_in,  //dds work enable
input [23:0] f_increment,  //frequency increment
input [23:0] p_increment,  //phase increment
output dac_clk_out,  //clock out
output [9:0] dac_data_out  //data out
);

reg [23:0] phase_accumulator;
wire [23:0] phase;
//wire [9:0] dac_data_out;
assign dac_clk_out = clk_in;

//next_phase = phase_accumulator + f_increment;
always @(posedge clk_in or negedge rst_n_in)
begin
	if(!rst_n_in) phase_accumulator <= 23'b0;
	else if(dds_en_in) phase_accumulator <= phase_accumulator + f_increment;
end

assign phase = phase_accumulator + p_increment; // phase is the high 8 bits
n lookup_table_uut
(
.phase(phase[23:16]), 
.dac_data_out(dac_data_out)
);

endmodule

/**************************************************
module: lookup_table
**************************************************/
module n
(
input [7:0] phase, 
output reg [9:0] dac_data_out
);

wire [5:0] address = phase[5:0];
wire [1:0] sel = phase[7:6];
wire [9:0] sine;

always@(sel or sine)
	case (sel)
		2'b00 : dac_data_out = {1'b1, sine[9:1]};
		2'b01 : dac_data_out = {1'b1, sine[9:1]};
		2'b10 : dac_data_out = {1'b0, 9'h1ff-sine[9:1]};
		2'b11 : dac_data_out = {1'b0, 9'h1ff-sine[9:1]};
	endcase

q sine_table_uut
(
.sel(sel),
.address(address),
.sine(sine)
);
	
endmodule

/**************************************************
module: sine_table
**************************************************/
module q
(
input [1:0] sel,
input [5:0] address,
output reg [9:0] sine
);

reg    [5:0] table_addr;

always @(sel or address)
	case (sel)
		2'b00: table_addr = address;
		2'b01: table_addr = 6'h3f - address;
		2'b10: table_addr = address;
		2'b11: table_addr = 6'h3f - address;
	endcase

always @(table_addr)
	case(table_addr)	
		6'h0: sine=10'h3ff;
		6'h1: sine=10'h3ff;
		6'h2: sine=10'h3ff;
		6'h3: sine=10'h3ff;
		6'h4: sine=10'h3ff;
		6'h5: sine=10'h3ff;
		6'h6: sine=10'h3ff;
		6'h7: sine=10'h3ff;
		6'h8: sine=10'h3ff;
		6'h9: sine=10'h3ff;
		6'ha: sine=10'h3ff;
		6'hb: sine=10'h3ff;
		6'hc: sine=10'h3ff;
		6'hd: sine=10'h3ff;
		6'he: sine=10'h3ff;
		6'hf: sine=10'h3ff;
		6'h10: sine=10'h3ff;
		6'h11: sine=10'h3ff;
		6'h12: sine=10'h3ff;
		6'h13: sine=10'h3ff;
		6'h14: sine=10'h3ff;
		6'h15: sine=10'h3ff;
		6'h16: sine=10'h3ff;
		6'h17: sine=10'h3ff;
		6'h18: sine=10'h3ff;
		6'h19: sine=10'h3ff;
		6'h1a: sine=10'h3ff;
		6'h1b: sine=10'h3ff;
		6'h1c: sine=10'h3ff;
		6'h1d: sine=10'h3ff;
		6'h1e: sine=10'h3ff;
		6'h1f: sine=10'h3ff;
		6'h20: sine=10'h3ff;
		6'h21: sine=10'h3ff;
		6'h22: sine=10'h3ff;
		6'h23: sine=10'h3ff;
		6'h24: sine=10'h3ff;
		6'h25: sine=10'h3ff;
		6'h26: sine=10'h3ff;
		6'h27: sine=10'h3ff;
		6'h28: sine=10'h3ff;
		6'h29: sine=10'h3ff;
		6'h2a: sine=10'h3ff;
		6'h2b: sine=10'h3ff;
		6'h2c: sine=10'h3ff;
		6'h2d: sine=10'h3ff;
		6'h2e: sine=10'h3ff;
		6'h2f: sine=10'h3ff;
		6'h30: sine=10'h3ff;
		6'h31: sine=10'h3ff;
		6'h32: sine=10'h3ff;
		6'h33: sine=10'h3ff;
		6'h34: sine=10'h3ff;
		6'h35: sine=10'h3ff;
		6'h36: sine=10'h3ff;
		6'h37: sine=10'h3ff;
		6'h38: sine=10'h3ff;
		6'h39: sine=10'h3ff;
		6'h3a: sine=10'h3ff;
		6'h3b: sine=10'h3ff;
		6'h3c: sine=10'h3ff;
		6'h3d: sine=10'h3ff;
		6'h3e: sine=10'h3ff;
		6'h3f: sine=10'h3ff;
	endcase
endmodule

总体设计及其感悟:总体设计是规定一种通信协议,以一个字节作为标准,最高两位作为本设计的波形的选择,剩余六位作为可调频率的设计。利用上位机根据协议利用串口下达指令利用DDS原理输出到DAC处,然后根据串口接收回来的协议数据,来控制输出的波形和频率。上面程序实现的就是波形信号发生器的设计。
在调试过程中特别注意DAC电阻网络的高低位,以及其对应关系,避免设计时分配引脚导致出错。最终导致波形出错。

5.oled液晶屏的实现

1)总模块的设计

module Uart_Bus #
(
parameter				BPS_PARA = 1250 //当使用12MHz时钟时波特率参数选择1250对应9600的波特率
)
(
input					clk_in,			//系统时钟
input					rst_n_in,		//系统复位,低有效
input					rs232_rx,		//FPGA中UART接收端,分配给UART模块中的发送端TXD



inout                 	one_wire,
output					rs232_tx,		//FPGA中UART发送端,分配给UART模块中的接收端RXD
output   		oled_csn,						//OLCD液晶屏使能
output			oled_rst,						//OLCD液晶屏复位
output			oled_dcn,						//OLCD数据指令控制
output			oled_clk,						//OLCD时钟信号
output			oled_dat,


output  	[8:0]			seg_led_1,
output     [8:0]           seg_led_2
);		
 
 	
	//input  clk_in,rst_n_in;
	//inout  one_wire;
	//output   oled_csn,oled_rst,oled_dcn,oled_clk,oled_dat;
	//output  [8:0]  seg_led_1,seg_led_2;
	reg     [7:0]    chuankouxianshi;
		
	wire [15:0]  data_out;
	wire [11:0] bcd;

DS18B20Z  u1
	(
		.clk_in(clk_in),			
		.rst_n_in(rst_n_in),		
		.one_wire(one_wire),		
		.data_out(data_out)		
	);
	
	
	bcd  u2
	(
		.rst_n(rst_n_in),
		.binary(data_out[10:4]),
		.bcd(bcd)
		);
		
		 LED u3
	 (
		.seg_data_1(bcd[3:0]),
		.seg_data_2(bcd[7:4]),
		.seg_led_1(seg_led_1),
		.seg_led_2(seg_led_2)
		);
	
	 OLED12832_Driver  u4
	(
		.clk(clk_in),							//12MHz系统时钟
		.rst_n(rst_n_in),      //系统复位,低有效
		.wendu(bcd[7:0]),
		.chuankouxianshi(chuankouxianshi),
		
		.oled_csn(oled_csn),						//OLCD液晶屏使能
		.oled_rst(oled_rst),						//OLCD液晶屏复位
		.oled_dcn(oled_dcn),						//OLCD数据指令控制
		.oled_clk(oled_clk),						//OLCD时钟信号
		.oled_dat(oled_dat)						//OLCD数据信号
	);
	
/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				(1		),	//系统复位,低有效
.bps_en					(bps_en_rx		),	//接收时钟使能
.bps_clk				(bps_clk_rx		)	//接收时钟输出
);
 
//UART接收数据模块 例化
Uart_Rx Uart_Rx_uut
(
.clk_in					(clk_in			),	//系统时钟
.rst_n_in				(1		),	//系统复位,低有效
.bps_en					(bps_en_rx		),	//接收时钟使能
.bps_clk				(bps_clk_rx		),	//接收时钟输入
.rs232_rx				(rs232_rx		),	//UART接收输入
.rx_data				(rx_data		)	//接收到的数据
);
 
 
 always@(posedge  clk_in)
	 begin
		 chuankouxianshi<=rx_data;
		end
	 
 
/UART发送功能模块例化
wire					bps_en_tx,bps_clk_tx;
 
//UART发送波特率时钟控制模块 例化
Baud #
(
.BPS_PARA				(BPS_PARA		)
)
Baud_tx
(
.clk_in					(clk_in			),	//系统时钟
.rst_n_in				(1		),	//系统复位,低有效
.bps_en					(bps_en_tx		),	//发送时钟使能
.bps_clk				(bps_clk_tx		)	//发送时钟输出
);
 
//UART发送数据模块 例化
Uart_Tx Uart_Tx_uut
(
.clk_in					(clk_in			),	//系统时钟
.rst_n_in				(1		),	//系统复位,低有效
.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

2)oled显示设计

module OLED12832_Driver
(
	input				clk,		//12MHz系统时钟
	input				rst_n,		//系统复位,低有效
	
	input     [7:0]    wendu,
	input     [7:0]    chuankouxianshi,
	
	output	reg			oled_csn,	//OLCD液晶屏使能
	output	reg			oled_rst,	//OLCD液晶屏复位
	output	reg			oled_dcn,	//OLCD数据指令控制
	output	reg			oled_clk,	//OLCD时钟信号
	output	reg			oled_dat	//OLCD数据信号
);
	
	localparam INIT_DEPTH = 16'd25; //LCD初始化的命令的数量
	localparam IDLE = 6'h1, MAIN = 6'h2, INIT = 6'h4, SCAN = 6'h8, WRITE = 6'h10, DELAY = 6'h20;
	localparam HIGH	= 1'b1, LOW = 1'b0;
	localparam DATA	= 1'b1, CMD = 1'b0;
	
	reg [7:0] cmd [24:0];
	reg [39:0] mem [122:32];
	reg	[7:0]	y_p, x_ph, x_pl;
	reg	[(8*21-1):0] char;
	reg	[7:0]	num, char_reg;			
	reg	[4:0]	cnt_main, cnt_init, cnt_scan, cnt_write;
	reg	[15:0]	num_delay, cnt_delay, cnt;
	reg	[5:0] 	state, state_back;
	
	
	reg     [7:0]    chuankouxianshi_ge,chuankouxianshi_shi;
	always  @(posedge clk)
			begin
			chuankouxianshi_shi=chuankouxianshi[7:4]+48;
			chuankouxianshi_ge=chuankouxianshi[3:0]+48;
			end
	
	
	reg  [7:0]  wendu_shi,wendu_ge;
	always  @(posedge clk)
			begin
			wendu_shi=wendu[7:4]+48;
			wendu_ge=wendu[3:0]+48;
			end
	
	always@(posedge clk or negedge rst_n) begin
		if(!rst_n) begin
			cnt_main <= 1'b0; cnt_init <= 1'b0; cnt_scan <= 1'b0; cnt_write <= 1'b0;
			y_p <= 1'b0; x_ph <= 1'b0; x_pl <= 1'b0;
			num <= 1'b0; char <= 1'b0; char_reg <= 1'b0;
			num_delay <= 16'd5; cnt_delay <= 1'b0; cnt <= 1'b0;
			oled_csn <= HIGH; oled_rst <= HIGH; oled_dcn <= CMD; oled_clk <= HIGH; oled_dat <= LOW;
			state <= IDLE; state_back <= IDLE;
			//chuankouxianshi_shi<=chuankouxianshi[7:4]+48;chuankouxianshi_ge<=chuankouxianshi[3:0]+48;
		end else begin
			case(state)
				IDLE:begin
						cnt_main <= 1'b0; cnt_init <= 1'b0; cnt_scan <= 1'b0; cnt_write <= 1'b0;
						y_p <= 1'b0; x_ph <= 1'b0; x_pl <= 1'b0;
						num <= 1'b0; char <= 1'b0; char_reg <= 1'b0;
						num_delay <= 16'd5; cnt_delay <= 1'b0; cnt <= 1'b0;
						oled_csn <= HIGH; oled_rst <= HIGH; oled_dcn <= CMD; oled_clk <= HIGH; oled_dat <= LOW;
						state <= MAIN; state_back <= MAIN;
					end
				MAIN:begin
						if(cnt_main >= 5'd4) cnt_main <= 5'd1;
						else cnt_main <= cnt_main + 1'b1;
						case(cnt_main)	//MAIN状态
							5'd0:	begin state <= INIT; end
								
							5'd1:	begin y_p <= 8'hb0; x_ph <= 8'h10; x_pl <= 8'h00; num <= 5'd16; 
									//char[(8*21-1):(8*21-6*40)]<="wendu:";  char[(8*21-6*40-1):(8*21-7*40)]=mem[wendu_shi];
									 //char[(8*21-7*40-1):(8*21-8*40)]<=mem[wendu_ge];
									// char <= {"wendu:",wendu_shi,wendu_ge,"        "};
									char <= {"chuankou:",chuankouxianshi_shi,chuankouxianshi_ge,"     "};
									 
							//char <= "Signal Generator";
									state <= SCAN; end
									  
							5'd2:	begin y_p <= 8'hb1; x_ph <= 8'h10; x_pl <= 8'h00; num <= 5'd16; 
									//char <= {"chuankou:",chuankouxianshi_shi,chuankouxianshi_ge,"     "};
									char <= {"wendu:",wendu_shi,wendu_ge,"        "};
									state <= SCAN; end
								
								
							5'd3:	begin y_p <= 8'hb2; x_ph <= 8'h10; x_pl <= 8'h00; num <= 5'd16; 
									char <= "freq:   000000Hz";state <= SCAN; end
									
									
							5'd4:	begin y_p <= 8'hb3; x_ph <= 8'h10; x_pl <= 8'h00; num <= 5'd16;
								char <= "ampl:    .   Vpp";state <= SCAN; end
							default: state <= IDLE;
						endcase
					end
				INIT:begin	//初始化状态
						case(cnt_init)
							5'd0:	begin oled_rst <= LOW; cnt_init <= cnt_init + 1'b1; end	//复位有效
							5'd1:	begin num_delay <= 16'd25000; state <= DELAY; state_back <= INIT; cnt_init <= cnt_init + 1'b1; end	//延时大于3us
							5'd2:	begin oled_rst <= HIGH; cnt_init <= cnt_init + 1'b1; end	//复位恢复
							5'd3:	begin num_delay <= 16'd25000; state <= DELAY; state_back <= INIT; cnt_init <= cnt_init + 1'b1; end	//延时大于220us
							5'd4:	begin 
										if(cnt>=INIT_DEPTH) begin	//当25条指令及数据发出后,配置完成
											cnt <= 1'b0;
											cnt_init <= cnt_init + 1'b1;
										end else begin	
											cnt <= cnt + 1'b1; num_delay <= 16'd5;
											oled_dcn <= CMD; char_reg <= cmd[cnt]; state <= WRITE; state_back <= INIT;
										end
									end
							5'd5:	begin cnt_init <= 1'b0; state <= MAIN; end	//初始化完成,返回MAIN状态
							default: state <= IDLE;
						endcase
					end
				SCAN:begin	//刷屏状态,从RAM中读取数据刷屏
						if(cnt_scan == 5'd11) 
							begin
							if(num) 
								cnt_scan <= 5'd3;
							else 
								cnt_scan <= cnt_scan + 1'b1;
							end 
						else if(cnt_scan == 5'd12) 
							cnt_scan <= 1'b0;
							else 
							cnt_scan <= cnt_scan + 1'b1;
						case(cnt_scan)
							5'd 0:	begin oled_dcn <= CMD; char_reg <= y_p; state <= WRITE; state_back <= SCAN; end		//定位列页地址
							5'd 1:	begin oled_dcn <= CMD; char_reg <= x_pl; state <= WRITE; state_back <= SCAN; end	//定位行地址低位
							5'd 2:	begin oled_dcn <= CMD; char_reg <= x_ph; state <= WRITE; state_back <= SCAN; end	//定位行地址高位
							
							5'd 3:	begin num <= num - 1'b1;end
							5'd 4:	begin oled_dcn <= DATA; char_reg <= 8'h00; state <= WRITE; state_back <= SCAN; end	//将5*8点阵编程8*8
							5'd 5:	begin oled_dcn <= DATA; char_reg <= 8'h00; state <= WRITE; state_back <= SCAN; end	//将5*8点阵编程8*8
							5'd 6:	begin oled_dcn <= DATA; char_reg <= 8'h00; state <= WRITE; state_back <= SCAN; end	//将5*8点阵编程8*8
							5'd 7:	begin oled_dcn <= DATA; char_reg <= mem[char[(num*8)+:8]][39:32]; state <= WRITE; state_back <= SCAN; end
							5'd 8:	begin oled_dcn <= DATA; char_reg <= mem[char[(num*8)+:8]][31:24]; state <= WRITE; state_back <= SCAN; end
							5'd 9:	begin oled_dcn <= DATA; char_reg <= mem[char[(num*8)+:8]][23:16]; state <= WRITE; state_back <= SCAN; end
							5'd10:	begin oled_dcn <= DATA; char_reg <= mem[char[(num*8)+:8]][15: 8]; state <= WRITE; state_back <= SCAN; end
							5'd11:	begin oled_dcn <= DATA; char_reg <= mem[char[(num*8)+:8]][ 7: 0]; state <= WRITE; state_back <= SCAN; end
							5'd12:	begin state <= MAIN; end
							default: state <= IDLE;
						endcase
					end
				WRITE:begin	//WRITE状态,将数据按照SPI时序发送给屏幕
						if(cnt_write >= 5'd17) cnt_write <= 1'b0;
						else cnt_write <= cnt_write + 1'b1;
						case(cnt_write)
							5'd 0:	begin oled_csn <= LOW; end	//9位数据最高位为命令数据控制位
							5'd 1:	begin oled_clk <= LOW; oled_dat <= char_reg[7]; end	//先发高位数据
							5'd 2:	begin oled_clk <= HIGH; end
							5'd 3:	begin oled_clk <= LOW; oled_dat <= char_reg[6]; end
							5'd 4:	begin oled_clk <= HIGH; end
							5'd 5:	begin oled_clk <= LOW; oled_dat <= char_reg[5]; end
							5'd 6:	begin oled_clk <= HIGH; end
							5'd 7:	begin oled_clk <= LOW; oled_dat <= char_reg[4]; end
							5'd 8:	begin oled_clk <= HIGH; end
							5'd 9:	begin oled_clk <= LOW; oled_dat <= char_reg[3]; end
							5'd10:	begin oled_clk <= HIGH; end
							5'd11:	begin oled_clk <= LOW; oled_dat <= char_reg[2]; end
							5'd12:	begin oled_clk <= HIGH; end
							5'd13:	begin oled_clk <= LOW; oled_dat <= char_reg[1]; end
							5'd14:	begin oled_clk <= HIGH; end
							5'd15:	begin oled_clk <= LOW; oled_dat <= char_reg[0]; end	//后发低位数据
							5'd16:	begin oled_clk <= HIGH; end
							5'd17:	begin oled_csn <= HIGH; state <= DELAY; end	//
							default: state <= IDLE;
						endcase
					end
				DELAY:begin	//延时状态
						if(cnt_delay >= num_delay) 
							begin
							cnt_delay <= 16'd0; state <= state_back; 
							end 
						else 
							cnt_delay <= cnt_delay + 1'b1;
						end
					default:state <= IDLE;
			endcase
		end
	end
	
	//OLED配置指令数据
	always@(posedge rst_n)
		begin
			cmd[ 0] = {8'hae}; 
			cmd[ 1] = {8'h00}; 
			cmd[ 2] = {8'h10}; 
			cmd[ 3] = {8'h00}; 
			cmd[ 4] = {8'hb0}; 
			cmd[ 5] = {8'h81}; 
			cmd[ 6] = {8'hff}; 
			cmd[ 7] = {8'ha1}; 
			cmd[ 8] = {8'ha6}; 
			cmd[ 9] = {8'ha8}; 
			cmd[10] = {8'h1f}; 
			cmd[11] = {8'hc8};
			cmd[12] = {8'hd3};
			cmd[13] = {8'h00};
			cmd[14] = {8'hd5};
			cmd[15] = {8'h80};
			cmd[16] = {8'hd9};
			cmd[17] = {8'h1f};
			cmd[18] = {8'hda};
			cmd[19] = {8'h00};
			cmd[20] = {8'hdb};
			cmd[21] = {8'h40};
			cmd[22] = {8'h8d};
			cmd[23] = {8'h14};
			cmd[24] = {8'haf};
		end 
		
	//5*8点阵字库数据
	always@(posedge rst_n)
		begin
			mem[ 32] = {8'h00, 8'h00, 8'h00, 8'h00, 8'h00};   // 32  sp 
			mem[ 33] = {8'h00, 8'h00, 8'h2f, 8'h00, 8'h00};   // 33  !  
			mem[ 34] = {8'h00, 8'h07, 8'h00, 8'h07, 8'h00};   // 34  
			mem[ 35] = {8'h14, 8'h7f, 8'h14, 8'h7f, 8'h14};   // 35  #
			mem[ 36] = {8'h24, 8'h2a, 8'h7f, 8'h2a, 8'h12};   // 36  $
			mem[ 37] = {8'h62, 8'h64, 8'h08, 8'h13, 8'h23};   // 37  %
			mem[ 38] = {8'h36, 8'h49, 8'h55, 8'h22, 8'h50};   // 38  &
			mem[ 39] = {8'h00, 8'h05, 8'h03, 8'h00, 8'h00};   // 39  '
			mem[ 40] = {8'h00, 8'h1c, 8'h22, 8'h41, 8'h00};   // 40  (
			mem[ 41] = {8'h00, 8'h41, 8'h22, 8'h1c, 8'h00};   // 41  )
			mem[ 42] = {8'h14, 8'h08, 8'h3E, 8'h08, 8'h14};   // 42  *
			mem[ 43] = {8'h08, 8'h08, 8'h3E, 8'h08, 8'h08};   // 43  +
			mem[ 44] = {8'h00, 8'h00, 8'hA0, 8'h60, 8'h00};   // 44  ,
			mem[ 45] = {8'h08, 8'h08, 8'h08, 8'h08, 8'h08};   // 45  -
			mem[ 46] = {8'h00, 8'h60, 8'h60, 8'h00, 8'h00};   // 46  .
			mem[ 47] = {8'h20, 8'h10, 8'h08, 8'h04, 8'h02};   // 47  /
			mem[ 48] = {8'h3E, 8'h51, 8'h49, 8'h45, 8'h3E};   // 48  0
			mem[ 49] = {8'h00, 8'h42, 8'h7F, 8'h40, 8'h00};   // 49  1
			mem[ 50] = {8'h42, 8'h61, 8'h51, 8'h49, 8'h46};   // 50  2
			mem[ 51] = {8'h21, 8'h41, 8'h45, 8'h4B, 8'h31};   // 51  3
			mem[ 52] = {8'h18, 8'h14, 8'h12, 8'h7F, 8'h10};   // 52  4
			mem[ 53] = {8'h27, 8'h45, 8'h45, 8'h45, 8'h39};   // 53  5
			mem[ 54] = {8'h3C, 8'h4A, 8'h49, 8'h49, 8'h30};   // 54  6
			mem[ 55] = {8'h01, 8'h71, 8'h09, 8'h05, 8'h03};   // 55  7
			mem[ 56] = {8'h36, 8'h49, 8'h49, 8'h49, 8'h36};   // 56  8
			mem[ 57] = {8'h06, 8'h49, 8'h49, 8'h29, 8'h1E};   // 57  9
			mem[ 58] = {8'h00, 8'h36, 8'h36, 8'h00, 8'h00};   // 58  :
			mem[ 59] = {8'h00, 8'h56, 8'h36, 8'h00, 8'h00};   // 59  ;
			mem[ 60] = {8'h08, 8'h14, 8'h22, 8'h41, 8'h00};   // 60  <
			mem[ 61] = {8'h14, 8'h14, 8'h14, 8'h14, 8'h14};   // 61  =
			mem[ 62] = {8'h00, 8'h41, 8'h22, 8'h14, 8'h08};   // 62  >
			mem[ 63] = {8'h02, 8'h01, 8'h51, 8'h09, 8'h06};   // 63  ?
			mem[ 64] = {8'h32, 8'h49, 8'h59, 8'h51, 8'h3E};   // 64  @
			mem[ 65] = {8'h7C, 8'h12, 8'h11, 8'h12, 8'h7C};   // 65  A
			mem[ 66] = {8'h7F, 8'h49, 8'h49, 8'h49, 8'h36};   // 66  B
			mem[ 67] = {8'h3E, 8'h41, 8'h41, 8'h41, 8'h22};   // 67  C
			mem[ 68] = {8'h7F, 8'h41, 8'h41, 8'h22, 8'h1C};   // 68  D
			mem[ 69] = {8'h7F, 8'h49, 8'h49, 8'h49, 8'h41};   // 69  E
			mem[ 70] = {8'h7F, 8'h09, 8'h09, 8'h09, 8'h01};   // 70  F
			mem[ 71] = {8'h3E, 8'h41, 8'h49, 8'h49, 8'h7A};   // 71  G
			mem[ 72] = {8'h7F, 8'h08, 8'h08, 8'h08, 8'h7F};   // 72  H
			mem[ 73] = {8'h00, 8'h41, 8'h7F, 8'h41, 8'h00};   // 73  I
			mem[ 74] = {8'h20, 8'h40, 8'h41, 8'h3F, 8'h01};   // 74  J
			mem[ 75] = {8'h7F, 8'h08, 8'h14, 8'h22, 8'h41};   // 75  K
			mem[ 76] = {8'h7F, 8'h40, 8'h40, 8'h40, 8'h40};   // 76  L
			mem[ 77] = {8'h7F, 8'h02, 8'h0C, 8'h02, 8'h7F};   // 77  M
			mem[ 78] = {8'h7F, 8'h04, 8'h08, 8'h10, 8'h7F};   // 78  N
			mem[ 79] = {8'h3E, 8'h41, 8'h41, 8'h41, 8'h3E};   // 79  O
			mem[ 80] = {8'h7F, 8'h09, 8'h09, 8'h09, 8'h06};   // 80  P
			mem[ 81] = {8'h3E, 8'h41, 8'h51, 8'h21, 8'h5E};   // 81  Q
			mem[ 82] = {8'h7F, 8'h09, 8'h19, 8'h29, 8'h46};   // 82  R
			mem[ 83] = {8'h46, 8'h49, 8'h49, 8'h49, 8'h31};   // 83  S
			mem[ 84] = {8'h01, 8'h01, 8'h7F, 8'h01, 8'h01};   // 84  T
			mem[ 85] = {8'h3F, 8'h40, 8'h40, 8'h40, 8'h3F};   // 85  U
			mem[ 86] = {8'h1F, 8'h20, 8'h40, 8'h20, 8'h1F};   // 86  V
			mem[ 87] = {8'h3F, 8'h40, 8'h38, 8'h40, 8'h3F};   // 87  W
			mem[ 88] = {8'h63, 8'h14, 8'h08, 8'h14, 8'h63};   // 88  X
			mem[ 89] = {8'h07, 8'h08, 8'h70, 8'h08, 8'h07};   // 89  Y
			mem[ 90] = {8'h61, 8'h51, 8'h49, 8'h45, 8'h43};   // 90  Z
			mem[ 91] = {8'h00, 8'h7F, 8'h41, 8'h41, 8'h00};   // 91  [
			mem[ 92] = {8'h55, 8'h2A, 8'h55, 8'h2A, 8'h55};   // 92  .
			mem[ 93] = {8'h00, 8'h41, 8'h41, 8'h7F, 8'h00};   // 93  ]
			mem[ 94] = {8'h04, 8'h02, 8'h01, 8'h02, 8'h04};   // 94  ^
			mem[ 95] = {8'h40, 8'h40, 8'h40, 8'h40, 8'h40};   // 95  _
			mem[ 96] = {8'h00, 8'h01, 8'h02, 8'h04, 8'h00};   // 96  '
			mem[ 97] = {8'h20, 8'h54, 8'h54, 8'h54, 8'h78};   // 97  a
			mem[ 98] = {8'h7F, 8'h48, 8'h44, 8'h44, 8'h38};   // 98  b
			mem[ 99] = {8'h38, 8'h44, 8'h44, 8'h44, 8'h20};   // 99  c
			mem[100] = {8'h38, 8'h44, 8'h44, 8'h48, 8'h7F};   // 100 d
			mem[101] = {8'h38, 8'h54, 8'h54, 8'h54, 8'h18};   // 101 e
			mem[102] = {8'h08, 8'h7E, 8'h09, 8'h01, 8'h02};   // 102 f
			mem[103] = {8'h18, 8'hA4, 8'hA4, 8'hA4, 8'h7C};   // 103 g
			mem[104] = {8'h7F, 8'h08, 8'h04, 8'h04, 8'h78};   // 104 h
			mem[105] = {8'h00, 8'h44, 8'h7D, 8'h40, 8'h00};   // 105 i
			mem[106] = {8'h40, 8'h80, 8'h84, 8'h7D, 8'h00};   // 106 j
			mem[107] = {8'h7F, 8'h10, 8'h28, 8'h44, 8'h00};   // 107 k
			mem[108] = {8'h00, 8'h41, 8'h7F, 8'h40, 8'h00};   // 108 l
			mem[109] = {8'h7C, 8'h04, 8'h18, 8'h04, 8'h78};   // 109 m
			mem[110] = {8'h7C, 8'h08, 8'h04, 8'h04, 8'h78};   // 110 n
			mem[111] = {8'h38, 8'h44, 8'h44, 8'h44, 8'h38};   // 111 o
			mem[112] = {8'hFC, 8'h24, 8'h24, 8'h24, 8'h18};   // 112 p
			mem[113] = {8'h18, 8'h24, 8'h24, 8'h18, 8'hFC};   // 113 q
			mem[114] = {8'h7C, 8'h08, 8'h04, 8'h04, 8'h08};   // 114 r
			mem[115] = {8'h48, 8'h54, 8'h54, 8'h54, 8'h20};   // 115 s
			mem[116] = {8'h04, 8'h3F, 8'h44, 8'h40, 8'h20};   // 116 t
			mem[117] = {8'h3C, 8'h40, 8'h40, 8'h20, 8'h7C};   // 117 u
			mem[118] = {8'h1C, 8'h20, 8'h40, 8'h20, 8'h1C};   // 118 v
			mem[119] = {8'h3C, 8'h40, 8'h30, 8'h40, 8'h3C};   // 119 w
			mem[120] = {8'h44, 8'h28, 8'h10, 8'h28, 8'h44};   // 120 x
			mem[121] = {8'h1C, 8'hA0, 8'hA0, 8'hA0, 8'h7C};   // 121 y
			mem[122] = {8'h44, 8'h64, 8'h54, 8'h4C, 8'h44};   // 122 z
		end
	
endmodule
**

2)总体设计与感悟:通过利用上位机以及利用温度传感器,根据SPI总线原理,将温度传感器采集到的温度显示到OLED屏以及通过串口发送数据,将数据显示到OLED屏,当温度达到设定温度时,通过触发蜂鸣器实现报警。
上述的设计过程中最重要的是三种总线协议,uart,I^2C,以及SPI三种总线的工作原理以及数据通信的协议格式来分别完成串口通信,传感器的数据采集,oled显示屏的显示等。
最重要的是利用数据手册去查看对应模块的时序要求以及其控制原理,根据时序的严格要求来完成底层设计电路,进而通过编程来控制并实现整个的流程。

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值