基于Robei:如何利用Lora与机器人进行无线通讯

文章目录

日常·唠嗑:

           今年华南赛区结束了,还有二十多天才进行国赛,也算是有几天清闲日子。对于Lora,我有着特殊的情感,从上届集创赛我就一直用到现在。起初我一直执着于WiFi模块,但是WiFi模块对FPGA小白程序员是一点都不友好,然后俩零同学就给我推荐了这款无线扩频模块。随着LoRa技术的不断成熟,现在LoRa已经在国内外得到广泛应用,在这个领域中的人对LoRa并不陌生。LoRa是一种专用于远距离低功耗的无线通信技术,其调制方式相对于其他通信方式大大增加了通信距离,可广泛应用于各种场合的远距离低速率物联网无线通信领域。下面就简单说说如何在Robei中设计Lora与机器人通讯。

一、什么是Lora模块

           要了解LoRa模块就要先了解LoRa,LoRa是低功耗广域网通信技术中的一种,是Semtech公司采用和推广的一种基于扩频技术的超远距离无线传输技术,是Semtech 射频部分产生的一种独特的调制格式。LoRa模块就是基于Semtech公司SX1276/1278芯片研发的无线数传模块,这种芯片集成规模小、效率高,从而让LoRa模块拥有高接收灵敏度。
基于Robei:如何利用Lora与机器人进行无线通讯

LoRa的优势主要体现在以下几个方面:

1、大大的改善了接收的灵敏度,降低了功耗。

           高达157db的链路预算使其通信距离可达15公里(与环境有关)。其接收电流仅10mA,睡眠电流200nA,这大大延迟了电池的使用寿命。

2、基于该技术的网关/集中器支持多信道多数据速率的并行处理,系统容量大。

           网关是节点与IP网络之间的桥梁(通过2G/3G/4G或者Ethernet)。每个网关每天可以处理500万次各节点之间的通信(假设每次发送10Bytes,网络占用率10%)。如果把网关安装在现有移动通信基站的位置,发射功率20dBm(100mW),那么在建筑密集的城市环境可以覆盖2公里左右,而在密度较低的郊区,覆盖范围可达10公里。

3、基于终端和集中器/网关的系统可以支持测距和定位。

           LoRa对距离的测量是基于信号的空中传输时间而非传统的RSSI(Received Signal Sterngth Ind-ication),而定位则基于多点(网关)对一点(节点)的空中传输时间差的测量。其定位精度可达5m(假设10km的范围)。

4、高保密性、高隐蔽性
    采用LoRa调制方式,传统无线设备无法对其进行获、解析,带内平均功率低于底噪时仍然可以正常通讯。

二、通讯方式是什么

1、模块选择

       某宝的lora模块有很多种,选择哪种模块呢?
       建议选择亿佰特,他们家是专门做lora模块的,有各种型号,价格也很便宜,模块加天线,两套才31RMB。而且他们家的模块,写起程序来要比其他的方便很多,想正点原子的lora模块就很麻烦,进行通讯还要配置各种环境。用亿佰特的,只要以UART协议 进行程序编写就行了。

2、参数及设置

我选择的是,E32-433T20DC LoRa扩频 ,一下是他的参数:
芯片方案:SX1278

载波频率:410~441MHz

发射功率:10~20dBm

通信距离:3km

通信接口:UART

默认波特率:9600

产品净量:6.3±0.1g

产品简介:其嵌入高速低功耗单片机和高性能LoRa扩频芯片SX1278,采用高效的循环交织纠检错编码,抗干扰和灵敏度都大大提高。发射功率100mW,低功耗,具有无线唤醒功能,LoRa扩频能够带来更远的通讯距离。
基于Robei:如何利用Lora与机器人进行无线通讯
这里提一下,他的波特率是默认9600的,你可以在他们官网下载APP修改波特率以及其他参数。
基于Robei:如何利用Lora与机器人进行无线通讯

3、接线方式

1、通信接线

    从下图可以看到,模块有7个排针,1-7号,M1,M2主要是选择工作模式,一般通信模式需要将这两个引脚接地(可以拿面包板将这两个引脚跟7引脚GND接在一起),3是RXD接开发板的TXD,4是TXD开发板RXD;5引脚不用理,悬空就好;6是VCC,接电源3.3V-5V。
