STM32学习-1 新建工程

news2024/9/21 22:44:12

教学资料来自【STM32入门教程-2023版 细致讲解 中文字幕】 https://www.bilibili.com/video/BV1th411z7sn/?p=5&share_source=copy_web&vd_source=c6cfedd1c739ca8502f041514e158616

在keil中,每个代码最后一行必须是空的,不然运行会报错

配置库函数

文件图标前面带个钥匙的就是只读文件,不可以更改,我们只需要更改user里面的文件

点一下三个箱子的按钮,把不用更改的放到最上面方便查看

效果如下:

用库函数实现点灯

1.开启时钟

时钟:单片机的心脏,所有的外设的运作都需要时钟供能。
时钟周期:又称为振荡周期,可以简单理解为传输一个0或1所需要的时间
指令周期:执行一条指令(如 MOV A, #34H)所需要的时间。对于不同类型的指令,指令周期长度可能不同。
机器周期:执行一个动作的时间周期。如:执行一个指令需要”取指令并译码“、”执行操作数“两个动作。
原文链接:https://blog.csdn.net/qq_43460068/article/details/122203020

简单的说,时钟是单片机的脉搏,是单片机的驱动源,使用任何一个外设都必须打开相应的时钟。这样的好处是,如果不使用一个外设的时候,就把它的时钟关掉,从而可以降低系统的功耗,达到节能,实现低功耗的效果。每个时钟tick,系统都会处理一步数据,这样才能让工作不出现紊乱。

首先,任何外设都需要时钟,51单片机,stm32,430等等,因为寄存器是由D触发器组成的,往触发器里面写东西,前提条件是有时钟输入。
51单片机不需要配置时钟,是因为一个时钟开了之后所有的功能都可以用了,而这个时钟是默认开启的,比如有一个水库,水库有很多个门,这些门默认是开启的,所以每个门都会出水,我们需要哪个门的水的时候可以直接用,但是也存在一个问题,其他没用到的门也在出水,即也在耗能。这里水库可以认为是能源,门可以认为是每个外设的使用状态,时钟可以认为是门的开关。stm32之所以是低功耗,他将所有的门都默认设置为disable,在你需要用哪个门的时候,开哪个门就可以,也就是说用到什么外设,只要打开对应外设的时钟就可以,其他的没用到的可以还是disable,这样耗能就会减少。
在51单片机中一个时钟把所有的都包了,而stm32的时钟是有分工的,并且每类时钟的频率不一样,因为没必要所有的时钟都是最高频率,只要够用就行,好比一个门出来水流大小,我只要洗脸,但是出来的是和洪水一样涌出来的水,那就gg了,消耗能源也多,所以不同的时钟也会有频率差别,或者在配置的时候可以配置时钟分频。              
原文链接:https://blog.csdn.net/qq_42384937/article/details/83512162

时钟是用来控制能源放出的,每个时钟放出的能源大小不一样

2.我们要配置寄存器来点灯,也就是pc13这个灯

(1)需要用RCC的一个寄存器来使能GPIOC的时钟,而GPIO都是APB2的外设

查看参考手册:

可以看到如果要打开GPIOC的时钟,我们需要将位4置1,所以这一位写1,其他位都为0,二进制转换为十六进制,也就是0 0 0 0 0 0 1 0 (四个位一分组)

也就是:

RCC->APB2ENR = 0x00000010;
(2)第二个寄存器需要配置PC13口的模式

其中的CNF13和MODE13就是配置13号口的

CNF13需要配置为通用推挽输出模式,也就是00,推挽输出是指既可以输出低电平,也可以输出高电平,可以直接驱动功耗不大的数字器件。

MODE13要配置为输出模式,最大速度50MHz,也就是11

这样子换算成十六进制就是 0 0 3 0 0 0 0 0(四个位分一组)

GPIOC->CRH= 0x00300000;
(3)给PC13口输出数据

我们需要将ODR13口置1,13号口高电平,换算成十六进制也就是 0 0 0 0 2 0 0 0

GPIOC->ODR= 0x00002000;

这个灯是低电平点亮,所以ODR全0就是亮,而 0 0 0 0 2 0 0 0就是灭

↑ODR全0

↑ODR为00002000

		//寄存器配置
		RCC->APB2ENR = 0x00000010;
		GPIOC->CRH = 0x00300000;
		GPIOC->ODR = 0x00002000;

库函数配置

与寄存器类似的步骤

1.需要一个函数使能时钟

这个函数是:

void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState)

