激光雷達:
首先來給大家稍微介紹以下激光雷達,激光雷達,即Light Detation and ranging,它相比於其他雷達,優點非常明確,包括 1)、具有極高的分辨率;
2)、抗干擾能力強;
3)、獲取的信息量豐富;
4)、全天時工作;
最近一段時間有幸接觸到鐳神LS01C型單線激光雷達,LS01C型激光雷達是深圳市鐳神智能系統公司研發的一款低成本二維掃描測距產品。該激光雷達可實現6米范圍內的360°二維平面掃描,產生空間的平面點雲地圖用於地圖繪制、機器人自主定位導航、智能設備壁障等應用。
激光測距采用激光三角測距系統,三角測距原理可參考
http://blog.csdn.net/xiangz_csdn/article/details/53814290
LSLIDAR通訊參數:
波特率:230400bps;
校驗位:NONE;
數據位:8bits;
停止位:1bits;
數據格式:十六進制。
首先接觸雷達,我從數據通信入手,通過uart串口發送啟動指令(0xA5 0x2C 0xE1 0xAA 0xBB 0xCC 0xDD
)和停止指令(0xA5 0x25 0xE1 0xAA 0xBB 0xCC 0xDD
)來控制雷達運行和停止。采用兩種方法來控制雷達運行狀態:(1)、將啟動和停止指令預存在程序中,然后和FPGA板子的開關相結合,通過開關來控制雷達;
(2)、采用串口助手來發送指令控制雷達運行和停止。
接下來貢上兩種程序代碼:
一、預存指令:
分為四個模塊:分頻模塊clkdiv.v、發送模塊uarttx.v、測試模塊(存指令模塊)test_tx_r.v、頂層模塊top_tx_r.v
module clkdiv(clk, clkout); //分頻模塊 input clk; output clkout; reg clkout; reg [15:0] cnt; always @(posedge clk) begin //板子時鍾為100MHZ,采用16倍波特率進行采樣,計算得分頻系數為27 if(cnt == 16'd13) begin clkout <= 1'b1; cnt <= cnt + 16'd1; end else if(cnt == 16'd27) begin clkout <= 1'b0; cnt <= 16'd0; end else begin cnt <= cnt + 16'd1; end end endmodule
module uarttx(clk, datain, wrsig, idle, tx);//發送模塊 input clk; input [7:0] datain; //並行輸入8位數據 input wrsig; //輸入控制位,上升沿有效 output idle;//輸出標志位 output tx; //串行輸出數據 reg idle, tx; reg send; reg wrsigbuf, wrsigrise; reg presult; //發送校驗 reg[7:0] cnt; parameter paritymode = 1'b0; always @(posedge clk) //判斷wrsig的上升沿 begin wrsigbuf <= wrsig; wrsigrise <= (~wrsigbuf) & wrsig; end always @(posedge clk) begin if (wrsigrise && (~idle)) //wrsig為上升沿且處於空閑狀態發送數據 begin send <= 1'b1; //進行發送 end else if(cnt == 8'd152) //8位數據發送完畢 begin send <= 1'b0; end end always @(posedge clk) begin if(send == 1'b1) begin case(cnt) 8'd0: //發送起始位 begin tx <= 1'b0; idle <= 1'b1; //處於忙狀態 cnt <= cnt + 8'd1; end 8'd16: //發送第一位 begin tx <= datain[0]; presult <= datain[0]^paritymode; idle <= 1'b1; //處於忙狀態 cnt <= cnt + 8'd1; end 8'd32: //發送第二位 begin tx <= datain[1]; presult <= datain[1]^presult; idle <= 1'b1; //處於忙狀態 cnt <= cnt + 8'd1; end 8'd48: //發送第三位 begin tx <= datain[2]; presult <= datain[2]^presult; idle <= 1'b1; //處於忙狀態 cnt <= cnt + 8'd1; end 8'd64: //發送第四位 begin tx <= datain[3]; presult <= datain[3]^presult; idle <= 1'b1; //處於忙狀態 cnt <= cnt + 8'd1; end 8'd80: //發送第五位 begin tx <= datain[4]; presult <= datain[4]^presult; idle <= 1'b1; //處於忙狀態 cnt <= cnt + 8'd1; end 8'd96: //發送第六位 begin tx <= datain[5]; presult <= datain[5]^presult; idle <= 1'b1; //處於忙狀態 cnt <= cnt + 8'd1; end 8'd112: //發送第七位 begin tx <= datain[6]; presult <= datain[6]^presult; idle <= 1'b1; //處於忙狀態 cnt <= cnt + 8'd1; end 8'd128: //發送第八位 begin tx <= datain[7]; presult <= datain[7]^presult; idle <= 1'b1; //處於忙狀態 cnt <= cnt + 8'd1; end 8'd144: //發送停止位 begin tx <= 1'b1; idle <= 1'b1; //處於忙狀態 cnt <= cnt + 8'd1; end 8'd152: begin tx <= 1'b1; idle <= 1'b0;// 處於空閑狀態,可以發數據 cnt <= cnt + 8'd1; end default: begin cnt <= cnt + 8'd1; end endcase end else begin tx <= 1'b1; cnt <= 8'd0; idle <= 1'b0; end end endmodule
module testuart(clk, dataout,wrsig,rst,key_mov,key_stop); input clk,rst; input key_mov;//開始開關 input key_stop;//停止開關 output[7:0] dataout; output wrsig; //發送指令標志位 reg [7:0] dataout; reg wrsig; reg [16:0] cnt; always @(posedge clk or negedge rst ) begin if(!rst)begin dataout<= 0; cnt <=0; end else begin if(key_mov==1'b1)//運行開關閉合有效 begin if(cnt <= 1779) //一組指令周期數 begin //發送開始指令 case(cnt) 16'd254: begin dataout <= 8'hA5;wrsig <= 1'b1; cnt <= cnt + 16'd1;end 16'd508: begin dataout <= 8'h2C;wrsig <= 1'b1; cnt <= cnt + 16'd1; end 16'd762: begin dataout <= 8'hE1;wrsig <= 1'b1; cnt <= cnt + 16'd1; end 16'd1016: begin dataout <= 8'hAA;wrsig <= 1'b1; cnt <= cnt + 16'd1; end 16'd1270: begin dataout <= 8'hBB;wrsig <= 1'b1; cnt <= cnt + 16'd1; end 16'd1524: begin dataout <= 8'hCC;wrsig <= 1'b1; cnt <= cnt + 16'd1; end 16'd1778: begin dataout <= 8'hDD;wrsig <= 1'b1; cnt <= cnt + 16'd1;end default:begin wrsig <= 1'b0; cnt <= cnt + 16'd1;end endcase end else begin wrsig <= 1'b0; cnt <= 16'd0; end end else if(key_stop==1'b1)//停止開關閉合 begin if(cnt <= 1779) begin //發送停止指令 case(cnt) 16'd254: begin dataout <= 8'hA5;wrsig <= 1'b1; cnt <= cnt + 16'd1;end 16'd508: begin dataout <= 8'h25;wrsig <= 1'b1; cnt <= cnt + 16'd1; end 16'd762: begin dataout <= 8'hE1;wrsig <= 1'b1; cnt <= cnt + 16'd1; end 16'd1016: begin dataout <= 8'hAA;wrsig <= 1'b1; cnt <= cnt + 16'd1; end 16'd1270: begin dataout <= 8'hBB;wrsig <= 1'b1; cnt <= cnt + 16'd1; end 16'd1524: begin dataout <= 8'hCC;wrsig <= 1'b1; cnt <= cnt + 16'd1; end 16'd1778: begin dataout <= 8'hDD;wrsig <= 1'b1; cnt <= cnt + 16'd1;end default:begin wrsig <= 1'b0; cnt <= cnt + 16'd1;end endcase end else begin wrsig <= 1'b0; cnt <= 16'd0; end end else begin wrsig <= 1'b0; cnt <= 16'd0; end end end endmodule
module uarttx(clk, datain, wrsig, idle, tx);//發送模塊 input clk; input [7:0] datain; //並行輸入8位數據 input wrsig; //輸入控制位,上升沿有效 output idle;//輸出標志位 output tx; //串行輸出數據 reg idle, tx; reg send; reg wrsigbuf, wrsigrise; reg presult; //發送校驗 reg[7:0] cnt; parameter paritymode = 1'b0; always @(posedge clk) //判斷wrsig的上升沿 begin wrsigbuf <= wrsig; wrsigrise <= (~wrsigbuf) & wrsig; end always @(posedge clk) begin if (wrsigrise && (~idle)) //wrsig為上升沿且處於空閑狀態發送數據 begin send <= 1'b1; //進行發送 end else if(cnt == 8'd152) //8位數據發送完畢 begin send <= 1'b0; end end always @(posedge clk) begin if(send == 1'b1) begin case(cnt) 8'd0: //發送起始位 begin tx <= 1'b0; idle <= 1'b1; //處於忙狀態 cnt <= cnt + 8'd1; end 8'd16: //發送第一位 begin tx <= datain[0]; presult <= datain[0]^paritymode; idle <= 1'b1; //處於忙狀態 cnt <= cnt + 8'd1; end 8'd32: //發送第二位 begin tx <= datain[1]; presult <= datain[1]^presult; idle <= 1'b1; //處於忙狀態 cnt <= cnt + 8'd1; end 8'd48: //發送第三位 begin tx <= datain[2]; presult <= datain[2]^presult; idle <= 1'b1; //處於忙狀態 cnt <= cnt + 8'd1; end 8'd64: //發送第四位 begin tx <= datain[3]; presult <= datain[3]^presult; idle <= 1'b1; //處於忙狀態 cnt <= cnt + 8'd1; end 8'd80: //發送第五位 begin tx <= datain[4]; presult <= datain[4]^presult; idle <= 1'b1; //處於忙狀態 cnt <= cnt + 8'd1; end 8'd96: //發送第六位 begin tx <= datain[5]; presult <= datain[5]^presult; idle <= 1'b1; //處於忙狀態 cnt <= cnt + 8'd1; end 8'd112: //發送第七位 begin tx <= datain[6]; presult <= datain[6]^presult; idle <= 1'b1; //處於忙狀態 cnt <= cnt + 8'd1; end 8'd128: //發送第八位 begin tx <= datain[7]; presult <= datain[7]^presult; idle <= 1'b1; //處於忙狀態 cnt <= cnt + 8'd1; end 8'd144: //發送停止位 begin tx <= 1'b1; idle <= 1'b1; //處於忙狀態 cnt <= cnt + 8'd1; end 8'd152: begin tx <= 1'b1; idle <= 1'b0;// 處於空閑狀態,可以發數據 cnt <= cnt + 8'd1; end default: begin cnt <= cnt + 8'd1; end endcase end else begin tx <= 1'b1; cnt <= 8'd0; idle <= 1'b0; end end endmodule
二、通過串口助手來發送:
分頻模塊和上面的一樣,此處不再呈上;
module top(clk,rx,tx,idle); input clk,rx; output tx,idle; wire tx,idle; wire clkout,rdsig; wire [7:0] dataout; clkdiv clkdiv_inst( .clk(clk), .clkout(clkout) ); uarttx uarttx_inst( .clk(clkout), .datain(dataout), .wrsig(rdsig), .idle(idle), .tx(tx) ); uartrx uartrx_inst( .clk(clkout), .rx(rx), .dataout(dataout), .rdsig(rdsig) ); endmodule
module uartrx(clk, rx, dataout, rdsig); input clk; //采樣時鍾 input rx; //UART 數據輸入 output dataout; //接收數據輸出 output rdsig; reg[7:0] dataout; reg rdsig; reg [7:0] cnt; reg rxbuf, rxfall, receive; parameter paritymode = 1'b0; reg presult, idle; always @(posedge clk) //檢測線路的下降沿 begin rxbuf <= rx; rxfall <= rxbuf & (~rx); end always @(posedge clk) begin if (rxfall && (~idle)) //檢測到線路的下降沿並且原先線路為空閑,啟動接收數據進程 begin receive <= 1'b1; end else if(cnt == 8'd152) //接收數據完成 begin receive <= 1'b0; end end always @(posedge clk) begin if(receive == 1'b1) begin case (cnt) 8'd0: begin idle <= 1'b1; cnt <= cnt + 8'd1; rdsig <= 1'b0; end 8'd24: //接收第 0 位數據 begin idle <= 1'b1; dataout[0] <= rx; presult <= paritymode^rx; cnt <= cnt + 8'd1; rdsig <= 1'b0; end 8'd40: //接收第 1 位數據 begin idle <= 1'b1; dataout[1] <= rx; presult <= presult^rx; cnt <= cnt + 8'd1; rdsig <= 1'b0; end 8'd56: //接收第 2 位數據 begin idle <= 1'b1; dataout[2] <= rx; presult <= presult^rx; cnt <= cnt + 8'd1; rdsig <= 1'b0; end 8'd72: //接收第 3 位數據 begin idle <= 1'b1; dataout[3] <= rx; presult <= presult^rx; cnt <= cnt + 8'd1; rdsig <= 1'b0; end 8'd88: //接收第 4 位數據 begin idle <= 1'b1; dataout[4] <= rx; presult <= presult^rx; cnt <= cnt + 8'd1; rdsig <= 1'b0; end 8'd104: //接收第 5 位數據 begin idle <= 1'b1; dataout[5] <= rx; presult <= presult^rx; cnt <= cnt + 8'd1; rdsig <= 1'b0; end 8'd120: //接收第 6 位數據 begin idle <= 1'b1; dataout[6] <= rx; presult <= presult^rx; cnt <= cnt + 8'd1; rdsig <= 1'b0; end 8'd136: //接收第 7 位數據 begin idle <= 1'b1; dataout[7] <= rx; presult <= presult^rx; cnt <= cnt + 8'd1; rdsig <= 1'b0; end 8'd144: begin idle <= 1'b1; cnt <= cnt + 1'b1; rdsig <= 1'b1; end default: begin cnt <= cnt + 8'd1; end endcase end else begin cnt <= 8'd0; idle <= 1'b0; rdsig <= 1'b0; end end endmodule
module uarttx(clk, datain, wrsig, idle, tx); input clk; //UART 時鍾 input [7:0] datain; //需要發送的數據 input wrsig; //發送命令,上升沿有效 output idle; //線路狀態指示,高為線路忙,低為線路空閑 output tx; //發送數據信號 reg idle, tx; reg send; reg wrsigbuf, wrsigrise; reg presult; reg[7:0] cnt; //計數器 parameter paritymode = 1'b0; //檢測發送命令是否有效 always @(posedge clk) begin wrsigbuf <= wrsig; wrsigrise <= (~wrsigbuf) & wrsig; end always @(posedge clk) begin if (wrsigrise && (~idle)) //當發送命令有效且線路為空閑時,啟動新的數據發送進程 begin send <= 1'b1; end else if(cnt == 8'd152) //一幀資料發送結束 begin send <= 1'b0; end end always @(posedge clk) begin if(send == 1'b1) begin case(cnt) //產生起始位 8'd0: begin tx <= 1'b0; idle <= 1'b1; cnt <= cnt + 8'd1; end 8'd16: begin tx <= datain[0]; //發送數據 0 位 presult <= datain[0]^paritymode; idle <= 1'b1; cnt <= cnt + 8'd1; end 8'd32: begin tx <= datain[1]; //發送數據 1 位 presult <= datain[1]^presult; idle <= 1'b1; cnt <= cnt + 8'd1; end 8'd48: begin tx <= datain[2]; //發送數據 2 位 presult <= datain[2]^presult; idle <= 1'b1; cnt <= cnt + 8'd1; end 8'd64: begin tx <= datain[3]; //發送數據 3 位 presult <= datain[3]^presult; idle <= 1'b1; cnt <= cnt + 8'd1; end 8'd80: begin tx <= datain[4]; //發送數據 4 位 presult <= datain[4]^presult; idle <= 1'b1; cnt <= cnt + 8'd1; end 8'd96: begin tx <= datain[5]; //發送數據 5 位 presult <= datain[5]^presult; idle <= 1'b1; cnt <= cnt + 8'd1; end 8'd112: begin tx <= datain[6]; //發送數據 6 位 presult <= datain[6]^presult; idle <= 1'b1; cnt <= cnt + 8'd1; end 8'd128: begin tx <= datain[7]; //發送數據 7 位 presult <= datain[7]^presult; idle <= 1'b1; cnt <= cnt + 10'd1; end 8'd144: begin tx <= 1'b1; //發送停止位 idle <= 1'b1; cnt <= cnt + 8'd1; end 8'd152: begin tx <= 1'b1; idle <= 1'b0; //一幀資料發送結束 cnt <= cnt + 8'd1; end default: begin cnt <= cnt + 8'd1; end endcase end else begin tx <= 1'b1; cnt <= 8'd0; idle <= 1'b0; end end endmodule
串口通信是熟悉板子的入門練習,可以深刻理解發送數據的方式,以及波特率的含義和計算。