这段时间开始学STM32F103ZET6,带着51的思路去看32,感觉还是有很多地方是共通的。昨天看了STM32的GPIO的八种输入输出模式,今天将之应用一下,还是以前51的实验——跑马灯。
STM32和51相比,资源多了很多,所以对于STM32的输入输出,也存在不同的代码写法。
(1)调用STM的库函数,从而实现32内部寄存器的配置。
(2)直接对寄存器进行操作。
(3)利用一些宏和宏函数,进行地址映射,从而实现寄存器配置。
总的来说,这三种方法的目的都是一样的,只是方法不一样罢了,最终效果都是配置一些寄存器。跑马灯这个实验有三个步骤:
1、开启对应GPIO的时钟使能
2、设置GPIO对应引脚
3、主函数显示
注:每一块开发板对应电路都不相同,所以GPIO的引脚配置是不一样的,本人两个LED灯对应的GPIO为:GPIOD13和GPIOD14,并且是共阴极。
一、库函数版本跑马灯
函数:void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState)
功能:配置APB2 外设复位寄存器 (RCC_APB2RSTR),这里我使用的是GPIOD,所以函数第一个参数为RCC_APB2Periph_GPIOD,第二个参数是判断状态的,所以为ENABLE,开启状态。
函数:void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct)
功能:该函数的第一个参数选定哪一个GPIO口,这里显然填GPIOD,第二个参数为一个结构体指针,只需定义一个结构体,将其数据填满,在将地址传参即可。
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;
结构体第一个参数选定引脚,这里为GPIO_Pin_13和GPIO_Pin_14,第二个参数选定速率,这里选了GPIO_Speed_50MHz,第三个参数选定输入输出模式,这里选择推挽输出,即GPIO_Mode_Out_PP。
注:这里的GPIO_Pin_13、GPIO_Speed_50MHz等都是STM库函数中定义的宏,可以在库函数头文件中查找。
函数:void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
功能:将对应的GPIO引脚置0
函数:void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
功能:将对应的GPIO引脚置1
库函数配置程序:
void LED_Init(void)
{
GPIO_InitTypeDef GPIO_init;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE);
GPIO_init.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_init.GPIO_Pin = GPIO_Pin_13;
GPIO_init.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOD, &GPIO_init);
GPIO_ResetBits(GPIOD, GPIO_Pin_13);
GPIO_init.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_init.GPIO_Pin = GPIO_Pin_14;
GPIO_init.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOD, &GPIO_init);
GPIO_ResetBits(GPIOD, GPIO_Pin_14);
}
主程序:
int main(void)
{
LED_Init();
delay_init();
while(1)
{
GPIO_ResetBits(GPIOD, GPIO_Pin_13);
GPIO_ResetBits(GPIOD, GPIO_Pin_14);
delay_ms(500);
GPIO_SetBits(GPIOD, GPIO_Pin_13);
GPIO_SetBits(GPIOD, GPIO_Pin_14);
delay_ms(500);
}
}
二、寄存器版本跑马灯
寄存器版本的跑马灯只需配置一些相关的寄存器即可,需要阅读STM32相关文档,对寄存器功能了解。
首先配置APB2 外设复位寄存器(RCC_APB2RSTR),这里可以阅读STM32中文参考手册的第7.4节,了解RCC寄存器的配置方法,我这里需要复位GPIOD,所以配置RCC_APB2RSTR的位5为1即可,即RCC->APB2ENR |= 1<<5;
然后配置GPIOx_CRH和GPIOx_ODR寄存器即可。
寄存器配置程序:
void LED_Init()
{
RCC->APB2ENR |= 1<<5; //¿ªÆôGPIODµÄʱÖÓ
//GPIOD.13 GPIOD.14
GPIOD->CRH &= 0xF00FFFFF;
GPIOD->CRH |= 0x03300000;
GPIOD->ODR |= 1<<13;
GPIOD->ODR |= 1<<14;
}
主函数:
int main(void)
{
delay_init();
LED_Init();
while(1)
{
GPIOD->ODR |= 3<<13;
delay_ms(500);
GPIOD->ODR &= 0x9fff;
delay_ms(500);
}
}
三、位操作版本跑马灯
位操作初始化和库函数初始化一样,区别就是对GPIO口进行输出赋值时不同,库函数版本使用GPIO_ResetBits和GPIO_SetBits函数进行赋值,而位操作可以操作宏,直接赋值。
位操作配置程序:
#include "sys.h"
#define LED0 PDout(13) // PD13
#define LED1 PDout(14) // PD14
void LED_Init(void)
{
GPIO_InitTypeDef GPIO_init;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE);
GPIO_init.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_init.GPIO_Pin = GPIO_Pin_13;
GPIO_init.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOD, &GPIO_init);
GPIO_ResetBits(GPIOD, GPIO_Pin_13);
GPIO_init.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_init.GPIO_Pin = GPIO_Pin_14;
GPIO_init.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOD, &GPIO_init);
GPIO_ResetBits(GPIOD, GPIO_Pin_14);
}
主函数:
int main(void)
{
delay_init();
LED_Init();
while(1)
{
LED0=1;
LED1=1;
delay_ms(500);
LED0=0;
LED1=0;
delay_ms(500);
}
}