STM32学习-1 新建工程

教学资料来自【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的型号分类及缩写

 

新建工程步骤

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

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

相关文章

Failed to start tomcat.service: Unit is not loaded properly: Bad message 如何解决?

错误 “Failed to start tomcat.service: Unit is not loaded properly: Bad message” 通常意味着的 tomcat.service systemd 配置文件存在语法错误或配置不正确。为了解决这个问题&#xff0c;一步步检查和修正这个服务文件。 1. 检查 tomcat.service 文件 首先&#xff0c…

免费泛域名证书申请

通配符证书是一种 SSL/TLS 证书&#xff0c;可用于保护多个域&#xff08;主机&#xff09;&#xff0c;由域名字段中的通配符 (*) 指示。 如果您有很多需要保护的域或子域&#xff0c;这会很有帮助&#xff0c;因为它可以节省您的时间和金钱。 本文将讨论通配符证书、它们的工…

【文献阅读】李井林等2021ESG促企业绩效的机制研究——基于企业创新的视角

ESG促进企业绩效的机制 摘要 0.引言与文献综述 1.理论分析与研究假设 1.1企业ESG表现与企业绩效 假设1a&#xff1a;企业的环境表现对企业绩效存在正向影响效应。 假设1b&#xff1a;企业的社会表现对企业绩效存在正向影响效应。 假设1c&#xff1a;企业的公司治理表现对企业…

开放式耳机哪款具有高性价比?5款高分开放式耳机倾力推荐

作为多年的耳机发烧友&#xff0c;强烈给你们安利开放式耳机&#xff0c;真的是舒适耐用&#xff0c;性价比高。开放式耳机以其独特的不入耳设计&#xff0c;给用户带来了最舒适的佩戴感受。如果小白还不知道怎么选择高性价比的开放式耳机那就看看我的总结吧&#xff01;下面就…

Fast-Poisson-Image-Editing代码介绍(二)

目录 2.fpei文件下 2.6 number_solver.py 2.7 process.py 2.8 taichi_solver.py 3. 算法总结 4. 代码运行 4.1 测试 4.2 基于GUI后端自定义框输出编辑图像结果 4.2.1 下载open-cv 4.2.2 输入命令 4.2.3 自定义框 4.2.4 按ESC退出 接续Fast-Poisson-Image-Editing代码…

MYSQL和JAVA中将中文汉字按照拼音首字母排序

一、MYSQL将中文汉字按照拼音首字母排序 数据库使用的字符编码是utf8_general_ci&#xff0c;如下 ORDER BY CONVERT(表名.字段名 USING gbk) COLLATE gbk_chinese_ci ASC;若是表查询&#xff0c;CONVERT中可以不添加表名。 查询结果如下&#xff1a; 二、JAVA中将中文汉字…

【Qt】widget圆角,styleSheet

仅配置widget&#xff0c;不设置其子组件。 #widget{background-color: rgba(255, 255, 255, 100); border-top-left-radius: 20; border-top-right-radius: 20; border-bottom-left-radius: 20; border-bottom-right-radius: 20;}

Vue3.0 一些总结 【持续更新】

