深度强化学习入门(待修改)

目录

前言

一、强化学习

1.马可洛夫链

2.蒙地卡罗

3.时序差分TD

 4.gym学习​编辑

FrozenLake

二、RL基本算法

1.Q-learning和SARSA

 2.DQN

Deep network + Qlearning = DQN

三、PG策略算法

总结


前言

这段时间学习深度强化学习的总结。


一、强化学习

        强化学习是做出最佳决策的科学。它可以帮助我们制定活的物种所表现出的奖励动机行为。比方说,你想让一个孩子坐下来学习考试。要做到这一点非常困难,但是如果每次完成一章/主题时都给他一块巧克力,他就会明白,如果他继续学习,他会得到更多的巧克力棒。所以他会有一些学习考试的动机。
        孩子代表着Agent代理 。奖励制度和考试代表了Environment环境。今天的题目是类似于强化学习的States状态。所以,孩子必须决定哪些话题更重要(即计算每种行为的价值)。这将是我们的工作的 Value-Function价值方程。所以,每次他从一个国家到另一个国家旅行时,他都会得到Reward奖励,他用来在时间内完成主题的方法就是我们的Policy决策

1.马可洛夫链

马尔科夫链是用来描述智能体和环境互动的过程。

马尔科夫链包含三要素:state,action,reward

智能体在一个状态(S)下,选择了某个动作(A),进入了另外一个状态,并获得奖励(用R代表)的过程。

所以,我们希望通过让智能体在环境里获取最多的奖励,把智能体训练成我们想要的样子——就是能完成某些特定的任务。

马尔科夫链,其实应该叫马尔科夫树

S到A是agent的选择 ,而A到S时环境的随机性。

马尔科夫链具有不确定性。

2.蒙地卡罗

Q和V:

评估动作的价值,称为Q值:它代表了选择这个动作后,一直到最终状态奖励总和期望

评估状态的价值,称为V值:它代表了在这个状态下,一直到最终状态的奖励总和期望

算上奖励R,Q和V之间的关系:

V就是子节点的Q的期望,Q就是子节点的V的期望.

蒙地卡罗

我们把agent放到环境的任意状态;从这个状态开始按照策略进行选择动作,并进入新的状态。

重复上一步,直到最终状态;我们从最终状态开始向前回溯:计算每个状态的G值

重复前面多次,然后平均每个状态的G值,这就是我们需要求的V值。

缺点: 每一次都需要先从头走到尾,再进行回溯更新。如果最终状态很难达到,可能每一次都要转很久很久才能更新一次G值。就是说如果环境的状态空间非常大,或者最终状态只有非常小的概率达到。

3.时序差分TD

TD算法对蒙地卡罗(MC)进行了改进:

1. 和蒙地卡罗(MC)不同:TD算法只需要走N步。就可以开始回溯更新。

2. 和蒙地卡罗(MC)一样:小猴需要先走N步,每经过一个状态,把奖励记录下来。然后开始回溯。

3. 状态的V值计算:和蒙地卡罗一样,假设N步之后,就到达了最终状态了。

可以简单来说就是,TD不走完整段路程,而是半路就截断。用半路的路牌,更新当前的路牌。就是说不需要一直到最后,我们可以先用后面的估算,然后调整当前状态。