查看它的定义,它是用来使能或者失能APB2的外设时钟,可以发现它有两个参数 

/**
  * @brief  Enables or disables the High Speed APB (APB2) peripheral clock.
  * @param  RCC_APB2Periph: specifies the APB2 peripheral to gates its clock.
  *   This parameter can be any combination of the following values:
  *     @arg RCC_APB2Periph_AFIO, RCC_APB2Periph_GPIOA, RCC_APB2Periph_GPIOB,
  *          RCC_APB2Periph_GPIOC, RCC_APB2Periph_GPIOD, RCC_APB2Periph_GPIOE,
  *          RCC_APB2Periph_GPIOF, RCC_APB2Periph_GPIOG, RCC_APB2Periph_ADC1,
  *          RCC_APB2Periph_ADC2, RCC_APB2Periph_TIM1, RCC_APB2Periph_SPI1,
  *          RCC_APB2Periph_TIM8, RCC_APB2Periph_USART1, RCC_APB2Periph_ADC3,
  *          RCC_APB2Periph_TIM15, RCC_APB2Periph_TIM16, RCC_APB2Periph_TIM17,
  *          RCC_APB2Periph_TIM9, RCC_APB2Periph_TIM10, RCC_APB2Periph_TIM11     
  * @param  NewState: new state of the specified peripheral clock.
  *   This parameter can be: ENABLE or DISABLE.
  * @retval None
  */

第一项选GPIOC,我们直接从上面的参数进行复制即可,第二个参数选ENABLE(使能)

void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState)
{
  /* Check the parameters */
  assert_param(IS_RCC_APB2_PERIPH(RCC_APB2Periph));
  assert_param(IS_FUNCTIONAL_STATE(NewState));
  if (NewState != DISABLE)
  {
    RCC->APB2ENR |= RCC_APB2Periph;
  }
  else
  {
    RCC->APB2ENR &= ~RCC_APB2Periph;
  }
}

这个函数其实还是在配置RCC_APB2ENR这个寄存器,但是函数包装之后我们不需要查手册确认哪一位是在干什么了,而且它使用&=和|=来操作,不会影响寄存器其他位,这就是库函数和寄存器的区别

可以看出库函数更加方便

2.配置端口模式

(1)使用函数:
void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct)

查看定义:

/**
  * @brief  Initializes the GPIOx peripheral according to the specified
  *         parameters in the GPIO_InitStruct.
  * @param  GPIOx: where x can be (A..G) to select the GPIO peripheral.
  * @param  GPIO_InitStruct: pointer to a GPIO_InitTypeDef structure that
  *         contains the configuration information for the specified GPIO peripheral.
  * @retval None
  */

第一个参数GPIOx,x为A到G,选择你要配置哪个GPIO,我们选GPIOC

第二个参数是一个结构体,所以我们需要自己先定义一个结构体

 这个结构体的三个参数分别是GPIO模式,端口,速度

(2)查看这些参数的定义:
typedef struct
{
  uint16_t GPIO_Pin;             /*!< Specifies the GPIO pins to be configured.
                                      This parameter can be any value of @ref GPIO_pins_define */

  GPIOSpeed_TypeDef GPIO_Speed;  /*!< Specifies the speed for the selected pins.
                                      This parameter can be a value of @ref GPIOSpeed_TypeDef */

  GPIOMode_TypeDef GPIO_Mode;    /*!< Specifies the operating mode for the selected pins.
                                      This parameter can be a value of @ref GPIOMode_TypeDef */
}GPIO_InitTypeDef;

发现他说这个参数可以写GPIOMode_TypeDef里面的值,选中这个字符,Ctrl+F,搜索这个定义的位置

