前言

此文介绍uart串口串口接收-控制LED的verilog实现和testbench的编写,仿真环境为vivado 2018.3。


提示:以下是本篇文章正文内容,下面案例可供参考

一、实现原理


【设计思路】:
1.uart_cmd模块:将uart_byte_rx的输出rx_data和rx_done作为uart_cmd的输入,将led控制模块的输入作为uart_cmd的输出,将两个模块连接起来。

2.协议制定:ctrl[7:0]与Time[31:0]的值怎么取,使用串口接收模块可能得到多个数据,那么哪些数据是我们所需要的Ctrl和Time呢?于是制定如下协议:

0x55 0xA5 | Time[7:0] Time[15:8] Time[23:16] Time[31:14] Ctrl[7:0] | 0xF0

当检测到第一个字节为8’h55,第二个字节为8‘hA5,第八个字节为8’hF0时将接收到的3-6字节作为TIme值,7字节作为ctrl值,这样能实现对LED等闪烁的控制。

3.协议判断:当每接收到8个字节时如何通过代码判断是否符合上述协议?

reg [7:0] data_str [7:0];always@(posedge Clk)if(rx_done)begindata_str[7] <= #1 rx_data;data_str[6] <= #1 data_str[7];data_str[5] <= #1 data_str[6];data_str[4] <= #1 data_str[5];data_str[3] <= #1 data_str[4];data_str[2] <= #1 data_str[3];data_str[1] <= #1 data_str[2];data_str[0] <= #1 data_str[1];        endalways@(posedge Clk or negedge Reset_n)if(!Reset_n) beginctrl <= #1 0;time_set <= #1 0;end else if(r_rx_done)beginif((data_str[0] == 8'h55) && (data_str[1] == 8'hA5) && (data_str[7] == 8'hF0))begintime_set[7:0] <= #1 data_str[2];time_set[15:8] <= #1 data_str[3];time_set[23:16] <= #1 data_str[4];time_set[31:24] <= #1 data_str[5];ctrl <= #1 data_str[6];endend

使用8字节的reg用作存储接收到的data,每次循环右移。将接收到的data与设定好的协议作比较,取出Time和Ctrl。

二、顶层模块

module uart_rx_ctrl_led(Clk,Reset_n,Led,uart_rx
);input Clk;input Reset_n;output Led;input uart_rx;wire [7:0]ctrl;wire [31:0]time_set;wire [7:0]rx_data;wire rx_done;counter_led_4 counter_led(.Clk(Clk),.Reset_n(Reset_n),.Ctrl(ctrl),.Time(time_set),.Led(Led)); uart_cmd uart_cmd(.Clk(Clk),.Reset_n(Reset_n),.rx_data(rx_data),.rx_done(rx_done),.ctrl(ctrl),.time_set(time_set));uart_byte_rx uart_byte_rx(.Clk(Clk),.Reset_n(Reset_n),.Baud_Set(4),.uart_rx(uart_rx),.Data(rx_data),.Rx_Done(rx_done)  ); endmodule

顶层模块用于例化下面三个模块,进行连接。

三、uart_cmd模块

代码如下(示例):

