1nnocent 发表于 2022-7-27 22:54

04、安路SparkRoad国产FPGA测评【学习篇】数码管显示

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

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

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

<p>&nbsp; &nbsp; &nbsp; 以下为四位位选控制信号和八段段选控制信号对应的FPGA引脚:</p>

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

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

<p>&nbsp;&nbsp;&nbsp;&nbsp;</p>

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

<p>&nbsp;&nbsp;&nbsp;&nbsp;此端代码控制每位数码管显示的具体数字数字,此时还不是具体的段选信号。</p>

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

<p>&nbsp; &nbsp; 这里是位选信号变换的间隔,由cnt_w控制(18位)。</p>

<pre>
<code>always@(posedge clk_24m or negedge rst_n)
begin
        if(!rst_n)
                sm_seg_num   &lt;= 4'h0;
        else
        begin
                case( cnt_w )
                2'b00:sm_seg_num   &lt;= sm_bit1_num;
                2'b01:sm_seg_num   &lt;= sm_bit2_num;
                2'b10:sm_seg_num   &lt;= sm_bit3_num;
                2'b11:sm_seg_num   &lt;= sm_bit4_num;
                endcase
        end
end</code></pre>

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

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

<p>&nbsp; &nbsp; 这里给段选寄存器sm_seg_num具体的段选信号。</p>

<p>&nbsp; &nbsp; 例程运行效果:</p>

<p> &nbsp;</p>

Wenjun99 发表于 2022-7-28 09:25

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

1nnocent 发表于 2022-7-28 10:29

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

<p>例程材料写得好哈哈哈</p>

<p>&nbsp;</p>

<p>&nbsp;</p>

<p>,</p>

wangerxian 发表于 2022-7-28 14:38

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

1nnocent 发表于 2022-7-28 14:40

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

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

<p>&nbsp;</p>

<p>&nbsp;</p>

<p>。</p>
页: [1]
查看完整版本: 04、安路SparkRoad国产FPGA测评【学习篇】数码管显示