基于Robei:如何利用Lora与机器人进行无线通讯
作者:互联网
文章目录
日常·唠嗑:
今年华南赛区结束了,还有二十多天才进行国赛,也算是有几天清闲日子。对于Lora,我有着特殊的情感,从上届集创赛我就一直用到现在。起初我一直执着于WiFi模块,但是WiFi模块对FPGA小白程序员是一点都不友好,然后俩零同学就给我推荐了这款无线扩频模块。随着LoRa技术的不断成熟,现在LoRa已经在国内外得到广泛应用,在这个领域中的人对LoRa并不陌生。LoRa是一种专用于远距离低功耗的无线通信技术,其调制方式相对于其他通信方式大大增加了通信距离,可广泛应用于各种场合的远距离低速率物联网无线通信领域。下面就简单说说如何在Robei中设计Lora与机器人通讯。
一、什么是Lora模块
要了解LoRa模块就要先了解LoRa,LoRa是低功耗广域网通信技术中的一种,是Semtech公司采用和推广的一种基于扩频技术的超远距离无线传输技术,是Semtech 射频部分产生的一种独特的调制格式。LoRa模块就是基于Semtech公司SX1276/1278芯片研发的无线数传模块,这种芯片集成规模小、效率高,从而让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扩频能够带来更远的通讯距离。
这里提一下,他的波特率是默认9600的,你可以在他们官网下载APP修改波特率以及其他参数。
3、接线方式
1、通信接线
从下图可以看到,模块有7个排针,1-7号,M1,M2主要是选择工作模式,一般通信模式需要将这两个引脚接地(可以拿面包板将这两个引脚跟7引脚GND接在一起),3是RXD接开发板的TXD,4是TXD开发板RXD;5引脚不用理,悬空就好;6是VCC,接电源3.3V-5V。
这里我觉得接面包板线太多,又乱,就画了快简单的扩展板:
有了扩展板,这样就很方便了,就像普通的串口通讯一样。
2、参数修改接线
上面说到,可以通过官网的软件修改模块波特率,修改参数的话,主要是在上一小节的基础上,将M1,M2置高电平, 也就是拉高。下面看一下模块的工作选择表;接线完,直接通过CH340模块接到电脑,打开APP读取参数,修改,保存就好了。
三、Robei程序设计
1、首先构建顶层,打开Robei EDA,new一个module: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
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
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、实物图
下位机:
上位机:
通过接线后就可以实现上位机与下位机回环通信。
也许有同学需要用到的是,下位机发送指定指令给上位机,比如人体检测模块检测到人的时候向上位机发送发现人员,这里一并满足大家。
按下按键后,开发板通过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中,有兴趣的同学在评论回留言: 对缓存数据有兴趣。人多的话,我会抽空写一下这个内容。
有其他问题的同学,可以加我好友,有看到会回答你的疑问,还有我们有不眠者技术交流群,可以进来互相学习。
标签:模块,clk,uart,sys,Robei,rst,Lora,reg,无线通讯 来源: https://blog.csdn.net/weixin_46423500/article/details/119259844