1. reactive 只适用于对象 (包括数组和内置类型&#xff0c;如 Map 和 Set&#xff0c;它不支持如 string、number 或 boolean 这样的原始类型) import { reactive } from vueconst counter reactive({count: 0 })console.log(counter.count) // 0 counter.count注意&#xf…

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

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

#Docker | Ngrok# 使用Ngrok和Docker进行内网穿透

一、注册 Ngrok官网注册&#xff0c;可以使用gmail或者outlook邮箱&#xff0c; 正常填写后你会收到一封电子邮件&#xff0c;点击邮件中链接即注册成功 二、获取密钥 登录&#xff0c;点击Your Authtoken&#xff0c;最上面copy左边就是你得密钥 三、使用内网穿透启动docker…

Xed编辑器开发第一期:使用Rust从0到1写一个文本编辑器

这是一个使用Rust实现的轻量化文本编辑器。学过Rust的都知道&#xff0c;Rust 从入门到实践中间还隔着好几个Go语言的难度&#xff0c;因此&#xff0c;如果你也正在学习Rust,那么恭喜你&#xff0c;这个项目被你捡到了。本项目内容较多&#xff0c;大概会分三期左右陆续发布&a…

后端之路第一站——Maven

前提&#xff1a;得会基础java 前言&#xff1a;不知道出于什么原因&#xff0c;可能是喜欢犯贱吧&#xff0c;本人从大一到大二都一直在专研前端开发&#xff0c;一点也没接触过后端&#xff0c;但是突然抽风想学后端了&#xff0c;想试着自己全栈搞一下项目&#xff0c;于是在…

为什么公司偏爱高薪招新人,老员工的我怎么办?

目录 前言 性价比 薪酬体系 心理学 技术迭代 老员工的价值 总结 前言 在当下的互联网行业&#xff0c;人才流动性极高&#xff0c;不少公司面临着一个棘手的问题&#xff1a;为什么宁愿花高薪聘请一名应届生&#xff0c;也不愿意给予现有老员工加薪以留住他们&#xff1…

Git大文件无法直接push用git lfs track 上传大文件具体操作

Git 因为大文件push失败 回退到git add前用git lfs track单独添加大文件 以下work flow仅代表个人解决问题的办法&#xff0c;有优化流程的欢迎交流 回退到git add前 以下指令回退一个commit git reset --soft HEAD~1以下指令撤销所有git add操作&#xff0c;但不删除本地修…

数据结构与算法学习笔记三---栈和队列

目录 前言 一、栈 1.栈的表示和实现 1.栈的顺序存储表示和实现 1.C语言实现 2.C实现 2.栈的链式存储表示和实现 1.C语言实现 2.C实现 2.栈的应用 1.数制转换 二、队列 1.栈队列的表示和实现 1.顺序队列的表示和实现 2.链队列的表示和实现 2.循环队列 前言 这篇文…

乡村振兴与农村基础设施建设:加大投入力度,提升建设水平,完善农村基础设施网络,打造宜居宜业的美丽乡村

一、引言 乡村振兴战略是我国在新时代推进农业农村现代化的重大战略部署&#xff0c;其核心目标是实现乡村的全面振兴&#xff0c;促进农业强、农村美、农民富。农村基础设施建设作为乡村振兴的基石&#xff0c;其建设水平直接关系到乡村经济的持续健康发展、乡村环境的改善以…

微软宣布GPT-4o模型,可在 Azure OpenAI上使用

5月14日&#xff0c;微软在官网宣布&#xff0c;OpenAI最新发布的多模态模型GPT-4o&#xff0c;可以在 Azure OpenAI 云服务中使用。 据悉&#xff0c;GPT-4o支持跨文本、视频、音频多模态推理&#xff0c;例如&#xff0c;通过GPT-4o打造一个AI助手&#xff0c;用于辅导孩子解…

【ORACLE战报】2024.4月最新OCP考试喜报.

课程介绍 DBA数据库管理必备认证&#xff1a;ORACLE OCP 19C 教材下载 ORACLE OCP 19C 官方电子教材 ORACLE OCP 12C官方电子教材 题库下载 ORACLE 19C题库 &#xff08;083384题、082362题&#xff09;-2024答案修正版.rar 所有的收获都是默默耕耘的成果 2024.4月【最新考试成…

数据挖掘流程是怎样的?数据挖掘平台基本功能有哪些?

数据挖掘是从大量的、不完全的、有噪声的、模糊的、随机的数据中提取隐含在其中的、人们事先不知道的、但又是潜在有用的信息和知识的过程。 数据挖掘的流程是&#xff1a; 清晰地定义出业务问题&#xff0c;确定数据挖掘的目的。 数据准备: 数据准备包括&am…

精酿啤酒:品质与口感的完善结合

在啤酒的世界中&#xff0c;Fendi club啤酒以其卓着的品质和与众不同的口感赢得了广泛的赞誉。作为精酿啤酒的品牌&#xff0c;Fendi club啤酒始终坚持对品质的追求&#xff0c;为消费者带来超卓的口感体验。 Fendi club啤酒的品质源于对原料的严格挑选和加工。他们选用上好的…