FPGA|CPLD|ASIC论坛
直播中

chenbingjy

13年用户 430经验值
擅长:嵌入式技术 嵌入式
私信 关注
[问答]

MAX7219的问题

我在网上找到一个verilog驱动MAX7219的例子,代码如下:

module MAX7219
(
input clk_i,
input rst_i,
//inout wire sdo_i,//串行数据回读
output reg sdin_o,//串行输出数据
output reg sclk_o,//串行时钟
output reg load_o//更新da寄存器

//	input wire [3:0]add,
				//input wire [15:0]segdata
				
			 );

reg [15:0] olddata;
reg [12:0] currentstate;
parameter s1 = 13'b0_0000_0000_0001;
parameter s2 = 13'b0_0000_0000_0010;//s1和S2状态设置译码寄存器
parameter s3 = 13'b0_0000_0000_0100;
parameter s4 = 13'b0_0000_0000_1000;//S3和S4状态设置亮度寄存器
parameter s5 = 13'b0_0000_0001_0000;//
parameter s6 = 13'b0_0000_0010_0000;//S6和S5状态设置扫描限值寄存器
parameter s7 = 13'b0_0000_0100_0000;//
parameter s8 = 13'b0_0000_1000_0000; //S7和S8状态 设置正常显示模式

parameter s10 =13'b0_0010_0000_0000;//
parameter s11 =13'b0_0100_0000_0000;//s10和是1状态 送入显示的数据
parameter Init=13'b0_1000_0000_0000;
parameter Init1=13'b1_0000_0000_0000;

//reg sclk_o;
reg [5:0]counter;

parameter
seg1 = 16'h1181, //1.
seg2 = 16'h1202, //2
seg3 = 16'h1303, //3
seg4 = 16'h1404; //4

reg [1:0]cnt;

