详解UART通信协议以及FPGA实现

文章目录

  • 一、UART概述
  • 二、UART协议帧格式
    • 2.1 波特率
    • 2.2 奇校验ODD
    • 2.3 偶校验EVEN
  • 三、UART接收器设计
    • 3.1 接收时序图
    • 3.2 Verilog代码
    • 3.3 仿真文件测试
    • 3.4 仿真结果
    • 3.5 上版测试
  • 四、UART发送器设计
    • 4.1 发送时序图
    • 4.2 Verilog代码
    • 4.3 仿真文件测试
    • 4.4 仿真结果
    • 4.5 上板测试
  • 五、UART回环测试
    • 5.1 系统框图
    • 5.2 Verilog代码
    • 5.3 仿真文件测试
    • 5.4 仿真结果
    • 5.5 上板测试
  • 六、参考


一、UART概述

  从《浅谈UART,TTL,RS-232,RS-485的区别》这篇文章,我们知道了UART是一种串行、异步、全双工的通信协议,属于协议层;传输过程一般采用RS-232,RS-485电平标准,将所需传输的数据一位接一位地传输;整体传输框架如下:

在这里插入图片描述
  串口通信由发送端和接收端构成,两根信号线实现,一根数据发送,一根数据接收。

二、UART协议帧格式

  在串口通信过程中,数据接收与发送双方没有共享时钟,因此,双方必须协商好数据传输波特率。根据双方协议好的波特率,接收端即可对发送端的数据进行采样。整个传输流程如下:

  1. 传输线空闲时为高电平,然后拉低一个码元时间表示起始位
  2. 接着传输 8 个数据位,先传输低位,再传输高位
  3. 然后传输一个校验位,用来检测本次传输的数据是否正确
  4. 最后输出高电平表示停止位,可以是 1 位、1.5 位、2 位的高电平,并且进入空闲状态,等待下一次的数据传输

协议帧格式如下:
在这里插入图片描述

2.1 波特率

  根据双方协议好的传输速率,接收端即可对发送端的数据进行采样。如果波特率为 9600也就是相当于每秒中划分成了 9600 等份的码元时间。常见的波特率标准为 300bps,600bps,800bps,9600bps,19200bps,38400bps,115200bps 等。通常对串口进行数据采样,采用更高频的时钟。
  一个码元的计算方法:例如我们采样时钟为 50M ,所使用的波特率为 115200,传输 1个码元需要的时间( 1 / 115200 ) = 8680ns

2.2 奇校验ODD

  使完整编码(有效位和校验位)中的 “1” 的个数为奇数个。如果原来信息中 1 的个数为奇数个,则校验位为 0,这样所有信息中1的个数还是奇数 ;如果原来信息中 1 的个数为偶数个,则校验位为 1,这样所有信息中1的个数还是奇数。
  常见的串口通信格式是(8 位数据位+1 位奇数校验位)。以发送字符:10010101和11010101 为例

数据第0位数据第1位数据第2位数据第3位数据第4位数据第5位数据第6位数据第7位校验位
101010011
101010110

2.3 偶校验EVEN

  使完整编码(有效位和校验位)中的 “1” 的个数为偶数个。如果原来信息中 1 的个数为奇数个,则校验位为 1,这样所有信息中1的个数还是偶数 ;如果原来信息中 1 的个数为偶数个,则校验位为 0,这样所有信息中1的个数还是偶数。
  常见的串口通信格式是(8 位数据位+1 位奇数校验位)。以发送字符:10010101和11010101 为例

数据第0位数据第1位数据第2位数据第3位数据第4位数据第5位数据第6位数据第7位校验位
101010010
101010111

三、UART接收器设计

开发平台:vivado2021.1
开发芯片:xc7a100tfgg484-2

3.1 接收时序图

  本次实现11500波特率,无奇偶校验位,时钟频率为50M,则每个码元计数次数为50000000/115200=434。时序图如下:
在这里插入图片描述

3.2 Verilog代码