基于Robei:如何利用Lora与机器人进行无线通讯
这里我觉得接面包板线太多,又乱,就画了快简单的扩展板:
基于Robei:如何利用Lora与机器人进行无线通讯

基于Robei:如何利用Lora与机器人进行无线通讯
基于Robei:如何利用Lora与机器人进行无线通讯
有了扩展板,这样就很方便了,就像普通的串口通讯一样。

2、参数修改接线

    上面说到,可以通过官网的软件修改模块波特率,修改参数的话,主要是在上一小节的基础上,将M1,M2置高电平, 也就是拉高。下面看一下模块的工作选择表;接线完,直接通过CH340模块接到电脑,打开APP读取参数,修改,保存就好了。
基于Robei:如何利用Lora与机器人进行无线通讯

三、Robei程序设计

1、首先构建顶层,打开Robei EDA,new一个module:robei_lora
基于Robei:如何利用Lora与机器人进行无线通讯

基于Robei:如何利用Lora与机器人进行无线通讯

module robei_lora(
	sys_clk,
	sys_rst_n,
	uart_rxd,
	uart_txd);

	//----Parameters:: generated by Robei-----
	parameter CLK_FREQ = 50000000;
	parameter  UART_BPS = 9600;

	//---Ports declearation: generated by Robei---
	input sys_clk;
	input sys_rst_n;
	input uart_rxd;
	output uart_txd;

	wire sys_clk;
	wire sys_rst_n;
	wire uart_rxd;
	wire uart_txd;

	//----Code starts here: integrated by Robei-----
	wire       uart_en_w;                 //UART发送使能
	wire [7:0] uart_data_w;               //UART发送数据
	wire       clk_1m_w;                  //1MHz时钟,用于Signaltap调试
	
	
	
	//---Module instantiation---
	lora_send #( 50000000, 9600) lora_send1(
		.sys_clk(sys_clk),
		.sys_rst_n(sys_rst_n),
		.uart_en(uart_en_w),
		.uart_din(uart_data_w),
		.uart_txd(uart_txd));

	lora_recv #( 50000000, 9600) lora_recv2(
		.sys_clk(sys_clk),
		.sys_rst_n(sys_rst_n),
		.uart_rxd(uart_rxd),
		.uart_done(uart_en_w),
		.uart_data(uart_data_w));

endmodule    //robei_lora

2、写一个接收模块:lora_recv
基于Robei:如何利用Lora与机器人进行无线通讯
基于Robei:如何利用Lora与机器人进行无线通讯