在MC,G是更新目标,而在TD,把更新目标从G,改成r+gamma*V

 4.gym学习

  1. 导入:首先我们先import gym。导入gym包。
  2. 创建环境:env = gym.make('环境名')。 其中环境名可以在这找到,还有相关的说明。其中,env就是environment的简称。 一般我们会顺手进行初始化。env.unwrapped 或者我们一起写。env = gym.make('环境名').unwrapped
  3. 获取状态特征数和动作空间 N_S = env.observation_space N_A = env.action_space 还记得我们之前说的吗?状态特征,就是我们能观察到的环境。 例如自动驾驶汽车,交通灯算是一个状态特征,这个特征有不同的值,红灯/绿灯。距离最近的行人是一个特征,例如距离这个行人多远。自动驾驶汽车能观察的环境特征越多,感知能力越强,对抉择就越有帮助。所以不一般来说,工程师都会想不断利用各种算法和硬件,从真实环境提取环境特征。 GYM环境对于初学者方便的地方是,对于每个实验,环境都直接提供了环境特征。不需要我们自己去提取了。 如果是连续的状态空间,和动作空间,我们可以获取到边界值 s_low_bound = env.observation_space.low s_high_bound = env.observation_space.high 在这里大家可以理解为,老师出题的格式,和学生答案的格式。
  4. 初始化环境,并返回一个初始状态。我们一般这样写。 s = env.reset() 老师出的第一道题!
  5. 学生开始做题了。这里的f其实就是我们的算法。 现在我们就有了一个初始状态s。 假设有一个函数f(s),输入s,获得可以选择出动作a。我们的目标就是找出一个f,能让我们在这个环境中获取最多的reward。 a = f(s)
  6. 学生提交答案,老师改卷了。把分返回给学生。并且开始出下一题。 我们选取a后。代入step函数,会根据 环境配置,会返回:进入的下一个状态,当前获得的奖励r。除此之外,还有一个标志位done,表示是否进入最终状态。另外还有一个包含信息的值(info),但一般我们用不到。可以先忽略。 s_,r,done,info = env.step(a)
  7. 我们把s = s_.并把4-6组成一个循环,那么游戏就能自动进行下去了。
  8. render。如果有render可以把游戏给渲染出来。

FrozenLake

S:start,出发点。 G:target,终点。 F:可以走的路,但偶尔你会因为滑到,自动往前滑一格。 H:hole:是陷阱。

FrozenLake-v0是一个4*4的网络格子,每个格子可以是起始块,目标块、冻结块或者危险块。 我们的目标是让agent学习从开始块如何行动到目标块上,而不是移动到危险块上。 agent可以选择向上、向下、向左或者向右移动,同时游戏中还有可能吹来一阵风,将agent吹到任意的方块上。

我们的任务就是让我们的agent,从起点,走到终点。

二、RL基本算法

1.Q-learning和SARSA

V(St+1)的意义是,在St+1到最终状态获得的奖励期望值。 Q(St,At)的意义是,在Q(St,At)到最终状态获得的奖励期望值。 所以我们可以把V(St+1)看成是下山途中的一个路牌,这个路牌告诉我们下山到底还有多远,然后加上R这一段路,就知道Q(St,At)离山脚有多长的路。

因为从状态St+1到动作At+1之间没有奖励反馈,所以我们直接用At+1的Q价值,代替St+1的V价值。 

在St+1下,可能有很多动作At+1。不同动作的Q值自然是不同的。 所以Q(St+1,At+1)并不能等价于V(St+1)。

虽然不相等,但不代表不能用其中一个来代表V(St+1)。人们认为有个可能的动作产生的Q值能够一定程度代表V(St+1)。

  1. 在相同策略下产生的动作At+1。这就是SARSA。
  2. 选择能够产生最大Q值的动作At+1。这就是Qlearning。

Qlearning和SARSA唯一的不同,就是用什么动作的Q值替代St+1的V值。SARSA 选择的是在St同一个策略产生的动作。Qlearning 选择的是能够产生最大的Q值的动作。

Qleanring的更新流程。 我们将会在任意的state出发

1. 我们将会用noisy-greedy的策略选定动作A

2. 在完成动作后,我们将会进入新状态St+1;

3. 检查St+1中所有动作,看看哪个动作的Q值最大;

4. 用以下的公式更新当前动作A的Q值;

5. 继续从s'出发,进行下一步更新 1-6步我们作为一个EP,进行N个EP的迭代。 

