Bootstrap

正点原子STM32F103综合课程操作学习笔记(包含代码)

整理资料来源

词汇解释

pin:引脚

specifies:指定

configure:配置

STM32固件库

解释:类似于C语言编程中调用printf()一样,调用标准外设库的库函数。为开发者访问底层硬件提供一个中间API

STM32F10x_StdPeriph_Lib_V3.5.0

在这里插入图片描述

Libraries:

​ CMSIS:内核库文件

CoreSuport:

Cortex-M3核内外设函数文件夹,Cortcx-M3内核通用源文件core_cm3.c和Cortcx-M3内核通用头文core_cm3.h

STM32F10x_StdPeriph_Lib_V3.5.0\Libraries\CMSIS\CM3\DeviceSupport\ST\STM32F10x\startup\arm:启动代码文件

DeviceSuport:

设备外设支持函数文件夹,STM32F0x头文件stm32f10x.h和系统初始化文件system_stm32f10x.c

​ STM32F10x_StdPeriph_Driver:

存放ST为STM32F10x每个外设而编写的库函数源代码文件和头文件

创建Template模板模板自取

Template:

​ |—Systems/CORE:相关的启动文件以及内核文件,系统初始化文件system_stm32f10x.c

​ |—FWLib/HALLIB:存放ST为STM32F10x每个外设而编写的库函数源代码文件和头文件

​ |—|---Src:.c

​ |—|---Inc:.h

​ |—BSP/OBJ:存放用户自己编写的硬件驱动文件,比如LED.c、LED.h等

​ |—USER:存放main函数和中断程序。复制stm32f10x_conf.h、stm32f10x_it.c、stm32f10x_it.h和main.c

  • 芯片型号Device:STMF103RB

  • 其中 DebugConfig 文件夹用于存储一些调试配置文件,Listings 和 Objects 文件夹用来存储 MDK 编译过程的一些中间文件(可删)

  • 把内核、启动文件、外设等相关的库文件添加进Keil工程

  • 在“Target”选项页中设置晶振为8MHz,并勾选“Use MicroLIB”(使用Micro库)

  • 在“Output”选项页中勾选“Create HEX File”,生成HEX文件

  • 在工程设置窗口的“C/C++”选项页的“Define”框中输入两个宏:
    USE_STDPERIPH_DRIVER , STM32F10X_MD

    目的:为了屏蔽编译器的默认搜索路径,转而使用添加到工程中的STM32F10x标准外设库,即使用STM32F10x标准外设库进行STM32的开发

  • 在工程设置窗口的“C/C++”选项页的“Include Paths”中,将工程头文件.h添加进搜索路径中

  • 单击Settings按钮,在弹出的界面中勾选中“Reset and Run”,选择“Erase Full Chip”,每次烧写都将擦除掉芯片上已有的内容

  • 软件模拟仿真??

错误总结

Error: L6320W: Ignoring --entry command. Cannot find argument ‘Reset_Handler’.
Warning: L6320W: Ignoring --first command. Cannot find argument ‘__Vectors’.

在这里插入图片描述

在这里插入图片描述

通用目的的输入输出口

1. GPIO:General Purpose Input/Output

端口号:端口号通常以大写字母命名,从A开始,依次类推。例如,GPIOA、GPIOB、GPIOC、…等

引脚号:每个端口有16个I/O引脚,分别命名为0-15。例如,STM32F103RB微控制器的GPIOA端口有16个引脚,分别为PA0、PA1、PA2、PA3、…、PA14和PA15。

在这里插入图片描述

IO口8种模式:

​ 1、输入浮空GPIO_Mode_IN_FLOATING:浮空(floating)就是逻辑器件的输入引脚即不接高电平,也不接低电平。由于逻辑器件的内部结构,当它输入引脚悬空时,相当于该引脚接了高电平。一般实际运用时,引脚不建议悬空,易受干扰。通俗讲就是让管脚什么都不接,浮空着。

​ 2、输入上拉GPIO_IPU:上拉就是把电位拉高,比如拉到Vcc。上拉就是将不确定的信号通过一个电阻嵌位在高电平!电阻同时起限流作用!强弱只是上拉电阻的阻值不同,没有什么严格区分。

​ 3、输入下拉GPIO_IPD:就是把电压拉低,拉到GND。与上拉原理相似

​ 4、模拟输入GPIO_AIN:应用ADC模拟输入,或者低功耗下省电

