[Title]
[Message]
电子森林
文档
  • 平台
  • 器件
    • 传感器
    • 模拟链路
    • 数据转换
    • 逻辑器件
    • 微处理器/微控制器
    • 多媒体处理
    • 网络与通信
    • 接口与协议
    • 电源管理
    • 电机
    • 时钟/定时
    • 无线和射频器件
    • 分立器件
    • 连接器
    • 显示及驱动
    • 开发板/模块
  • 应用
    • 物联网
    • 通信
    • 工业控制
    • 智能电网
    • 安防监控
    • 人工智能
    • 交通运输
    • 医疗保健
    • 计算机及外设
    • 智能家居/家电
    • 可穿戴设备
    • 全国大学生设计竞赛
    • 智能车比赛
    • 硬禾实战培训
    • 毕业设计
  • 工具
    • PCB设计
    • 仿真工具
    • FPGA编程
    • 测试测量
    • 参考资源
    • 众筹产品
  • 招募
    • 人才招聘
    • 项目外包
  • 项目
  • 百科
  • 硬禾学堂
  • 电路仿真
  • 论坛
    • 发布项目
    • 登录
    • 注册
    电子森林
    • 登录
    文档
    项目
    百科
    硬禾学堂
    电路仿真
    基于16管脚FPGA最小系统的简易口袋仪器DIY套件

    基于16管脚FPGA最小系统的简易口袋仪器DIY套件

    进度
    100%

    时间

    2020年12月19日 00:00 - 2021年02月28日 00:00

    子曰

    更新

    2021年03月08日

    标签

    • FPGA
    • 测试
    • 口袋仪器
    • 寒假在家一起练
    896

    基本信息

    规则

    项目进度

    视频课程

    案例

    评论

    内容介绍

    软件 & 硬件

    元器件

    TP1961-TR

    超高速(7ns)比较器, 可工作于+3V/+5V

    XO2-1200HC

    定位于灵活桥接和IO扩展的FPGA器件,1280个LUTS、64Kbits 块SRAM、64Kbits用户闪存、一个锁相环、支持双启动

    TL974

    输出为轨到轨超低噪声的运算放大器

    LM2776

    开关电容逆变器

    TPL740

    500mA输出,高PSRR, 低压差线性稳压器

    软件

    Verilog

    Verilog HDL是一种硬件描述语言,用于设计和归档电子系统。

    工具

    Diamond

    Lattice的FPGA开发环境,支持Windows/Linux操作系统,支持器件XO、XO2、XO3系列FPGA器件

    平台

    基于Lattice的XO2、自带下载器的FPGA最小系统模块

    基于Lattice的XO2-1200HC FPGA构建的最小系统核心模块,支持最多14个数字IO,并能够提供3.3V的供电。板载FPGA下载器,可以通过MicroUSB供电、FPGA配置和UART通信。

    电路图

    物料清单

    附件

    • SimpleSigmaDeltaADCSourceCode.zip

      Lattice提供的Sigma Delta ADC的源代码

    • DDS_16.pdf

      基于XO2-1200HC FPGA核心模块的简易示波器原理图 PDF

    • 01-规格书与控制芯片手册.zip

      OLED显示屏的数据手册及驱动说明 - ZIP

    规则:参见2020年12月16日的微信公众号文章 - 用一颗“很小的FPGA”搞定可调电压源、信号源、示波器、频率计... - 寒假在家一起练(3)

    具体功能需求:

    • 可调电压源 - 能够产生直流电压,且电压值可以数控,变化范围从-3V到+3V,由于是原型设计,负载能力支持到20mA即可;

    • 信号发生器 - 基于DDS的任意波形产生,能够生成频谱分量高达100KHz的任意波形,尤其是3种常用的波形:正弦波、方波、三角波,除了波形可以选择外,频率设置的精度达到1Hz,幅度调节范围为最高5Vpp,且都可数字控制;

    • 电压表/示波器 - 能够测量直流电压、采集0-10KHz的交流信号,并将采集到的波形进行频谱分析;

    • 频率计的功能 - 能够测量外部信号的频率

    当然,测量仪器离不开人机交互,因此按键的输入和图形化的显示也是必不可少的,有两种选择:

    • 在板上连接一个SPI或I2C的OLED显示屏 + 按键,做本地控制

    • 不接本地显示屏和按键,所有的人机交互可以通过上位机PC来实现,这需要通过FPGA编程UART逻辑跟PC连接并且在PC上编写人机接口界面,上位机的软件可以用LabView、Matlab、一些开源的图形化界面或干脆自己编写

    强烈建议自己有条件焊接、调试硬件的同学能够自己来设计电路,无论是用面包板(选用非SMD的器件)还是自己制作PCB都可以,这样可以贡献出更多的创意,实现更高的性能指标,同时也提升自己的系统设计能力。我们提供的FPGA已经做成模块,比较方便接插和焊接。

    强烈建议自己有条件焊接、调试硬件的同学能够自己来设计电路,无论是用面包板(选用非SMD的器件)还是自己制作PCB都可以,这样可以贡献出更多的创意,实现更高的性能指标,同时也提升自己的系统设计能力。我们提供的FPGA已经做成模块,比较方便接插和焊接。

    时间安排、规则和基本要求跟前两个平台的项目要求一致,但在这个项目的上传文件中需包含最终生成的FPGA的JED文件以及占用的FPGA的资源报告,以便我们对代码进行验证,并评比资源利用的效率。

    PCB设计完成,并去加工 更新发布于 2020年12月16日

    预计周末能够拿到样板,进行完整的性能测试,如果顺利,下周一可以开始批量生产。

    主要功能测试完成,可以开始批量加工 更新发布于 2020年12月22日

    测试了以下的功能:

    • 128*64 OLED显示及4个按键的控制
    • 双路可调输出直流电压,-3V ~ 3V可以通过设置寄存器调节
    • 用PWM+RC的DDS信号发生器,在FPGA主频工作在396MHz的情况下,可以输出频率分量高达200KHz的任意波形,输出信号幅度最高5Vpp可调,下图为输出100KHz的正弦波,输出幅度设定为3Vpp的波形,用ADALM2000口袋仪器观察到的。

    Frr9s5zr8fkJjZe45Q1WBJqqH_Gd

    • 采用TP1961高速比较器 + Sigma Delta FPGA逻辑做ADC,在FPGA主频工作在360MHz的情况下,可以采集到1KHz以内的信号,效果见下面用ADI的ADALM2000口袋仪器测试的截屏:

    FrsJz1tw1V3t8jaGAn2APVDOHZ3K

    补充了与该平台相关的一些技术资料和信息 更新发布于 2020年12月27日

    关联了本平台用到的FPGA16核心模块的资源页面。

    补充了与每项功能相关的设计要点以及扩展的可能性。

    拿到板子前你可以预习的内容 更新发布于 2021年01月02日

    这款板卡是基于Lattice的XO2-1200HC FPGA做的,此款FPGA体积小巧(仅32只管脚)才能放在16管脚的核心模块上,但资源强大,内部有1200个LUTs,96Kbits的Block RAM,PLL能够让内部的逻辑跑到400MHz(亲测可以达到这个频率),通过这个活动,就是让大家体会这只FPGA的能力。

    在拿到板子前你可以先对核心板做一下了解,关于这个核心板,我们专门有一个介绍页面 - 基于Lattice的XO2、自带下载器的FPGA最小系统模块。

    大家会惊叹,在如此小的模块里面竟然集成了下载器!集成了下载器竟然还能进行UART的通信,用同一个USB端口。

    是的,这是我们工程师花了很久的时间开发的STEPLINK的功能:

    可以用任何操作系统的电脑(Mac电脑、树莓派等)对其进行配置,只需要像复制文件到U盘中一样就完成了对FPGA的编程;

    可以通过USB端口进行UART的数据传输,多数开发板都是要附加一个USB端口,用另外一个PC的USB端口 + 另外一根线,非常麻烦

    既然它是基于Lattice XO2系列的FPGA,那它的开发环境就可和Lattice版本的小脚丫一样了,是的 - 用Diamond IDE来进行开发,点击这个链接,你就知道该如何下载Diamond、如何安装和配置Diamond,按照刚才链接中的文档,你可以一步步自学,把板上的灯点亮,当然是在你拿到板子以后。

     

    还有很多参考的例程你可以看一下,可以从小脚丫网站的首页看起。

     

    相关的视频资料以及参考案例,会持续整理发布在这个项目页面中,如大家有任何问题可以在技术交流群中讨论,也可以在本项目的“评论”区域留言。

     

     

    发货前的硬件功能测试 更新发布于 2021年01月05日

    为这次活动,加工了500套主板和500套核心模块,今天已经拿到手,做了简单测试:

    测试条目 测试内容 测试状态
    OLED显示屏   能否通过SPI逻辑让128*64分辨率的OLED显示屏正常工作 Ok - 能够正常显示字符并随按键的状态发生变化
    4个按键 FPGA的逻辑对4个按键的输入响应正常 OK - 能够通过按键调节OLED显示屏上的信息
    板上电压测试 通过核心模块上的LDO产生的3.3V、通过LM2776由3.3V产生的-3.3V、通过扩展板上的LDO产生的3.0V和1.5V的直流电压,用于给模拟电路的运算放大器提供偏置

    实测3.3V为3.28V、-3.3V为-3.21V(压降下降不大),能够满足板上电路的工作;3.0V为2.99V

    、1.5V为1.498V,工作正常(测量的相对偏差与所用万用表也有关系)。

    输出直流电压DC1    通过PWM输出平均值为1-3V的模拟电压,经RC组成的低通滤波器 + 3x放大以后在DC1输出-3V-+3V的可调直流电压 PWM的8位寄存器设置为“78”(78/255*3.3 = 1V),DC1输出为3.02V,设置为“232”(232/255*3.3 = 3V),DC1输出为-2.98V,设置为中间值“155”(155/255*3.3=2V),DC1的输出为0.003V
    输出直流电压DC2 通过PWM输出平均值为1-3V的模拟电压,经RC组成的低通滤波器 + 3x放大以后在DC2输出-3V-+3V的可调直流电压 PWM的8位寄存器设置为“78”(78/255*3.3 = 1V),DC2输出为2.99V,设置为“232”(232/255*3.3 = 3V),DC2输出为-2.93V,设置为中间值“155”(155/255*3.3=2V),DC2的输出为-0.006V
    DDS任意波形发生器产生正弦波信号

    测试DDS AWG的输出信号是否满足要求

    设置FPGA内部时钟为192MHz,生成100KHz的正弦波信号,频率控制字为0x002222,输出100KHz的正弦波信号
    Sigma Delta ADC数据采集 调用Sigma Delta的逻辑采集口袋仪器M2k的模拟信号,再通过DDS输出,用M2K测试 1KHz的正弦波信号,可以完美采样并输出,采样率能够达到20Ksps(FPGA的内部时钟运行在192MHz的情况下)

    同样的控制寄存器DC1和DC2的的输出是存在一定偏差的,原因就是我们使用的电阻都是5%精度的,因此两个通道的电阻的不同就会导致输出结果的差异,在本测试中(3.02-2.99)/3 ~ 1%,合理。

    在本案例中我们采用了8位的调节分辨率,调节精度为3.3V/255 * 3 = 0.038V,如果采用10位的调节分辨率产生PWM输出,则调节精度可以为3.3V/1023 * 3 = 0.01V,直流输出采用的RC截至频率可以很低,在这个设计中R = 3K,C =1uF, 截至频率为50Hz,因此多用两个寄存器可以实现更高精度的调节是值得的,大家可以尝试一下。

    FizoTvu6-9wz3deJCHDCvYiA_lCP

    FrsJz1tw1V3t8jaGAn2APVDOHZ3K

     

    测试程序已经放到附件中 - 文件名为FPGA16_Instru_impl1.jed

    自此,本板卡上的所有硬件功能都已经测试完毕且良好。

    期待大家能够在这个板子上实现更多、更好的功能。

     

    在小脚丫FPGA上实现频率计和计数器的功能 更新发布于 2021年01月14日

    FtdZfbbL5my9jjGWuoPZx-_dQ2ccFtji6Y1qx4Gi1uIcdlOfS4p-Ycpy

    直播课程安排 更新发布于 2021年01月15日

    日期

    内容 直播视频链接 课前准备
    2021年1月20日下午2-3点

    FPGA是什么?能做啥?怎么用?以及项目需求介绍

    FPGA是什么?能做什么?怎么用?以及寒假项目的具体要求
    阅读本项目页面中的一些信息
    2021年1月21日下午2-3点

    Lattice FPGA XO2-1200HC核心模块的特点、应用以及设计流程

    Lattice FPGA XO2-1200HC核心模块的特点、应用以及设计流程 安装Diamond,并观看短视频课程,尝试自己设计一个文件,走一遍流程
    2021年1月27日下午2-3点 口袋仪器的FPGA实现以及相关参考资源  

    学习一下测试测量仪器相关的短视频、PWM的应用及实现方式的视频课程

    时间待定

    直播答疑1    

    时间待定

    直播答疑2    

     

    除上面的直播课程之外,我们还会陆续推出30个与我们正在做的项目相关的专题文章或短视频。

    数字IO - 单根

    状态监测 - 开关/传感器, 消抖

     

    输出状态控制 - 开/关,上下拉、驱动

     

    编码信息的携带 - 信号产生、PWM、温度传感器

     

    PWM的原理、应用及实现

    数字IO - 多根

    串行总线 vs 并行总线

     

    SPI的特点、应用及实现

     

    I2C的特点、应用及实现

     

    UART的特点、应用及实现

    IO扩展使用

    矩阵键盘

     

    点阵显示、点阵LED的连接和驱动

     

    OLED屏的应用和驱动

    数据转换

    ADC/DAC的应用及关键技术指标

     

    高速ADC的选用

     

    串行ADC的实现

     

    高速DAC及R-2R的工作原理

     

    串行DAC的实现

     

    DDS的实现机制及注意要点

     

    信号发生器中DAC的选用

     

    示波器中的ADC的实现及数据处理

    系统设计

    示波器的功能、使用和设计要点

     

    信号发生器的功能、使用和设计要点

     

    万用表的功能、使用和设计要点

     

    电压源的功能、使用和设计要点

     

    模式发生器的功能、使用和设计要点

     

    逻辑分析仪的功能、使用和设计要点

     

    频率计的实现

     

    模拟链路的构成及关键技术指标

     

    模拟器件的选用及主要的供应商

     

    模拟电路的仿真工具LTSpice的使用

     

    PC端测试、调试工具的使用

    直播 - FPGA是什么?能做什么?怎么用?以及寒假项目的具体要求 更新发布于 2021年01月20日

    针对三个与FPGA相关的项目平台做了一次直播(直播链接):

    作为“寒假在家一起练”两个FPGA项目的第一场直播,简单介绍一下FPGA的基本知识、FPGA的应用、FPGA的设计流程以及FPGA相关的设计资源,并介绍寒假在家一起练的两个与FPGA相关的项目的基本要求。

    • FPGA是什么?

    • FPGA内部的主要资源介绍

    • FPGA与MCU的区别

    • FPGA的典型应用领域

    • FPGA的设计流程

    • FPGA的选型要点

    • FPGA在电赛中的应用

    • 用好FPGA的要点

    • 学用FPGA相关的资源

    • 本次活动两个项目的要求以及涉及到的技术要点

     

    并安排下次直播前需要观看、准备的资料和视频。

    直播 - 演示如何编写FPGA逻辑进行点灯? 更新发布于 2021年01月21日

    直播内容

    同学们使用中遇到的几个问题:

    • Diamond安装中证书的申请、正确放置到目录中
    • 数据线 - 有些充电宝带的线不具备数据传输功能

    授课内容

    FPGA的设计流程介绍

    FuLN1c_ezyAO-Q-OnlnWKn3fQ8kb

    项目示例:点灯

    • LED点灯的工作原理
      • 前向电压Vbias,每种LED电压值不同
      • 流过的电流影响亮度,调节电流可以改变亮度
        • 改变电阻值 I = (3.3V-Vbias)/R1
        • 电阻不变,调节平均电流

    FsBkGr8uUurE7ilwKRWGoM3Itn2m

    • 项目1 - 点亮LED:
      1. 创建项目 - LED
      2. 创建Verilog代码 module(led),体会Verilog的语法结构;
        module LED (led); 
        output led;
        
          assign led = 1'b0; 
        endmodule​
      3. 编译
      4. 分配管脚(查找管脚映射表,通过电路图或项目中的表格)
      5. 生成jed文件
      6. 查看资源占用情况
      7. 下载到16管脚的FPGA模块上
    • 项目2 - 心跳灯
      1. 在module的端口中添加clk的输入信号
      2. 在verilog逻辑中通过计数分频产生12M/223 (1.5Hz) 的周期信号,体会wire、reg的区别以及计数分频的实现方法
        module LED (clk_in,led);
        input clk_in;
        output led;
        
        reg [23:0] counter;
        
        always @(posedge clk_in) counter = counter + 1'b1; 
        
        assign led = counter[23];                                       
        
        endmodule​
      3. 编译
      4. 分配管脚中补充新的clk管脚
      5. 生成jed文件
      6. 查看资源占用情况
      7. 下载到16管脚的FPGA模块上
    • 项目3 - 精确到1Hz的心跳灯
      1. 修改Verilog逻辑,能够产生精准的1Hz的周期信号,体会偶数分频乃至奇数分频的实现方法
        module LED (clk_in,led);
        input clk_in;
        output led;
        
        parameter T1S = 12_000_000;
        parameter T05S = T1S/2;
        
        reg [23:0] counter;
        
        always @(posedge clk_in) begin
         if(counter < T1S-1) counter <= counter + 1'b1; 
         else counter <= 1'b0; 
        end
        
        assign led = (counter < T05S);
        
        endmodule​
      2. 生成jed文件
      3. 查看资源占用情况
      4. 下载到16管脚的fpga模块上,对比结果
    • 项目4 - 50Hz的心跳灯
      1. 修改verilog逻辑,产生50Hz的周期信号
      2. 生成jed文件
      3. 下载到16管脚的fpga模块上,LED亮度变化,视觉暂留的效果,可以通过调节占空比控制LED的亮度(PWM),亮度与占空比(平均电流)非线性

    FtiF6Jr1I-l7x-xO3kAacACd3LoX

    单色的LED - 通过调节驱动信号的占空比调节LED的亮度

     

    FtZcYzNOEa9Ucj78qY5RQ-qVnG_-

    三色的LED - 通过调节每种颜色的LED的亮度实现不同的颜色组合

    • 项目5 - 体验内部锁相环的使用以及内部IP Core的调用方式
      1. 添加PLL的IP
      2. 修改Verilog逻辑,通过PLL输出的时钟,产生1Hz的周期信号
      3. 生成jed文件
      4. 查看资源占用情况
      5. 下载到16管脚的fpga模块上

     

    参考代码 - DDS信号发生器、可编程电压、串行ADC 更新发布于 2021年03月08日

    在这个平台上主要用到PWM来完成所有的功能,因为PWM + 由电阻、电容构成的低通滤波器(LPF)能够实现DAC的功能,也就是可以将变化的数字信息转换为变化的模拟信号:

    1. 在任意波形发生器中,可以通过PWM+LPF将DDS生成的任意波形信号(数字)转换为模拟信号,模拟波形的频率和幅度都可以通过数字的方式进行调节生成;
    2. 在实现可编程直流电压输出时,可以通过PWM的占空比 + LPF得到直流电压,其实直流电压本质上也是任意波形的一种;
    3. ADC的实现实质上是在某一时刻将输入的模拟信号跟某一个特定值的电压进行比较,通过其处的电压区间来确定该输入信号在该时刻的电压值,被用来做比较的电压可以由PWM来生成;
    4. 频率计/计数器中,外部输入的被测信号其幅度的变化范围比较宽,需要通过高速的比较器对其进行整形,生成0、1高低电平,而比较器的另一个输入端为可变的直流电压,以适应不同幅度和直流偏移的输入信号,该可变的直流电压就可以通过PWM来产生

    PWM的产生请参见文章:PWM的应用及相应的Verilog代码,由该文章得知,通过Sigma Delta的方式产生的PWM具有较好的频率特性,比较容易通过简单的低通滤波器滤除掉高频的脉冲信号,尤其是占空比约接近50%,输出信号其直流分量将约远离PWM的高频脉冲。 因此在实际的使用中,我们一般避免将占空比用到0%或100%,比如可以从10% - 90%之间变化,经过低通滤波器平滑输出后的直流在3.3*10% ~ 3.3 * 90% - 0.33V - 2.97V

    在生成PWM的波形的时候要充分理解PWM的时序关系,见下图:

    PWM的时序关系

    t为生成PWM信号的主时钟,通过对这个高频时钟计数,得到一个周期T内电平进行0、1反转的脉宽不同的信号。一个T内有多少个t,也就决定了PWM的分辨率,转换到模拟信号的时候也就对应于DAC的位数。根据最高频率/分辨率,也就可以推算出T的最小值。

    比如采用12MHz(t=83ns)的时钟作为PWM的主时钟,如果要生成8位精度的DAC,对应的一个PWM周期T ~ 12MHz/256 = 21μs,最高的频率为47KHz 如果通过FPGA内部PLL产生高倍频的时钟,比如12M * 16 ~ 192MHz,生成8位精度的DAC,其最高频率可以达到47KHz * 16 同样192MHz的主时钟来产生12位精度的DAC,则能够生成PWM信号的频率为47KHz。

    OLED显示及按键控制

    本平台采用了128*64分辨率的OLED显示屏,并有4个按键进行参数的设置或菜单的控制,这些按键的功能可以根据自己的需要进行定制。

    下面的代码完成了OLED显示屏的驱动,并在屏幕上显示一些与口袋仪器相关的参数,4个按键的扫描控制功能也一并包含在内。

    // --------------------------------------------------------------------
    // >>>>>>>>>>>>>>>>>>>>>>>>> COPYRIGHT NOTICE <<<<<<<<<<<<<<<<<<<<<<<<<
    // --------------------------------------------------------------------
    // Module: OLED12832
    // 
    // Author: Step
    // 
    // Description: OLED12832_Driver
    // 
    // Web: www.stepfpga.com
    // 
    // --------------------------------------------------------------------
    // Code Revision History :
    // --------------------------------------------------------------------
    // Version: |Mod. Date:   |Changes Made:
    // V1.0     |2015/11/11   |Initial ver
    // --------------------------------------------------------------------
    module OLED12832
    (
    	input clk,	//
    	input rst_n,	//	
    	input [3:0]  sw,// 4 push buttons as control input
    	input [7:0]  freq_100, 
    	input [7:0]  freq_10, 
    	input [7:0]  freq_1,
    	input [7:0]  dc1_10,
    	input [7:0]  dc1_1,
    	input [7:0]  dc1_01,
    	input [7:0]  dc2_10,
    	input [7:0]  dc2_1,
    	input [7:0]  dc2_01,
     
    	output	reg oled_csn,	//
    	output	reg oled_rst,	//
    	output	reg oled_dcn,	//
    	output	reg oled_clk,	//
    	output	reg oled_dat
    );
     
    	localparam INIT_DEPTH = 16'd28; //
    	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 [27:0];
    	reg [39:0] mem [122:0];
    	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;
     
    	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;
    		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'd16) cnt_main <= 5'd9;
    						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 <= "----------------";state <= SCAN; end
    							5'd2:	begin y_p <= 8'hb1; x_ph <= 8'h10; x_pl <= 8'h00; num <= 5'd16; char <= " FPGA Training  ";state <= SCAN; end
    							5'd3:	begin y_p <= 8'hb2; x_ph <= 8'h10; x_pl <= 8'h00; num <= 5'd16; char <= " www.eetree.cn  ";state <= SCAN; end
    							5'd4:	begin y_p <= 8'hb3; x_ph <= 8'h10; x_pl <= 8'h00; num <= 5'd16; char <= "----------------";state <= SCAN; end
    							5'd5:	begin y_p <= 8'hb4; x_ph <= 8'h10; x_pl <= 8'h00; num <= 5'd16; char <= "                 ";state <= SCAN; end
    							5'd6:	begin y_p <= 8'hb5; x_ph <= 8'h10; x_pl <= 8'h00; num <= 5'd16; char <= "                 ";state <= SCAN; end
    							5'd7:	begin y_p <= 8'hb6; x_ph <= 8'h10; x_pl <= 8'h00; num <= 5'd16; char <= "                 ";state <= SCAN; end
                                                            5'd8:	begin y_p <= 8'hb7; x_ph <= 8'h10; x_pl <= 8'h00; num <= 5'd16; char <= "                ";state <= SCAN; end
    							5'd9:	begin y_p <= 8'hb4; x_ph <= 8'h10; x_pl <= 8'h00; num <= 5'd13; char <= {"I-->W,DC-1KHz"} ;state <= SCAN; end
    							5'd10:	begin y_p <= 8'hb5; x_ph <= 8'h10; x_pl <= 8'h00; num <= 5'd10; char <= {"DC1: +3.0V"}   ;state <= SCAN; end
    							5'd11:	begin y_p <= 8'hb6; x_ph <= 8'h10; x_pl <= 8'h00; num <= 5'd10; char <= {"DC2: -3.0V"}   ;state <= SCAN; end
                                                            5'd12:	begin y_p <= 8'hb7; x_ph <= 8'h10; x_pl <= 8'h00; num <= 5'd12; char <= {"Have Fun! :)" };state <= SCAN; end
    							5'd13:	begin y_p <= 8'hb4; x_ph <= 8'h17; x_pl <= 8'h08; num <= 5'd 1; char <= sw; state <= SCAN; end
    							5'd14:	begin y_p <= 8'hb5; x_ph <= 8'h17; x_pl <= 8'h08; num <= 5'd 1; char <= sw; state <= SCAN; end
    							5'd15:	begin y_p <= 8'hb6; x_ph <= 8'h17; x_pl <= 8'h08; num <= 5'd 1; char <= sw; state <= SCAN; end
    							5'd16:	begin y_p <= 8'hb7; x_ph <= 8'h17; x_pl <= 8'h08; num <= 5'd 1; char <= sw; 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	//
    							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	//
    							5'd4:	begin 
    										if(cnt>=INIT_DEPTH) begin	//
    											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	//
    							default: state <= IDLE;
    						endcase
    					end
    				SCAN:begin	//
    						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'd 5:	begin oled_dcn <= DATA; char_reg <= 8'h00; state <= WRITE; state_back <= SCAN; end	//
    							5'd 6:	begin oled_dcn <= DATA; char_reg <= 8'h00; state <= WRITE; state_back <= SCAN; end	//
    							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	//
    						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	//
    							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
     
    	//
    	always@(negedge rst_n)
     
    		begin
    			cmd[ 0] = {8'hae}; 
    			cmd[ 1] = {8'h00}; 
    			cmd[ 2] = {8'h10}; 
    			cmd[ 3] = {8'h40}; 
    			cmd[ 4] = {8'h81}; 
    			cmd[ 5] = {8'hcf}; 
    			cmd[ 6] = {8'ha1}; 
    			cmd[ 7] = {8'hc8}; 
    			cmd[ 8] = {8'ha6}; 
    			cmd[ 9] = {8'ha8}; 
    			cmd[10] = {8'h3f}; 
    			cmd[11] = {8'hd3};
    			cmd[12] = {8'h00};
    			cmd[13] = {8'hd5};
    			cmd[14] = {8'h80};
    			cmd[15] = {8'hd9};
    			cmd[16] = {8'hf1};
    			cmd[17] = {8'hda};
    			cmd[18] = {8'h12};
    			cmd[19] = {8'hdb};
    			cmd[20] = {8'h40};
    			cmd[21] = {8'h20};
    			cmd[22] = {8'h02};
                cmd[23] = {8'h8d};
    			cmd[24] = {8'h14};
                cmd[25] = {8'ha4};
                cmd[26] = {8'ha6};
    			cmd[27] = {8'haf};
    		end
     
    	always@(negedge rst_n)
    	//initial
    		begin
    			mem[  0] = {8'h3E, 8'h51, 8'h49, 8'h45, 8'h3E};   // 48  0
    			mem[  1] = {8'h00, 8'h42, 8'h7F, 8'h40, 8'h00};   // 49  1
    			mem[  2] = {8'h42, 8'h61, 8'h51, 8'h49, 8'h46};   // 50  2
    			mem[  3] = {8'h21, 8'h41, 8'h45, 8'h4B, 8'h31};   // 51  3
    			mem[  4] = {8'h18, 8'h14, 8'h12, 8'h7F, 8'h10};   // 52  4
    			mem[  5] = {8'h27, 8'h45, 8'h45, 8'h45, 8'h39};   // 53  5
    			mem[  6] = {8'h3C, 8'h4A, 8'h49, 8'h49, 8'h30};   // 54  6
    			mem[  7] = {8'h01, 8'h71, 8'h09, 8'h05, 8'h03};   // 55  7
    			mem[  8] = {8'h36, 8'h49, 8'h49, 8'h49, 8'h36};   // 56  8
    			mem[  9] = {8'h06, 8'h49, 8'h49, 8'h29, 8'h1E};   // 57  9
    			mem[ 10] = {8'h7C, 8'h12, 8'h11, 8'h12, 8'h7C};   // 65  A
    			mem[ 11] = {8'h7F, 8'h49, 8'h49, 8'h49, 8'h36};   // 66  B
    			mem[ 12] = {8'h3E, 8'h41, 8'h41, 8'h41, 8'h22};   // 67  C
    			mem[ 13] = {8'h7F, 8'h41, 8'h41, 8'h22, 8'h1C};   // 68  D
    			mem[ 14] = {8'h7F, 8'h49, 8'h49, 8'h49, 8'h41};   // 69  E
    			mem[ 15] = {8'h7F, 8'h09, 8'h09, 8'h09, 8'h01};   // 70  F
     
    			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
    通过DDS+PWM产生任意波形
    DDS得到任意波形

    相位累加器代码:

    wire   	[23:0] 	next_phase;
    wire   	[7:0] 	phase;
    reg    	[23:0] 	accumulator;
     
    assign next_phase = 24'H002222 + accumulator;   // set frequency = 24'H002222 / 2^24 * clock, if PLL not used, clock = 12MHz, output frequency = 6.25KHz
     
    always @(posedge clk_hs) accumulator <= #1 next_phase;
     
    assign phase = accumulator[23:16];   	// phase is the high 8 bits as address of the look up table
     
    wire [9:0] sine_data;                   // sine table is 8 bit wide, 10bit resolution.
     
    lookup_tables u_lookup_tables(phase, sine_data);
    查找表代码:
    module lookup_tables(phase, sin_out);
    input  	[7:0] 	phase;    //sine table is 8bits wide, 10 bits resolution
    output 	[9:0] 	sin_out;
     
    wire     [9:0]   sin_out;
     
    reg   	[5:0] 	address;
    wire   	[1:0] 	sel;
    wire   	[8:0] 	sine_table_out;
     
    reg     [9:0]   sine_onecycle_amp;
     
    //assign sin_out = {1'b0, sine_onecycle_amp[9:1]} + 9'hff;
    assign sin_out = sine_onecycle_amp[9:0];
     
    	assign sel = phase[7:6];
     
       	sin_table u_sin_table(address,sine_table_out);
     
    always @(sel or sine_table_out or phase)
    begin
    	case(sel)
    	2'b00: 	begin
    			sine_onecycle_amp = 9'h1ff + sine_table_out[8:0];
    			address = phase[5:0];
    	     	end
      	2'b01: 	begin
    			sine_onecycle_amp = 9'h1ff + sine_table_out[8:0];
    			address = ~phase[5:0];
    	     	end
      	2'b10: 	begin
    			sine_onecycle_amp = 9'h1ff - sine_table_out[8:0];
    			address = phase[5:0];
         		end
      	2'b11: 	begin
    			sine_onecycle_amp = 9'h1ff - sine_table_out[8:0];
    			address = ~ phase[5:0];
         		end
    	endcase
    end
     
    endmodule
     
    module sin_table(address,sin);
    output [8:0] sin;
    input  [5:0] address;
     
    reg    [8:0] sin;
     
    always @(address)
    	begin
                      case(address)	
                          6'h0: sin=9'h0;
                          6'h1: sin=9'hC;
                          6'h2: sin=9'h19;
                          6'h3: sin=9'h25;
                          6'h4: sin=9'h32;
                          6'h5: sin=9'h3E;
                          6'h6: sin=9'h4B;
                          6'h7: sin=9'h57;
                          6'h8: sin=9'h63;
                          6'h9: sin=9'h70;
                          6'ha: sin=9'h7C;
                          6'hb: sin=9'h88;
                          6'hc: sin=9'h94;
                          6'hd: sin=9'hA0;
                          6'he: sin=9'hAC;
                          6'hf: sin=9'hB8;
                          6'h10: sin=9'hC3;
                          6'h11: sin=9'hCF;
                          6'h12: sin=9'hDA;
                          6'h13: sin=9'hE6;
                          6'h14: sin=9'hF1;
                          6'h15: sin=9'hFC;
                          6'h16: sin=9'h107;
                          6'h17: sin=9'h111;
                          6'h18: sin=9'h11C;
                          6'h19: sin=9'h126;
                          6'h1a: sin=9'h130;
                          6'h1b: sin=9'h13A;
                          6'h1c: sin=9'h144;
                          6'h1d: sin=9'h14E;
                          6'h1e: sin=9'h157;
                          6'h1f: sin=9'h161;
                          6'h20: sin=9'h16A;
                          6'h21: sin=9'h172;
                          6'h22: sin=9'h17B;
                          6'h23: sin=9'h183;
                          6'h24: sin=9'h18B;
                          6'h25: sin=9'h193;
                          6'h26: sin=9'h19B;
                          6'h27: sin=9'h1A2;
                          6'h28: sin=9'h1A9;
                          6'h29: sin=9'h1B0;
                          6'h2a: sin=9'h1B7;
                          6'h2b: sin=9'h1BD;
                          6'h2c: sin=9'h1C3;
                          6'h2d: sin=9'h1C9;
                          6'h2e: sin=9'h1CE;
                          6'h2f: sin=9'h1D4;
                          6'h30: sin=9'h1D9;
                          6'h31: sin=9'h1DD;
                          6'h32: sin=9'h1E2;
                          6'h33: sin=9'h1E6;
                          6'h34: sin=9'h1E9;
                          6'h35: sin=9'h1ED;
                          6'h36: sin=9'h1F0;
                          6'h37: sin=9'h1F3;
                          6'h38: sin=9'h1F6;
                          6'h39: sin=9'h1F8;
                          6'h3a: sin=9'h1FA;
                          6'h3b: sin=9'h1FC;
                          6'h3c: sin=9'h1FD;
                          6'h3d: sin=9'h1FE;
                          6'h3e: sin=9'h1FF;
                          6'h3f: sin=9'h1FF;
                       endcase
                  end
    endmodule
    调用DDS结果通过PWM生成需要的波形
    //Generate AWG using 10bit resolution PWM + external RC LPF as DAC, up to 100KHz
    wire [9:0] PWM_WAV_in;
    assign PWM_WAV_in = sine_data[9:0];
     
    reg [10:0] PWM_WAV_accumulator;
    always @(posedge clk_hs) PWM_WAV_accumulator <= PWM_WAV_accumulator[9:0] + PWM_WAV_in;
    assign pwm_awg = PWM_WAV_accumulator[10];

     

    通过PWM产生可调直流电压

    通过PWM产生可变直流电压的模拟电路原理图

    // Generate adjustable DC voltage using PWM for 2 channels, from 0.5V to 3.0V
    wire [7:0] PWM_DC1_in, PWM_DC2_in;
    assign PWM_DC1_in = 8'd78;   //Generate 1.0V at PWM output, 3V after amplifier 
    assign PWM_DC2_in = 8'd234;  //Generate 3.0V at PWM output, -3V after amplifier
    
    reg [8:0] PWM_DC1_accumulator;
    always @(posedge clk_hs) PWM_DC1_accumulator <= PWM_DC1_accumulator[7:0] + PWM_DC1_in;
    assign dc1_pwm = PWM_DC1_accumulator[8];
    
    reg [8:0] PWM_DC2_accumulator;
    always @(posedge clk_hs) PWM_DC2_accumulator <= PWM_DC2_accumulator[7:0] + PWM_DC2_in;
    assign dc2_pwm = PWM_DC2_accumulator[8];
    
    通过PWM和高速比较器实现低速串行ADC的功能

    Sigma Delta实现ADC的模拟电路原理图

    通过高速比较器实现频率计的功能

    参见全国大学生电子设计竞赛中的数字频率计的实现

     

    硬禾电赛训练营:屡次斩获电赛国奖的中央民族大学教师团队为你揭秘备赛的秘诀(精剪版)

    专栏 硬禾电赛训练营:屡次斩获电赛国奖的中央民族大学教师团队为你揭秘备赛的秘诀(精剪版) 手机观看 中央民族大学信息工程学院教授王继业老师将从模拟电路设计、数字电路设计(FPGA设计)、单片机原理以及电赛赛题分析等多方面、多维度带领大家进行针对性训练。 已更新12期 立即学习 详情目录 未命名333.png 对于电子类专业的学生来讲,每两年一度的全国大学生电子设计大赛是当前高校提升学生综合技能的最佳途径,因此每个学生在大学四年都应该参加、体验一下。 但面对学科技能如此综合、全面的赛事,如何有效地准备并获得较好的成绩,也是众多高校师生面临的挑战,尤其是参赛历史比较短的高校,师生们无论从经验还是资源储备上都处于劣势。 为满足众多高校师生的要求,我们硬禾学堂邀请了全国各大赛区知名的指导老师来通过直播的方式给大家分享一下他们的经验和心得,同时我们也邀请中央民族大学信息工程学院教授王继业老师及其教师团队为大家开设电赛加油站栏目,将从模拟电路设计、FPGA、单片机原理以及电赛赛题分析等多方面、多维度解惑电赛,为你电赛加油。 单片机的内容都是针对大二没有学过单片机和微机原理的同学讲的。我们假设学生只学过模拟电路、数字电路和c语言课。这也是大量参加电子竞赛的学生的实际情况。如果你单片机很熟悉,可以忽略这些内容。 我们首先给大家一个最简版本的微机原理和接口技术,因为你没有一个单片机的模型在脑子里,后面的东西就没法接受。然后介绍单片机中非常重要的时钟、复位、定时器、AD转换等。 这里选择MSP430是因为TI公司是电子竞赛赞助商,而且MSP430单片机也很优秀,容易学,官方的开发板便宜。推荐使用MSP-EXP430G2ET LaunchPad作为开发板,电子竞赛时可以自制一个引脚更多的核心板,完全满足竞赛的要求。开发环境既可以用TI的CCS,也可以用IAR。讲授中的实例用的是IAR,大家也可以预先装好软件。 主讲老师:王继业教授, 现任中央民族大学教授,北京大学物理系本科、南开大学物理系光学专业硕士,主要从事光学中的混沌和人体心脏的混沌研究。1995年毕业后进入北大青鸟公司工作,从事过分析仪器、电子技术、计算机等许多方面的开发工作,后任公司总工程师。2001年10月调入中央民族大学物理与电子工程系任教至今, 主讲《数学物理方法》《C编程语言》、《Linux操作系统应用与编程》、《电子技术》、《单片机原理与应用》、《高等可编程逻辑设计》、《嵌入式系统原理与应用》等课程。 自2007年起到去年一直任中央民大电子信息工程系主任,把电子系的教学、竞赛水平带上了一个新台阶,并亲自带领电赛队伍获得了多个全国电赛一等奖。

    苏老师带你玩转“基于DDS的信号源”设计(精剪版)

    硬禾学堂精心定制的训练板,详解任意信号(波形)发生器信号源的作用、构成、制作的过程,并通过实际的项目制作流程详解信号源每一部分的设计要点。

    用FPGA来学习数字电路原理与设计(精剪版)

    本课程面向电子专业的低年级学生、电子爱好者和硬件工程师。在这个课程中,将带领大家掌握数字电路方面的基本理论、基本知识和基本技能,培养和训练出能独立的应用所学知识去分析和解决数字电路的实际问题的能力。

    小脚丫FPGA及其开发环境上手课程

    这个专栏汇集了硬禾学堂上关于FPGA基本概念、小脚丫FPGA开发板开发环境(分别有Lattice版本/Intel(Altera)版本)的介绍内容,浅显易懂,方便同学们快速上手。

    示波器基础知识小课堂

    示波器(Oscilloscope)作为电子工程师和电子爱好者工具箱中用途最大的一个工具,主要用途就是将随时间变化的电信号以图形的方式画出来,所以也被称为工程师的眼睛。 为了帮助大家更好地认识和使用这双重要的“眼睛”,从今天开始,硬禾学堂将推出一系列的示波器知识视频课程。我们请来了RS公司DesignSpark团队的大林子老师为大家开设十讲《示波器基础知识小课堂》。每一讲都用5分钟左右的时间,为大家介绍一个关键的知识点。

    “三分钟学会”用FPGA玩转PWM系列

    PWM,脉宽调制,可以算是数字电路中的“独臂”神通——只需一根线,就在很多关键的应用中起到栋梁的作用。比如当今几乎所有的LED照明、LED背光、乃至装饰都是通过PWM控制来实现;在多种领域被广泛使用的伺服电机,则可以通过PWM实现其旋转定位以及速度控制。在这个“三分钟学会”系列课程里,具备十多年FPGA开发经验的吴志军老师,将会带你用FPGA玩转PWM。

    国内龙头FPGA芯片公司教你学FPGA设计(精剪版)

    本课程面向电子专业的学生和硬件工程师。国内龙头FPGA芯片公司安路信息科技的核心工程师,将利用8天的时间,带领大家学习FPGA设计。

    Lattice行业专家带你认识FPGA及其专业应用

    全球著名的FPGA厂商Lattice Semiconductor的资深应用工程师介绍什么是FPGA、FPGA的应用,尤其是在专业领域的典型应用。

    华为工程师带你规范做FPGA实例系列

    FPGA开发入门并不难,但是怎么做得规范、清晰、可维护,让合作伙伴或者两年后的自己能够高效准确地理解一个设计?我们请来了前华为FPGA开发资深工程师陈波,在这个系列课程里,从简单到复杂,用多个有趣的工程实例来给大家介绍在做FPGA项目的过程中,该遵循怎样的开发规范,怎样去整理和优化项目整体的系统设计思路,以及如何写出更加高效的FPGA综合实现方法。

    FPGA是什么?能做什么?怎么用?以及寒假项目的具体要求

    1月20日下午2-3:30PM,通过直播介绍FPGA是什么?能做什么?怎么用?以及寒假在家一起练的两个与FPGA相关的项目的具体要求以及后期的安排。

    全国大学生电子设计竞赛中与电子仪器仪表设计相关的题目及理论基础

    汇总了全国大学生电子设计竞赛历年来与测试测量相关的题目以及相关的理论基础

    用单片机ATtiny84来测量频率/周期/电压

    转自www.technoblogy.com的一篇文章,原文名字:Frequency Probe,对于本项目中的测量频率/周期以及电压有借鉴作用,FPGA能达到更高的性能。

    基于16管脚的FPGA学习套件功能演示

    基于16管脚FPGA最小系统的简易口袋仪器DIY套件,实现可调电压源、信号发生器、电压表/示波器 、频率计的功能。

    使用示波器测量正弦信号幅值和相位误差仿真

    对测量出的幅值和相位结果中的误差随着示波器的时基( time base )不同而改变的原因

    近乎完美的DDS正弦波信号音生成器

    在测试和验证分辨率高于16位的高精度快速模数转换器(ADC)的交流性能时,需要用到近乎完美的正弦波生成器,该生成器至少支持0kHz至20kHz音频带宽。

    寒假在家练项目3_杜彩卉

    本项目是基于FPGAXo21200HC的训练板,制作了一个可以用作可调电压源、频率计、电压表、示波器和任意波形发生器的口袋仪器

    数字频率计设计

    以全国大学生电子设计竞赛2015年的F题为例,提供了使用FPGA完成频率计的设计参考,包括FPGA逻辑实现、按键输入、OLED信息显示。

    FPGA的应用 - 开源项目参考

    汇总了与FPGA相关的开源项目 - 来源于小脚丫FPGA、OpenCores、FPGA4FUN、FPGA4Students、IcoBoard等。

    用两根FPGA管脚+比较器做成的ADC

    本文介绍了如何使用FPGA的两根数字IO + 模拟比较器 + FPGA内部数字逻辑实现Sigma Delta ADC的功能。

    滤波器曲线及基本参数

    汇总整理了滤波器的一些基本参数以及相应的曲线表示

    使用数字示波器DS6104测量交流信号的幅值和相位

    使用普通的万用表测量交流信号的时候,通常会遇到 万用表的频率响应[1] 的问题。使用可以联网的示波器可以获得它采集到的数据,进而可以计算出所测量的交流信号的有效值和相位。

    用作简易口袋仪器的DIY套件

    搭配16管脚的FPGA最小系统模块,支持数控电压源、信号发生器、示波器、频率计等功能,并有输出显示和输入控制的功能。

    ¥169.00
    支持一下

    16管脚的FPGA最小系统模块

    基于Lattice的XO2-1200HC FPGA,14根数字IO、板载下载器并支持串口通信,可以插座连接或邮票孔焊接

    ¥99.00
    支持一下

    团队介绍

    • 苏州硬禾信息科技有限公司 - 硬禾工程师团队专注于基于FPGA和嵌入式系统学习平台的开发和生态系统的建设,在过去5年里成功推出的小脚丫FPGA学习平台被全国上百所高校采用于数字电路教学实践中,并一直积极推动开源、免费PCB设计工具KiCad在高校学生及硬件工程师中的应用。

    团队成员

    • 苏公雨

      与非网/硬禾学堂创始人,电子创客爱好者,15年硬件研发、设计背景。

    • 王安然

      资深硬件设计工程师、FPGA教学导师,12年硬件研发经验,主持开发了基于小脚丫FPGA的系列学习平台。

    • 吴志军

      苏州思得普科技有限公司创始人/总经理,负责小脚丫FPGA平台的研发及生态建设,20年硬件系统研发经验。

    • 陈强

      控制工程硕士,资深硬件研发工程师,丰富的嵌入式产品研发与技术支持经验,熟悉嵌入式系统编程、FPGA和数字系统设计。

    猜你喜欢

    寒假在家一起练(2021)- 完成任务即返款!

    寒假在家一起练(2021)- 完成任务即返款!

    硬禾学堂特别设计了5个同学们能够在家动手做、在网上和其他同学们一道学习的小项目,制作了物美、价廉的硬件学习套装,并设定了一些简单的规则,目的是让更多的同学们参与进来、学有成效。

    进度
    100%

    更新1次
    “简易示波器DIY套件V2.0 - 基于STM32G031最小系统模块”

    “简易示波器DIY套件V2.0 - 基于STM32G031最小系统模块”

    “简易示波器DIY套件V2.0 - 基于STM32G031最小系统模块”

    基于16管脚的FPGA学习套件功能演示

    基于16管脚的FPGA学习套件功能演示

    基于16管脚FPGA最小系统的简易口袋仪器DIY套件,实现可调电压源、信号发生器、电压表/示波器 、频率计的功能。

    @2019 电子森林   苏ICP备19040198号