"""Q-Table learning algorithm.
Non deep learning - TD Learning, Off-Policy, e-Greedy Exploration
Q(S, A) <- Q(S, A) + alpha * (R + lambda * Q(newS, newA) - Q(S, A))
See David Silver RL Tutorial Lecture 5 - Q-Learning for more details.
For Q-Network, see tutorial_frozenlake_q_network.py
EN: https://medium.com/emergent-future/simple-reinforcement-learning-with-tensorflow-part-0-q-learning-with-tables-and-neural-networks-d195264329d0#.5m3361vlw
CN: https://zhuanlan.zhihu.com/p/25710327
tensorflow==2.0.0a0
tensorlayer==2.0.0
"""import argparse
import os
import timeimport gym
import matplotlib.pyplot as plt
import numpy as npparser = argparse.ArgumentParser()
parser.add_argument('--train', dest='train', action='store_true', default=True)
parser.add_argument('--test', dest='test', action='store_true', default=True)parser.add_argument('--save_path', default=None, help='folder to save if mode == train else model path,''qnet will be saved once target net update'
)
parser.add_argument('--seed', help='random seed', type=int, default=0)
parser.add_argument('--env_id', default='FrozenLake-v0')
args = parser.parse_args()## Load the environment
alg_name = 'Qlearning'
env_id = args.env_id
env = gym.make(env_id)
render = False  # display the game environment##================= Implement Q-Table learning algorithm =====================##
## Initialize table with all zeros
Q = np.zeros([env.observation_space.n, env.action_space.n])
## Set learning parameters
lr = .85  # alpha, if use value function approximation, we can ignore it
lambd = .99  # decay factor
num_episodes = 10000
t0 = time.time()if args.train:all_episode_reward = []for i in range(num_episodes):## Reset environment and get first new observations = env.reset()rAll = 0## The Q-Table learning algorithmfor j in range(99):if render: env.render()## Choose an action by greedily (with noise) picking from Q tablea = np.argmax(Q[s, :] + np.random.randn(1, env.action_space.n) * (1. / (i + 1)))## Get new state and reward from environments1, r, d, _ = env.step(a)## Update Q-Table with new knowledgeQ[s, a] = Q[s, a] + lr * (r + lambd * np.max(Q[s1, :]) - Q[s, a])rAll += rs = s1if d is True:breakprint('Training  | Episode: {}/{}  | Episode Reward: {:.4f}  | Running Time: {:.4f}'.format(i + 1, num_episodes, rAll,time.time() - t0))if i == 0:all_episode_reward.append(rAll)else:all_episode_reward.append(all_episode_reward[-1] * 0.9 + rAll * 0.1)# savepath = os.path.join('model', '_'.join([alg_name, env_id]))if not os.path.exists(path):os.makedirs(path)np.save(os.path.join(path, 'Q_table.npy'), Q)plt.plot(all_episode_reward)if not os.path.exists('image'):os.makedirs('image')plt.savefig(os.path.join('image', '_'.join([alg_name, env_id])))# print("Final Q-Table Values:/n %s" % Q)if args.test:path = os.path.join('model', '_'.join([alg_name, env_id]))Q = np.load(os.path.join(path, 'Q_table.npy'))for i in range(num_episodes):## Reset environment and get first new observations = env.reset()rAll = 0## The Q-Table learning algorithmfor j in range(99):## Choose an action by greedily (with noise) picking from Q tablea = np.argmax(Q[s, :])## Get new state and reward from environments1, r, d, _ = env.step(a)## Update Q-Table with new knowledgerAll += rs = s1if d is True:breakprint('Testing  | Episode: {}/{}  | Episode Reward: {:.4f}  | Running Time: {:.4f}'.format(i + 1, num_episodes, rAll,time.time() - t0))

 2.DQN

Deep network + Qlearning = DQN

在Qlearning中,有一个Qtable,记录着在每一个状态下,各个动作的Q值。

Qtable的作用是当输入状态S,通过查表返回能够获得最大Q值的动作A。也就是需要找一个S-A的对应关系。

这种方式很适合格子游戏。因为格子游戏中的每一个格子就是一个状态,但在现实生活中,很多状态并不是离散而是连续的。

例如在GYM中经典的CartPole游戏,杆子的角度是连续而不是离散的。在Atari游戏中,状态也是连续的。

遇到这些情况,Qtable就没有办法解决。

Qtable的作用就是找一个S-A的对应关系。所以我们就可以用一个函数F表示,我们有F(S) = A。这样我们就可以不用查表了,而且还有个好处,函数允许连续状态的表示。

这时候,我们深度神经网络就可以派上用场了。因为神经网络可以看成一个万能的函数

这个万能函数接受输入一个状态S,它能告诉我,每个动作的Q值是怎样的。

Qlearning和DQN并没有根本的区别。只是DQN用神经网络,也就是一个函数替代了原来Qtable而已。解决连续问题。

更新当前状态St下的某动作A的Q值:Q(S,A),我们可以这样做:

1. 执行A,往前一步,到达St+1;

2. 把St+1输入Q网络,计算St+1下所有动作的Q值;

3. 获得最大的Q值加上奖励R作为更新目标;

4. 计算损失 - Q(S,A)相当于有监督学习中的logits - maxQ(St+1) + R 相当于有监督学习中的lables - 用mse函数,得出两者的loss

5. 用loss更新Q网络。 