`timescale 1ns/1ns
module uart_rx#
(
    parameter CLK_FREQ = 'd50_000_000,  //时钟频率
    parameter UART_BPS = 'd115200       //波特率
) 
(
    input                                               clk ,       
    input                                               rst_n   ,   
    input                                               rx  ,       //uart_rx
    output  reg     [7:0]                               rx_data ,   //uart_rx_data
    output  reg                                         rx_data_valid  //uart_rx_data_valid    
);

    localparam                                          BAUD_CNT_MAX    = CLK_FREQ/UART_BPS ;//一个码元的长度
    localparam                                          BAUD_CNT_MAX_div2   = BAUD_CNT_MAX/2 ;  

    reg                                                 rx_reg1 ;
    reg                                                 rx_reg2 ;
    reg                                                 rx_reg3 ;
    reg                                                 rx_flag ;
    reg             [23:0]                              baud_cnt    ;
    reg             [3:0]                               bit_cnt ;
    reg                                                 bit_flag    ;
    
//打两拍,消除亚稳态
always @(posedge clk, negedge rst_n) begin
    if(rst_n == 1'b0)begin
        rx_reg1 <= 1'b1;
        rx_reg2 <= 1'b1;
    end
    else begin
        rx_reg1 <= rx;
        rx_reg2 <= rx_reg1;
    end
end

//再打一拍用于判断RX下降沿
always @(posedge clk, negedge rst_n) begin
    if(rst_n == 1'b0)
        rx_reg3 <= 1'b1;
    else
        rx_reg3 <= rx_reg2;
    
end

//接收范围
always @(posedge clk, negedge rst_n) begin
    if(rst_n == 1'b0)
        rx_flag <= 1'b0;
    else if (rx_reg3 == 1'b1 && rx_reg2 == 1'b0)
        rx_flag <= 1'b1;
    else if(bit_cnt == 'd8 && bit_flag ==1'b1)
        rx_flag <= 1'b0;
    else
        rx_flag <= rx_flag;
end

//baud_cnt:波特率计数器计数,从 0 计数到 BAUD_CNT_MAX
always @(posedge clk, negedge rst_n) begin
    if(rst_n == 1'b0)
        baud_cnt <= 'd0;
    else if(baud_cnt == BAUD_CNT_MAX || rx_flag == 1'b0)
        baud_cnt <= 'd0;
    else if(rx_flag == 1'b1)
        baud_cnt <= baud_cnt + 1'b1;
    else
        baud_cnt <= baud_cnt;
end

//bit_flag: baud_cnt 计数器计数到码元中间,时采样的数据最稳定
always @(posedge clk, negedge rst_n) begin
    if(rst_n == 1'b0)
        bit_flag <= 1'b0;
    else if(baud_cnt == BAUD_CNT_MAX_div2)
        bit_flag <= 1'b1;
    else
        bit_flag <= 1'b0;
    
end

//bit_cnt:有效数据计数器, 8 个有效数据(不含起始位和停止位)
always @(posedge clk, negedge rst_n) begin
    if(rst_n == 1'b0)
        bit_cnt <= 'd0;
    else if(bit_cnt == 'd8 && bit_flag == 1'b1)
        bit_cnt <= 'd0;
    else if(bit_flag == 1'b1)
        bit_cnt <= bit_cnt + 1'b1;
    else
        bit_cnt <= bit_cnt;
end

//输出数据
always @(posedge clk, negedge rst_n) begin
    if(rst_n == 1'b0)
        rx_data <= 'd0;
    else if(bit_cnt >= 'd1 && bit_flag == 1'b1)
        rx_data <= {rx_reg3,rx_data [7:1]};
    else
        rx_data <= rx_data ;
end

//输出数据有效信号,当接受完8个数据位后拉高
always @(posedge clk, negedge rst_n) begin
    if(rst_n == 1'b0)
        rx_data_valid  <= 1'b0;
    else if(bit_cnt == 'd8 && bit_flag == 1'b1)
        rx_data_valid  <= 1'b1;
    else
        rx_data_valid  <= 1'b0;
end

endmodule

3.3 仿真文件测试

这次仿真文件使用task任务来模拟uart发送数据

`timescale 1ns/1ns
module tb_uart_rx();

    reg                                                 clk ;
    reg                                                 rst_n   ;
    reg                                                 rx  ;
    wire            [7:0]                               rx_data ;
    wire                                                rx_data_valid  ;

    initial begin
        clk = 0;
        rst_n = 0;
        rx = 1;
        #100
        rst_n = 1;
    end