(3)找到GPIOMode_TypeDef定义:
typedef enum
{ GPIO_Mode_AIN = 0x0,
  GPIO_Mode_IN_FLOATING = 0x04,
  GPIO_Mode_IPD = 0x28,
  GPIO_Mode_IPU = 0x48,
  GPIO_Mode_Out_OD = 0x14,
  GPIO_Mode_Out_PP = 0x10,
  GPIO_Mode_AF_OD = 0x1C,
  GPIO_Mode_AF_PP = 0x18
}GPIOMode_TypeDef;

其中 GPIO_Mode_Out_PP就是通用推挽输出,我们选择它

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;

(4)查找Pin定义

查看pin的定义时发现有多个定义,选择类型为member的:

它的值可以取GPIO_pins_define的,我们搜索可得到有这些:

#define GPIO_Pin_0                 ((uint16_t)0x0001)  /*!< Pin 0 selected */
#define GPIO_Pin_1                 ((uint16_t)0x0002)  /*!< Pin 1 selected */
#define GPIO_Pin_2                 ((uint16_t)0x0004)  /*!< Pin 2 selected */
#define GPIO_Pin_3                 ((uint16_t)0x0008)  /*!< Pin 3 selected */
#define GPIO_Pin_4                 ((uint16_t)0x0010)  /*!< Pin 4 selected */
#define GPIO_Pin_5                 ((uint16_t)0x0020)  /*!< Pin 5 selected */
#define GPIO_Pin_6                 ((uint16_t)0x0040)  /*!< Pin 6 selected */
#define GPIO_Pin_7                 ((uint16_t)0x0080)  /*!< Pin 7 selected */
#define GPIO_Pin_8                 ((uint16_t)0x0100)  /*!< Pin 8 selected */
#define GPIO_Pin_9                 ((uint16_t)0x0200)  /*!< Pin 9 selected */
#define GPIO_Pin_10                ((uint16_t)0x0400)  /*!< Pin 10 selected */
#define GPIO_Pin_11                ((uint16_t)0x0800)  /*!< Pin 11 selected */
#define GPIO_Pin_12                ((uint16_t)0x1000)  /*!< Pin 12 selected */
#define GPIO_Pin_13                ((uint16_t)0x2000)  /*!< Pin 13 selected */
#define GPIO_Pin_14                ((uint16_t)0x4000)  /*!< Pin 14 selected */
#define GPIO_Pin_15                ((uint16_t)0x8000)  /*!< Pin 15 selected */
#define GPIO_Pin_All               ((uint16_t)0xFFFF)  /*!< All pins selected */

我们选择pin13

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;

 

(5)查找speed定义

搜索speed的定义可得到:

typedef enum
{ 
  GPIO_Speed_10MHz = 1,
  GPIO_Speed_2MHz, 
  GPIO_Speed_50MHz
}GPIOSpeed_TypeDef;

选择50MHz

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

最终结构体三个参数填写如下:

		GPIO_InitTypeDef GPIO_InitStructure; 
		GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
		GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;	
		GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

(6)填写GPIO_Init函数第二个参数

又因为GPIO_Init函数第二个参数是一个指向结构体的指针

void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct)

所以我们要传递结构体地址:在结构体名字前加上取址符&即可

GPIO_Init(GPIOC,&GPIO_InitStructure);

3.最后设置端口的高低电平进行点灯

(1)使用函数GPIO_SetBits()把指定端口设置为高电平:
/**
  * @brief  Sets the selected data port bits.
  * @param  GPIOx: where x can be (A..G) to select the GPIO peripheral.
  * @param  GPIO_Pin: specifies the port bits to be written.
  *   This parameter can be any combination of GPIO_Pin_x where x can be (0..15).
  * @retval None
  */
void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)

按照参数定义填写

GPIO_SetBits(GPIOC,GPIO_Pin_13);

 

(2)使用函数GPIO_ResetBits()把指定端口设置为低电平:

参数和上面的一样

GPIO_ResetBits(GPIOC,GPIO_Pin_13);

 