用Q网络估算出来的两个相邻状态的Q值,他们之间的距离,就是一个r的距离。

和有监督学习不同,深度强化学习中,我们需要自己找更新目标。通常在马尔科夫链体系下,两个相邻状态状态差一个奖励r,经常能被利用。 

"""
Deep Q-Network Q(a, s)
-----------------------
TD Learning, Off-Policy, e-Greedy Exploration (GLIE).
Q(S, A) <- Q(S, A) + alpha * (R + lambda * Q(newS, newA) - Q(S, A))
delta_w = R + lambda * Q(newS, newA)
See David Silver RL Tutorial Lecture 5 - Q-Learning for more details.
Reference
----------
original paper: https://storage.googleapis.com/deepmind-media/dqn/DQNNaturePaper.pdf
EN: https://medium.com/emergent-future/simple-reinforcement-learning-with-tensorflow-part-0-q-learning-with-tables-and-neural-networks-d195264329d0#.5m3361vlw
CN: https://zhuanlan.zhihu.com/p/25710327
Note: Policy Network has been proved to be better than Q-Learning, see tutorial_atari_pong.py
Environment
-----------
# The FrozenLake v0 environment
https://gym.openai.com/envs/FrozenLake-v0
The agent controls the movement of a character in a grid world. Some tiles of
the grid are walkable, and others lead to the agent falling into the water.
Additionally, the movement direction of the agent is uncertain and only partially
depends on the chosen direction. The agent is rewarded for finding a walkable
path to a goal tile.
SFFF       (S: starting point, safe)
FHFH       (F: frozen surface, safe)
FFFH       (H: hole, fall to your doom)
HFFG       (G: goal, where the frisbee is located)
The episode ends when you reach the goal or fall in a hole. You receive a reward
of 1 if you reach the goal, and zero otherwise.
Prerequisites
--------------
tensorflow>=2.0.0a0
tensorlayer>=2.0.0
To run
-------
python tutorial_DQN.py --train/test
"""
import argparse
import os
import timeimport gym
import matplotlib.pyplot as plt
import numpy as np
import tensorflow as tfimport tensorlayer as tl# add arguments in command  --train/test
parser = argparse.ArgumentParser(description='Train or test neural net motor controller.')
parser.add_argument('--train', dest='train', action='store_true', default=True)
parser.add_argument('--test', dest='test', action='store_true', default=True)
args = parser.parse_args()tl.logging.set_verbosity(tl.logging.DEBUG)#####################  hyper parameters  ####################
env_id = 'FrozenLake-v0'
alg_name = 'DQN'
lambd = .99  # decay factor
e = 0.1  # e-Greedy Exploration, the larger the more random
num_episodes = 10000
render = False  # display the game environment##################### DQN ##########################def to_one_hot(i, n_classes=None):a = np.zeros(n_classes, 'uint8')a[i] = 1return a## Define Q-network q(a,s) that ouput the rewards of 4 actions by given state, i.e. Action-Value Function.
# encoding for state: 4x4 grid can be represented by one-hot vector with 16 integers.
def get_model(inputs_shape):ni = tl.layers.Input(inputs_shape, name='observation')nn = tl.layers.Dense(4, act=None, W_init=tf.random_uniform_initializer(0, 0.01), b_init=None, name='q_a_s')(ni)return tl.models.Model(inputs=ni, outputs=nn, name="Q-Network")def save_ckpt(model):  # save trained weightspath = os.path.join('model', '_'.join([alg_name, env_id]))if not os.path.exists(path):os.makedirs(path)tl.files.save_weights_to_hdf5(os.path.join(path, 'dqn_model.hdf5'), model)def load_ckpt(model):  # load trained weightspath = os.path.join('model', '_'.join([alg_name, env_id]))tl.files.save_weights_to_hdf5(os.path.join(path, 'dqn_model.hdf5'), model)if __name__ == '__main__':qnetwork = get_model([None, 16])qnetwork.train()train_weights = qnetwork.trainable_weightsoptimizer = tf.optimizers.SGD(learning_rate=0.1)env = gym.make(env_id)t0 = time.time()if args.train:all_episode_reward = []for i in range(num_episodes):## Reset environment and get first new observations = env.reset()  # observation is state, integer 0 ~ 15rAll = 0if render: env.render()for j in range(99):  # step index, maximum step is 99## Choose an action by greedily (with e chance of random action) from the Q-networkallQ = qnetwork(np.asarray([to_one_hot(s, 16)], dtype=np.float32)).numpy()a = np.argmax(allQ, 1)## e-Greedy Exploration !!! sample random actionif np.random.rand(1) < e:a[0] = env.action_space.sample()## Get new state and reward from environments1, r, d, _ = env.step(a[0])if render: env.render()## Obtain the Q' values by feeding the new state through our networkQ1 = qnetwork(np.asarray([to_one_hot(s1, 16)], dtype=np.float32)).numpy()## Obtain maxQ' and set our target value for chosen action.maxQ1 = np.max(Q1)  # in Q-Learning, policy is greedy, so we use "max" to select the next action.targetQ = allQtargetQ[0, a[0]] = r + lambd * maxQ1## Train network using target and predicted Q values# it is not real target Q value, it is just an estimation,# but check the Q-Learning update formula:#    Q'(s,a) <- Q(s,a) + alpha(r + lambd * maxQ(s',a') - Q(s, a))# minimizing |r + lambd * maxQ(s',a') - Q(s, a)|^2 equals to force Q'(s,a) ≈ Q(s,a)with tf.GradientTape() as tape:_qvalues = qnetwork(np.asarray([to_one_hot(s, 16)], dtype=np.float32))_loss = tl.cost.mean_squared_error(targetQ, _qvalues, is_mean=False)grad = tape.gradient(_loss, train_weights)optimizer.apply_gradients(zip(grad, train_weights))rAll += rs = s1## Reduce chance of random action if an episode is done.if d ==True:e = 1. / ((i / 50) + 10)  # reduce e, GLIE: Greey in the limit with infinite Explorationbreak## Note that, the rewards here with random actionprint('Training  | Episode: {}/{}  | Episode Reward: {:.4f} | Running Time: {:.4f}' \.format(i, num_episodes, rAll, time.time() - t0))if i == 0:all_episode_reward.append(rAll)else:all_episode_reward.append(all_episode_reward[-1] * 0.9 + rAll * 0.1)save_ckpt(qnetwork)  # save modelplt.plot(all_episode_reward)if not os.path.exists('image'):os.makedirs('image')plt.savefig(os.path.join('image', '_'.join([alg_name, env_id])))if args.test:load_ckpt(qnetwork)  # load modelfor i in range(num_episodes):## Reset environment and get first new observations = env.reset()  # observation is state, integer 0 ~ 15rAll = 0if render: env.render()for j in range(99):  # step index, maximum step is 99## Choose an action by greedily (with e chance of random action) from the Q-networkallQ = qnetwork(np.asarray([to_one_hot(s, 16)], dtype=np.float32)).numpy()a = np.argmax(allQ, 1)  # no epsilon, only greedy for testing## Get new state and reward from environments1, r, d, _ = env.step(a[0])rAll += rs = s1if render: env.render()## Reduce chance of random action if an episode is done.if d: breakprint('Testing  | Episode: {}/{}  | Episode Reward: {:.4f} | Running Time: {:.4f}' \.format(i, num_episodes, rAll, time.time() - t0))