module lora_recv(
	sys_clk,
	sys_rst_n,
	uart_rxd,
	uart_done,
	uart_data);

	//----Parameters:: generated by Robei-----
	parameter CLK_FREQ = 50000000;
	parameter UART_BPS = 9600;

	//---Ports declearation: generated by Robei---
	input sys_clk;
	input sys_rst_n;
	input uart_rxd;
	output uart_done;
	output [7:0] uart_data;

	wire sys_clk;
	wire sys_rst_n;
	wire uart_rxd;
	reg uart_done;
	reg [7:0] uart_data;

	//----Code starts here: integrated by Robei-----
	localparam BPS_CNT  = CLK_FREQ/UART_BPS;        //为得到指定波特率,
	//需要对系统时钟计数BPS_CNT次
	//reg define
	reg        uart_rxd_d0;
	reg        uart_rxd_d1;
	reg [15:0] clk_cnt;                             //系统时钟计数器
	reg [ 3:0] rx_cnt;                              //接收数据计数器
	reg        rx_flag;                             //接收过程标志信号
	reg [ 7:0] rxdata;                              //接收数据寄存器
	
	//wire define
	wire       start_flag;
	//捕获接收端口下降沿(起始位),得到一个时钟周期的脉冲信号
	assign  start_flag = uart_rxd_d1 & (~uart_rxd_d0);    
	
	//对UART接收端口的数据延迟两个时钟周期
	always @(posedge sys_clk or negedge sys_rst_n) begin 
	    if (!sys_rst_n) begin 
	        uart_rxd_d0 <= 1'b0;
	        uart_rxd_d1 <= 1'b0;          
	    end
	    else begin
	        uart_rxd_d0  <= uart_rxd;                   
	        uart_rxd_d1  <= uart_rxd_d0;
	    end   
	end
	
	//当脉冲信号start_flag到达时,进入接收过程           
	always @(posedge sys_clk or negedge sys_rst_n) begin         
	    if (!sys_rst_n)                                  
	        rx_flag <= 1'b0;
	    else begin
	        if(start_flag)                          //检测到起始位
	            rx_flag <= 1'b1;                    //进入接收过程,标志位rx_flag拉高
	        else if((rx_cnt == 4'd9)&&(clk_cnt == BPS_CNT/2))
	            rx_flag <= 1'b0;                    //计数到停止位中间时,停止接收过程
	        else
	            rx_flag <= rx_flag;
	    end
	end
	
	//进入接收过程后,启动系统时钟计数器与接收数据计数器
	always @(posedge sys_clk or negedge sys_rst_n) begin         
	    if (!sys_rst_n) begin                             
	        clk_cnt <= 16'd0;                                  
	        rx_cnt  <= 4'd0;
	    end                                                      
	    else if ( rx_flag ) begin                   //处于接收过程
	            if (clk_cnt < BPS_CNT - 1) begin
	                clk_cnt <= clk_cnt + 1'b1;
	                rx_cnt  <= rx_cnt;
	            end
	            else begin
	                clk_cnt <= 16'd0;               //对系统时钟计数达一个波特率周期后清零
	                rx_cnt  <= rx_cnt + 1'b1;       //此时接收数据计数器加1
	            end
	        end
	        else begin                              //接收过程结束,计数器清零
	            clk_cnt <= 16'd0;
	            rx_cnt  <= 4'd0;
	        end
	end
	
	//根据接收数据计数器来寄存uart接收端口数据
	always @(posedge sys_clk or negedge sys_rst_n) begin 
	    if ( !sys_rst_n)  
	        rxdata <= 8'd0;                                     
	    else if(rx_flag)                            //系统处于接收过程
	        if (clk_cnt == BPS_CNT/2) begin         //判断系统时钟计数器计数到数据位中间
	            case ( rx_cnt )
	             4'd1 : rxdata[0] <= uart_rxd_d1;   //寄存数据位最低位
	             4'd2 : rxdata[1] <= uart_rxd_d1;
	             4'd3 : rxdata[2] <= uart_rxd_d1;
	             4'd4 : rxdata[3] <= uart_rxd_d1;
	             4'd5 : rxdata[4] <= uart_rxd_d1;
	             4'd6 : rxdata[5] <= uart_rxd_d1;
	             4'd7 : rxdata[6] <= uart_rxd_d1;
	             4'd8 : rxdata[7] <= uart_rxd_d1;   //寄存数据位最高位
	             default:;                                    
	            endcase
	        end
	        else 
	            rxdata <= rxdata;
	    else
	        rxdata <= 8'd0;
	end
	
	//数据接收完毕后给出标志信号并寄存输出接收到的数据
	always @(posedge sys_clk or negedge sys_rst_n) begin        
	    if (!sys_rst_n) begin
	        uart_data <= 8'd0;                               
	        uart_done <= 1'b0;
	    end
	    else if(rx_cnt == 4'd9) begin               //接收数据计数器计数到停止位时           
	        uart_data <= rxdata;                    //寄存输出接收到的数据
	        uart_done <= 1'b1;                      //并将接收完成标志位拉高
	    end
	    else begin
	        uart_data <= 8'd0;                                   
	        uart_done <= 1'b0; 
	    end    
	end
	
	
	
endmodule    //lora_recv

3、写一个发送模块:lora_send
基于Robei:如何利用Lora与机器人进行无线通讯

module lora_send(
	sys_clk,
	sys_rst_n,
	uart_en,
	uart_din,
	uart_txd);

	//----Parameters:: generated by Robei-----
	parameter CLK_FREQ = 50000000;
	parameter UART_BPS = 9600;

	//---Ports declearation: generated by Robei---
	input sys_clk;
	input sys_rst_n;
	input uart_en;
	input [7:0] uart_din;
	output uart_txd;

	wire sys_clk;
	wire sys_rst_n;
	wire uart_en;
	wire [7:0] uart_din;
	reg uart_txd;

	//----Code starts here: integrated by Robei-----
	localparam BPS_CNT  = CLK_FREQ/UART_BPS;    //为得到指定波特率,对系统时钟计数BPS_CNT次
	
	//reg define
	reg        uart_en_d0; 
	reg        uart_en_d1;  
	reg [15:0] clk_cnt;                         //系统时钟计数器
	reg [ 3:0] tx_cnt;                          //发送数据计数器
	reg        tx_flag;                         //发送过程标志信号
	reg [ 7:0] tx_data;                         //寄存发送数据
	
	//wire define
	wire       en_flag;
	
	//捕获uart_en上升沿,得到一个时钟周期的脉冲信号
	assign en_flag = (~uart_en_d1) & uart_en_d0;
	                                                 
	//对发送使能信号uart_en延迟两个时钟周期
	always @(posedge sys_clk or negedge sys_rst_n) begin         
	    if (!sys_rst_n) begin
	        uart_en_d0 <= 1'b0;                                  
	        uart_en_d1 <= 1'b0;
	    end                                                      
	    else begin                                               
	        uart_en_d0 <= uart_en;                               
	        uart_en_d1 <= uart_en_d0;                            
	    end
	end
	
	//当脉冲信号en_flag到达时,寄存待发送的数据,并进入发送过程          
	always @(posedge sys_clk or negedge sys_rst_n) begin         
	    if (!sys_rst_n) begin                                  
	        tx_flag <= 1'b0;
	        tx_data <= 8'd0;
	    end 
	    else if (en_flag) begin                 //检测到发送使能上升沿                      
	            tx_flag <= 1'b1;                //进入发送过程,标志位tx_flag拉高
	            tx_data <= uart_din;            //寄存待发送的数据
	        end
	        else 
	        if ((tx_cnt == 4'd9)&&(clk_cnt == BPS_CNT/2))
	        begin                               //计数到停止位中间时,停止发送过程
	            tx_flag <= 1'b0;                //发送过程结束,标志位tx_flag拉低
	            tx_data <= 8'd0;
	        end
	        else begin
	            tx_flag <= tx_flag;
	            tx_data <= tx_data;
	        end 
	end
	
	//进入发送过程后,启动系统时钟计数器与发送数据计数器
	always @(posedge sys_clk or negedge sys_rst_n) begin         
	    if (!sys_rst_n) begin                             
	        clk_cnt <= 16'd0;                                  
	        tx_cnt  <= 4'd0;
	    end                                                      
	    else if (tx_flag) begin                 //处于发送过程
	        if (clk_cnt < BPS_CNT - 1) begin
	            clk_cnt <= clk_cnt + 1'b1;
	            tx_cnt  <= tx_cnt;
	        end
	        else begin
	            clk_cnt <= 16'd0;               //对系统时钟计数达一个波特率周期后清零
	            tx_cnt  <= tx_cnt + 1'b1;       //此时发送数据计数器加1
	        end
	    end
	    else begin                              //发送过程结束
	        clk_cnt <= 16'd0;
	        tx_cnt  <= 4'd0;
	    end
	end
	
	//根据发送数据计数器来给uart发送端口赋值
	always @(posedge sys_clk or negedge sys_rst_n) begin        
	    if (!sys_rst_n)  
	        uart_txd <= 1'b1;        
	    else if (tx_flag)
	        case(tx_cnt)
	            4'd0: uart_txd <= 1'b0;         //起始位 
	            4'd1: uart_txd <= tx_data[0];   //数据位最低位
	            4'd2: uart_txd <= tx_data[1];
	            4'd3: uart_txd <= tx_data[2];
	            4'd4: uart_txd <= tx_data[3];
	            4'd5: uart_txd <= tx_data[4];
	            4'd6: uart_txd <= tx_data[5];
	            4'd7: uart_txd <= tx_data[6];
	            4'd8: uart_txd <= tx_data[7];   //数据位最高位
	            4'd9: uart_txd <= 1'b1;         //停止位
	            default: ;
	        endcase
	    else 
	        uart_txd <= 1'b1;                   //空闲时发送端口为高电平
	end
	
	
	
endmodule    //lora_send

4、将这两个子模块加进顶层模块连线就行了。
5、实物图
下位机:
基于Robei:如何利用Lora与机器人进行无线通讯
上位机:
基于Robei:如何利用Lora与机器人进行无线通讯
通过接线后就可以实现上位机与下位机回环通信。

也许有同学需要用到的是,下位机发送指定指令给上位机,比如人体检测模块检测到人的时候向上位机发送发现人员,这里一并满足大家。

按下按键后,开发板通过Lora向上位机发送:Fa Xian,需要其他指令的同学可以自己修改。

module UART(clk, rst, rxd, txd, en, seg_data, key_input, lowbit);
input clk,rst;
input rxd; //串行数据接收端
input key_input; //按键输入
output[7:0] en /*synthesis keep*/ ;
output[7:0] seg_data;
reg[7:0] seg_data;
output txd; //串行数据发送端
output lowbit;

//***************************inner reg*******************************//
reg[15:0] div_reg; //分频计数器,分频值由波特率决定。分频后得到频率8倍波特率的时钟
reg[2:0] div8_tras_reg; //该寄存器的计数值对应发送时当前位于的时隙数
reg[2:0] div8_rec_reg; //该寄存器的计数值对应接收时当前位于的时隙数
reg[3:0] state_tras; //发送状态寄存器
reg[3:0] state_rec; //接受状态寄存器
reg clkbaud_tras; //以波特率为频率的发送使能信号
reg clkbaud_rec; //以波特率为频率的接受使能信号
reg clkbaud8x; //以8倍波特率为频率的时钟,它的作用是将发送或接受一个bit的时钟周期分为8个时隙
reg recstart; //开始发送标志
reg recstart_tmp;
reg trasstart; //开始接受标志
reg rxd_reg1; //接收寄存器1
reg rxd_reg2; //接收寄存器2,因为接收数据为异步信号,故用两级缓存
reg txd_reg; //发送寄存器
reg[7:0] rxd_buf  /*synthesis keep*/ ; //接受数据缓存
reg[7:0] txd_buf /*synthesis keep*/ ; //发送数据缓存
reg[2:0] send_state /*synthesis keep*/ ; //每次按键给PC发送"Welcome"字符串,这是发送状态寄存器
reg[19:0] cnt_delay; //延时去抖计数器
reg start_delaycnt; //开始延时计数标志
reg key_entry1, key_entry2;//确定有键按下标志
parameter div_par = 16'h145; //分频参数,其值由对应的波特率计算而得,按此参数分频的时钟频率是波倍特率的8
//倍,此处值对应9600的波特率,即分频出的时钟频率是9600*8 (CLK 50M)
//**********************************************************//
assign txd = txd_reg;
assign lowbit = 0;
assign en = 0; //7段数码管使能信号赋值
//**********************************************************//
always@(posedge clk)
begin
if(!rst) begin
cnt_delay <= 0;
start_delaycnt <= 0; end
else if(start_delaycnt) begin
if(cnt_delay != 20'd800000) begin
cnt_delay <= cnt_delay + 1;end
else begin
cnt_delay <= 0;
start_delaycnt <= 0; end end
else begin
if(!key_input && cnt_delay == 0)
start_delaycnt <= 1; end
end
//**********************************************************//
always@(posedge clk)
begin
if(!rst)
key_entry1 <= 0;
else begin
if(key_entry2)
key_entry1 <= 0;
else if(cnt_delay == 20'd800000) begin
if(!key_input)
key_entry1 <= 1; end end
end
//**********************************************************//
always@(posedge clk)
begin
if(!rst)
div_reg <= 0;
else begin
if(div_reg == div_par - 1)
div_reg <= 0;
else
div_reg <= div_reg + 1; end
end
//**********************************************************//
always@(posedge clk) //分频得到8倍波特率的时钟
begin
if(!rst)
clkbaud8x <= 0;
else if(div_reg == div_par - 1)
clkbaud8x <= ~clkbaud8x;
end
//**********************************************************//
always@(posedge clkbaud8x or negedge rst)
begin
if(!rst)
div8_rec_reg <= 0;
else if(recstart) //接收开始标志
div8_rec_reg <= div8_rec_reg + 1; //接收开始后,时隙数在8倍波特率的时钟下加1循环
end
//**********************************************************//
always@(posedge clkbaud8x or negedge rst)
begin
if(!rst)
div8_tras_reg <= 0;
else if(trasstart)
div8_tras_reg <= div8_tras_reg + 1; //发送开始后,时隙数在8倍波特率的时钟下加1循环
end
//**********************************************************//
always@(div8_rec_reg)
begin
if(div8_rec_reg == 7)
clkbaud_rec = 1; //在第7个时隙,接收使能信号有效,将数据打入
else
clkbaud_rec = 0;
end
//**********************************************************//
always@(div8_tras_reg)
begin
if(div8_tras_reg == 7)
clkbaud_tras = 1; //在第7个时隙,发送使能信号有效,将数据发出
else
clkbaud_tras = 0;
end
//**********************************************************//
always@(posedge clkbaud8x or negedge rst)
begin
if(!rst) begin
txd_reg <= 1;
trasstart <= 0;
txd_buf <= 0;
state_tras <= 0;
send_state <= 0;
key_entry2 <= 0; end
else begin
if(!key_entry2) begin
if(key_entry1) begin
key_entry2 <= 1;
txd_buf <= 8'd70; end end//"F"
else begin
case(state_tras)
4'b0000: begin //发送起始位
if(!trasstart && send_state < 7)
trasstart <= 1;
else if(send_state < 7) begin
if(clkbaud_tras) begin
txd_reg <= 0;
state_tras <= state_tras + 1;end end
else begin
key_entry2 <= 0;
state_tras <= 0; end end
4'b0001: begin //发送第1位
if(clkbaud_tras) begin
txd_reg <= txd_buf[0];
txd_buf[6:0] <= txd_buf[7:1];
state_tras <= state_tras + 1; end end
4'b0010: begin //发送第2位
if(clkbaud_tras) begin
txd_reg <= txd_buf[0];
txd_buf[6:0] <= txd_buf[7:1];
state_tras <= state_tras + 1; end end
4'b0011: begin //发送第3位
if(clkbaud_tras) begin
txd_reg <= txd_buf[0];
txd_buf[6:0] <= txd_buf[7:1];
state_tras <= state_tras + 1; end end
4'b0100: begin //发送第4位
if(clkbaud_tras) begin
txd_reg <= txd_buf[0];
txd_buf[6:0] <= txd_buf[7:1];
state_tras <= state_tras + 1; end end
4'b0101: begin //发送第5位
if(clkbaud_tras) begin
txd_reg <= txd_buf[0];
txd_buf[6:0] <= txd_buf[7:1];
state_tras <= state_tras + 1; end end
4'b0110: begin //发送第6位
if(clkbaud_tras) begin
txd_reg <= txd_buf[0];
txd_buf[6:0] <= txd_buf[7:1];
state_tras <= state_tras + 1; end end
4'b0111: begin //发送第7位
if(clkbaud_tras) begin
txd_reg <= txd_buf[0];
txd_buf[6:0] <= txd_buf[7:1];
state_tras <= state_tras + 1; end end
4'b1000: begin //发送第8位
if(clkbaud_tras) begin
txd_reg<=txd_buf[0];
txd_buf[6:0]<=txd_buf[7:1];
state_tras<=state_tras+1;
end
end
4'b1001: begin //发送停止位
if(clkbaud_tras) begin
txd_reg<=1;
txd_buf<=8'h55;
state_tras<=state_tras+1;
end
end
4'b1111:begin
if(clkbaud_tras) begin
state_tras<=state_tras+1;
send_state<=send_state+1;
trasstart<=0;
case(send_state)
3'b000:
txd_buf<=8'd97;//"a"
3'b001:
txd_buf<=8'd32;//" "
3'b010:
txd_buf<=8'd88;//"X"


3'b011:
txd_buf<=8'd105;//"i"
3'b100:
txd_buf<=8'd97;//"a"
3'b101:
txd_buf<=8'd110;//"n"
3'b111:
txd_buf<=8'd110;//"n"

/*
3'b011:
txd_buf<=8'd82;//"R"
3'b100:
txd_buf<=8'd101;//"e"
3'b101:
txd_buf<=8'd110;//"n"
3'b111:
txd_buf<=8'd132;//" "
*/

default:
txd_buf<=0;
endcase
end
end
default: begin
if(clkbaud_tras) begin
state_tras<=state_tras+1;
trasstart<=1;
end
end
endcase
end
end
end
//**********************************************************//
always@(posedge clkbaud8x or negedge rst)//接受PC机的数据
begin
if(!rst) begin
rxd_reg1<=0;
rxd_reg2<=0;
rxd_buf<=0;
state_rec<=0;
recstart<=0;
recstart_tmp<=0;
end
else begin
rxd_reg1<=rxd;
rxd_reg2<=rxd_reg1;
if(state_rec==0) begin
if(recstart_tmp==1) begin
recstart<=1;
recstart_tmp<=0;
state_rec<=state_rec+1;
end
else if(!rxd_reg1&&rxd_reg2) //检测到起始位的下降沿,进入接受状态
recstart_tmp<=1;
end
else if(state_rec>=1&&state_rec<=8) begin
if(clkbaud_rec) begin
rxd_buf[7]<=rxd_reg2;
rxd_buf[6:0]<=rxd_buf[7:1];
state_rec<=state_rec+1;
end
end
else if(state_rec==9) begin
if(clkbaud_rec) begin
state_rec<=0;
recstart<=0;
end
end
end
end
always@(rxd_buf) //将接受的数据用数码管显示出来
begin
case (rxd_buf)
8'h30: seg_data=8'b11000000;
8'h31: seg_data=8'b11111001;
8'h32: seg_data=8'b10100100;
8'h33: seg_data=8'b10110000;
8'h34: seg_data=8'b10011001;
8'h35: seg_data=8'b10010010;
8'h36: seg_data=8'b10000010;
8'h37: seg_data=8'b11111000;
8'h38: seg_data=8'b10000000;
8'h39: seg_data=8'b10010000;
8'h41: seg_data=8'b10001000;//a
8'h42: seg_data=8'b10000011;
8'h43: seg_data=8'b11000110;
8'h44: seg_data=8'b10100001;
8'h45: seg_data=8'b10000110;
8'h46: seg_data=8'b10001110;
default: seg_data=8'b11111111;
endcase
end
endmodule


//本模块的功能是验证实现和PC机进行基本的串口通信的功能。需要在
//PC机上安装一个串口调试工具来验证程序的功能。
//程序实现了一个收发一帧10个bit(即无奇偶校验位)的串口控
//制器,10个bit是1位起始位,8个数据位,1个结束
//位。串口的波特律由程序中定义的div_par参数决定,更改该参数可以实
//现相应的波特率。程序当前设定的div_par 的值是0x145,对应的波特率是
//9600。用一个8倍波特率的时钟将发送或接受每一位bit的周期时间
//划分为8个时隙以使通信同步.
//程序的工作过程是:串口处于全双工工作状态,按动key1,FPGA/CPLD向PC发送“Fa Xian"
//字符串(串口调试工具设成按ASCII码接受方式);PC可随时向FPGA/CPLD发送0-F的十六进制
//数据,FPGA接受后显示在7段数码管上。

总结

    洋洋洒洒写了两个晚上,很多东西都好没整理好,后面有时间会继续更新。比如,上位机通过Lora向开发板发送指令后将数据缓存到RAM中,有兴趣的同学在评论回留言: 对缓存数据有兴趣。人多的话,我会抽空写一下这个内容。

    有其他问题的同学,可以加我好友,有看到会回答你的疑问,还有我们有不眠者技术交流群,可以进来互相学习。
基于Robei:如何利用Lora与机器人进行无线通讯

上一篇:Harbor镜像仓库


下一篇:Android NDK开发篇(一):新版NDK环境搭建(免Cygwin,超级快)