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的型号分类及缩写

 

新建工程步骤

  • 22
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值