基于PYNQ的AD采集系统
基于PYNQ的AD采集系统
- 系统概述
- AN706的控制
- SPI通讯
- AXI4-LITE总线
- 打包IP核
- 建立PYNQ工程
- 编写SDK程序
- 上板验证
- 代码下载地址
系统概述
打算用PYNQ-Z2开发板做MMC变化器的控制,遇到的第一个问题就是做MMC控制需要采集大量的电容电压、电流信号。但是考虑到XILINX官方的PYNQ-Z2开发板管脚很少,所以使用另一块XLINX的FPGA(SPANTAN-6)接两片黑金的AN706AD进行数据采集,通过SPI协议把采集到的数据从SPI从机传输到位于PYNQ开发板上的SPI主机上。最后通过AXI4-Lite总线传输到ARM核上。系统的总图如下:
AN706的控制
关于AN706AD的控制,这里直接使用黑金官方的例程就可以了,就是注意去理解其时序,如下图所示:
直接上代码:
module ad7606(input clk,input rst_n,input [15:0] ad_data, input ad_busy, input first_datoutput [2:0] ad_os, output reg ad_cs, output reg ad_rd, output reg ad_reset, output reg ad_convstab,output reg [15:0] ad_ch1,output reg [15:0] ad_ch2,output reg [15:0] ad_ch3,output reg [15:0] ad_ch4,output reg [15:0] ad_ch5,output reg [15:0] ad_ch6,output reg [15:0] ad_ch7,output reg [15:0] ad_ch8,output reg ad_finish);
reg [15:0] cnt;
reg [5:0] i;
reg [3:0] state; parameter IDLE=4'd0;
parameter AD_CONV=4'd1;
parameter Wait_1=4'd2;
parameter Wait_busy=4'd3;
parameter READ_CH1=4'd4;
parameter READ_CH2=4'd5;
parameter READ_CH3=4'd6;
parameter READ_CH4=4'd7;
parameter READ_CH5=4'd8;
parameter READ_CH6=4'd9;
parameter READ_CH7=4'd10;
parameter READ_CH8=4'd11;
parameter READ_DONE=4'd12; assign ad_os=3'b000;
always@(posedge clk) begin if(cnt<16'hffff) begincnt<=cnt+1; ad_reset<=1'b1; end else ad_reset<=1'b0; end
always @(posedge clk) begin if (ad_reset==1'b1) begin state<=IDLE; ad_ch1<=0; ad_ch2<=0; ad_ch3<=0; ad_ch4<=0; ad_ch5<=0; ad_ch6<=0; ad_ch7<=0; ad_ch8<=0; ad_cs<=1'b1; ad_rd<=1'b1; ad_convstab<=1'b1; i<=0; ad_finish<=1'b0; end else begin case(state) IDLE: begin ad_cs<=1'b1; ad_rd<=1'b1; ad_convstab<=1'b1; if(i==20) begin i<=0; state<=AD_CONV; end else i<=i+1'b1; end AD_CONV: begin if(i==2) begin i<=0; state<=Wait_1; ad_convstab<=1'b1; ad_finish<=1'b0; end else begin i<=i+1'b1; ad_convstab<=1'b0; end end Wait_1: begin if(i==5) begin i<=0; state<=Wait_busy; end else i<=i+1'b1; end Wait_busy: begin if(ad_busy==1'b0) begin i<=0; state<=READ_CH1; end end READ_CH1: begin ad_cs<=1'b0; if(i==3) begin ad_rd<=1'b1; i<=0; ad_ch1<=ad_data; state<=READ_CH2; end else begin ad_rd<=1'b0; i<=i+1'b1; end end READ_CH2: begin if(i==3) begin ad_rd<=1'b1; i<=0; ad_ch2<=ad_data; state<=READ_CH3; end else begin ad_rd<=1'b0; i<=i+1'b1; end end READ_CH3: begin if(i==3) begin ad_rd<=1'b1; i<=0; ad_ch3<=ad_data; state<=READ_CH4; end else begin ad_rd<=1'b0; i<=i+1'b1; end end READ_CH4: begin if(i==3) begin ad_rd<=1'b1; i<=0; ad_ch4<=ad_data; state<=READ_CH5; end else begin ad_rd<=1'b0; i<=i+1'b1; end end READ_CH5: begin if(i==3) begin ad_rd<=1'b1; i<=0; ad_ch5<=ad_data; state<=READ_CH6; end else begin ad_rd<=1'b0; i<=i+1'b1; end end READ_CH6: begin if(i==3) begin ad_rd<=1'b1; i<=0; ad_ch6<=ad_data; state<=READ_CH7; end else begin ad_rd<=1'b0; i<=i+1'b1; end end READ_CH7: begin if(i==3) begin ad_rd<=1'b1; i<=0; ad_ch7<=ad_data; state<=READ_CH8; end else begin ad_rd<=1'b0; i<=i+1'b1; end end READ_CH8: begin if(i==3) begin ad_rd<=1'b1; i<=0; ad_ch8<=ad_data; state<=READ_DONE; end else begin ad_rd<=1'b0; i<=i+1'b1; end end READ_DONE:begin ad_rd<=1'b1; ad_cs<=1'b1; state<=IDLE; ad_finish<=1'b1; end default: state<=IDLE; endcase end end endmodule
这里在黑金官方的代码的基础上加入了ad_finish这个输出信号,目的是每次AD读完8个通道的值后告知SPI从机可以进行数据传输了。
SPI通讯
在两个FPGA之间的通讯,准备采用SPI模式,但是因为数据的流动方向只是从SPANTAN-6流向PYNQ-Z2,所以在这里对SPI通讯协议进行了修改。首先在传统的4线SPI模式中,去掉MOSI这根线,其次为了在传输时加大传输速度,把MISO的数据位宽改为16位,与AD输出的位宽相同。传输时遵从在时钟的下降沿从机准备好需要传输的数据,在时钟的上升沿主机采集数据。
下面直接上代码:
从机
//下降沿发送数据
module SPI_SLAVE
( input clk, input rst_n, input CS_N, input SCK, input tx_en, // output reg [15:0]MISO, input [16*16-1:0] txd_data
);
//---------------------spi_slaver send data---------------------------
reg [3:0] txd_state;
always@(negedge SCK or negedge rst_n)
begin if(!rst_n) begin txd_state <= 1'b0; MISO<=0; end else if(!CS_N) begin case(txd_state) 4'd0:begin MISO <= txd_data[255:240]; txd_state <= 4'd1; end 4'd1:begin MISO <= txd_data[239:224]; txd_state <= 4'd2; end 4'd2:begin MISO <= txd_data[223:208]; txd_state <= 4'd3; end 4'd3:begin MISO <= txd_data[207:192]; txd_state <= 4'd4; end 4'd4:begin MISO <= txd_data[191:176]; txd_state <= 4'd5; end 4'd5:begin MISO <= txd_data[175:160]; txd_state <= 4'd6; end 4'd6:begin MISO <= txd_data[159:144]; txd_state <= 4'd7; end 4'd7:begin MISO <= txd_data[143:128]; txd_state <= 4'd8; end 4'd8:begin MISO <= txd_data[127:112]; txd_state <= 4'd9; end 4'd9:begin MISO <= txd_data[111:96]; txd_state <= 4'd10; end 4'd10:begin MISO <= txd_data[95:80]; txd_state <= 4'd11; end 4'd11:begin MISO <= txd_data[79:64]; txd_state <= 4'd12; end 4'd12:begin MISO <= txd_data[63:48]; txd_state <= 4'd13; end 4'd13:begin MISO <= txd_data[47:32]; txd_state <= 4'd14; end 4'd14:begin MISO <= txd_data[31:16]; txd_state <= 4'd15; end 4'd15:begin MISO <= txd_data[15:0]; txd_state <= 4'd0; end default: ; endcase end
end endmodule
主机
//上升沿发送数据
module SPI_MASTER
( input clk,//100M input rst_n, input rx_en, output rx_done, output reg [16*16-1:0]data_out, input [15:0]MISO, output reg SCK, output reg CS_N
); reg [6:0]i;
reg rx_en_r;
reg rx_done_r;
reg [5:0]rxd_state;
always @(posedge clk or negedge rst_n)
if(~rst_n)
begin rxd_state<=5'b0; CS_N<=1'b1; SCK<=1'b1; rx_done_r<=1'b0; data_out<=0; i<=7'b0;
end
else
begin if(rx_en_r) begin CS_N<=1'b0; case(rxd_state) 6'd0,6'd2,6'd4,6'd6,6'd8,6'd10,6'd12,6'd14,6'd16,6'd18,6'd20,6'd22,6'd24,6'd26,6'd28,6'd30: begin if(i==100) begin SCK<=1'b0; i<=0; rxd_state<=rxd_state+1'b1; end else i<=i+1; rx_done_r<=1'b0; end 6'd1://接收第15位 begin if(i==100) begin SCK<=1'b1; rxd_state<=rxd_state+1'b1; rx_done_r<=1'b0; data_out[255:240]<=MISO; i<=0; end else i<=i+1; end 6'd3://接收第14位 begin if(i==100) begin SCK<=1'b1; rxd_state<=rxd_state+1'b1; rx_done_r<=1'b0; data_out[239:224]<=MISO; i<=0; end else i<=i+1; end 6'd5://接收第13位 begin if(i==100) begin SCK<=1'b1; rxd_state<=rxd_state+1'b1; rx_done_r<=1'b0; data_out[223:208]<=MISO; i<=0; end else i<=i+1; end 6'd7://接收第12位 begin if(i==100) begin SCK<=1'b1; rxd_state<=rxd_state+1'b1; rx_done_r<=1'b0; data_out[207:192]<=MISO; i<=0; end else i<=i+1; end 6'd9://接收第11位 begin if(i==100) begin SCK<=1'b1; rxd_state<=rxd_state+1'b1; rx_done_r<=1'b0; data_out[191:176]<=MISO; i<=0; end else i<=i+1; end 6'd11://接收第10位 begin if(i==100) begin SCK<=1'b1; rxd_state<=rxd_state+1'b1; rx_done_r<=1'b0; data_out[175:160]<=MISO; i<=0; end else i<=i+1; end 6'd13://接收第9位 begin if(i==100) begin SCK<=1'b1; rxd_state<=rxd_state+1'b1; rx_done_r<=1'b0; data_out[159:144]<=MISO; i<=0; end else i<=i+1; end 6'd15://接收第8位 begin if(i==100) begin SCK<=1'b1; rxd_state<=rxd_state+1'b1; rx_done_r<=1'b0; data_out[143:128]<=MISO; i<=0; end else i<=i+1; end 6'd17://接收第7位 begin if(i==100) begin SCK<=1'b1; rxd_state<=rxd_state+1'b1; rx_done_r<=1'b0; data_out[127:112]<=MISO; i<=0; end else i<=i+1; end 6'd19://接收第6位 begin if(i==100) begin SCK<=1'b1; rxd_state<=rxd_state+1'b1; rx_done_r<=1'b0; data_out[111:96]<=MISO; i<=0; end else i<=i+1; end 6'd21://接收第5位 begin if(i==100) begin SCK<=1'b1; rxd_state<=rxd_state+1'b1; rx_done_r<=1'b0; data_out[95:80]<=MISO; i<=0; end else i<=i+1; end 6'd23://接收第4位 begin if(i==100) begin SCK<=1'b1; rxd_state<=rxd_state+1'b1; rx_done_r<=1'b0; data_out[79:64]<=MISO; i<=0; end else i<=i+1; end 6'd25://接收第3位 begin if(i==100) begin SCK<=1'b1; rxd_state<=rxd_state+1'b1; rx_done_r<=1'b0; data_out[63:48]<=MISO; i<=0; end else i<=i+1; end 6'd27://接收第2位 begin if(i==100) begin SCK<=1'b1; rxd_state<=rxd_state+1'b1; rx_done_r<=1'b0; data_out[47:32]<=MISO; i<=0; end else i<=i+1; end 6'd29://接收第1位 begin if(i==100) begin SCK<=1'b1; rxd_state<=rxd_state+1'b1; rx_done_r<=1'b0; data_out[31:16]<=MISO; i<=0; end else i<=i+1; end 6'd31://接收第0位 begin if(i==100) begin SCK<=1'b1; rxd_state<=rxd_state+1; rx_done_r<=1'b1; data_out[15:0]<=MISO; i<=0; end else i<=i+1; end 6'd32: begin SCK<=1'b1; rxd_state<=rxd_state+1'b1; rx_done_r<=1'b1; end default: begin rxd_state<=6'd0; end endcase end
end //上升沿检测
reg btn1;
reg btn2;
always @(posedge clk or negedge rst_n)
if(~rst_n)
begin btn1 <= 1'b0; btn2 <= 1'b0;
end
else
begin btn1 <= rx_done; btn2 <= btn1;
end
wire done=btn1 & ~btn2; always @(posedge clk or negedge rst_n)
if(~rst_n) rx_en_r<=1'b0;
else if(rx_en) rx_en_r<=1'b1; else if(done) rx_en_r<=1'b0; assign rx_done=rx_done_r;
因为偶数状态的逻辑都一样,所以可以合并起来。这里为了方便ARM核通过AXI4总线对主机SPI模块进行控制和读取,加入了rx_en和rx_done两个信号。当rx_en置1时,启动SPI传输。当rx_done置1时,表示SPI传输完成,有了这两个信号就可以很方便的使用ARM的定时器定时读取AD值。具体原理可以结合仿真时序进行理解。
AXI4-LITE总线
在基于zynq架构的Xilinx的FPGA上,PS(ARM核)和PL(可编程逻辑部分)的通讯都是基于AXI4总线的。因为要传输的数据量不大,就16个寄存器中的数据(分别对应于16个AD通道),所以就使用了AXI4-LITE总线,而没有使用AXI4-HP总线。这个总线总结起来就是地址先达,数据随后。就是不管是读寄存器还是写寄存器都要先送地址,然后才能读(写)数据。
具体的总线原理可以参考这篇文章:AXI4总线。需要注意的是LITE总线是不支持突发传输的。
下面直接上基于AXI4-LITE总线的AD寄存器代码:
module axi_reg
( input clk, input rst_n, //AR channel input S_AXI_ARVALID, output S_AXI_ARREADY, input [6:0]S_AXI_ARADDR, input [2:0]S_AXI_ARPROT, //Rd channel output [32-1:0]S_AXI_RDATA, output [1:0]S_AXI_RRESP, output S_AXI_RVALID, input S_AXI_RREADY, //AW channel input S_AXI_AWVALID, output S_AXI_AWREADY, input [6:0]S_AXI_AWADDR, input [2:0]S_AXI_AWPROT, //Wr channel input [32-1:0]S_AXI_WDATA, input S_AXI_WVALID, output S_AXI_WREADY, input [4-1:0]S_AXI_WSTRB, //Wr Resp output [1:0]S_AXI_BRESP, output S_AXI_BVALID, input S_AXI_BREADY, //from ad fifo input [16*16-1:0]ad_data, input data_vld, //cmd to SPI_master input rx_done, //最好放在一个叫做done 的寄存器里 output rx_en //rx_en=start
); //内部寄存器 //start reg0
reg done_r; //reg1
reg [15:0]ad1; //reg2
reg [15:0]ad2; //reg3
reg [15:0]ad3; //reg4
reg [15:0]ad4; //reg5
reg [15:0]ad5; //reg6
reg [15:0]ad6; //reg7
reg [15:0]ad7; //reg8
reg [15:0]ad8; //reg9
reg [15:0]ad9; //reg10
reg [15:0]ad10; //reg11
reg [15:0]ad11; //reg12
reg [15:0]ad12; //reg13
reg [15:0]ad13; //reg14
reg [15:0]ad14; //reg15
reg [15:0]ad15; //reg16
reg [15:0]ad16; //reg17 wire start; always @(posedge clk or negedge rst_n)
if(~rst_n)
begin done_r<=0; ad1<=0; ad2<=0; ad3<=0; ad4<=0; ad5<=0; ad6<=0; ad7<=0; ad8<=0; ad9<=0; ad10<=0; ad11<=0; ad12<=0; ad13<=0; ad14<=0; ad15<=0; ad16<=0;
end
else
begin done_r<=rx_done; if(data_vld) begin ad1<=ad_data[15:0]; ad2<=ad_data[31:16]; ad3<=ad_data[47:32]; ad4<=ad_data[63:48]; ad5<=ad_data[79:64]; ad6<=ad_data[95:80]; ad7<=ad_data[111:96]; ad8<=ad_data[127:112]; ad9<=ad_data[143:128]; ad10<=ad_data[159:144]; ad11<=ad_data[175:160]; ad12<=ad_data[191:176]; ad13<=ad_data[207:192]; ad14<=ad_data[223:208]; ad15<=ad_data[239:224]; ad16<=ad_data[255:240]; end
end
/**********************************AXI4_LITE****************************************/
//写应答
assign S_AXI_BRESP=2'b0;
reg axi_bvalid;
assign S_AXI_BVALID=axi_bvalid;
always @(posedge clk or negedge rst_n)
if(~rst_n) axi_bvalid<=1'b0;
else if(S_AXI_WVALID & S_AXI_WREADY) axi_bvalid<=1'b1; else if(S_AXI_BREADY) axi_bvalid<=1'b0;
//写地址
reg [4:0]addr_word_w;
wire [4:0]addr_word_w_comb;
always @(posedge clk or negedge rst_n)
if(~rst_n) addr_word_w<=0;
else if(S_AXI_AWVALID & S_AXI_AWREADY) addr_word_w<=S_AXI_AWADDR[6:2]; assign addr_word_w_comb=(S_AXI_AWVALID & S_AXI_AWREADY)?S_AXI_AWADDR[6:2]:addr_word_w;
assign S_AXI_AWREADY=1'b1;//S_AXI_AWVALID&S_AXI_WVALID;
//保障写完地址后再写数据
reg w_phase;
always @(posedge clk or negedge rst_n)
if(~rst_n) w_phase<=1'b0;
else if(S_AXI_AWVALID & S_AXI_AWREADY) w_phase<=1; else if(S_AXI_WVALID & S_AXI_WREADY) w_phase<=0; assign S_AXI_WREADY=w_phase;
//读地址,数据
assign S_AXI_ARREADY=1'b1; assign S_AXI_RRESP=2'b0;
reg [32-1:0]rdata;
assign S_AXI_RDATA=rdata;
reg rvalid;
assign S_AXI_RVALID=rvalid;
always @(posedge clk or negedge rst_n)
if(~rst_n)
begin rvalid<=1'b0; rdata<=32'b0;
end
else if(S_AXI_ARVALID & S_AXI_ARREADY) begin rvalid<=1'b1; case(S_AXI_ARADDR[6:2]) 1:rdata<={31'b0,done_r}; 2:rdata<={31'b0,ad1}; 3:rdata<={31'b0,ad2}; 4:rdata<={31'b0,ad3}; 5:rdata<={31'b0,ad4}; 6:rdata<={31'b0,ad5}; 7:rdata<={31'b0,ad6}; 8:rdata<={31'b0,ad7}; 9:rdata<={31'b0,ad8}; 10:rdata<={31'b0,ad9}; 11:rdata<={31'b0,ad10}; 12:rdata<={31'b0,ad11}; 13:rdata<={31'b0,ad12}; 14:rdata<={31'b0,ad13}; 15:rdata<={31'b0,ad14}; 16:rdata<={31'b0,ad15}; 17:rdata<={31'b0,ad16}; default:rdata<=32'b0; endcase end else if(S_AXI_RVALID&S_AXI_RREADY) rvalid<=1'b0; assign start=S_AXI_WVALID & S_AXI_WREADY & (addr_word_w_comb==0) & S_AXI_WDATA[0];
assign rx_en=start;
endmodule
这里在设计时每个寄存器都设计为了32位的,而AD数据只有16位的,所以需要对高位补零。这么设计的原因主要是为了方便地利用地址的[6:2]位确定到底是哪个寄存器(地址的1位,对应于数据的16位),方便SDK软件程序的编写。
打包IP核
需要注意的是需要在AD寄存器模块和SPI主机模块之间加一个FIFO进行数据缓存,FIFO的深度设置为1即可。FIFO采用同步FIFO,且输出输入端口利用握手信号(data_in_rdy,data_in_vld,data_out_rdy,data_out_vld)进行控制。其中data_in_rdy直接置1,data_in_vld由rx_done控制,data_out_rdy直接置1,data_out_vld接到axi_reg模块的data_vld。
最后编写顶层模块(AD),打包成IP核(AD_0)。在顶层模块中需要例化SPI_MASTER、fifo、axi_reg模块。如何打包自定义的IP核可以参考这里。需要注意的是前面的代码已经满足AXI4总线的规范,所以可以自动生成AXI4接口,不需要其他操作。
建立PYNQ工程
建立好的PYNQ系统图如图所示:
如何建工程可以参考这里。
注意,把比特流文件和硬件文件导入Jupyter Notebook就可以使用PYTHON编写驱动和算法了,但是本文为了方便,使用SDK裸机开发。
编写SDK程序
#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"
#include "xparameters.h"
#include "xil_io.h" #define AD_BASEADDR XPAR_AD_0_BASEADDR u32 *rdata;
u32 *rdata1;
u32 *rdata2;
u32 *rdata3;
u32 *rdata4;
u32 *rdata5;
u32 *rdata6;
u32 *rdata7;
u32 *rdata8;
u32 *rdata9;
u32 *rdata10;
u32 *rdata11;
u32 *rdata12;
u32 *rdata13;
u32 *rdata14;
u32 *rdata15;
u32 *rdata16; void wirte_ad(int reg, u32 data)
{ Xil_Out32(AD_BASEADDR+reg*4, data);
} void read_ad(int reg, u32 *data)
{ u32 x; float y; *data=Xil_In32(AD_BASEADDR+reg*4); x=*data&0x7fff;//提取低15位的数据位,16位为符号位y=(float)(x)*5/32758; printf("read reg%d,data:%f\r\n",reg,y);
} void read_ad_reg1(int reg, u32 *data)
{ *data=Xil_In32(AD_BASEADDR+reg*4);
} int main()
{ init_platform(); print("Hello World\n\r"); while(1) { //kick of run wirte_ad(0,1); read_ad_reg1(1,rdata); while(*rdata!=1)//等待SPI传输完成 { read_ad_reg1(1,rdata); } read_ad(2,rdata1); read_ad(3,rdata2); read_ad(4,rdata3); read_ad(5,rdata4); read_ad(6,rdata5); read_ad(7,rdata6); read_ad(8,rdata7); read_ad(9,rdata8); read_ad(10,rdata9); read_ad(11,rdata10); read_ad(12,rdata11); read_ad(13,rdata12); read_ad(14,rdata13); read_ad(15,rdata14); read_ad(16,rdata15); read_ad(17,rdata16); } cleanup_platform(); return 0;
}
上板验证
注意,在两块FPGA烧写好程序后,需要对从机的FPGA进行复位(按一下rst_n信号连接的那个按键)才可以进行可靠传输。
演示图如图所示:
把3.3V接到了第一片AD的第6输入通道,可以看到对应的串口输出的reg7的值为3.3V,实验成功。(reg1为SPI的done信号,reg2存放第一片AD第一个通道的值,所以第一片AD的第6输入通道的值存放在reg7)注意:AD的悬空电压为1.7V.
代码下载地址
https://download.csdn.net/download/qq_34329669/11975542
基于PYNQ的AD采集系统相关推荐
- 基于FPGA的数据采集系统
目录 一.理论基础 二.核心程序 三.测试结果 一.理论基础 数据采集是指将模拟量采集转换成数字量后,再由计算机进行存储.处理.显示或打印的过程,相应的系统称为数据采集系统.随着科技进步,人们对数据采 ...
- 基于互联网的温度采集系统
1 绪论... 1 1.1 课题背景... 1 1.2 研究内容... 1 1.3 发展前景... 1 1.4 研究意义... 2 2. 开发平台介绍... 2 2.1 开发环境... 2 2.2 操 ...
- 基于pynq的数字识别神经网络加速器设计
文章目录 基于pynq的数字识别神经网络加速器设计 软件部分 1. 全连接神经网络: 2. 卷积神经网络搭建: 3. 文件格式转换: 硬件部分 1. MNIST的硬件实现思路 2. 代码编写与硬件综合 ...
- 基于JAVA水质监测数据采集系统计算机毕业设计源码+数据库+lw文档+系统+部署
基于JAVA水质监测数据采集系统计算机毕业设计源码+数据库+lw文档+系统+部署 基于JAVA水质监测数据采集系统计算机毕业设计源码+数据库+lw文档+系统+部署 本源码技术栈: 项目架构:B/S架构 ...
- 基于 PYNQ 的 AXI 总线主从控制编写(ddr3的读写)
菜鸟一枚,最近也学习了关于 AXI 总线的相关知识.基于 PYNQ 编写了一个简单的 AXI 主从控制(牵涉到 DDR3 的读写). 设计目的 设计出以下一个通过 AXI 总线连接的简单片上系统.包含 ...
- 基于MQTT的数据采集系统
基于MQTT的数据采集系统 1.实验目的 本次研究推出一款实用的轻量型智能家居系统,本系统采用STM32为主控芯片,将MQTT通信协议移植到STM32中,将其作为一个MQTTClient.该系统的核心 ...
- stm32ad测量范围_基于STM32F103内部AD测量电池电压
STM32的ADC介绍: STM32 拥有 1~3 个 ADC ( STM32F101/102系列只有1个ADC),这些ADC可以独立使用,也可以使用双重模式(提高采样率).STM32 的 ADC 是 ...
- 基于PYNQ的深度学习模型设计与实现
本人其实做过一段基于ZYNQ的FPGA加速开发,但是后面不了了之了,也不太清楚脉动阵列发展到什么程度了,还有不断从ISE(CHIPSCOPE),到VIVADO(ILA,也包含SG,SDK套件)以及对应 ...
- 基于单片机的数据采集系统
摘 要:本文以AT89C51单片机为核心,设计一个基于单片机的数据采集系统.系统可以采集16路模拟量,精度为12位,16路开关量和2路脉冲量,并将采集到的数据每隔一分钟通过串口发送到PC机. 关键字: ...
最新文章
- 这是一份非常全面的开源数据集!
- Kafka监控架构设计
- github服务器停止响应,如何解决“git pull,致命:无法访问'https://github.com ... \':服务器空回复”...
- Linux 系统启动流程图/系统初始化流程图
- 程序员福利各大平台免费接口,非常适用
- linux文本文件和win文本文件的格式互换
- mysql视图应用_MySQL视图的概念与实际应用
- ORACLE HANDBOOK系列之十:字符集、编码以及Oracle的那些事
- 学习 Message(13): 解析 TWMMouse.Keys 参数
- 消费者价格研究中的数据分析
- JAVA MIDP_Java MIDP2.1和JAVA MIDP2.0的本质区别是什么啊?
- Program Library HOWTO(2)
- RaspberryPI 3b 技术总结(包括Linux)
- JAVA 线程池的分析和使用
- Kotlin习惯用语和编码风格[转自Kotlin中文文档]
- Notepad++删除空白行
- 美妆护肤做短视频,利用选题策划来涨粉?
- 20222817《Linux内核原理与分析》第五周作业
- Ansible playbook
- matlab-基础 复数 实部、虚部、模、共轭、辐角
热门文章
- 《自然-机器智能》:神经形态技术可使大型深度学习网络节能16倍
- ST MCSDK 初探
- BUFF:iPad真的能当砧板用
- 量子计算机需要mK温度工作吗,格林函数法分析冷槽离子量子计算机中的温度效应.pdf...
- Got a packet bigger than 'max_allowed_packet' bytes 问题的解决方法
- 在宜家兼职收银员创收
- 容联云聚客SCRM如何破SCRM保险应用困局
- 1米*1米*1米*1米*1米等于什么?
- 96道前端面试题,作出的职业规划建议
- 脸上有酒窝,脖子后有痣,胸前有颗痣,此三种人不能错过