三、PG策略算法


总结

对深度强化学习的初步学习,从强化学习到深度强化学习,学习了一下算法,之后还需要深入实验,如GYM等。加油加油。

好的参考:

强化学习极简入门:通俗理解MDP、DP MC TC和Q学习、策略梯度、PPO_强化学习极简入门:通俗理解mdp、dpmc-CSDN博客

【强化学习】Q-Learning算法详解-CSDN博客

强化学习方法汇总 | 莫烦Python (mofanpy.com)

深度强化学习【1】-强化学习入门必备基础(含Python迷宫游戏求解实例)_强化学习 迷宫-CSDN博客

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

选项 打光 试题总结

试题1 被测物体100100mm&#xff0c;精度要求被测物体 &#xff0c;精度要求0.1mm&#xff0c;相机距被测物体在200&#xff5e;320mm之间&#xff0c;要求选择合适的相机和镜头&#xff1f; 分析如下&#xff1a; 通常我们用的相机靶面是4:3 的所以我们要用短边来计算视场&am…

亿道信息发布两款升级款全加固笔记本电脑

2022年5月19日&#xff0c;加固手持终端。加固平板电脑、加固笔记本电脑专业设计商和制造商&#xff0c;以及加固型移动计算机软硬件整体定制解决方案提供商亿道信息&#xff0c;宣布对其两款广受欢迎的加固笔记本电脑产品EM-X14U和EM-X15U进行重大升级。新发布的两款升级款全加…