测试发现,13号口高电平则灯灭,低电平则灯亮

		//库函数配置
		RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);
		GPIO_InitTypeDef GPIO_InitStructure; 
		GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
		GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;	
		GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
		GPIO_Init(GPIOC,&GPIO_InitStructure);
	
		//GPIO_SetBits(GPIOC,GPIO_Pin_13); //高电平
	
		GPIO_ResetBits(GPIOC,GPIO_Pin_13); //低电平

 

STM32的型号分类及缩写

 

新建工程步骤

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2024自学网络安全的三个必经阶段(含路线图)_网络安全自学路线

一、为什么选择网络安全&#xff1f; 这几年随着我国《国家网络空间安全战略》《网络安全法》《网络安全等级保护2.0》等一系列政策/法规/标准的持续落地&#xff0c;网络安全行业地位、薪资随之水涨船高。 未来3-5年&#xff0c;是安全行业的黄金发展期&#xff0c;提前踏入…

C++类与对象基础探秘系列(三)

目录 再谈构造函数 构造函数体赋值 初始化列表 explicit关键字 static成员 概念 特性 友元 友元函数 友元类 内部类 概念 特性 匿名对象 再次理解类和对象 再谈构造函数 构造函数体赋值 在创建对象时&#xff0c;编译器会通过调用构造函数&#xff0c;给对象中的各个成员…

【数据分析面试】44.分析零售客户群体(Python 集合Set的用法)

题目 假设你是一家在线零售商的数据库管理员&#xff0c;需要分析两类客户的数据。一个集合 purchased_customers 包含在最近一次促销活动中购买了商品的客户ID&#xff0c;另一个集合 newsletter_subscribers 包含订阅了新闻通讯的客户ID。编写一个函数 analyze_customers&am…

2024一站式解决 python打包代码,发布到pypi

2024一站式解决 python打包代码&#xff0c;发布到pypi 文章目录 2024一站式解决 python打包代码&#xff0c;发布到pypi一、前言二、pypi账户注册与配置2.1 账户注册2.2 双因素认证2.3 API token生成 三、代码打包3.1 准备代码3.2 编写setup.py文件3.3 LICENSE3.3.1 常见的开源…

生信人写程序1. Perl语言模板及配置

生物信息领域常用语言 个人认为&#xff1a;是否能熟悉使用Shell(项目流程搭建)R(数据统计与可视化)Perl/Python/Java…(胶水语言&#xff0c;数据格式转换&#xff0c;软件间衔接)三门语言是一位合格生物信息工程师的标准。 生物信息常用语言非常广泛&#xff0c;我常用的有…

IT行业的现状和未来发展趋势:技术创新、市场需求、人才培养、政策法规和社会影响

&#x1f3a9; 欢迎来到技术探索的奇幻世界&#x1f468;‍&#x1f4bb; &#x1f4dc; 个人主页&#xff1a;一伦明悦-CSDN博客 ✍&#x1f3fb; 作者简介&#xff1a; C软件开发、Python机器学习爱好者 &#x1f5e3;️ 互动与支持&#xff1a;&#x1f4ac;评论 &…

SOLIDWORKS 2024云服务新功能

一、简单的分享一下&#xff0c;在线观看&#xff0c;轻松标记 在达索系统SOLIDWORKS 2024云服务中&#xff0c;您只需在达索系统SOLIDWORKS中点击按钮&#xff0c;就可以将当前的设计分享给其他人&#xff0c;无论是客户、供应商还是团队内部成员。共享的用户只要打开浏览器里…

volatile能保证原子性吗?为什么?

一、问题解析 volatile通常被比喻成”轻量级的synchronized“&#xff0c;也是Java并发编程中比较重要的一个关键字。和synchronized不同&#xff0c;volatile是一个变量修饰符&#xff0c;只能用来修饰变量。无法修饰方法及代码块等。 volatile的用法比较简单&#xff0c;只需…

intel三年来首次大更新竟然倒吸牙膏,线程数砍掉25%!

每年科技圈最热闹的几个话题&#xff0c;无非是几大科技公司发布新的产品&#xff0c;那这其中必然有核心巨头 intel 的身影。 据外媒 Benchlife 披露&#xff0c;英特尔计划在其 Arrow Lake-S 架构 Core Ultra 200 台式机 CPU 系列中推出共计 21 款 CPU。 这是 intel 首次在桌…