​ 5、开漏输出GPIO_OUT_OD:IO输出0接GND,IO输出1,悬空,需要外接上拉电阻,才能实现输出高电平。当输出为1时,IO口的状态由上拉电阻拉高电平,但由于是开漏输出模式,这样IO口也就可以由外部电路改变为低电平或不变。可以读IO输入电平变化,实现C51的IO双向功能

​ 6、推挽输出GPIO_OUT_PP:高低电平,IO输出0-接GND, IO输出1 -接VCC,读输入值是未知的

​ 7、复用功能的推挽输出GPIO_AF_PP:片内外设功能(I2C的SCL,SDA)

​ 8、复用功能的开漏输出GPIO_AF_OD:片内外设功能(TX1,MOSI,MISO.SCK.SS)

  • 复用开漏输出、复用推挽输出:可以理解为GPIO口被用作第二功能时的配置情况(即并非作为通用IO口使用)

在这里插入图片描述

  • 通常有5种方式使用某个引脚功能,它们的配置方式如下:
    1、作为普通GPIO输入:根据需要配置该引脚为浮空输入、带弱上拉输入或带弱下拉输入,同时不要使能该引脚对应的所有复用功能模块。
    2、作为普通GPIO输出:根据需要配置该引脚为推挽输出或开漏输出,同时不要使能该引脚对应的所有复用功能模块。
    3、作为普通模拟输入:配置该引脚为模拟输入模式,同时不要使能该引脚对应的所有复用功能模块。
    4、作为内置外设的输入:根据需要配置该引脚为浮空输入、带弱上拉输入或带弱下拉输入,同时使能该引脚对应的某个复用功能模块。
    5、作为内置外设的输出:根据需要配置该引脚为复用推挽输出或复用开漏输出,同时使能该引脚对应的所有复用功能模块。
    注意如果有多个复用功能模块对应同一个引脚,只能使能其中之一,其它模块保持非使能状态。 比如要使用STM32F103VBT6的47、48脚的USART3功能,则需要配置47脚为复用推挽输出或复用开漏输出,配置48脚为某种输入模式,同时使能USART3并保持I2C2的非使能状态。 如果要使用STM32F103VBT6的47脚作为TIM2_CH3,则需要对TIM2进行重映射,然后再按复用功能的方式配置对应引脚。

2. IO口库函数介绍(官方库最终也是操作寄存器)

在这里插入图片描述

在这里插入图片描述

GPIO_Init参数:

​ GPIO_TypeDef* GPIOx:选择哪个GPIO端口

​ GPIO_InitTypeDef* GPIO_InitStruct:相关参数初始化

注意:`assert_param`后面 /* Check the parameters */可以获取其参数可选值。选择要获取的typedef struct信息右击Go To the Definition of "typedef struct"
(要先编译才可以跳转参数)

初始化示例代码

GPIO_InitTypeDef GPIO_InitStructure; //定义一个初始化化结构体,之后在这个结构体中设置参数	

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC , ENABLE); //时钟	

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All;//这里初始化了所有引脚,前提是这些IO口的配置方式一样
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz; 
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ; 

GPIO_Init(GPIOC, &GPIO_InitStructure); //根据参数初始化,GPIOC组

GPIO_InitStructure.GPIO_Mode:

表示命名为GPIO_InitStructure的结构体(typedef struct)里面定义的GPIO_Mode。如下例

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;

跑马灯实验步骤

  1. 创建LED.c LED.h文件

    .h文件要点:

    ​ 写下公共宏定义和函数声明,可以被多个.c文件引用,避免重复代码

    ​ 头文件中使用#ifndef、#define开始,#endif结尾,避免头文件内容被重复编译

    #ifndef _LED_H
    #define _LED_H
    #include "stm32f10x.h"//必须引用,包含所有外设寄存器和结构体定义,这样就可以引用具体可函数就不会报错
    void LEDInit(void);
    void LEDdisplay(void);
    
    #endif
    
  2. 使能IO口时钟

时钟库文件stm32f10x_rcc.c源文件

void RCC_AHBPeriphClockCmd(uint32_t RCC_AHBPeriph, FunctionalState NewState);
void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState);
void RCC_APB1PeriphClockCmd(uint32_t RCC_APB1Periph, FunctionalState NewState);
  • AHB总线时钟

  • APB1低速外设:TIM2~7、TIM12、TIM13、TIM14、WWDG、SPI2、SPI3、USART2、USART3、UART4、UART5、12C1、12C2、USB、CAN1、CAN2、BKP、PWR、DAC、CEC

  • APB2高速外设:AFIO、GPIOAG、ADC12、TIM1、SPI1、TIM8、USART1、ADC3、TIM15、TIM16、TIM17、TIM9、TIM10、TIM11

