FPGADDS信号发生器+串口调频(设置精确到1HZ)
1)实验目的:FPGA 实现 DDS,可采用 IP 核/串口设置两种方式(二选一) , 实现任意波形、 频率发生器 。
2)实验平台:ALINIX黑金AX301开发板,芯片型号:ALTERA 公司的 Cyclone IV 系列 FPGA,型号为 EP4CE6F17C8, 芯片封装为FBGA,AN108ADDA模块。
3)实验原理:FPGA 程序要输出 8 位的正弦波数据给 AD/DA 模块, 使 AD/DA 模块的 DA 输出一个正弦波信号,这个正弦波信号通过 BNC 线又输入到 AD 电路, 程序读取 AD 的数据输出显示在 Signaltap 界面中。 在这里我们需要用到 FPGA 内部的 ROM 来存储正选波的数据。
3-1使用相应软件生成ROM的初始化.mif文件,本实验采用的数据长度为256,数据位宽为8(由AD/DA模块决定),生成后点击保存,存至相应的工程文件夹同一目录。
3-2在工程中生成romIP核来存储数据,详细设置如下,注意最后一栏设置要生成_inst.v文件便于例化模块:
(由于本实验需要变换波形,所以存了3种波形数据,三角波、方波、正弦波)
3-2本实验采用按键更改波形AX301的按键电路特性为:按键没有按下的时候,连接到 FPGA 管脚的按键信号的电平为高,当有按键按下的时候,连接到 FPGA 管脚的此按键信号的电平被拉低。
按键模块大体思路为使用一个4位寄存器,存取按键的值,考虑到按键消抖问题使用双重锁存,led_r1为最终按键数据。代码如下。
1 `timescale 1ns / 1ps 2 module key_test 3 ( 4 clk, //system clock 50Mhz on board 5 key, //input four key signal,when the keydown,the value is 0 6 led //LED display ,when the siganl high,LED lighten 7 ); 8 9 10 input clk; //system clock 50Mhz on board 11 input [3:0] key; //input four key signal,when the keydown,the value is 0 12 output[3:0] led; 13 14 15 16 reg[3:0] led_r; //define the first stage register , generate four D Flip-flop 17 reg[3:0] led_r1; //define the second stage register ,generate four D Flip-flop 18 always@(posedge clk) 19 begin 20 led_r <= ~key; //first stage latched data 21 end 22 23 always@(posedge clk) 24 begin 25 led_r1 <= led_r; //second stage latched data 26 end 27 28 assign led = led_r1; 29 30 endmodule
3-3本实验使用串口改频率,黑金的例程分uart_rx和uart_tx为接收和发送模块,并使用uart_test作为前两模块的应用模块,串口收发的详解以及各个接口的作用详细见教程。附上代码,读者可尝试理解。
1 module uart_rx 2 #( 3 parameter CLK_FRE = 50, //clock frequency(Mhz) 4 parameter BAUD_RATE = 115200 //serial baud rate 5 ) 6 ( 7 input clk, //clock input 8 input rst_n, //asynchronous reset input, low active 9 output reg[7:0] rx_data, //received serial data 10 output reg rx_data_valid, //received serial data is valid 11 input rx_data_ready, //data receiver module ready 12 input rx_pin //serial data input 13 ); 14 //calculates the clock cycle for baud rate 15 localparam CYCLE = CLK_FRE * 1000000 / BAUD_RATE; 16 //state machine code 17 localparam S_IDLE = 1; 18 localparam S_START = 2; //start bit 19 localparam S_REC_BYTE = 3; //data bits 20 localparam S_STOP = 4; //stop bit 21 localparam S_DATA = 5; 22 23 reg[2:0] state; 24 reg[2:0] next_state; 25 reg rx_d0; //delay 1 clock for rx_pin 26 reg rx_d1; //delay 1 clock for rx_d0 27 wire rx_negedge; //negedge of rx_pin 28 reg[7:0] rx_bits; //temporary storage of received data 29 reg[15:0] cycle_cnt; //baud counter 30 reg[2:0] bit_cnt; //bit counter 31 32 assign rx_negedge = rx_d1 && ~rx_d0; 33 34 always@(posedge clk or negedge rst_n) 35 begin 36 if(rst_n == 1'b0) 37 begin 38 rx_d0 <= 1'b0; 39 rx_d1 <= 1'b0; 40 end 41 else 42 begin 43 rx_d0 <= rx_pin; 44 rx_d1 <= rx_d0; 45 end 46 end 47 48 49 always@(posedge clk or negedge rst_n) 50 begin 51 if(rst_n == 1'b0) 52 state <= S_IDLE; 53 else 54 state <= next_state; 55 end 56 57 always@(*) 58 begin 59 case(state) 60 S_IDLE: 61 if(rx_negedge) 62 next_state <= S_START; 63 else 64 next_state <= S_IDLE; 65 S_START: 66 if(cycle_cnt == CYCLE - 1)//one data cycle 67 next_state <= S_REC_BYTE; 68 else 69 next_state <= S_START; 70 S_REC_BYTE: 71 if(cycle_cnt == CYCLE - 1 && bit_cnt == 3'd7) //receive 8bit data 72 next_state <= S_STOP; 73 else 74 next_state <= S_REC_BYTE; 75 S_STOP: 76 if(cycle_cnt == CYCLE/2 - 1)//half bit cycle,to avoid missing the next byte receiver 77 next_state <= S_DATA; 78 else 79 next_state <= S_STOP; 80 S_DATA: 81 if(rx_data_ready) //data receive complete 82 next_state <= S_IDLE; 83 84 /*************串口接收结束******************* 85 rx_data<=8'd0; 86 /*******************************************/ 87 else 88 next_state <= S_DATA; 89 default: 90 next_state <= S_IDLE; 91 endcase 92 end 93 94 always@(posedge clk or negedge rst_n) 95 begin 96 if(rst_n == 1'b0) 97 rx_data_valid <= 1'b0; 98 else if(state == S_STOP && next_state != state) 99 rx_data_valid <= 1'b1; 100 else if(state == S_DATA && rx_data_ready) 101 rx_data_valid <= 1'b0; 102 end 103 104 always@(posedge clk or negedge rst_n) 105 begin 106 if(rst_n == 1'b0) 107 rx_data <= 8'd0; 108 else if(state == S_STOP && next_state != state) 109 rx_data <= rx_bits;//latch received data 110 end 111 112 always@(posedge clk or negedge rst_n) 113 begin 114 if(rst_n == 1'b0) 115 begin 116 bit_cnt <= 3'd0; 117 end 118 else if(state == S_REC_BYTE) 119 if(cycle_cnt == CYCLE - 1) 120 bit_cnt <= bit_cnt + 3'd1; 121 else 122 bit_cnt <= bit_cnt; 123 else 124 bit_cnt <= 3'd0; 125 end 126 127 128 always@(posedge clk or negedge rst_n) 129 begin 130 if(rst_n == 1'b0) 131 cycle_cnt <= 16'd0; 132 else if((state == S_REC_BYTE && cycle_cnt == CYCLE - 1) || next_state != state) 133 cycle_cnt <= 16'd0; 134 else 135 cycle_cnt <= cycle_cnt + 16'd1; 136 end 137 //receive serial data bit data 138 always@(posedge clk or negedge rst_n) 139 begin 140 if(rst_n == 1'b0) 141 rx_bits <= 8'd0; 142 else if(state == S_REC_BYTE && cycle_cnt == CYCLE/2 - 1) 143 rx_bits[bit_cnt] <= rx_pin; 144 else 145 rx_bits <= rx_bits; 146 end 147 endmodule
1 module uart_tx 2 #( 3 parameter CLK_FRE = 50, //clock frequency(Mhz) 4 parameter BAUD_RATE = 115200 //serial baud rate 5 ) 6 ( 7 input clk, //clock input 8 input rst_n, //asynchronous reset input, low active 9 input[7:0] tx_data, //data to send 10 input tx_data_valid, //data to be sent is valid 11 output reg tx_data_ready, //send ready 12 output tx_pin //serial data output 13 ); 14 //calculates the clock cycle for baud rate 15 localparam CYCLE = CLK_FRE * 1000000 / BAUD_RATE; 16 //state machine code 17 localparam S_IDLE = 1; 18 localparam S_START = 2;//start bit 19 localparam S_SEND_BYTE = 3;//data bits 20 localparam S_STOP = 4;//stop bit 21 reg[2:0] state; 22 reg[2:0] next_state; 23 reg[15:0] cycle_cnt; //baud counter 24 reg[2:0] bit_cnt;//bit counter 25 reg[7:0] tx_data_latch; //latch data to send 26 reg tx_reg; //serial data output 27 assign tx_pin = tx_reg; 28 always@(posedge clk or negedge rst_n) 29 begin 30 if(rst_n == 1'b0) 31 state <= S_IDLE; 32 else 33 state <= next_state; 34 end 35 36 always@(*) 37 begin 38 case(state) 39 S_IDLE: 40 if(tx_data_valid == 1'b1) 41 next_state <= S_START; 42 else 43 next_state <= S_IDLE; 44 S_START: 45 if(cycle_cnt == CYCLE - 1) 46 next_state <= S_SEND_BYTE; 47 else 48 next_state <= S_START; 49 S_SEND_BYTE: 50 if(cycle_cnt == CYCLE - 1 && bit_cnt == 3'd7) 51 next_state <= S_STOP; 52 else 53 next_state <= S_SEND_BYTE; 54 S_STOP: 55 if(cycle_cnt == CYCLE - 1) 56 next_state <= S_IDLE; 57 else 58 next_state <= S_STOP; 59 default: 60 next_state <= S_IDLE; 61 endcase 62 end 63 always@(posedge clk or negedge rst_n) 64 begin 65 if(rst_n == 1'b0) 66 begin 67 tx_data_ready <= 1'b0; 68 end 69 else if(state == S_IDLE) 70 if(tx_data_valid == 1'b1) 71 tx_data_ready <= 1'b0; 72 else 73 tx_data_ready <= 1'b1; 74 else if(state == S_STOP && cycle_cnt == CYCLE - 1) 75 tx_data_ready <= 1'b1; 76 end 77 78 79 always@(posedge clk or negedge rst_n) 80 begin 81 if(rst_n == 1'b0) 82 begin 83 tx_data_latch <= 8'd0; 84 end 85 else if(state == S_IDLE && tx_data_valid == 1'b1) 86 tx_data_latch <= tx_data; 87 88 end 89 90 always@(posedge clk or negedge rst_n) 91 begin 92 if(rst_n == 1'b0) 93 begin 94 bit_cnt <= 3'd0; 95 end 96 else if(state == S_SEND_BYTE) 97 if(cycle_cnt == CYCLE - 1) 98 bit_cnt <= bit_cnt + 3'd1; 99 else 100 bit_cnt <= bit_cnt; 101 else 102 bit_cnt <= 3'd0; 103 end 104 105 106 always@(posedge clk or negedge rst_n) 107 begin 108 if(rst_n == 1'b0) 109 cycle_cnt <= 16'd0; 110 else if((state == S_SEND_BYTE && cycle_cnt == CYCLE - 1) || next_state != state) 111 cycle_cnt <= 16'd0; 112 else 113 cycle_cnt <= cycle_cnt + 16'd1; 114 end 115 116 always@(posedge clk or negedge rst_n) 117 begin 118 if(rst_n == 1'b0) 119 tx_reg <= 1'b1; 120 else 121 case(state) 122 S_IDLE,S_STOP: 123 tx_reg <= 1'b1; 124 S_START: 125 tx_reg <= 1'b0; 126 S_SEND_BYTE: 127 tx_reg <= tx_data_latch[bit_cnt]; 128 default: 129 tx_reg <= 1'b1; 130 endcase 131 end 132 133 endmodule
以下为顶层应用模块的代码,输入为时钟clk,复位信号rst_n,uart_rx为信号接收端口,uart_tx为信号发送端口,receive_data为存储接收到的数据,rxflag为数据接收标志位,接收数据完成置1,平常为0。
顶层为串口收发底层模块的例化。
1 //注意每次只能接收8bit的数据并且保存,如果数据大于8位的话会直接进行数据更新 2 3 module uart_test( 4 clk, 5 rst_n, 6 uart_rx, 7 uart_tx, 8 receive_data, 9 rxflag 10 ); 11 12 output [7:0] receive_data; 13 output rxflag; 14 assign receive_data=rx_data; 15 assign rxflag=rx_data_valid; 16 17 input clk; 18 input rst_n; 19 input uart_rx; 20 output uart_tx; 21 22 parameter CLK_FRE = 50;//Mhz 23 localparam IDLE = 0; 24 localparam SEND = 1; //send HELLO ALINX\r\n 25 localparam WAIT = 2; //wait 1 second and send uart received data 26 reg[7:0] tx_data; 27 reg[7:0] tx_str; 28 reg tx_data_valid; 29 wire tx_data_ready; 30 reg[7:0] tx_cnt; 31 wire[7:0] rx_data; 32 wire rx_data_valid; 33 wire rx_data_ready; 34 reg[31:0] wait_cnt; 35 reg[3:0] state; 36 37 assign rx_data_ready = 1'b1;//always can receive data, 38 //if HELLO ALINX\r\n is being sent, the received data is discarded 39 40 always@(posedge clk or negedge rst_n) 41 begin 42 if(rst_n == 1'b0) 43 begin 44 wait_cnt <= 32'd0; 45 tx_data <= 8'd0; 46 state <= IDLE; 47 tx_cnt <= 8'd0; 48 tx_data_valid <= 1'b0; 49 end 50 else 51 case(state) 52 IDLE: 53 state <= SEND; 54 SEND: 55 begin 56 wait_cnt <= 32'd0; 57 tx_data <= tx_str; 58 59 if(tx_data_valid == 1'b1 && tx_data_ready == 1'b1 && tx_cnt < 8'd12)//Send 12 bytes data 60 begin 61 tx_cnt <= tx_cnt + 8'd1; //Send data counter 62 end 63 else if(tx_data_valid && tx_data_ready)//last byte sent is complete 64 begin 65 tx_cnt <= 8'd0; 66 tx_data_valid <= 1'b0; 67 state <= WAIT; 68 end 69 else if(~tx_data_valid) 70 begin 71 tx_data_valid <= 1'b1; 72 end 73 end 74 WAIT: 75 begin 76 wait_cnt <= wait_cnt + 32'd1; 77 78 if(rx_data_valid == 1'b1) 79 begin 80 tx_data_valid <= 1'b1; 81 tx_data <= rx_data; // send uart received data 发送接收到的数据 82 end 83 else if(tx_data_valid && tx_data_ready) 84 begin 85 tx_data_valid <= 1'b0; 86 end 87 //else if(wait_cnt >= CLK_FRE * 1000000) // wait for 1 second and back to send state 88 //state <= SEND; 89 end 90 default: 91 state <= IDLE; 92 endcase 93 end 94 95 //combinational logic 96 //Send "HELLO ALINX\r\n" 97 always@(*) 98 begin 99 case(tx_cnt) 100 8'd0 : tx_str <= "H"; 101 8'd1 : tx_str <= "E"; 102 8'd2 : tx_str <= "L"; 103 8'd3 : tx_str <= "L"; 104 8'd4 : tx_str <= "O"; 105 8'd5 : tx_str <= " "; 106 8'd6 : tx_str <= "A"; 107 8'd7 : tx_str <= "L"; 108 8'd8 : tx_str <= "I"; 109 8'd9 : tx_str <= "N"; 110 8'd10: tx_str <= "X"; 111 8'd11: tx_str <= "\r"; 112 8'd12: tx_str <= "\n"; 113 default:tx_str <= 8'd0; 114 endcase 115 end 116 117 uart_rx#//如果只要接收的话应该只需要这个模块就行 118 ( 119 .CLK_FRE(CLK_FRE), 120 .BAUD_RATE(115200) 121 ) uart_rx_inst 122 ( 123 .clk (clk ), 124 .rst_n (rst_n ), 125 .rx_data (rx_data ), 126 .rx_data_valid (rx_data_valid ), 127 .rx_data_ready (rx_data_ready ), 128 .rx_pin (uart_rx ) 129 ); 130 131 uart_tx# 132 ( 133 .CLK_FRE(CLK_FRE), 134 .BAUD_RATE(115200) 135 ) uart_tx_inst 136 ( 137 .clk (clk ), 138 .rst_n (rst_n ), 139 .tx_data (tx_data ), 140 .tx_data_valid (tx_data_valid ), 141 .tx_data_ready (tx_data_ready ), 142 .tx_pin (uart_tx ) 143 ); 144 endmodule
3-4频率的控制使用相位累加器,具体原理可以参考底部模块。使用freqctrl1的最高8位用于频率控制以提高输出频率的精度,相位累加器代码如下:
1 `timescale 1ns/1ps 2 module addr_ctrl( 3 input wire clk_50M, 4 input wire rst_n, 5 output wire [7:0] addr, 6 7 8 input wire [31:0] freqctrl//频率控制字 9 10 ); 11 reg [31:0] cnt; 12 assign addr = cnt[31:24]; 13 14 always@(posedge clk_50M,negedge rst_n) 15 begin 16 if(rst_n==0) 17 cnt<=0; 18 else 19 cnt<=cnt+freqctrl; 20 21 end 22 endmodule
3-4工程顶层模块
代码如下
1 `timescale 1ns/1ps 2 module adda_out( 3 input clk, 4 output wire [7:0] dacdata, 5 output dac_clk, 6 7 8 input [3:0] key_in, 9 10 11 input uart_rx,//串口通信相关 12 output uart_tx 13 14 ); 15 wire rst_n=key_in[0]; 16 17 wire [7:0] rom_address;//例化的输出只能为wire型 18 assign dac_clk=clk; 19 20 21 22 initial 23 begin 24 25 truefre=60'd0; 26 27 end 28 29 30 /***********************************************/ 31 reg [3:0] key;//检测按键是否按下 32 wire[3:0] flag; 33 34 //按键状态锁存 35 always@(negedge clk) 36 begin 37 if(flag==4'b1000) 38 begin 39 key<=4'b1000; 40 end 41 else if (flag==4'b0100) 42 begin 43 key<=4'b0100; 44 end 45 else if (flag==4'b0010) 46 begin 47 key<=4'b0010; 48 end 49 end 50 /***********波形选择*************************/ 51 wire [7:0] rom_data; 52 wire [7:0] rom_datarec;//save rec 53 wire [7:0] rom_datatri;//save tri 54 reg [7:0] save_data;//存储选择的输出的波形 55 assign dacdata = save_data;//get rom data 56 57 58 always @(negedge clk) 59 begin 60 if(key==4'b1000 ) 61 begin 62 save_data<=rom_data; 63 end 64 else if(key==4'b0100 ) 65 begin 66 save_data<=rom_datarec; 67 end 68 else if(key==4'b0010 ) 69 begin 70 save_data<=rom_datatri; 71 end 72 end 73 /**************频率控制*********************** 74 75 ***********串口通信相关************************/ 76 wire [7:0] receive_data; //存储串口得到的数据 77 reg [59:0] truefre; 78 wire rxflag;//判断数据是否接收完毕 79 //计算公式:fre=2^32*F(希望得到的频率)*TCLK(时钟源的周期,此处为20ns) 80 81 82 always@(negedge clk) 83 begin 84 if(rxflag==1'b1) 85 begin 86 if( receive_data>=8'd48 && receive_data<=8'd57) 87 begin 88 truefre<=truefre*10+receive_data-8'd48; 89 end 90 else if(receive_data==8'd115) 91 92 begin 93 truefre<=truefre*8589934/100000;//注意数据溢出 94 end 95 96 else 97 98 begin 99 truefre<=60'd0; 100 end 101 102 end 103 104 105 end 106 /**************模块例化过程*******************/ 107 108 addr_ctrl addr_ctrl_inst( 109 .clk_50M(clk), 110 .rst_n(rst_n), 111 .addr(rom_address), 112 .freqctrl(truefre[31:0]) 113 114 ); 115 116 sin sin_inst( 117 .clock(clk), 118 .address(rom_address), 119 .q(rom_data) 120 121 ); 122 123 124 125 rec rec_inst( 126 .clock(clk), 127 .address(rom_address), 128 .q(rom_datarec) 129 130 131 ); 132 133 tri_x tri_x_inst( 134 .clock(clk), 135 .address(rom_address), 136 .q(rom_datatri) 137 ); 138 139 key_test key_test_inst( //key模块例化 140 .clk(clk), 141 .key(key_in), 142 .led(flag) 143 ); 144 145 uart_test uart_test_inst( 146 .clk(clk), 147 .rst_n(key_in[0]), 148 .uart_rx(uart_rx), 149 .uart_tx(uart_tx), 150 .receive_data(receive_data), 151 .rxflag(rxflag) 152 ); 153 154 155 endmodule
主要注意点为:
1.truefre作为频率控制寄存器,设为60位主要考虑到 (88行和93行)数据相乘过大可能造成数据溢出,而设成的位数较多可以避免数据溢出,而调用时只需要将truefre的低32位接入相位累加器模块即可。
2.uart_test的模块例化,rxflag为数据接收的判断位,在82~102行为串口接收的数据处理,save_data[7:0]为接收到的数据单字节数据。
rxflag=1,确认接收到数据之后判断,如果为‘0’~‘9’接收到数字,则truefre*10并加上接收到的单字节字符,若接收到's',ASCII码为115则认一次接收数据结束,并重新设置频率。(当然也可以用典型的状态机实现)
如果接收到非以上几种情况则将之前的数据清空避免重复叠加。
4)实验结果:
成功实现2MHZ内精确的频率设置(2MHZ内精确到1HZ应该是没问题的,但是示波器2M时精确度的小数位数未设置所以不能直接观察到),并通过按键来实现3种频率的转换。以下为实际效果图。
参考的DDS原理博客:https://www.cnblogs.com/fendoudexiaohai/p/9504027.html
https://www.cnblogs.com/fendoudexiaohai/archive/2004/01/13/9506170.html
原文地址:https://www.cnblogs.com/sars1003/p/13680226.html
- Enterprise Library 4 数据访问应用程序块
- 替换EnterPrise Library 4.0 缓存应用程序块的CacheManager
- Enterprise Library 4.0缓存应用程序块
- 通过.htaccess 让WordPress 的上传文件夹更安全
- asp.net 性能调较
- 零基础学习大数据,搭建Hadoop处理环境
- 为你的WordPress 博客开启两步验证功能(技术支持:谷歌)
- 为你的WordPress 博客开启两步验证功能(技术支持:谷歌)
- WordPress 注册页面显示自定义提示信息
- Windows Server 2008密码重设盘
- Dynamite动态排序库
- WordPress 顶部管理工具条添加自定义栏目
- WordPress 在后台文章和页面列表显示对应的ID
- WordPress 修改默认的 wp_ 数据库前缀
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 重磅 | 青藤与腾讯安全隆重举办容器安全平台新品战略合作发布会
- 如何使用强化学习玩21点?
- 这3个Scikit-learn的特征选择技术,能够有效的提高你的数据预处理能力
- 使用神经网络解决拼图游戏
- 用机器学习预测收益
- 一种基于深度学习的低成本细胞生物学研究方法
- 从零搭建Spring Boot脚手架(2):增加通用的功能
- Qt官方示例-K线图
- 一个快速构造GAN的教程:如何用pytorch构造DCGAN
- 从0到1开发测试平台(八)后端服务添加lombok第三方类库
- 【CSS】470- 是时候开始用 CSS 自定义属性了
- 一个安卓App,如何成为DuerOS 上的技能应用呢?
- 什么是SPU、SKU、SKC、ARPU
- C++判断类型的模板
- 强化学习/增强学习/再励学习介绍 | 深度学习 | 干货分享 | 解读技术