【嵌入式大赛应用赛道】机械手臂

电机 进步电机&#xff1a;它的转动是以确定的步数进行的&#xff0c;只要计算好脉冲数量和频率&#xff0c;就可以准确预测和控制电机的转动角度、速度以及停止的位置 伺服电机&#xff1a;将输入的电信号&#xff08;如电压或电流指令&#xff09;转换成轴上的精确旋转运动…

突发!超60篇被标记!Elsevier旗下顶刊,“On Hold”长达10个月!再次沦陷“新”风波!

【欧亚科睿学术】 近日&#xff0c;中科院老牌TOP期刊Chemosphere对超过60篇论文发布了关注声明&#xff0c;原因是正在调查可能存在的编辑利益冲突、作者身份异常以及同行评审和引用操纵问题。 图片来源&#xff1a;期刊官网 2024年4月11日&#xff0c;该期刊在线发布的一份…

WT99C262-SG LoRa开发板使用教程

WT99C262-SG模块是全新一代的Wi-FiBLELoRa无线扩频模块&#xff0c;基于启明云端WTLRC262-SG系列模组设计开发的新一代LoRa扩频芯片方案设计的无线串口模块。具有多种传输方式&#xff0c;LoRa扩频技术&#xff0c;且模组大部分管脚均已引出至两侧排针&#xff0c;开发人员可根…

msvcp140_codecvt_ids.dll找不到要如何处理?简单的修复方法分享

在使用Windows操作系统时&#xff0c;用户可能会遇到“无法找到msvcp140_codecvt_ids.dll”这一错误信息。该提示通常发生在启动某些应用程序时&#xff0c;提示失去了关键的动态链接库文件&#xff08;DLL&#xff09;依赖。此DLL文件属于Microsoft Visual C Redistributable软…

二进制搭建k8s

实验环境&#xff1a; k8s集群master01:192.168.1.11 k8s集群master02:192.168.1.22 master虚拟ip&#xff1a;192.168.1.100 k8s集群node01:192.168.1.33 k8s集群node01:192.168.1.44 nginxkeepalive01&#xff08;master&#xff09;:192.168.1.55 nginxkeepalive02&a…

纯血鸿蒙APP实战开发——Navigation页面跳转对象传递案例

介绍 本示例主要介绍在使用Navigation实现页面跳转时&#xff0c;如何在跳转页面得到转入页面传的类对象的方法。实现过程中使用了第三方插件class-transformer&#xff0c;传递对象经过该插件的plainToClass方法转换后可以直接调用对象的方法&#xff0c; 效果图预览 使用说…

CIBERSORTx网页版报错

解决方式&#xff1a;bulk RNA-seq不能包含NA值

大白话!大模型(LLMs)私有化的三种方式:Prompts、Embeddings、Fine-tuning

私有化大模型的三种方式 随着我们使用大模型的深入呢&#xff0c;我们会发现这样一个现象&#xff0c;我们正常情况下问大模型的问题&#xff0c;会得到一个非常普适的回答&#xff0c;就是大模型会根据自己的训练的这个过往的一些知识的积累&#xff0c;然后告诉我们他认为最…

海外盲盒系统开发,开拓全球盲盒市场

盲盒作为经久不衰的行业&#xff0c;市场发展空间不断扩大。近几年&#xff0c;盲盒出海成为了我国盲盒发展的新赛道&#xff0c;各个盲盒企业更是纷纷摩拳擦掌&#xff0c;开拓海外市场&#xff0c;我国盲盒正在全世界范围内实现多元化发展。此外&#xff0c;我国是世界上有名…

光伏行业该如何起步?

随着全球对可再生能源的需求日益增长&#xff0c;光伏行业作为其中的佼佼者&#xff0c;正迎来前所未有的发展机遇。然而&#xff0c;对于新进入者或希望在这一领域有所建树的企业来说&#xff0c;如何起步并稳健发展是一个值得深思的问题。以下是一些关于光伏行业起步的建议。…