`timescale 1ns/1nsmodule uart_cmd(Clk,Reset_n,rx_data,rx_done,ctrl,time_set
);input Clk;input Reset_n;input [7:0]rx_data;input rx_done;output reg[7:0]ctrl;output reg[31:0]time_set;reg [7:0] data_str [7:0];always@(posedge Clk)if(rx_done)begindata_str[7] <=  rx_data;data_str[6] <=  data_str[7];data_str[5] <=  data_str[6];data_str[4] <=  data_str[5];data_str[3] <=  data_str[4];data_str[2] <=  data_str[3];data_str[1] <=  data_str[2];data_str[0] <=  data_str[1];        endreg r_rx_done;   //延迟一个时钟周期,当rx_done检测为1时,并没有做到8个字节全赋值,所以可以使用延迟的方法always@(posedge Clk)r_rx_done <= rx_done;always@(posedge Clk or negedge Reset_n)if(!Reset_n) beginctrl <= #1 0;time_set <= #1 0;end else if(r_rx_done)beginif((data_str[0] == 8'h55) && (data_str[1] == 8'hA5) && (data_str[7] == 8'hF0))begintime_set[7:0] <= #1 data_str[2];time_set[15:8] <= #1 data_str[3];time_set[23:16] <= #1 data_str[4];time_set[31:24] <= #1 data_str[5];ctrl <= #1 data_str[6];endend    endmodule

将上述代码注释处删除后会出现:

时间延迟后,可以明显看出在时钟上升沿,rx_done=1时,还没有完全赋值。于是让rx_done晚一拍。

四、uart_byte_rx模块

代码如下(示例):

`timescale 1ns/1nsmodule uart_byte_rx(Clk,Reset_n,Baud_Set,uart_rx,Data,Rx_Done,
);input Clk;input Reset_n;input [2:0]Baud_Set;input uart_rx;output reg[7:0]Data; output reg Rx_Done;reg [1:0]uart_rx_r;always@(posedge Clk)beginuart_rx_r[0] <= #1 uart_rx;uart_rx_r[1] <= #1 uart_rx_r[0] ;endwire pedge_uart_rx;
//    assign pedge_uart_rx = ((uart_rx_r[1] == 0) && (uart_rx_r[0] == 1));assign pedge_uart_rx = (uart_rx_r == 2'b01);wire nedge_uart_rx;
//    assign nedge_uart_rx = ((uart_rx_r[1] == 1) && (uart_rx_r[0] == 0));  assign nedge_uart_rx = (uart_rx_r == 2'b10);  reg [8:0]  Bps_DR;always@(*)case(Baud_Set)0:Bps_DR = 1000000000/9600/16/20 - 1;1:Bps_DR = 1000000000/19200/16/20 - 1;2:Bps_DR = 1000000000/38400/16/20 - 1;3:Bps_DR = 1000000000/57600/16/20 - 1;4:Bps_DR = 1000000000/115200/16/20 - 1;default:Bps_DR = 1000000000/9600/16/20 - 1;endcasewire bps_clk_16x;assign bps_clk_16x = (div_cnt == Bps_DR / 2);reg RX_EN;always@(posedge Clk or negedge Reset_n)if(!Reset_n) RX_EN <=  0;else if(nedge_uart_rx)RX_EN <=  1;else if(Rx_Done || (sta_bit >= 4))RX_EN <= 0;reg [8:0]div_cnt;always@(posedge Clk or negedge Reset_n)if(!Reset_n)    div_cnt <=  0;else if(RX_EN)beginif(div_cnt == Bps_DR)div_cnt <=  0;elsediv_cnt <=  div_cnt + 1'b1;endelsediv_cnt <=  0;reg [7:0]bps_cnt;always@(posedge Clk or negedge Reset_n)if(!Reset_n) bps_cnt <=  0;else if(RX_EN)beginif(bps_clk_16x)beginif(bps_cnt == 159)bps_cnt <=  0;elsebps_cnt <=  bps_cnt + 1'b1;endelsebps_cnt <=  bps_cnt;endelsebps_cnt <=  0;//reg width name number/depthreg[2:0]r_data[7:0];reg [2:0]sta_bit;reg [2:0]sto_bit;always@(posedge Clk or negedge Reset_n)if(!Reset_n) beginsta_bit <=  0;sto_bit <=  0;r_data[0] <=  0;r_data[1] <=  0;r_data[2] <=  0;r_data[3] <=  0;r_data[4] <=  0;r_data[5] <=  0;r_data[6] <=  0;r_data[7] <=  0;endelse if(bps_clk_16x)begincase(bps_cnt)0:beginsta_bit <=  0;sto_bit <=  0;r_data[0] <=  0;r_data[1] <=  0;r_data[2] <=  0;r_data[3] <=  0;r_data[4] <=  0;r_data[5] <=  0;r_data[6] <=  0;r_data[7] <=  0;end5,6,7,8,9,10,11:sta_bit <= #1 sta_bit + uart_rx;21,22,23,24,25,26,27: r_data[0] <=  r_data[0] + uart_rx;37,38,39,40,41,42,43: r_data[1] <=  r_data[1] + uart_rx;53,54,55,56,57,58,59: r_data[2] <=  r_data[2] + uart_rx;69,70,71,72,73,74,75: r_data[3] <=  r_data[3] + uart_rx;85,86,87,88,89,90,91: r_data[4] <=  r_data[4] + uart_rx;101,102,103,104,105,106,107: r_data[5] <=  r_data[5] + uart_rx;117,118,119,120,121,122,123: r_data[6] <=  r_data[6] + uart_rx;133,134,135,136,137,138,139: r_data[7] <=  r_data[7] + uart_rx;149,150,151,152,153,154,155: sto_bit <=  sto_bit + uart_rx;default:;endcaseendalways@(posedge Clk or negedge Reset_n)if(!Reset_n) Data <= #1 0;        else if(bps_clk_16x && (bps_cnt == 159))beginData[0] <=  (r_data[0] >= 4)?1'b1:1'b0;Data[1] <=  (r_data[1] >= 4)?1'b1:1'b0;Data[2] <=  (r_data[2] >= 4)?1'b1:1'b0;Data[3] <=  (r_data[3] >= 4)?1'b1:1'b0;Data[4] <=  (r_data[4] >= 4)?1'b1:1'b0;Data[5] <=  (r_data[5] >= 4)?1'b1:1'b0;Data[6] <=  (r_data[6] >= 4)?1'b1:1'b0;Data[7] <=  (r_data[7] >= 4)?1'b1:1'b0;end //    always@(posedge Clk or negedge Reset_n)
//    if(!Reset_n)
//        Data <= #1 0;
//    else if(bps_clk_16x && (bps_cnt == 159))begin
//        Data[0] <= #1 r_data[0][2];
//        Data[1] <= #1 r_data[1][2];
//        Data[2] <= #1 r_data[2][2];
//        Data[3] <= #1 r_data[3][2];
//        Data[4] <= #1 r_data[4][2];
//        Data[5] <= #1 r_data[5][2];
//        Data[6] <= #1 r_data[6][2];
//        Data[7] <= #1 r_data[7][2];
//    end always@(posedge Clk or negedge Reset_n)if(!Reset_n) Rx_Done <=  0;else if((div_cnt == Bps_DR/2) && (bps_cnt == 159))Rx_Done <=  1;elseRx_Done <=  0; endmodule