//调用task函数,连续发送八个数据
    initial begin
        #300
        tx_data(8'h6);
        tx_data(8'h6);
        tx_data(8'h1);
        tx_data(8'hA);
        tx_data(8'hB);
        tx_data(8'hC);
        tx_data(8'hD);
        tx_data(8'hE);
        tx_data(8'hF);
    end

//定义task函数
    task tx_data(
        input   [7:0] tx_data
    );
        integer  i;
        for (i=0; i<10; i=i+1 ) begin
            case(i)
            0:  rx <= 1'b0;
            1:  rx <= tx_data[0];
            2:  rx <= tx_data[1];
            3:  rx <= tx_data[2];
            4:  rx <= tx_data[3];
            5:  rx <= tx_data[4];
            6:  rx <= tx_data[5];
            7:  rx <= tx_data[6];
            8:  rx <= tx_data[7];
            9:  rx <= 1'b1;
            endcase
            #(434*20);//每发送完一个bit数据后,延迟一个码元的时间
        end
    endtask

always #10 clk = ~ clk;
uart_rx#(
    .CLK_FREQ ( 'd50_000_000 	),
    .UART_BPS ( 'd115200 		)
)u1_uart_rx
(
    .clk      		( clk      			),
    .rst_n    		( rst_n    			),
    .rx       		( rx       			),
    .rx_data		( rx_data			),
    .rx_data_valid  ( rx_data_valid  	)
);

endmodule

3.4 仿真结果

在这里插入图片描述

  由仿真结果可以看出,我们接收到的依次是(661ABCDEF)8个数据,和仿真文件给的一致。

3.5 上版测试

  调用ila核,准备抓取rx_data,rx_data_valid信号。通过上位机发送数据,观察rx_data是否正确
在这里插入图片描述
  上位机没发送数据时候,ila采集不到rx_data_valid信号拉高。
在这里插入图片描述
  上位机发送一个9F时,ila采集到rx_data_valid信号拉高,并且输出rx_data为9F

四、UART发送器设计

4.1 发送时序图

在这里插入图片描述

4.2 Verilog代码

`timescale 1ns / 1ps
module uart_tx#
(
    parameter CLK_FREQ = 'd50_000_000,  //时钟频率
    parameter UART_BPS = 'd115200       //波特率
)
(
    input                                               clk ,
    input                                               rst_n   ,
    input           [7:0]                               tx_data ,       //发送数据
    input                                               tx_data_en  ,   //发送数据有效信号
    output  reg                                         tx  
);

    localparam                                          BAUD_CNT_MAX    = CLK_FREQ/UART_BPS;//待计数的码元周期最大值
    reg             [7:0]                               tx_data_reg ;
    reg             [23:0]                              baud_cnt    ;
    reg             [3:0]                               bit_cnt ;
    reg                                                 bit_flag    ;
    reg                                                 tx_flag ;

//将待发送的数据缓存起来
always @(posedge clk or negedge rst_n) begin
    if(rst_n == 1'b0)
        tx_data_reg <= 'd0;
    else if(tx_data_en == 1'b1)
        tx_data_reg <= tx_data;
    else
        tx_data_reg <= tx_data_reg;
end

//tx_flag拉高时刻
always @(posedge clk or negedge rst_n) begin
    if(rst_n == 1'b0)
        tx_flag <= 1'b0;
    else if(tx_data_en == 1'b1)
        tx_flag <= 1'b1;
    else if(bit_cnt == 'd9 && bit_flag == 1'b1)
        tx_flag <= 1'b0;
    else
        tx_flag <= tx_flag;
end

//baud_cnt 计数器
always @(posedge clk or negedge rst_n) begin
    if(rst_n == 1'b0)
        baud_cnt <= 'd0;
    else if(baud_cnt == BAUD_CNT_MAX)
        baud_cnt <= 'd0;
    else if(tx_flag == 1'b1)
        baud_cnt <= baud_cnt + 1'b1;
    else
        baud_cnt <= 'd0;
end
//bit_flag拉高时刻
always @(posedge clk or negedge rst_n) begin
    if(rst_n == 1'b0)
        bit_flag <= 1'b0;
    else if(baud_cnt == 'd1)
        bit_flag <= 1'b1;
    else
        bit_flag <= 1'b0;
end

//bit_cnt 计数器
always @(posedge clk or negedge rst_n) begin
    if(rst_n == 1'b0)
        bit_cnt <= 'd0;
    else if(bit_cnt == 'd9 && bit_flag == 1'b1)
        bit_cnt <= 'd0;
    else if(bit_flag == 1'b1)
        bit_cnt <= bit_cnt + 1'b1;
    else
        bit_cnt <= bit_cnt;
end

//移位data,由低到高发送至tx
always @(posedge clk or negedge rst_n) begin
    if(rst_n == 1'b0)
        tx <= 1'b1;
    else if(bit_flag == 1'b1)
        case(bit_cnt)
        0:  tx <= 1'b0;
        1:  tx <= tx_data_reg[0];
        2:  tx <= tx_data_reg[1];
        3:  tx <= tx_data_reg[2];
        4:  tx <= tx_data_reg[3];
        5:  tx <= tx_data_reg[4];
        6:  tx <= tx_data_reg[5];
        7:  tx <= tx_data_reg[6];
        8:  tx <= tx_data_reg[7];
        9:  tx <= 1'b1;
        default:tx <= 1'b1;
        endcase
end

endmodule

4.3 仿真文件测试

  模拟两个数据(1A,3B)的输入,让tx模块发送

`timescale 1ns / 1ns
module tb_uart_tx();

    reg                                                 clk ;
    reg                                                 rst_n   ;
    wire                                                tx  ;
    reg             [7:0]                               tx_data ;
    reg                                                 tx_data_en  ;

    initial begin
        clk = 0;
        rst_n = 0;
        tx_data = 8'd0;
        tx_data_en = 0;
        #100
        rst_n = 1;
        #300
        tx_data = 8'h1a;
        tx_data_en = 1;
        #20 
        tx_data_en = 0;
        #(434*20*10+100)//等待10个码元周期时间再等待100ns
        tx_data = 8'h3b;
        tx_data_en = 1;
        #20 
        tx_data_en = 0;
        #(434*20*10+100)
        $stop;
    end
    
always #10 clk = ~clk;

uart_tx#
(
    .CLK_FREQ    ( 'd50_000_000 ),
    .UART_BPS    ( 'd115200     )
)
u1_uart_tx
(
    .clk         ( clk         ),
    .rst_n       ( rst_n       ),
    .tx_data     ( tx_data     ),
    .tx_data_en  ( tx_data_en  ),
    .tx          ( tx          )
);

endmodule

4.4 仿真结果

在这里插入图片描述
  因为发送数据是(1A:00011010)uart先发送起始位,再发送数据位从低到高,最后拉高一个停止位。理论上tx发送的顺序就是0_01011000_1
  从仿真结果来看,tx线上的顺序和理论一致,3B数据同理。

4.5 上板测试

  我们创建一个顶层,调用uart_tx模块,在顶层上输入一个数据,让发送模块发出,然后在上位机上接送,观察和我们发送的数据是否一致,代码如下:

`timescale 1ns / 1ps


module uart_top(
    input                                               clk ,
    input                                               rst_n   ,
    output                                              tx  
    );

    reg             [7:0]                               tx_data ;
    reg                                                 tx_data_en  ;
    reg             [1:0]                               cnt ;

always @(posedge clk or negedge rst_n) begin
    if(rst_n == 1'b0)
        cnt <= 'd0;
    else if(cnt == 'd3)
        cnt <= cnt;
    else 
        cnt <= cnt +1'b1;
    
end

always @(posedge clk or negedge rst_n) begin
    if(rst_n == 1'b0)begin
        tx_data     <= 'd0;
        tx_data_en  <= 1'b0;
    end
    else if (cnt == 'd2)begin
        tx_data     <= 8'h6D;
        tx_data_en  <= 1'b1;
    end
    else begin
        tx_data     <= 'd0;
        tx_data_en  <= 1'b0;
    end

end

uart_tx#
(
    .CLK_FREQ    ( 'd50_000_000 ),
    .UART_BPS    ( 'd115200 	)
)
u_uart_tx
(
    .clk         ( clk         ),
    .rst_n       ( rst_n       ),
    .tx_data     ( tx_data     ),
    .tx_data_en  ( tx_data_en  ),
    .tx          ( tx          )
);

endmodule

  我们在顶层模块发送了一个 6D数据。

在这里插入图片描述
上板后,上位机收到了 6D数据

五、UART回环测试

5.1 系统框图

  上面我们测试了UART发送和接收模块都正常,接下来我们将接收模块的输出信号接到发送模块的输入信号,在上位机上面发送数据和接收数据,看是否一致,系统框图如下:
在这里插入图片描述

5.2 Verilog代码

`timescale 1ns / 1ps

module uart_top(
    input                                               clk ,
    input                                               rst_n   ,
    input                                               rx  ,
    output                                              tx  
    );

    wire             [7:0]                               rx_data ;
    wire                                                 rx_data_valid  ;


uart_rx#
(
    .CLK_FREQ ( 'd50_000_000    ),
    .UART_BPS ( 'd115200        )    
)
u_uart_rx(
    .clk            ( clk               ),
    .rst_n          ( rst_n             ),
    .rx             ( rx                ),
    .rx_data        ( rx_data           ),
    .rx_data_valid  ( rx_data_valid     )
);


uart_tx#
(
    .CLK_FREQ    ( 'd50_000_000 ),
    .UART_BPS    ( 'd115200     )
)
u_uart_tx
(
    .clk         ( clk              ),
    .rst_n       ( rst_n            ),
    .tx_data     ( rx_data          ),
    .tx_data_en  ( rx_data_valid    ),
    .tx          ( tx               )
);

endmodule

5.3 仿真文件测试

  我们依然用uart_rx里的测试代码,调用task函数,发送661abcdef

`timescale 1ns / 1ps
module tb_uart_top();

    reg                                                 clk ;
    reg                                                 rst_n   ;
    reg                                                 rx  ;
    wire                                                tx  ;

initial begin
        clk = 0;
        rst_n = 0;
        rx = 1;
        #100
        rst_n = 1;
    end

//调用task函数,连续发送八个数据
    initial begin
        #300
        tx_data(8'h6);
        tx_data(8'h6);
        tx_data(8'h1);
        tx_data(8'hA);
        tx_data(8'hB);
        tx_data(8'hC);
        tx_data(8'hD);
        tx_data(8'hE);
        tx_data(8'hF);
    end

//定义task函数
    task tx_data(
        input   [7:0] tx_data
    );
        integer  i;
        for (i=0; i<10; i=i+1 ) begin
            case(i)
            0:  rx <= 1'b0;
            1:  rx <= tx_data[0];
            2:  rx <= tx_data[1];
            3:  rx <= tx_data[2];
            4:  rx <= tx_data[3];
            5:  rx <= tx_data[4];
            6:  rx <= tx_data[5];
            7:  rx <= tx_data[6];
            8:  rx <= tx_data[7];
            9:  rx <= 1'b1;
            endcase
            #(434*20);//每发送完一个bit数据后,延迟一个码元的时间
        end
    endtask

always #10 clk  =~clk;
uart_top u_uart_top(
    .clk    ( clk    ),
    .rst_n  ( rst_n  ),
    .rx     ( rx     ),
    .tx     ( tx     )
);

endmodule

5.4 仿真结果

在这里插入图片描述
可以看出接收后的数据和发送的数据没问题

5.5 上板测试

在这里插入图片描述
可以看到发送和接收都正常

六、参考


UART介绍

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/550306.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

HarmonyOS开发实战:【亲子拼图游戏】

概述 本篇Codelab是基于TS扩展的声明式开发范式编程语言编写的一个分布式益智拼图游戏&#xff0c;可以两台设备同时开启一局拼图游戏&#xff0c;每次点击九宫格内的图片&#xff0c;都会同步更新两台设备的图片位置。效果图如下&#xff1a; 说明&#xff1a; 本示例涉及使…

2016NOIP普及组真题 1. 金币

线上OJ&#xff1a; 一本通&#xff1a;http://ybt.ssoier.cn:8088/problem_show.php?pid1969 核心思想&#xff1a; 解法1、由于数据量只有 10000 天&#xff0c;估可以采用 模拟每一天 的方式。 #include <bits/stdc.h> using namespace std;int k 0;int main() {i…

SpringBoot项目基于java的教学辅助平台

采用技术 SpringBoot项目基于java的教学辅助平台的设计与实现~ 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SpringBootMyBatis 工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 页面展示效果 学生信息管理 教师信息管理 课程信息管理 科目分类管…

【面试经典 150 | 链表】K 个一组翻转链表

文章目录 写在前面Tag题目来源解题思路方法一&#xff1a;迭代 写在最后 写在前面 本专栏专注于分析与讲解【面试经典150】算法&#xff0c;两到三天更新一篇文章&#xff0c;欢迎催更…… 专栏内容以分析题目为主&#xff0c;并附带一些对于本题涉及到的数据结构等内容进行回顾…

xxl-job使用自动注册节点,ip不对,如何解决????

很明显这时我们本机的ip和我们xxl-job自动注册的ip是不一致的&#xff0c;此时该如何处理呢&#xff1f;&#xff1f;&#xff1f;&#xff1f; 方法一&#xff1a;在配置文件中&#xff0c;将我们的ip固定写好。 ### xxl-job executor server-info xxl.job.executor.ip写你的…

pandas基本用法

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、pandas的数据结构1、一维数组pd.Series1.1 pd.Series&#xff08;data,index,dtype&#xff09;示例1&#xff1a;不定义index示例2&#xff1a;自定义inde…

基于HMM隐马尔可夫模型的金融数据预测算法matlab仿真

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.本算法原理 5.完整程序 1.程序功能描述 基于HMM隐马尔可夫模型的金融数据预测算法.程序实现HMM模型的训练&#xff0c;使用训练后的模型进行预测。 2.测试软件版本以及运行结果展示 MATLAB2022A版本运…

excel 无法正确处理 1900-03-01 前的日期

问题由来&#xff1a;excel 用公式 TEXT(A1,"yyyy-mm-dd") 转日期时&#xff0c;当A1 的值等于59 的时候&#xff0c;返回值是1900-02-28&#xff1b;当A1 的值等于61 的时候&#xff0c;返回值是1900-03-01&#xff1b;那么当 A1的值为 60 的时候&#xff0c;返回值…

数图智慧零售解决方案,赋能零售行业空间资源价值最大化

数图智慧零售解决方案 赋能零售行业空间资源价值最大 在激烈的市场竞争中&#xff0c;如何更好地提升空间资源价值&#xff0c;提高销售额&#xff0c;成为行业关注的焦点。近日&#xff0c;NIQ发布的《2024年中国饮料行业趋势与展望》称&#xff0c;“在传统零售业态店内&…

第十一章数据仓库和商务智能10分

【数据仓库-后端&#xff0c;商务智能-前端】 基本算法&#xff1a;关联关系&#xff08;牵手-谈恋爱&#xff09;&#xff0c;集群关系&#xff08;杭州人爱吃酸甜口&#xff09;&#xff0c;决策树&#xff0c;线性回归&#xff0c;贝叶斯&#xff0c;神经网络&#xff0c;时…

Adobe AE(After Effects)2015下载地址及安装教程

Adobe After Effects是一款专业级别的视觉效果和动态图形处理软件&#xff0c;由Adobe Systems开发。它被广泛用于电影、电视节目、广告和其他多媒体项目的制作。 After Effects提供了强大的合成和特效功能&#xff0c;可以让用户创建出令人惊艳的动态图形和视觉效果。用户可以…

使用大模型来实现医疗领域的隐私信息保护

大模型隐私主要分为训练阶段、推理阶段以及用户与大模型交互过程中的隐私泄露&#xff0c;目前的研究重点在大模型训练阶段。传统隐私保护技术主要包括联邦学习、差分隐私、同态加密等&#xff0c;这些技术在大模型背景下的应用挑战不断加剧&#xff1a;(1)联邦学习应用于大模型…

ArkTs

一、概述 ArkTs是由TypeScript扩展而来&#xff0c;在继承TypeScript语法的基础上进行了一系列优化&#xff0c;使开发者能够以更简洁、更自然的方式开发应用。 TypeScript语法: 线上网站:https://www.typescriptlang.org/zh/play 二、TS变量 变量声明: 常量声明: const b…

【高端电流检测IC储能产品应用方案】耐压45V侧轨的电流检测芯片FP137 应用于电脑电源,开关电源以及多口快充充电器,户外移动电源,适配器,电池充电器等

近年来&#xff0c;随着电子产品的飞速发展&#xff0c;对电流检测精度和可靠性的要求也越来越高。特别是在电脑电源、开关电源以及多口快充充电器、户外移动电源、适配器、电池充电器等领域&#xff0c;对电流检测技术的需求更是日益增长。 电流检测芯片是一种关键的电子元器…

强化学习(三)基于动态规划 Dynamic Programming 的求解方法

文章目录 1. 动态规划与强化学习的联系2. 利用动态规划求解最优价值函数2.1 案例背景2.2 策略评估&#xff08;预测&#xff09;2.3 策略迭代&#xff08;控制&#xff09; 在前文《强化学习的数学框架&#xff1a;马尔科夫决策过程 MDP》中&#xff0c;我们用马尔可夫过程抽象…

STM32 软件I2C方式读取MT6701磁编码器获取角度例程

STM32 软件I2C方式读取MT6701磁编码器获取角度例程 &#x1f4cd;相关篇《STM32 软件I2C方式读取AS5600磁编码器获取角度例程》&#x1f33f;《Arduino通过I2C驱动MT6701磁编码器并读取角度数据》&#x1f530;MT6701芯片和AS5600从软件读取对比&#xff0c;只是读取的寄存器和…

Adobe AE(After Effects)2024下载地址及安装教程

Adobe After Effects是一款专业级别的视觉效果和动态图形处理软件&#xff0c;由Adobe Systems开发。它被广泛用于电影、电视节目、广告和其他多媒体项目的制作。 After Effects提供了强大的合成和特效功能&#xff0c;可以让用户创建出令人惊艳的动态图形和视觉效果。用户可以…

【OpenGL实验】在python、Qt5、pyOpenGL程序的若干要点

实验效果图&#xff1a; 代码 目录 一、说明二、关于QGLWidget2.1 三个方便的虚函数2.2 析构函数2.3 QGLWidget析构函数 三、关于QGLWidget的三个虚函数分工3.1 initializeGL&#xff1a;数据准备、数据绑定分离3.2 resizeGL&#xff1a;视角改变函数3.3 paintGL&#xff1a;…

苍穹外卖分类管理

分析 需求分析 SQL的写法 1 在mapper中写 2 在xml中写 Mapper public interface CategoryMapper {/*** 插入数据* param category*/AutoFill(OperationType.INSERT)Insert("insert into category(type, name, sort, status, create_time, update_time, create_user, upd…

docker安装并跑通QQ机器人实践(2)-签名服务器bs-qsign搭建

在前文中&#xff0c;我们详尽阐述了QQ机器人的搭建过程及其最终实现的各项功能展示。接下来&#xff0c;我们将转向探讨该项目基于Docker构建服务的具体实践。本篇将以QQ机器人签名服务——qsign为起点&#xff0c;逐步展开论述。 1 获取和运行 xzhouqd/qsign:8.9.63 镜像 1.…