功能描述:

  使用遵循uart协议的接收模块接收控制信号,用来控制led的闪烁。

设计输入:

  1.uart输入信号

  2.时钟信号

  3.复位信号

  4.led信号

设计思路:

  总体上:前面已经写了串口接收模块,led闪烁模块。现在要把接收到的多个数据对应传送给led闪烁模块的输入(闪烁周期,亮灭模式设置),我们再写一个模块来实现传输的功能,然后在顶层把这三个模块进行连线就可以了。

  细节处:单个数据的传输遵循uart协议,而为了确定传送来的数据哪个对应led的时间设置,哪个对应亮灭模式设置,我们也需要人为再设定一个协议,第一,二个数据为某固定值时,视为开端,然后接着是对应数据,最后一个数据是固定值。发送数据端应按照这个协议来发送各个数据,这样子接收端就可以按照这个协议来控制输入led的信号了。

注意

  ①在代码中用到了延时,如#xx......等,则应在文件第一行写明时间单位和精度:·timescale ns/ns 。

  ②如果想让某个标志信号siagnl_a 延后一个周期,可以新设定一个信号siagnl_b,让siagnl_b永远等于siagnl_a就行。

  ③在本次设计中,修正了receive_rx_1代码中把r_data赋给data的时刻以及清零时刻。

学习:

  ①设计底层模块convert,顶层直接连线很方便。

  ②对于串口通信的应用,一般都有串口接收模块+移位寄存器+协议+应用功能 四个部分组成,其中,串口模块和功能模块一般已经设计好了,我们要设计移位寄存器和协议,即接收到的数据用来干嘛,怎么排序对应。

  ③判断条件设定的技巧: if(const <= variable),有两个好处:Ⅰ.常数const不能被变量variabl赋值,以此检查会不会把比较符写成赋值符。Ⅱ.用<=取代 == ,可以避免 == 的时刻已经被跳过,导致判断条件无法实现。

设计:

代码:

  1. `timescale 1ns / 1ns
  2. module uart_rx_ctrl_led(//顶层,就是连线
  3. clk,
  4. reset,
  5. uart_tx,
  6. led
  7. );
  8. input clk;
  9. input reset;
  10. input uart_tx;
  11. output led;
  12.  
  13. //本模型由uart_receive到led_chang的传输协议为:
  14. //0x0f,0xab,tim[31:24] tim[23:16] tim[15:8] tim[7:0] ctrl[7:0] oxa5
  15.  
  16. //首先例化三个模块进来
  17. wire [2:0]baud_rate ;
  18. assign baud_rate = 3'd5 ;
  19. wire [7:0]data;
  20. wire rx_done;
  21. uart_receive_1 uart_receive(//接收模块
  22. clk ,
  23. reset ,
  24. baud_rate ,
  25. uart_tx,
  26. data ,
  27. rx_done
  28. );
  29.  
  30. wire [31:0]tim;
  31. wire [7:0]ctrl;
  32. uart_led_convert uart_led_convert(//转换模块
  33. data,
  34. rx_done,
  35. clk,
  36. reset,
  37. tim,
  38. ctrl
  39. );
  40.  
  41. led_change4 led_change4(//led闪烁模块
  42. clk,
  43. reset,
  44. ctrl,
  45. tim,
  46. led
  47. );
  48.  
  49. endmodule
  1. module uart_receive_1(
  2. clk ,
  3. reset ,
  4. baud_rate ,
  5. uart_tx,
  6. data ,
  7. rx_done
  8. );
  9. input clk ;
  10. input reset ;
  11. input [2:0]baud_rate ;
  12. input uart_tx ;
  13. output reg [7:0]data ;
  14. output reg rx_done ;
  15.  
  16. reg [2:0]r_data[7:0] ;//接收每一位数据
  17. reg [2:0]sta_bit ;
  18. reg [2:0]sto_bit ;
  19.  
  20. reg [17:0]bit_tim ;//每一位持续的时间(计数)
  21. always@(baud_rate) //在这里一个 码元由一位组成,所以波特率=比特率
  22. begin
  23. case(baud_rate) //常见的串口传输波特率
  24. 3'd0 : bit_tim = 1000000000/300/20 ; //波特率为300
  25. 3'd1 : bit_tim = 1000000000/1200/20 ; //波特率为1200
  26. 3'd2 : bit_tim = 1000000000/2400/20 ; //波特率为2400
  27. 3'd3 : bit_tim = 1000000000/9600/20 ; //波特率为9600
  28. 3'd4 : bit_tim = 1000000000/19200/20 ; //波特率为19200
  29. 3'd5 : bit_tim = 1000000000/115200/20 ; //波特率为115200
  30. default bit_tim = 1000000000/9600/20 ; //多余的寄存器位置放什么:默认速率
  31. endcase
  32. end
  33.  
  34. wire [17:0]bit_tim_16 ;//每1/16位的持续时间(计数)
  35. assign bit_tim_16 = bit_tim / 16;
  36.  
  37. wire [8:0]bit16_mid ; //在中心点产生采样脉冲
  38. assign bit16_mid = bit_tim_16 / 2 ;
  39.  
  40. //边沿检测
  41. reg [1:0]edge_detect ;
  42. always @( posedge clk or negedge reset )
  43. begin
  44. if (!reset )
  45. edge_detect <= 2'd0 ;
  46. else
  47. begin
  48. edge_detect[0] <= uart_tx ;
  49. edge_detect[1] <= edge_detect[0] ;
  50. end
  51. end
  52.  
  53. wire byte_sta_neg ;
  54. assign byte_sta_neg = ( edge_detect == 2'b10 ) ? 1 : 0 ;//输入的数据开始出现下降沿,说明出现了起始位(一直运行?)
  55.  
  56. reg receive_en ;//接收使能端
  57. reg [17:0]div_cnt ;//每1/16bit内的计数
  58. reg [7:0]bit16_cnt ;//计数到了第几个状态(10位,每位分成16份,总共160个状态)
  59. always @( posedge clk or negedge reset )
  60. begin
  61. if (!reset )
  62. receive_en <= 1'd0 ;
  63. else if ( byte_sta_neg ) //检测到下降沿,使能段有效(只要有下降沿就使能?)
  64. receive_en <= 1'd1 ;
  65. else if ( (rx_done) || (sta_bit >= 3'd4 ))
  66. receive_en <= 1'd0 ; //检测到结束信号,使能端无效
  67. else if ( ( bit16_cnt == 8'd159 ) && (div_cnt == bit_tim_16 - 1'd1 ) )//跑完159后re_en置零
  68. receive_en <= 1'd0 ;
  69. end
  70.  
  71. always@( posedge clk or negedge reset )
  72. begin
  73. if ( ! reset )
  74. div_cnt <= 18'd0 ;
  75. else if (receive_en)
  76. begin
  77. if ( div_cnt == bit_tim_16 - 1'd1 )//计数,每1/16bit清零
  78. div_cnt <= 18'd0 ;
  79. else
  80. div_cnt <= div_cnt + 1'b1 ;
  81. end
  82. else
  83. div_cnt <= 18'd0 ;
  84. end
  85.  
  86. reg bit16_pulse ;//产生采样脉冲
  87. always@( posedge clk or negedge reset )
  88. begin
  89. if ( ! reset )
  90. bit16_pulse <= 18'd0 ;
  91. else if (receive_en)
  92. if ( div_cnt == bit16_mid )
  93. bit16_pulse <= 1'd1 ;
  94. else
  95. bit16_pulse <= 1'd0 ;
  96. else
  97. bit16_pulse <= 1'd0 ;
  98. end
  99.  
  100. always@( posedge clk or negedge reset )
  101. begin
  102. if ( ! reset )
  103. bit16_cnt <= 8'd0 ;
  104. else if (receive_en)
  105. begin
  106. if (( bit16_cnt == 8'd159 ) && (div_cnt == bit_tim_16 - 1'd1 ))
  107. bit16_cnt <= 8'd0 ;
  108. else if ( div_cnt == bit_tim_16 - 1'd1 )
  109. bit16_cnt <= bit16_cnt + 1'b1 ;
  110. end
  111. end
  112.  
  113. always@(posedge clk or negedge reset)
  114. begin
  115. if(!reset)
  116. begin
  117. sta_bit <= 3'd0 ;
  118. r_data[0] <= 3'd0 ;
  119. r_data[1] <= 3'd0 ;
  120. r_data[2] <= 3'd0 ;
  121. r_data[3] <= 3'd0 ;
  122. r_data[4] <= 3'd0 ;
  123. r_data[5] <= 3'd0 ;
  124. r_data[6] <= 3'd0 ;
  125. r_data[7] <= 3'd0 ;
  126. sto_bit <= 3'd0 ;
  127. end
  128. else if (bit16_pulse)//舍弃前5后4取中7
  129. case(bit16_cnt)
  130. 0:
  131. begin
  132. sta_bit <= 3'd0 ;
  133. r_data[0] <= 3'd0 ;
  134. r_data[1] <= 3'd0 ;
  135. r_data[2] <= 3'd0 ;
  136. r_data[3] <= 3'd0 ;
  137. r_data[4] <= 3'd0 ;
  138. r_data[5] <= 3'd0 ;
  139. r_data[6] <= 3'd0 ;
  140. r_data[7] <= 3'd0 ;
  141. sto_bit <= 3'd0 ;
  142. end
  143. 5,6,7,8,9,10,11 : sta_bit <= sta_bit + uart_tx ;
  144. 21,22,23,24,25,26,27 : r_data[0] <= r_data[0] + uart_tx ;
  145. 37,38,39,41,42,43,44 : r_data[1] <= r_data[1] + uart_tx ;
  146. 53,54,55,56,57,58,59 : r_data[2] <= r_data[2] + uart_tx ;
  147. 69,70,71,72,73,74,75 : r_data[3] <= r_data[3] + uart_tx ;
  148. 85,86,87,88,89,90,91 : r_data[4] <= r_data[4] + uart_tx ;
  149. 101,102,103,104,105,106,107 : r_data[5] <= r_data[5] + uart_tx ;
  150. 117,118,119,120,121,122,123 : r_data[6] <= r_data[6] + uart_tx ;
  151. 133,134,135,136,137,138,139 : r_data[7] <= r_data[7] + uart_tx ;
  152. 149,150,151,152,153,154,155 : sto_bit <= sto_bit + uart_tx ;
  153. default ;
  154. endcase
  155. end
  156.  
  157. always@( posedge clk or negedge reset )
  158. begin
  159. if ( ! reset )
  160. rx_done <= 8'd0 ;
  161. else if ( ( bit16_cnt == 8'd159 ) && (div_cnt == bit_tim_16 - 1'd1 ) )//跑完159后产生一个rx_done信号
  162. rx_done <= 8'd1 ;
  163. else if (rx_done <= 8'd1 )
  164. rx_done <= 8'd0 ;
  165. end
  166.  
  167. always@( posedge clk or negedge reset )//接收完数据发出rx_done后,把数据从r_data传递给data
  168. begin
  169. if ( ! reset )
  170. data <= 8'd0 ;
  171. else if (bit16_pulse)//舍弃前5后4取中7
  172. case(bit16_cnt)
  173. 28:data[0] = ( r_data[0] >3 ) ? 1 : 0 ;
  174. 44:data[1] = ( r_data[1] >3 ) ? 1 : 0 ;
  175. 60:data[2] = ( r_data[2] >3 ) ? 1 : 0 ;
  176. 76:data[3] = ( r_data[3] >3 ) ? 1 : 0 ;
  177. 92:data[4] = ( r_data[4] >3 ) ? 1 : 0 ;
  178. 108:data[5] = ( r_data[5] >3 ) ? 1 : 0 ;
  179. 124:data[6] = ( r_data[6] >3 ) ? 1 : 0 ;
  180. 140:data[7] = ( r_data[7] >3 ) ? 1 : 0 ;
  181. endcase
  182. else if(rx_done)
  183. data <= 8'd0 ;
  184. end
  185.  
  186. endmodule
  1. `timescale 1ns / 1ns
  2. module uart_led_convert(
  3. data,
  4. rx_done,
  5. clk,
  6. reset,
  7. tim,
  8. ctrl
  9. );
  10. input [7:0]data;
  11. input rx_done;
  12. input clk;
  13. input reset;
  14. output reg [31:0]tim;
  15. output reg [7:0]ctrl;
  16.  
  17. //设定本模型由uart_receive到led_chang的传输协议为:
  18. //0x0f,0xab,tim[31:24] tim[23:16] tim[15:8] tim[7:0] ctrl[7:0] oxa5
  19. //设计一个二维移位寄存器
  20. reg [7:0]data_regist[7:0];
  21. always@(posedge clk or negedge reset)
  22. begin
  23. if(!reset)
  24. begin
  25. data_regist[0] <= 0;
  26. data_regist[1] <= 0;
  27. data_regist[2] <= 0;
  28. data_regist[3] <= 0;
  29. data_regist[4] <= 0;
  30. data_regist[5] <= 0;
  31. data_regist[6] <= 0;
  32. data_regist[7] <= 0;
  33. end
  34. else if(rx_done)
  35. begin
  36. data_regist[0] <= data ;
  37. data_regist[1] <= data_regist[0] ;
  38. data_regist[2] <= data_regist[1] ;
  39. data_regist[3] <= data_regist[2] ;
  40. data_regist[4] <= data_regist[3] ;
  41. data_regist[5] <= data_regist[4] ;
  42. data_regist[6] <= data_regist[5] ;
  43. data_regist[7] <= data_regist[6] ;
  44. end
  45. end
  46.  
  47. always@(posedge clk or negedge reset)
  48. begin
  49. if(!reset)
  50. begin
  51. tim <= 0 ;
  52. ctrl <= 0 ;
  53. end
  54. else if ( ( data_regist[0] == 8'ha5 ) && ( data_regist[6] == 8'hab ) && ( data_regist[7] == 8'h0f ) )
  55. begin
  56. ctrl[7:0] <= data_regist[1] ;
  57. tim[7:0] <= data_regist[2] ;
  58. tim[15:8] <= data_regist[3] ;
  59. tim[23:16] <= data_regist[4] ;
  60. tim[31:24] <= data_regist[5] ;
  61. end
  62. end
  63. endmodule
  1. module led_change4( //以tim*20/8 ns为变化周期,tim*20 ns为一个循环,每个周期的亮灭模式,tim由用户设置。.
  2. clk,
  3. reset,
  4. ctrl,
  5. tim,
  6. led
  7. );
  8. input clk;
  9. input reset;
  10. input [7:0]ctrl;
  11. input [31:0]tim;
  12. output reg led ;
  13.  
  14. reg [31:0]counter0;
  15.  
  16. always@( posedge clk or negedge reset )
  17. begin
  18. if ( reset == 0 )
  19. counter0 <= 32'b0 ;
  20. else if ( tim - 1 <= counter0 )
  21. counter0 <= 0 ;
  22. else
  23. counter0 <= counter0 + 1'd1;
  24. end
  25.  
  26. always@( posedge clk or negedge reset )
  27. begin
  28. if ( reset == 0 )
  29. led <= 0 ;
  30. else case( counter0 ) //可以用第二个计数器的方法来设置判断条件
  31. tim * 1 / 8 - 1 : led <= ctrl[0] ;
  32. tim * 2 / 8 - 1 : led <= ctrl[1] ;
  33. tim * 3 / 8 - 1 : led <= ctrl[2] ;
  34. tim * 4 / 8 - 1 : led <= ctrl[3] ;
  35. tim * 5 / 8 - 1 : led <= ctrl[4] ;
  36. tim * 6 / 8 - 1 : led <= ctrl[5] ;
  37. tim * 7 / 8 - 1 : led <= ctrl[6] ;
  38. tim * 8 / 8 - 1 : led <= ctrl[7] ;
  39. default led <= led ;
  40. endcase
  41. end
  42. endmodule

使用uart串口接收模块接收信号,控制led灯闪烁的更多相关文章

  1. 树莓派开机运行Python脚本 控制LED灯闪烁

    一.新建一个开机运行文件 在 /home/pi/.config 下创建一个文件夹,名称为 autostart,并在该文件夹下创建一个led.desktop文件(文件名以.desktop结尾) 编辑le ...

  2. C#与Arduino通过串口通信来控制LED灯的状态

    一.引言 最近摆弄了一段时间的Arduino,发现Arduino做一些电子类项目.监控.机器人.电子玩具比较容易,并且Arduino与.NET程序集成也不难.接下来介绍一个简单的小程序,C#做的一个W ...

  3. arduino入门学习实现语音控制LED灯

    需要的准备的硬件arduino+PC+麦克风实现语音命令控制LED灯的亮灭. 首先需要将写好的arduino程序烧录到arduino uno主板中,下面是代码如下: int val;//定义变量val ...

  4. arduino 红外遥控器控制LED灯

    /* 日期:2016.9.1 功能:红外遥控器控制LED灯 开,关,闪烁,呼吸 元件: 跳线公公头 * 5 led 220欧电阻 红外接收管,红外遥控 接线: 红外灯面向自己从左到右分别接 IO3 , ...

  5. BLE 安卓APP控制LED灯的实现(转)

    源:BLE 安卓APP控制LED灯的实现 //注:参考AmoMcu源代码修改. 打开APP,检查蓝牙是否打开 BluetoothAdapter mBluetoothAdapter; final Blu ...

  6. Arduino控制LED灯(开关控制)

    问题:当使用"digitalRead(BUT) == 1"控制LED灯时会出现"digitalWrite(LED, ledState);"的值出现跳动. 原因: ...

  7. 嵌入式Linux学习入门:控制LED灯

    记录自己linux学习过程,让自己能够一直坚持下去 1.原理图分析: nLED_1, nLED_2, nLED_4, 给低电平则对应LED灯亮,高电平则对应LED灯灭, S3C2440芯片GPF4-G ...

  8. enc28J60 网页控制LED灯

    软件IDE:Arduino 1.6.3 1.库的安装: 从https://github.com/jcw/ethercard 下载源码包,解压,复制ethercard-master文件夹到Arduino ...

  9. 云中树莓派(4):利用声音传感器控制Led灯

    云中树莓派(1):环境准备 云中树莓派(2):将传感器数据上传到AWS IoT 并利用Kibana进行展示 云中树莓派(3):通过 AWS IoT 控制树莓派上的Led 云中树莓派(4):利用声音传感 ...

随机推荐

  1. 关于JS精度缺失问题

    问题描述 在Java后端传一个比较大的Long值的时候 前端接收值的时候会出现精度的缺失: 解决办法 添加一个转换类 点击查看代码 public class JacksonObjectMapper e ...

  2. 一些特殊的CSS属性

    1.<form>标签的enctype属性 enctype属性规定在发送到服务器之前应该如何对表单数据进行编码,属性值如下: application/x-www-form-urlencode ...

  3. PHP代码审计之SQL注入

    代码审计之SQL注入 SQL注入攻击(SQLInjection),是攻击者在表单中提交精心构造的sql语句,改变原来的sql语句,如果web程序没有对提交的数据经过检查,那么就会造成sql注入攻击. ...

  4. 浅尝Spring注解开发_Servlet3.0与SpringMVC

    浅尝Spring注解开发_Servlet 3.0 与 SpringMVC 浅尝Spring注解开发,基于Spring 4.3.12 Servlet3.0新增了注解支持.异步处理,可以省去web.xml ...

  5. 用 Python 远程控制 Windows 服务器,太好用了!

    在很多企业会使用闲置的 Windows 机器作为临时服务器,有时候我们想远程调用里面的程序或查看日志文件 Windows 内置的服务「 winrm 」可以满足我们的需求 它是一种基于标准简单对象访问协 ...

  6. 请求扩展、蓝图、g对象

    今日内容概要 请求扩展 蓝图 g对象 内容详细 1.请求扩展 # 在请求来了,请求走了,可以做一些校验和拦截,通过装饰器来实现 7 个 # 1 before_request 类比django中间件中的 ...

  7. SQL多表多字段比对方法

    目录 表-表比较 整体思路 找出不同字段的明细 T1/T2两表ID相同的部分,是否存在不同NAME 两表的交集与差集:判断两表某些字段是否相同 两表的交集与差集:找出T2表独有的id 字段-字段比较 ...

  8. 详细剖析pyecharts大屏的Page函数配置文件:chart_config.json

    目录 一.问题背景 二.揭开json文件神秘面纱 三.巧用json文件 四.关于Table图表 五.同步讲解视频 5.1 讲解json的视频 5.2 讲解全流程大屏的视频 5.3 讲解全流程大屏的文章 ...

  9. Linux:可执行程序的Shell传参格式规范

    1. Linux下可执行程序的Shell传参格式规范 Linux下的可执行程序在运行时经常需要传一些参数,而这些参数是有规范的.包括我们自己写的在Linux系统下运行的Shell脚本.Python脚本 ...

  10. IDEA windows版本快捷键

    使用本快捷键前,可以在idea使用下面方法确认版本! Ctrl 快捷键 介绍 Ctrl + F 在当前文件进行文本查找 (必备)Ctrl + R 在当前文件进行文本替换 (必备) Ctrl + Z 撤 ...