//产生时钟
always @(posedge clk_i)
begin
if(!rst_i) begin
counter<=6'd0;
sclk_o <= 1'b1;
end
else begin
if(counter==6'd9) begin
sclk_o <= ~sclk_o;
counter<=6'd0;
end
else counter<=counter+6'd1;
end
end

reg [3:0] sclk_cnt;//同步时钟计数器,15
always @(posedge sclk_o or negedge rst_i)
begin
if(!rst_i) sclk_cnt <= 1'b0;
else
case(currentstate)
Init1,s2,s4,s6,s8,s11:
if(4'd15 == sclk_cnt)
sclk_cnt <= 1'b0;
else sclk_cnt <= sclk_cnt + 1'b1;
default: sclk_cnt <= 1'b0;
endcase
end
//主状态机
always @(posedge sclk_o or negedge rst_i)
begin
if(!rst_i) begin currentstate <=Init; cnt = 2'b0; end
else
case(currentstate)
Init:currentstate <=Init1;
Init1:begin
if(4'd15 == sclk_cnt) //16个时钟周期将数据送出去
currentstate <= s1;
else
currentstate <= Init1;
end
s1: currentstate <= s2; //s1和S2状态设置译码寄存器
s2:begin
if(4'd15 == sclk_cnt) //16个时钟周期将数据送出去
currentstate <= s3;
else
currentstate <= s2;
end
s3: currentstate <= s4;//S3和S4状态设置亮度寄存器
s4: begin
if(4'd15 == sclk_cnt) //16个时钟周期将数据送出去
currentstate <= s5;
else
currentstate <= s4;
end
s5: currentstate <= s6;// S6和S5状态设置扫描限值寄存器
s6: begin
if(4'd15 == sclk_cnt) //16个时钟周期将数据送出去
currentstate <= s7;
else
currentstate <= s6;
end
s7: currentstate <= s8;// S7和S8状态 设置正常显示模式
s8: begin
if(4'd15 == sclk_cnt) //16个时钟周期将数据送出去
currentstate <= s10;
else
currentstate <= s8;
end

//初始化完成	 
s10: if(olddata != data)
			currentstate <= s11;//	正常送数据显示
	  else
			currentstate <= s10;
s11: begin 
		if(4'd15 == sclk_cnt) //16个时钟周期将数据送出去
			begin
				currentstate <= s10;
				cnt = cnt + 1'b1; 
			end	
		else
	   currentstate <= s11;
	end	 
endcase

end
//各状态的处理
reg [15:0] data;
always @(posedge sclk_o or negedge rst_i)
begin
if(!rst_i)begin data <= 16'h0000; olddata <= 16'h0000; end
else case(currentstate)
Init:data <= 16'h0a04;
s1: data <= 16'h0c01; //正常显示模式
s3: data <= 16'h09ff; //编码寄存器 ALL CODE B DECODE
s5: data <= 16'h0f00; //亮度寄存器 ALL max on
s7: data <= 16'h0b07; //扫描限值寄存器 ALL on

s10: begin 
		case(cnt)
		2'd0: data <= seg1;
		2'd1: data <= seg2;
		2'd2: data <= seg3;
		2'd3: data <= seg4;
		
		endcase

		olddata <= data;
	end//{4'b0000,dd,4'b000,dd};olddata <=16'h0c01;end//{4'b0000,4'd4,8'd6};olddata <= {4'b0000,4'd4,8'd6};;;end//16'h080e;  //待显示的数据
	Init1,s2,s4,s6,s8,s11: begin data <= data << 1;	olddata <= olddata; end//循环移位 将高位送出
	default: begin data <= 16'h0000; olddata <= olddata; end
endcase

end
//----------数据串行---------
always @(posedge sclk_o or negedge rst_i)
begin
if(!rst_i) sdin_o <= 1'b0;
else case(currentstate)
Init1,s2,s4,s6,s8,s11: sdin_o <= data[15];
default: sdin_o <= 1'b0;
endcase
end
//----------串行数据写有效LOAD----------
always @(posedge sclk_o or negedge rst_i)
begin
if(!rst_i) load_o <= 1'b1;
else case(currentstate)
Init1,s2,s4,s6,s8,s11: load_o <= 1'b0; //送数的时候处于低
default: load_o <= 1'b1; //非送数时候,拉高 锁存数据
endcase
end

endmodule

我有一点不明白,为什么parameter没有S9。我试了一下,加上S9,去掉s11,就不显示了。

为什么呢?高手解惑,谢谢!

已退回1积分

回帖(5)

卿小小_9e6

2022-10-13 11:45:39
//------问题
不太确定你描述的“加上s9,去掉s11”是什么操作。
如果你只是在case语句中添加了“s9”,但是并未指定parameter(或者paramter s9的值与其他状态机数值一致),那么理论上程序会卡在某一个状态。运气好了能跑通。
//------建议
由代码可知s11是发送数据的状态机之一,s10是显示。
你将代码中的s11全部替换为s9,这样最省事。
举报

卿小小_9e6

2022-10-13 11:57:50
//-------问题
不太确定“加上S9,去掉s11”是什么操作。
如果你添加某个状态机(s9):
  1. a.先通过parameter定义状态机s9;
  2. b.功能设计好,即什么条件跳转进入s9,以及什么条件跳出s9进入其他状态机。
  3. c.假如只有状态机的进入而无状态机的跳出,理论上会在当前状态机死循环。

//------建议
如果没有增加额外的功能,只是感觉中间缺少s9不顺眼,可以将代码中的s11全部替换为s9。这样对代码的功能没有任何影响。
举报

chenbingjy

2022-10-13 19:08:42
parameter s10 =13'b0_0010_0000_0000;//
parameter s11 =13'b0_0100_0000_0000;//s10和是1状态 送入显示的数据

我改为
parameter s9 =13'b0_0001_0000_0000;//
parameter s10 =13'b0_0010_0000_0000;//s10和是1状态 送入显示的数据
就不行了
举报

chenbingjy

2022-10-13 21:20:55
中间隔了一个,我总觉得有一些深意
1 举报

infortrans

2022-10-20 11:07:54
学习学习。                                       
举报

更多回帖

发帖
×
20
完善资料,
赚取积分