五、counter_led_4模块

module counter_led_4(Clk,Reset_n,Ctrl,Time,Led
);input Clk;input Reset_n;input [7:0]Ctrl;input [31:0]Time;output reg Led;reg [31:0]counter;always@(posedge Clk or negedge Reset_n)if(!Reset_n)counter <=  0;else if(Time - 1 <=  counter)counter <=  0;elsecounter <=  counter + 1'b1;reg [2:0]counter2;always@(posedge Clk or negedge Reset_n)if(!Reset_n) counter2 <=  0; else if(  Time - 1 <=  counter)counter2 <=  counter2 + 1'b1;always@(posedge Clk or negedge Reset_n)if(!Reset_n)Led <=  0;else case(counter2)0:Led <=  Ctrl[0];1:Led <=  Ctrl[1];2:Led <=  Ctrl[2];3:Led <=  Ctrl[3];4:Led <=  Ctrl[4];5:Led <=  Ctrl[5];6:Led <=  Ctrl[6];7:Led <=  Ctrl[7];default:Led <=  Led;endcaseendmodule

【注】:上述代码中写成Time - 1 <= counter而不是counter = Time - 1的原因:

上电的时候, counter ==0-1发现不满足,就 couter 一直自加,直到自加到32’ hFFFFFFFFFFFFFFFF '才会清零。←由于实际板级运行的时候,当我们的 time 值更新时(25000000), counter 的值已经大于该值,所以无法通过计数比较的方式清零, 能一直自加下去,直到32位计满了,溢出清零,然后才能正常的循环技术清零。于是写成Time - 1 <= counter能解决这个问题,且这样写利大于弊。

【附件:】链接:https://pan.baidu.com/s/1nIBn_n_6DYezlvRN4OfkCQ?pwd=h7ub
提取码:h7ub

