差别

这里会显示出您选择的修订版和当前版本之间的差别。

到此差别页面的链接

两侧同时换到之前的修订记录 前一修订版
后一修订版
前一修订版
contest_board_dds [2022/06/25 17:31]
gongyu [OLED显示模块]
contest_board_dds [2022/06/25 17:59] (当前版本)
gongyu
行 1: 行 1:
 ## 在电赛训练板上实现DDS的功能 ## 在电赛训练板上实现DDS的功能
 关于用FPGA实现DDS的过程可以参考文档:[[https://​www.eetree.cn/​wiki/​dds_verilog|DDS生成任意波形的方法及Verilog代码实例]] 关于用FPGA实现DDS的过程可以参考文档:[[https://​www.eetree.cn/​wiki/​dds_verilog|DDS生成任意波形的方法及Verilog代码实例]]
 +{{ :​contest_training_board1.png |}}<WRAP centeralign>​基于小脚丫FPGA核心板的电赛训练板 </​WRAP>​
  
-### 顶层模块+### 1. 顶层模块 
 +{{ :​contest_board_dds_block.png |}} 
 +FPGA片内逻辑的结构框图如上图所示,FPGA片上实现的逻辑包括: 
 +  - 调用内部锁相环由输入的12M时钟得到120MHZ工作时钟,驱动DDS控制模块,输出作为DAC的转换时钟。 
 +  - 处理旋转编码器的输入。判断旋转编码器的转动和按下,顺时针转动对应信号频率的增加,逆时针转动对应信号频率的减小,按下对应波形的切换。 
 +  - 存储正弦波的波形数据。 
 +  - 实现的波形包括正弦波、三角波、方波、锯齿波四种波形,波形频率范围为100kHZ到10MHZ。 
 +  - 通过spi总线驱动OLED屏幕指示当前的波形和频率。 
 + 
 +代码如下:
 <code verilog> <code verilog>
 module top(clk_in,​sys_rst_n,​key_a,​key_b,​key_ok,​dac_data,​dac_clk,​oled_rst,​oled_dcn,​oled_clk,​oled_dat);​ module top(clk_in,​sys_rst_n,​key_a,​key_b,​key_ok,​dac_data,​dac_clk,​oled_rst,​oled_dcn,​oled_clk,​oled_dat);​
行 77: 行 87:
  
  
-### DDS核心模块 +### 2. DDS核心模块 
-这是DDS的主代码,可以选择输出的波形以及相应的频率+DDS控制模块是信号发生器设计的核心,利用Verilog实现DDS的结构框图如下图所示。 
 +{{drawio>​contest_board_dds_module_block.png}} 
 + 
 +从图中可以看出,DDS控制模块根据旋转编码器模块的输入信号调节频率控制字、切换波形,输出一定频率的方波、三角波、锯齿波或正弦波数据至DAC。同时,DDS控制模块还会将当前波形信息和频率信息输出给OLED模块用于显示。四种波形的产生使用同一个相位累加寄存器,如下图所示,相位累加寄存器本质上是一个不断累加的计数器,单次累加的幅度是频率控制字,频率控制字由旋转编码器调节,当旋转编码器顺时针转动时增大频率控制字,当旋转编码器逆时针转动时减小频率控制字。接下来分别介绍四种波形的原理。 
 + 
 +  - 方波 - 取相位累加寄存器的最高位作为判断条件,当最高位为逻辑1,则对DAC的输入赋值10’h3ff;当最高位为逻辑0,则则对DAC的输入赋值10’h000,从而实现了方波波形。 
 +  - 锯齿波 - 取相位累加寄存器的高十位直接作为DAC的输入,随着相位累加寄存器不断累加,DAC的输入也周期性地以锯齿波形状循环。 
 +  - 三角波 - 取相位累加寄存器的最高位作为判断条件,当最高位为逻辑1,则将相位累加寄存器的13到22位直接作为DAC数据的输入;当最高位为逻辑0,则将相位累加寄存器的13到22位取反后作为DAC数据的输入。 
 +  - 正弦波 - 与其它三种波形不同,正弦波不能直接用取相位累加寄存器作为DAC的输入,需要将相位累加寄存器的高8位作为正弦波表的地址输入,样的话,就实现了在一个周期内以一定间隔读出正弦波表内的数据作为DAC的输入。 
 + 
 +下面是DDS的主代码,可以选择输出的波形以及相应的频率
  
 <code verilog> <code verilog>
行 304: 行 324:
 </​code>​ </​code>​
  
-### 编码器输入模块+### 3. 编码器输入模块
 <code verilog> <code verilog>
 // -------------------------------------------------------------------- // --------------------------------------------------------------------
行 416: 行 436:
 </​code>​ </​code>​
  
-### OLED显示模块+### 4. 将频率值转换为OLED显示器上的字符 
 +<code verilog>​ 
 +module getChar3 ( 
 +    input                   ​clk,​ 
 +    input                   ​rst_n,​ 
 +    input   ​[31:​0] ​         WaveFreq, 
 +    output ​ reg[(8*16-1):​0] ​   char 
 +); 
 + 
 +reg [31:​0] ​ t_bin; 
 +reg [3:​0] ​  ​bcd8,​bcd7,​bcd6,​bcd5,​bcd4,​bcd3,​bcd2,​bcd1;​ 
 + 
 +reg [3:0] state; 
 + 
 +always@(posedge clk or negedge rst_n) 
 +begin 
 + if(!rst_n) begin 
 + t_bin<​=WaveFreq;​ 
 +        char<= 0; 
 + bcd8<= 0; 
 + bcd7<= 0; 
 + bcd6<= 0; 
 + bcd5<= 0; 
 + bcd4<= 0; 
 + bcd3<= 0; 
 + bcd2<= 0; 
 + bcd1<= 0; 
 +        state<​=0;​ 
 + end 
 + else begin 
 +        case (state) 
 +            0: begin 
 +                t_bin<​=WaveFreq;​ 
 +                state<​=state+1;​ 
 +            end 
 +            1: begin 
 +                if($signed(t_bin)-$signed(10000000)>​=0)begin 
 +                    bcd8<​=bcd8+1;​ 
 +                    t_bin<​=t_bin-10000000;​ 
 +                end 
 +                else begin 
 +                    state<​=state+1;​ 
 +                end 
 +            end 
 +            2: begin 
 +                if($signed(t_bin)-$signed(1000000)>​=0)begin 
 +                    bcd7<​=bcd7+1;​ 
 +                    t_bin<​=t_bin-1000000;​ 
 +                end 
 +                else begin 
 +                    state<​=state+1;​ 
 +                end 
 +            end 
 +            3: begin 
 +                if($signed(t_bin)-$signed(100000)>​=0)begin 
 +                    bcd6<​=bcd6+1;​ 
 +                    t_bin<​=t_bin-100000;​ 
 +                end 
 +                else begin 
 +                    state<​=state+1;​ 
 +                end 
 +            end 
 +            4: begin 
 +                if($signed(t_bin)-$signed(10000)>​=0)begin 
 +                    bcd5<​=bcd5+1;​ 
 +                    t_bin<​=t_bin-10000;​ 
 +                end 
 +                else begin 
 +                    state<​=state+1;​ 
 +                end 
 +            end 
 +            5: begin 
 +                if($signed(t_bin)-$signed(1000)>​=0)begin 
 +                    bcd4<​=bcd4+1;​ 
 +                    t_bin<​=t_bin-1000;​ 
 +                end 
 +                else begin 
 +                    state<​=state+1;​ 
 +                end 
 +            end 
 +            6: begin 
 +                if($signed(t_bin)-$signed(100)>​=0)begin 
 +                    bcd3<​=bcd3+1;​ 
 +                    t_bin<​=t_bin-100;​ 
 +                end 
 +                else begin 
 +                    state<​=state+1;​ 
 +                end 
 +            end 
 +            7: begin 
 +                if($signed(t_bin)-$signed(10)>​=0)begin 
 +                    bcd2<​=bcd2+1;​ 
 +                    t_bin<​=t_bin-10;​ 
 +                end 
 +                else begin 
 +                    state<​=state+1;​ 
 +                end 
 +            end 
 +            8: begin 
 +                if($signed(t_bin)-$signed(1)>​=0)begin 
 +                    bcd1<​=bcd1+1;​ 
 +                    t_bin<​=t_bin-1;​ 
 +                end 
 +                else begin 
 +                    state<​=state+1;​ 
 +                end 
 +            end 
 +            9:begin 
 +                t_bin<​=WaveFreq;​ 
 +                char<​={" ​ ",​4'​h0,​bcd8,​4'​h0,​bcd7,"​_",​ 
 +                4'​h0,​bcd6,​4'​h0,​bcd5,​4'​h0,​bcd4,"​_",​ 
 +                4'​h0,​bcd3,​4'​h0,​bcd2,​4'​h0,​bcd1,"​Hz ​ "}; 
 +                bcd8<= 0; 
 +                bcd7<= 0; 
 +                bcd6<= 0; 
 +                bcd5<= 0; 
 +                bcd4<= 0; 
 +                bcd3<= 0; 
 +                bcd2<= 0; 
 +                bcd1<= 0; 
 +                state<​=0;​ 
 +            end 
 +            default: begin 
 +                t_bin<​=WaveFreq;​ 
 +                bcd7<= 0; 
 +                bcd6<= 0; 
 +                bcd5<= 0; 
 +                bcd4<= 0; 
 +                bcd3<= 0; 
 +                bcd2<= 0; 
 +                bcd1<= 0; 
 +                state<​=0;​ 
 +            end 
 +        endcase  
 + end 
 +end 
 +  
 +endmodule 
 +</​code>​ 
 + 
 +### 5. OLED显示模块
 这是通过SPI总线方式来驱动128*64分辨率的OLED显示屏显示相应信息的逻辑代码 这是通过SPI总线方式来驱动128*64分辨率的OLED显示屏显示相应信息的逻辑代码
 +
 +该模块的输入包括时钟、复位、输入变量,输出是驱动ssd1306的的五根总线:包括spi的三条总线、一条ssd1306复位线、一条ssd1306数据指令选择线。
 +该模块通过SPI总线完成OLED屏幕的显示,能够显示字符和汉字。该模块中,利用查找表实现字符、汉字模的存储,利用一个一段式状态机实现:初始化配置SSD1306驱动芯片、在屏幕上显示指定的信息。其中,IDLE状态作为初始状态完成所有寄存器变量的初始化;MAIN状态作为总调度实现了整个OLED模块的流程调度,如果想要使用本模块,只需要在本状态进行修改;INIT状态通过调用WRITE状态将23条SSD1306的配置指令通过SPI时序发出,完成SSD1306的配置;SCAN状态通过调用WRITE状态完成字符的显示;CHINESE状态通过调用WRITE状态完成汉字的显示;WRITE状态作为底层状态,完成SPI的传输过程;DELAY状态的功能是延时。
 +本模块的使用通过在MAIN状态里进行添加相应的逻辑来实现,如果显示汉字则需要在汉字字模中添加相应的字模信息。如果想要实时刷新信息,需要将动态显示的信息通过本module的输入端口sw传入模块本在MAIN状态里进行调用,也可自行添加输入端口变量。
 +
 <code verilog> <code verilog>
 // -------------------------------------------------------------------- // --------------------------------------------------------------------
 // Module: OLED12864 ​ // Module: OLED12864 ​
-// Description:​ OLED12864_Driver锛屼娇鐢*8鐐归樀瀛楀簱锛屾瘡琛屾樉绀28/​8=16涓瓧绗+// Description:​ OLED12864_Driver
 // -------------------------------------------------------------------- // --------------------------------------------------------------------
 module OLED12864 module OLED12864