目录
库函数ver.
原理
1.使能IO口时钟
RCC_APB2PeriphClockCmd()
这里需要了解一下时钟的作用:
首先,寄存器是基于D触发器的(D触发器属于寄存器),想要往触发器里面写东西,前提条件是有时钟输入。换句话说,只有给触发器送来了时钟,触发器才能被改写值,这样寄存器才会工作。
STM32是低功耗的,即采用了时钟门控的技术。其所有的门都默认设置为disable(不使能),如果要使用,就需要让其enable(使能),也就是说用到什么外设,只要打开对应外设的时钟就可以
2.初始化IO口模式
调用GPIO_Init()
3.操作IO口输出高低电平
GPIO_SetBits() 高电平 GPIO_ResetBits() 低电平
代码
1. LED.c
包括使能IO口时钟,初始化IO口模式
#include "stm32f10x.h" // Device header
#include "LED.h"
void LED_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
/*使能时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//使能GPIOB的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE,ENABLE);//使能GPIOE的时钟
/*GPIOB初始化*/
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP; //设置为推挽模式
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_5; //GPIOB5
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; //最大输出速度
GPIO_Init(GPIOB,&GPIO_InitStruct);
/*GPIOE初始化**/
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP; //设置为推挽模式
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_5; //GPIOE5
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; //最大输出速度
GPIO_Init(GPIOE,&GPIO_InitStruct);
/*将接LED的引脚置为高电平,使LED不亮*/
GPIO_SetBits(GPIOB,GPIO_Pin_5);
GPIO_SetBits(GPIOE,GPIO_Pin_5);
}
/* LED.h
#ifndef _LED_H_
#define _LED_H_
#include "sys.h" //为了引用端口
//LED 端口定义
#define LED0 PBout(5)// DS0
#define LED1 PEout(5)// DS1
void LED_Init(void);
#endif
*/
2.main.c
包括反复操作IO口输出高低电平,对delay初始化,调用delay函数
#include "stm32f10x.h" // Device header
#include "LED.h"
#include "delay.h"
int main()
{
LED_Init(); //LED初始化
delay_init(); //delay初始化
while(1)
{
/* 对IO口置高电平,LED不亮 */
GPIO_SetBits(GPIOB,GPIO_Pin_5);
GPIO_SetBits(GPIOE,GPIO_Pin_5);
delay_ms(500);
/* 对IO口置低电平,LED亮 */
GPIO_ResetBits(GPIOB,GPIO_Pin_5);
GPIO_ResetBits(GPIOE,GPIO_Pin_5);
delay_ms(500);
}
}
寄存器ver.
原理
1.使能IO口时钟
配置寄存器RCC_APB2ENR
RCC寄存器是一个用于控制系统时钟和外设时钟的寄存器,其包括APB2 外设时钟使能 寄存器(RCC_APB2ENR),因为GPIO都挂载到APB2总线上,故使能IO口的时钟也就是配置 寄存器RCC_APB2ENR的对应位,使其为1(ENABLE)
2.初始化IO口模式
配置寄存器GPIOx_CRH/CRL
3.操作IO口输出高低电平
配置寄存器GPIOx_ODR或BSRR,BRR
代码
1.LED.c
包括使能IO口时钟,初始化IO口模式
#include "stm32f10x.h" // Device header
#include "LED.h"
void LED_Init()
{
/*直接配置RCC_APB2ENR对应位,使能IO口的时钟*/
RCC->APB2ENR |= 1 << 3; //使能GPIOB
RCC->APB2ENR |= 1 << 6; //使能GPIOE
/*GPIOB5初始化*/
GPIOB->CRL &= 0xFF0FFFFF; //只对CRL寄存器内控制PB5的位清零
GPIOB->CRL |= 0x00300000;
//让CRL寄存器内控制PB5的位表示为推挽输出模式,50MHz
/*GPIOE5初始化*/
GPIOE->CRL &= 0xFF0FFFFF; //只对CRL寄存器内控制PE5的位清零
GPIOE->CRL |= 0x00300000;
//让CRL寄存器内控制PE5的位表示为推挽输出模式,50MHz
/*直接控制ODR寄存器,使IO口输出高电平,LED初始为灭*/
GPIOB->ODR |= 1 << 5;
GPIOE->ODR |= 1 << 5;
}
/* LED.h
#ifndef _LED_H_
#define _LED_H_
#include "sys.h" //为了引用端口
//LED 端口定义
#define LED0 PBout(5)// DS0
#define LED1 PEout(5)// DS1
void LED_Init(void);
#endif
*/
需要非常注意的是:在声明函数时,如果函数没有形参,应在参数表内写入"void",否则keil会报错!!!
2.main.c
包括直接操作ODR寄存器改变IO口电平,设置系统时钟,对delay函数初始化(寄存器ver.的需要系统时钟作为参数)
#include "stm32f10x.h" // Device header
#include "delay.h"
#include "LED.h"
int main()
{
Stm32_Clock_Init(9);
//设置系统时钟,配置系统时钟为 9 倍频,即8(外部晶振8Mhz)*9(倍频) == 72MHz
delay_init(72); //寄存器ver.的delay初始化函数需要系统时钟作为参数
LED_Init();
while(1)
{
GPIOB->ODR |= 1 << 5;
GPIOE->ODR |= 1 << 5;
delay_ms(500);
GPIOB->ODR &= ~(1 << 5);
GPIOE->ODR &= ~(1 << 5);
delay_ms(500);
}
}
位操作ver.
位操作原理
位带别名区把寄存器的每个位都膨胀为一个32bit的字,当你通过位带别名区去访问这些字,或是说去访问这映射的32个地址时,就可以达到访问原始比特的目的
位操作优点
1.系统读写数据更方便,效率更高
2.代码更简洁
程序原理
使能时钟,初始化IO口可参考库函数ver.的
唯一的改变就是利用位操作控制IO口输出高低电平
代码
涉及的位操作函数在 sys.h 中
1.LED.c
参考前文库函数ver.
2.main.c
#include "stm32f10x.h" // Device header
#include "LED.h"
#include "delay.h"
int main()
{
LED_Init();
delay_init();
while(1)
{
PBout(5) = 1;
PEout(5) = 1;
delay_ms(500);
PBout(5) = 0;
PEout(5) = 0;
delay_ms(500);
}
}