串口接收-控制LED闪烁(VerilogVivado)相关推荐

  1. STM32通过串口控制LED闪烁或者呼吸效果

    STM32通过串口控制LED闪烁或者呼吸效果 目录 STM32通过串口控制LED闪烁或者呼吸效果 1.准备工作 2.思路分析 3.实际操作 4.小结 1.准备工作 1.首先我们需要准备32的最小系统板 ...

  2. STM32F103C8T6串口控制LED闪烁

    任务:开启时单片机回复已打开:关闭时在电脑显示已关闭:发 送 1 打开:发送 2 关闭. 本次学习是基于STM32的通用定时器结合串口,进行对LED灯闪烁的控制,使得延时函数时带来的误差性,以及消耗大 ...

  3. ZigBee-CC2530单片机 - 实现计算机串口通讯控制LED发光二极管

    ZigBee-CC2530单片机 - 实现计算机串口通讯控制LED发光二极管 程序源码 /******************************************************* ...

  4. 嵌入式STM32入门之定时器控制LED闪烁与产生PWM脉冲宽度调制信号

    定时器控制LED闪烁与产生PWM脉冲宽度调制信号 一.前言 二.定时器基本介绍 (一)STM32定时器 (二)通用定时器主要功能 (三)计数器模式 (四)定时器工作原理 三.实验(1)初识定时器 (一 ...

  5. NE555时基电路实验(二)NE555控制LED闪烁

    NE555时基电路实验(二)NE555控制LED闪烁 实验用到的元器件: 1.NE555芯片,1片: 2. 470uF.100uF电解电容,耐压值16v,1个: 3.发光 LED,2个: 4.10千欧 ...

  6. 定时器中断控制LED闪烁(每隔1s)---普中科技开发仪

    定时器中断o,利用中断控制LED闪烁每隔1s闪烁一次(精确的1s) notes: (1)工作方式寄存器TMOD ,低四位用于To,高四位用于T1,(GATE,C/T- ,M1,M0) 一般让GATE ...

  7. 用定时器T0查询方式P0口8位控制LED闪烁

    #include<reg52.h> #define uchar unsigned char #define uint unsigned int void main (void) { uch ...

  8. STM32实现定时器控制LED闪烁

    文章目录 一.定时器介绍 二.STM32C配置项目 1.新建工程 2.配置引脚 3.配置SYS 4.配置GPIO 5.配置定时器 6.配置中断 7.时钟配置 8.创建代码 三.修改keil代码 四.实 ...

  9. CC2530控制LED闪烁

    CC2530控制LED闪烁 CC2530 控制LED闪烁 电路图 知识点 CC2530有两个高频时钟 输入输出配置 程序及注释 CC2530 控制LED闪烁 CC2530拥有21个数字I/O(输入/输 ...

最新文章

  1. 手把手教你 用C++实现一个 可持久化 的http_server
  2. 密码6-12位数字和字母组成
  3. linux安装软件测试报告,软件测试实习报告
  4. 第五天 断点续传和下载
  5. 明显调用的表达式前的括号必须具有函数类型_Chisel(二) Scala语法 变量与函数...
  6. django mysql filter_Django filter中用contains 在mysql中的问题
  7. staruml java_非常详细的StarUML使用教程,推荐阅读!
  8. C/C++ sizeof(上)
  9. Python读取系统文件夹内所有文件并统计数量
  10. mysql和mybaits自增长序列详解_MyBatis Oracle 自增序列的实现方法
  11. HTTPHEAD中referer应用
  12. 写论文时遇到的问题及解决办法
  13. C --cp2 类似cat工具的小程序。
  14. HDLBITS笔记15:组合逻辑之7420芯片
  15. Python:实现jaccard similarity相似度无平方因子数算法(附完整源码)
  16. 微信公众平台编辑模式
  17. 乐高大颗粒作品14:导弹发射车
  18. 计算机毕业设计SSM电影售票管理系统【附源码数据库】
  19. UDP 实现多收多发,广播发送,组播发送 TCP 实现多收多发
  20. Cache的地址结构,tag到底与Cache什么关系,Cache容量与总容量,Cache行长,Cache字地址?

热门文章

  1. 关于编程,程序员的一些语录
  2. sqlzoo刷题(部分题目含解题思路)
  3. IDC发布视频云市场报告:公有云厂商占主导,腾讯云持续领跑
  4. 【数据结构功法】第1话 · 数据结构入门竟如此简单?
  5. #### 标题关于Quartus Ⅱ启动ModelSim仿真软件时提示Can't lauch the ModelSim的问题
  6. Android 13(targetSdkVersion:33)必需添加com.google.android.gms.permission.AD_ID
  7. 一般的在线教育平台需具备哪些功能?
  8. js中两个感叹号的作用
  9. 工具及方法 - 安装播放器pot player
  10. vue阻止穿透滚动穿透