例如使能APB2的GPIOC时钟:

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC , ENABLE);
  1. 初始化IO口模式。调用函数GPIO_Init()
  2. 操作IO口,输出高低电平,高GPIO_SetBits()、低GPIO_ResetBits()
#include "Led.h"
#include "stm32f10x.h"
void LEDInit()
{
     
	GPIO_InitTypeDef GPIO_InitStructure; 
	SystemInit();
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC , ENABLE); 
	
	//定义一个初始化结构体,因为要传入的参数不止一个
		
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All; //所有引脚
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz; 
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ; 
	
	GPIO_Init(GPIOC, &GPIO_InitStructure); //根据参数初始化,GPIOC端口
  GPIO_Write(GPIOC,0x00);
}	

void LEDdisplay()
{
    
	u32 i;
  GPIO_SetBits(GPIOC, GPIO_Pin_All);	
	GPIO_ResetBits(GPIOC, GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_6); 
	for(i=0;i<18000000;i++) ;
	while(1)
	{
   
		//方法一GPIO_SetBits£¬GPIO_ResetBits
		/* 
		GPIO_ResetBits(GPIOC, GPIO_Pin_1); 
		GPIO_SetBits(GPIOC, GPIO_Pin_0);
		for(i=0;i<12000000;i++);		
		GPIO_SetBits(GPIOC, GPIO_Pin_1); 
		for(i=0;i<12000000;i++);
		GPIO_ResetBits(GPIOC, GPIO_Pin_All); 
		GPIO_SetBits(GPIOC, GPIO_Pin_1);
		for(i=0;i<18000000;i++)
		GPIO_ResetBits(GPIOC, GPIO_Pin_All); 
		GPIO_SetBits(GPIOC, GPIO_Pin_2);
		*/
		
		//方法二GPIO_Write
	GPIO_Write(GPIOC, 0xfe); 
	for(i=0;i<6000000;i++) ;
	GPIO_Write(GPIOC, 0xfd); 
	for(i=0;i<6000000;i++) ;
	GPIO_Write(GPIOC, 0xfb); 
	for(i=0;i<6000000;i++) ;
	GPIO_Write(GPIOC, 0xf7); 
	for(i=0;i<6000000;i++) ;
	GPIO_Write(GPIOC, 0xef); 
	for(i=0;i<6000000;i++) ;
	GPIO_Write(GPIOC, 0xdf); 
	for(i=0;i<6000000;i++) ;
	GPIO_Write(GPIOC, 0xbf); 
	for(i=0;i<6000000;i++) ;
	GPIO_Write(GPIOC, 0x7f); 
	for(i=0;i<6000000;i++) ; 
	}
}

蜂鸣器实验

  1. 蜂鸣器简介

    有源蜂鸣器自带了震荡电路,一通电就会发声;无源蜂鸣器则没有自带震荡电路,必须外部提供 2~5Khz 左右的方波驱动,才能发声。

  2. 硬件设计

在这里插入图片描述

蜂鸣器的驱动信号连接在 STM32 的 PB8 上。图中我们用到一个 PNP 三极管(S8550)放大电流来驱动蜂鸣器,R25 主要用于控制 PNP 管饱和导通作用。当 PB.8 输出低电平的时候,蜂鸣器将发声,当 PB.8 输出高电平的时候,蜂鸣器停止发声。

  1. 软件设计

    beep.h

#ifndef _BEEP_H
#define _BEEP_H
#include "stm32f10x.h"
#include "sys.h"

void BEEP_Init(void);

#endif

beep.c

#include "beep.h"
//蜂鸣器IO口初始化
void BEEP_Init(void){
   
GPIO_InitTypeDef GPIO_Initure;
	//开启GPIOB时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
	GPIO_Initure.GPIO_Pin=GPIO_Pin_8;//开启蜂鸣器连接的PB8引脚 
	GPIO_Initure.GPIO_Mode=GPIO_Mode_Out_PP;//推挽输出
	GPIO_Initure.GPIO_Speed=GPIO_Speed_50MHz;//高速
	GPIO_Init(GPIOB,&GPIO_Initure);
	//BEEP引脚输入高电平,三级管导通,蜂鸣器发声。反之,截止,蜂鸣器关闭。
	GPIO_SetBits(GPIOB,GPIO_Pin_8);//输出1,关闭蜂鸣器输出
}

main.c

#
;