[其他芯片] 04、安路SparkRoad国产FPGA测评【学习篇】数码管显示

1nnocent   2022-7-27 22:54 楼主

    例程数码管实现999秒计时,精度为0.1秒,按照历程的功能,推测四位数码管应该为动态显示,即四位数码管的段选信号同时控制,轮流点亮位选信号。因为余晖效应人眼看四位数码管时四个数码管是同时亮的。动态显示的优点是节省IO资源,缺点是每个时刻只有一个数码管点亮,视觉效果上比静态数码管差(个人觉得没区别)。

    现在看一下数码管的原理图:通过原理图可知数码管为共阴极,位选信号由AN0,AN1,AN2,AN3控制,段选信号由CG,CC,CH,CD,CE,CA,CF,CB控制,由此可知为八段数码管。

image.png       以下为四位位选控制信号和八段段选控制信号对应的FPGA引脚:

image.png       接下来分析代码实现,首先是输入输出接口,这里除了时钟和复位(还不太习惯,安路这个板子没有复位输入,依然是“rst.v”来实现复位给寄存器赋初值)信号外还有位选信号sm_bit位宽为四,段选信号sm_seg位宽为八,此外还定义了一个常量CNT_TIME,具体值为2400_000,2400000个系统时钟周期刚好实现0.1s的计时功能,用于动态显示四个数码管。

    想要实现动态显示的话需要做到两布,一是段选信号的控制,数码管的四个位的段选都是并联的,所以只需要8个FPGA引脚来进行控制,如果只是给段选信号的话这时看到的现象是乱序的,因为这个段选信号包含了百位,十位,各位以及小数点后一位的段选信号;二是位选信号的控制,位选信号的作用是让段选信号在合适的时间在合适的位置显示,比如这次的段选信号是十位显示的数据,此时就让十位的数码管导通、下次的段选信号是个位的显示信号,下一次就选通个位的数码管点亮。

    

always@(posedge clk_24m or negedge rst_n)	// 小数点后一位
begin
	if(!rst_n)
		sm_bit1_num <= 4'h0;
	else if(cnt == CNT_TIME)//0.1s
	begin
		if(sm_bit1_num == 9)
			sm_bit1_num <= 4'h0;
		else
			sm_bit1_num <= sm_bit1_num + 1'b1;
	end
	else
		sm_bit1_num <= sm_bit1_num;
end
	
always@(posedge clk_24m or negedge rst_n)	// 个位
begin
	if(!rst_n)
		sm_bit2_num <= 4'h0;
	else if(cnt == CNT_TIME && sm_bit1_num == 9)
	begin		
		if(sm_bit2_num == 10 )
			sm_bit2_num <= 4'h0;
		else 
			sm_bit2_num <= sm_bit2_num + 1;
	end
	else
		sm_bit2_num <= sm_bit2_num;
end	
		
always@(posedge clk_24m or negedge rst_n)	// 十位
begin
	if(!rst_n)
		sm_bit3_num <= 4'h0;
	else if(cnt == CNT_TIME && sm_bit2_num == 9 && sm_bit1_num == 9)
	begin		
		if(sm_bit3_num == 10 )
			sm_bit3_num <= 4'h0;
		else
			sm_bit3_num <= sm_bit3_num + 1;
	end
	else
		sm_bit3_num <= sm_bit3_num;
end	
	
always@(posedge clk_24m or negedge rst_n)	// 百位
begin
	if(!rst_n)
		sm_bit4_num <= 4'h0;
	else if(cnt == CNT_TIME && sm_bit3_num == 9 && sm_bit2_num == 9 && sm_bit1_num == 9)
	begin		
		if(sm_bit4_num == 10)
			sm_bit4_num <= 4'h0;
		else
			sm_bit4_num <= sm_bit4_num + 1;
	end
	else
		sm_bit4_num <= sm_bit4_num;
end						

    此端代码控制每位数码管显示的具体数字数字,此时还不是具体的段选信号。

always@(posedge clk_24m or negedge rst_n)
begin
	if(!rst_n)
		cnt_w <= 18'd0;
	else if(cnt_w == 18'b111_111_111_111_111_111)  // 0.1s 1/24M*262144
	// else if(&cnt_w)  
		cnt_w <= 18'd0;
	else
		cnt_w <= cnt_w + 1;
end

    这里是位选信号变换的间隔,由cnt_w控制(18位)。

always@(posedge clk_24m or negedge rst_n)
begin
	if(!rst_n)
		sm_seg_num   <= 4'h0;
	else
	begin
		case( cnt_w[17:16] )
		2'b00:sm_seg_num   <= sm_bit1_num; 
		2'b01:sm_seg_num   <= sm_bit2_num; 
		2'b10:sm_seg_num   <= sm_bit3_num; 
		2'b11:sm_seg_num   <= sm_bit4_num; 
		endcase
	end
end

    这里让四个位的具体数字幅值给段选寄存器sm_seg_num,后面根据这个寄存器的值选择具体的段选信号。这里sm_seg_num的幅值由上面提到的cnt_w高二位控制,刚好可以控制四个数码管,刚开始以为这里的cnt_w和计数器cnt的间隔是一致的,其实不然,计数器的间隔是0.1S也就是计数2400000次,而这里的cnt_w为18位,计数次数为262144次,比0.1S小,也就是说四位数码管以小于0.1S的间隔依次点亮。

always@(*)
begin
	case ( sm_seg_num )
	S0:
		sm_seg_reg <= 8'hc0;
	S1:               
		sm_seg_reg <= 8'hf9;
	S2:               
		sm_seg_reg <= 8'ha4;
	S3:               
		sm_seg_reg <= 8'hb0;
	S4:               
		sm_seg_reg <= 8'h99;
	S5:               
		sm_seg_reg <= 8'h92;
	S6:               
		sm_seg_reg <= 8'h82;
	S7:               
		sm_seg_reg <= 8'hf8;
	S8:               
		sm_seg_reg <= 8'h80;
	S9:               
		sm_seg_reg <= 8'h90;
	default:sm_seg_reg <= 8'hc0;
	endcase
end	

    这里给段选寄存器sm_seg_num具体的段选信号。

    例程运行效果:

image.png  

本帖最后由 1nnocent 于 2022-7-23 21:42 编辑

回复评论 (4)

好材料,学习了,寄存器的值选择具体的段选信号,收藏学习

点赞  2022-7-28 09:25
引用: Wenjun99 发表于 2022-7-28 09:25 好材料,学习了,寄存器的值选择具体的段选信号,收藏学习

例程材料写得好哈哈哈

 

 

点赞  2022-7-28 10:29

这芯片性能如何,安路是国产做的最大的FPGA厂家吧?

点赞  2022-7-28 14:38
引用: wangerxian 发表于 2022-7-28 14:38 这芯片性能如何,安路是国产做的最大的FPGA厂家吧?

才刚开始学不久,评估性能这方面可能还没什么概念

 

 

点赞  2022-7-28 14:40
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复