Vue3+vite打包后页面空白问题

vite.config.js vite.config.js 增加 base: ./ import { fileURLToPath, URL } from node:url import { defineConfig } from vite import vue from vitejs/plugin-vue// https://vitejs.dev/config/ export default defineConfig({base: ./,resolve: {alias: {: fileURLToPath…

初学selenuim[1]($x(‘xpath语法’)、WebDriverWait())

文章目录 初学selenuim记录1、执行driver webdriver.Chrome()后很久才打开浏览器2、浏览器多元素定位 $x(‘xpath语法’)3、打开浏览器driver.get("网址")执行了很久才开始定位元素&#xff1a;等待&#xff08;1&#xff09;driver.set_page_load_timeout(t)&#…

yolov9从头开始训练

yolov9从头开始训练 一、准备数据集 数据集相关文件存放布局如下 yolov9-datasets ├── train │ ├── images │ │ ├── image.jpg │ │ ├── │ └── labels │ ├── image.txt │ ├── ├── valid │ ├── images │ │ ├── image.jpg │ │ ├─…

Gitlab: 私有化部署

目录 1. 说明 2. 资源要求 3. 安装 4. 配置实践 4.1 服务器 4.2 人员与项目 4.2 部署准备 4.2.1 访问变量及用户账号设置 4.2.2 Runner设置 4.2.3 要点 5. 应用项目 CI/CD 6. 参考 1. 说明 gitlab是一个强大且免费的代码管理/部署工具&#xff0c;能统一集成代码仓…

【探索AI】十二 深度学习之第2周:深度神经网络(一)深度神经网络的结构与设计

第2周&#xff1a;深度神经网络 将从以下几个部分开始学习&#xff0c;第1周的概述有需要详细讲解的的同学自行百度&#xff1b; 深度神经网络的结构与设计 深度学习的参数初始化策略 过拟合与正则化技术 批标准化与Dropout 实践&#xff1a;使用深度学习框架构建简单的深度神…

单词规律00

题目链接 单词规律 题目描述 注意点 pattern只包含小写英文字母s只包含小写英文字母和 ’ ’s不包含任何前导或尾随对空格s中每个单词都被 单个空格 分隔 解答思路 本题与上一次同构字符串类似&#xff0c;思路可以参照同构字符串 代码 class Solution {public boolean …

Facebook Messenger链接分享:如何创建链接并设置自动化内容

Facebook Messenger链接是指基于Facebook用户名创建的会话链接&#xff0c;用户可以在其Facebook页面的设置部分复制此链接进行分享。然后将该链接直接粘贴到独立站、电子邮件、名片或社交媒体中&#xff0c;让目标受众可以一键进入对话。为了满足某些商家的需求&#xff0c;Fa…

理想汽车狂飙18%,造车新势力洗牌

2月27日&#xff0c;#理想汽车狂飙18%#话题冲上热搜&#xff1b;前一日&#xff0c;理想汽车(02015.HK)公布了2023年第四季度及全年财报。尽管其营收净利双增长&#xff0c;但业绩增长背后仍有隐忧。 「不二研究」据其2023年报发现&#xff1a;2023年&#xff0c;理想汽车研发…

Vivado Vitis 2023.2 环境配置 Git TCL工程管理 MicroBlaze和HLS点灯测试

文章目录 本篇概要Vivado Vitis 环境搭建Vivado 免费标准版 vs 企业版Vivado Windows 安装Vivado 安装更新 Vivado 工程操作GUI 创建工程打开已有工程从已有工程创建, 重命名工程GUI导出TCL, TCL复原工程TCL命令 Vivado 版本控制BlinkTcl脚本新建导出重建工程纯Verilog BlinkTc…

STM32存储左右互搏 QSPI总线FATS文件读写FLASH W25QXX

STM32存储左右互搏 QSPI总线FATS文件读写FLASH W25QXX FLASH是常用的一种非易失存储单元&#xff0c;W25QXX系列Flash有不同容量的型号&#xff0c;如W25Q64的容量为64Mbit&#xff0c;也就是8MByte。这里介绍STM32CUBEIDE开发平台HAL库Quad SPI总线实现FATS文件操作W25Q各型号…