使用uart串口接收模块接收信号,控制led灯闪烁
功能描述:
使用遵循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赋值,以此检查会不会把比较符写成赋值符。Ⅱ.用<=取代 == ,可以避免 == 的时刻已经被跳过,导致判断条件无法实现。
设计:
代码:
- `timescale 1ns / 1ns
- module uart_rx_ctrl_led(//顶层,就是连线
- clk,
- reset,
- uart_tx,
- led
- );
- input clk;
- input reset;
- input uart_tx;
- output led;
- //本模型由uart_receive到led_chang的传输协议为:
- //0x0f,0xab,tim[31:24] tim[23:16] tim[15:8] tim[7:0] ctrl[7:0] oxa5
- //首先例化三个模块进来
- wire [2:0]baud_rate ;
- assign baud_rate = 3'd5 ;
- wire [7:0]data;
- wire rx_done;
- uart_receive_1 uart_receive(//接收模块
- clk ,
- reset ,
- baud_rate ,
- uart_tx,
- data ,
- rx_done
- );
- wire [31:0]tim;
- wire [7:0]ctrl;
- uart_led_convert uart_led_convert(//转换模块
- data,
- rx_done,
- clk,
- reset,
- tim,
- ctrl
- );
- led_change4 led_change4(//led闪烁模块
- clk,
- reset,
- ctrl,
- tim,
- led
- );
- endmodule
- module uart_receive_1(
- clk ,
- reset ,
- baud_rate ,
- uart_tx,
- data ,
- rx_done
- );
- input clk ;
- input reset ;
- input [2:0]baud_rate ;
- input uart_tx ;
- output reg [7:0]data ;
- output reg rx_done ;
- reg [2:0]r_data[7:0] ;//接收每一位数据
- reg [2:0]sta_bit ;
- reg [2:0]sto_bit ;
- reg [17:0]bit_tim ;//每一位持续的时间(计数)
- always@(baud_rate) //在这里一个 码元由一位组成,所以波特率=比特率
- begin
- case(baud_rate) //常见的串口传输波特率
- 3'd0 : bit_tim = 1000000000/300/20 ; //波特率为300
- 3'd1 : bit_tim = 1000000000/1200/20 ; //波特率为1200
- 3'd2 : bit_tim = 1000000000/2400/20 ; //波特率为2400
- 3'd3 : bit_tim = 1000000000/9600/20 ; //波特率为9600
- 3'd4 : bit_tim = 1000000000/19200/20 ; //波特率为19200
- 3'd5 : bit_tim = 1000000000/115200/20 ; //波特率为115200
- default bit_tim = 1000000000/9600/20 ; //多余的寄存器位置放什么:默认速率
- endcase
- end
- wire [17:0]bit_tim_16 ;//每1/16位的持续时间(计数)
- assign bit_tim_16 = bit_tim / 16;
- wire [8:0]bit16_mid ; //在中心点产生采样脉冲
- assign bit16_mid = bit_tim_16 / 2 ;
- //边沿检测
- reg [1:0]edge_detect ;
- always @( posedge clk or negedge reset )
- begin
- if (!reset )
- edge_detect <= 2'd0 ;
- else
- begin
- edge_detect[0] <= uart_tx ;
- edge_detect[1] <= edge_detect[0] ;
- end
- end
- wire byte_sta_neg ;
- assign byte_sta_neg = ( edge_detect == 2'b10 ) ? 1 : 0 ;//输入的数据开始出现下降沿,说明出现了起始位(一直运行?)
- reg receive_en ;//接收使能端
- reg [17:0]div_cnt ;//每1/16bit内的计数
- reg [7:0]bit16_cnt ;//计数到了第几个状态(10位,每位分成16份,总共160个状态)
- always @( posedge clk or negedge reset )
- begin
- if (!reset )
- receive_en <= 1'd0 ;
- else if ( byte_sta_neg ) //检测到下降沿,使能段有效(只要有下降沿就使能?)
- receive_en <= 1'd1 ;
- else if ( (rx_done) || (sta_bit >= 3'd4 ))
- receive_en <= 1'd0 ; //检测到结束信号,使能端无效
- else if ( ( bit16_cnt == 8'd159 ) && (div_cnt == bit_tim_16 - 1'd1 ) )//跑完159后re_en置零
- receive_en <= 1'd0 ;
- end
- always@( posedge clk or negedge reset )
- begin
- if ( ! reset )
- div_cnt <= 18'd0 ;
- else if (receive_en)
- begin
- if ( div_cnt == bit_tim_16 - 1'd1 )//计数,每1/16bit清零
- div_cnt <= 18'd0 ;
- else
- div_cnt <= div_cnt + 1'b1 ;
- end
- else
- div_cnt <= 18'd0 ;
- end
- reg bit16_pulse ;//产生采样脉冲
- always@( posedge clk or negedge reset )
- begin
- if ( ! reset )
- bit16_pulse <= 18'd0 ;
- else if (receive_en)
- if ( div_cnt == bit16_mid )
- bit16_pulse <= 1'd1 ;
- else
- bit16_pulse <= 1'd0 ;
- else
- bit16_pulse <= 1'd0 ;
- end
- always@( posedge clk or negedge reset )
- begin
- if ( ! reset )
- bit16_cnt <= 8'd0 ;
- else if (receive_en)
- begin
- if (( bit16_cnt == 8'd159 ) && (div_cnt == bit_tim_16 - 1'd1 ))
- bit16_cnt <= 8'd0 ;
- else if ( div_cnt == bit_tim_16 - 1'd1 )
- bit16_cnt <= bit16_cnt + 1'b1 ;
- end
- end
- always@(posedge clk or negedge reset)
- begin
- if(!reset)
- begin
- sta_bit <= 3'd0 ;
- r_data[0] <= 3'd0 ;
- r_data[1] <= 3'd0 ;
- r_data[2] <= 3'd0 ;
- r_data[3] <= 3'd0 ;
- r_data[4] <= 3'd0 ;
- r_data[5] <= 3'd0 ;
- r_data[6] <= 3'd0 ;
- r_data[7] <= 3'd0 ;
- sto_bit <= 3'd0 ;
- end
- else if (bit16_pulse)//舍弃前5后4取中7
- case(bit16_cnt)
- 0:
- begin
- sta_bit <= 3'd0 ;
- r_data[0] <= 3'd0 ;
- r_data[1] <= 3'd0 ;
- r_data[2] <= 3'd0 ;
- r_data[3] <= 3'd0 ;
- r_data[4] <= 3'd0 ;
- r_data[5] <= 3'd0 ;
- r_data[6] <= 3'd0 ;
- r_data[7] <= 3'd0 ;
- sto_bit <= 3'd0 ;
- end
- 5,6,7,8,9,10,11 : sta_bit <= sta_bit + uart_tx ;
- 21,22,23,24,25,26,27 : r_data[0] <= r_data[0] + uart_tx ;
- 37,38,39,41,42,43,44 : r_data[1] <= r_data[1] + uart_tx ;
- 53,54,55,56,57,58,59 : r_data[2] <= r_data[2] + uart_tx ;
- 69,70,71,72,73,74,75 : r_data[3] <= r_data[3] + uart_tx ;
- 85,86,87,88,89,90,91 : r_data[4] <= r_data[4] + uart_tx ;
- 101,102,103,104,105,106,107 : r_data[5] <= r_data[5] + uart_tx ;
- 117,118,119,120,121,122,123 : r_data[6] <= r_data[6] + uart_tx ;
- 133,134,135,136,137,138,139 : r_data[7] <= r_data[7] + uart_tx ;
- 149,150,151,152,153,154,155 : sto_bit <= sto_bit + uart_tx ;
- default ;
- endcase
- end
- always@( posedge clk or negedge reset )
- begin
- if ( ! reset )
- rx_done <= 8'd0 ;
- else if ( ( bit16_cnt == 8'd159 ) && (div_cnt == bit_tim_16 - 1'd1 ) )//跑完159后产生一个rx_done信号
- rx_done <= 8'd1 ;
- else if (rx_done <= 8'd1 )
- rx_done <= 8'd0 ;
- end
- always@( posedge clk or negedge reset )//接收完数据发出rx_done后,把数据从r_data传递给data
- begin
- if ( ! reset )
- data <= 8'd0 ;
- else if (bit16_pulse)//舍弃前5后4取中7
- case(bit16_cnt)
- 28:data[0] = ( r_data[0] >3 ) ? 1 : 0 ;
- 44:data[1] = ( r_data[1] >3 ) ? 1 : 0 ;
- 60:data[2] = ( r_data[2] >3 ) ? 1 : 0 ;
- 76:data[3] = ( r_data[3] >3 ) ? 1 : 0 ;
- 92:data[4] = ( r_data[4] >3 ) ? 1 : 0 ;
- 108:data[5] = ( r_data[5] >3 ) ? 1 : 0 ;
- 124:data[6] = ( r_data[6] >3 ) ? 1 : 0 ;
- 140:data[7] = ( r_data[7] >3 ) ? 1 : 0 ;
- endcase
- else if(rx_done)
- data <= 8'd0 ;
- end
- endmodule
- `timescale 1ns / 1ns
- module uart_led_convert(
- data,
- rx_done,
- clk,
- reset,
- tim,
- ctrl
- );
- input [7:0]data;
- input rx_done;
- input clk;
- input reset;
- output reg [31:0]tim;
- output reg [7:0]ctrl;
- //设定本模型由uart_receive到led_chang的传输协议为:
- //0x0f,0xab,tim[31:24] tim[23:16] tim[15:8] tim[7:0] ctrl[7:0] oxa5
- //设计一个二维移位寄存器
- reg [7:0]data_regist[7:0];
- always@(posedge clk or negedge reset)
- begin
- if(!reset)
- begin
- data_regist[0] <= 0;
- data_regist[1] <= 0;
- data_regist[2] <= 0;
- data_regist[3] <= 0;
- data_regist[4] <= 0;
- data_regist[5] <= 0;
- data_regist[6] <= 0;
- data_regist[7] <= 0;
- end
- else if(rx_done)
- begin
- data_regist[0] <= data ;
- data_regist[1] <= data_regist[0] ;
- data_regist[2] <= data_regist[1] ;
- data_regist[3] <= data_regist[2] ;
- data_regist[4] <= data_regist[3] ;
- data_regist[5] <= data_regist[4] ;
- data_regist[6] <= data_regist[5] ;
- data_regist[7] <= data_regist[6] ;
- end
- end
- always@(posedge clk or negedge reset)
- begin
- if(!reset)
- begin
- tim <= 0 ;
- ctrl <= 0 ;
- end
- else if ( ( data_regist[0] == 8'ha5 ) && ( data_regist[6] == 8'hab ) && ( data_regist[7] == 8'h0f ) )
- begin
- ctrl[7:0] <= data_regist[1] ;
- tim[7:0] <= data_regist[2] ;
- tim[15:8] <= data_regist[3] ;
- tim[23:16] <= data_regist[4] ;
- tim[31:24] <= data_regist[5] ;
- end
- end
- endmodule
- module led_change4( //以tim*20/8 ns为变化周期,tim*20 ns为一个循环,每个周期的亮灭模式,tim由用户设置。.
- clk,
- reset,
- ctrl,
- tim,
- led
- );
- input clk;
- input reset;
- input [7:0]ctrl;
- input [31:0]tim;
- output reg led ;
- reg [31:0]counter0;
- always@( posedge clk or negedge reset )
- begin
- if ( reset == 0 )
- counter0 <= 32'b0 ;
- else if ( tim - 1 <= counter0 )
- counter0 <= 0 ;
- else
- counter0 <= counter0 + 1'd1;
- end
- always@( posedge clk or negedge reset )
- begin
- if ( reset == 0 )
- led <= 0 ;
- else case( counter0 ) //可以用第二个计数器的方法来设置判断条件
- tim * 1 / 8 - 1 : led <= ctrl[0] ;
- tim * 2 / 8 - 1 : led <= ctrl[1] ;
- tim * 3 / 8 - 1 : led <= ctrl[2] ;
- tim * 4 / 8 - 1 : led <= ctrl[3] ;
- tim * 5 / 8 - 1 : led <= ctrl[4] ;
- tim * 6 / 8 - 1 : led <= ctrl[5] ;
- tim * 7 / 8 - 1 : led <= ctrl[6] ;
- tim * 8 / 8 - 1 : led <= ctrl[7] ;
- default led <= led ;
- endcase
- end
- endmodule
使用uart串口接收模块接收信号,控制led灯闪烁的更多相关文章
- 树莓派开机运行Python脚本 控制LED灯闪烁
一.新建一个开机运行文件 在 /home/pi/.config 下创建一个文件夹,名称为 autostart,并在该文件夹下创建一个led.desktop文件(文件名以.desktop结尾) 编辑le ...
- C#与Arduino通过串口通信来控制LED灯的状态
一.引言 最近摆弄了一段时间的Arduino,发现Arduino做一些电子类项目.监控.机器人.电子玩具比较容易,并且Arduino与.NET程序集成也不难.接下来介绍一个简单的小程序,C#做的一个W ...
- arduino入门学习实现语音控制LED灯
需要的准备的硬件arduino+PC+麦克风实现语音命令控制LED灯的亮灭. 首先需要将写好的arduino程序烧录到arduino uno主板中,下面是代码如下: int val;//定义变量val ...
- arduino 红外遥控器控制LED灯
/* 日期:2016.9.1 功能:红外遥控器控制LED灯 开,关,闪烁,呼吸 元件: 跳线公公头 * 5 led 220欧电阻 红外接收管,红外遥控 接线: 红外灯面向自己从左到右分别接 IO3 , ...
- BLE 安卓APP控制LED灯的实现(转)
源:BLE 安卓APP控制LED灯的实现 //注:参考AmoMcu源代码修改. 打开APP,检查蓝牙是否打开 BluetoothAdapter mBluetoothAdapter; final Blu ...
- Arduino控制LED灯(开关控制)
问题:当使用"digitalRead(BUT) == 1"控制LED灯时会出现"digitalWrite(LED, ledState);"的值出现跳动. 原因: ...
- 嵌入式Linux学习入门:控制LED灯
记录自己linux学习过程,让自己能够一直坚持下去 1.原理图分析: nLED_1, nLED_2, nLED_4, 给低电平则对应LED灯亮,高电平则对应LED灯灭, S3C2440芯片GPF4-G ...
- enc28J60 网页控制LED灯
软件IDE:Arduino 1.6.3 1.库的安装: 从https://github.com/jcw/ethercard 下载源码包,解压,复制ethercard-master文件夹到Arduino ...
- 云中树莓派(4):利用声音传感器控制Led灯
云中树莓派(1):环境准备 云中树莓派(2):将传感器数据上传到AWS IoT 并利用Kibana进行展示 云中树莓派(3):通过 AWS IoT 控制树莓派上的Led 云中树莓派(4):利用声音传感 ...
随机推荐
- 关于JS精度缺失问题
问题描述 在Java后端传一个比较大的Long值的时候 前端接收值的时候会出现精度的缺失: 解决办法 添加一个转换类 点击查看代码 public class JacksonObjectMapper e ...
- 一些特殊的CSS属性
1.<form>标签的enctype属性 enctype属性规定在发送到服务器之前应该如何对表单数据进行编码,属性值如下: application/x-www-form-urlencode ...
- PHP代码审计之SQL注入
代码审计之SQL注入 SQL注入攻击(SQLInjection),是攻击者在表单中提交精心构造的sql语句,改变原来的sql语句,如果web程序没有对提交的数据经过检查,那么就会造成sql注入攻击. ...
- 浅尝Spring注解开发_Servlet3.0与SpringMVC
浅尝Spring注解开发_Servlet 3.0 与 SpringMVC 浅尝Spring注解开发,基于Spring 4.3.12 Servlet3.0新增了注解支持.异步处理,可以省去web.xml ...
- 用 Python 远程控制 Windows 服务器,太好用了!
在很多企业会使用闲置的 Windows 机器作为临时服务器,有时候我们想远程调用里面的程序或查看日志文件 Windows 内置的服务「 winrm 」可以满足我们的需求 它是一种基于标准简单对象访问协 ...
- 请求扩展、蓝图、g对象
今日内容概要 请求扩展 蓝图 g对象 内容详细 1.请求扩展 # 在请求来了,请求走了,可以做一些校验和拦截,通过装饰器来实现 7 个 # 1 before_request 类比django中间件中的 ...
- SQL多表多字段比对方法
目录 表-表比较 整体思路 找出不同字段的明细 T1/T2两表ID相同的部分,是否存在不同NAME 两表的交集与差集:判断两表某些字段是否相同 两表的交集与差集:找出T2表独有的id 字段-字段比较 ...
- 详细剖析pyecharts大屏的Page函数配置文件:chart_config.json
目录 一.问题背景 二.揭开json文件神秘面纱 三.巧用json文件 四.关于Table图表 五.同步讲解视频 5.1 讲解json的视频 5.2 讲解全流程大屏的视频 5.3 讲解全流程大屏的文章 ...
- Linux:可执行程序的Shell传参格式规范
1. Linux下可执行程序的Shell传参格式规范 Linux下的可执行程序在运行时经常需要传一些参数,而这些参数是有规范的.包括我们自己写的在Linux系统下运行的Shell脚本.Python脚本 ...
- IDEA windows版本快捷键
使用本快捷键前,可以在idea使用下面方法确认版本! Ctrl 快捷键 介绍 Ctrl + F 在当前文件进行文本查找 (必备)Ctrl + R 在当前文件进行文本替换 (必备) Ctrl + Z 撤 ...