STM32 跑马灯实验介绍及三种实现方法
三种方法:
1. 基于库函数h
2. 基于寄存器
3. 位操作
一. 基于库函数h
1.1 硬件连接
用到的硬件只有 LED(DS0 和 DS1)。其电路在 ALIENTEK MiniSTM32 开发板上默认是已经连接好了的。DS0 接 PA8,DS1 接 PD2。所以在硬件上不需要动任何东西。
IO口输出高电平,LED灭,IO口输出低电平,LED亮
GPIO的输出方式是推挽输出
库函数:
头文件:stm32f10x_gpio.h
源文件:stm32f10x_gpio.c
1.2 编写流程:
1 使能IO口时钟,调用函数RCC_APB2PeriphColckCmd()
2 初始化IO口模式。调用函数GPIO_Init();
3 操作IO口,输出高低电平。
GPIO_Setbits();
GPIO_ResetBit();
编写led.c
#include "led.h"
//初始化PA8和PD2为输出口.并使能这两个口的时钟
//LED IO初始化
void LED_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOD, ENABLE); //使能PA,PD端口时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8; //LED0-->PA.8 端口配置
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz
GPIO_Init(GPIOA, &GPIO_InitStructure); //根据设定参数初始化GPIOA.8
GPIO_SetBits(GPIOA,GPIO_Pin_8); //PA.8 输出高
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; //LED1-->PD.2 端口配置, 推挽输出
GPIO_Init(GPIOD, &GPIO_InitStructure); //推挽输出 ,IO口速度为50MHz
GPIO_SetBits(GPIOD,GPIO_Pin_2); //PD.2 输出高
}
编写led.h
#ifndef __LED_H
#define __LED_H
#include "sys.h"
#define LED0 PAout(8) // PA8
#define LED1 PDout(2) // PD2
void LED_Init(void);//初始化
#endif
main函数
#include "led.h"
#include "delay.h"
#include "sys.h"
int main(void)
{
delay_init(); //延时函数初始化
LED_Init(); //初始化与LED连接的硬件接口
while(1)
{
LED0=0;
LED1=1;
delay_ms(300); //延时300ms
LED0=1;
LED1=0;
delay_ms(300); //延时300ms
}
}
寄存器版本
1.IO介绍
STM32 的 IO 口可以由软件配置成如下 8 种模式:
1、输入浮空
2、输入上拉
3、输入下拉
4、模拟输入
5、开漏输出
6、推挽输出
7、推挽式复用功能
8、开漏复用功能
STM32 的每个 IO 端口都有 7 个寄存器来控制。他们分别是:配置模式的 2 个 32 位的端口
配置寄存器 CRL 和 CRH;2 个 32 位的数据寄存器 IDR 和 ODR;1 个 32 位的置位/复位寄存器
BSRR;一个 16 位的复位寄存器 BRR;1 个 32 位的锁存寄存器 LCKR;这里我们仅介绍常用 的
几个寄存器,我们常用的 IO 端口寄存器只有 4 个:CRL、CRH、IDR ODR。
CRL 和 CRH 控制着每个 IO 口的模式及输出速率。
1.2 编写流程
1 使能IO口时钟。配置寄存器RCC APB2ENR。
2 初始化IO口模式。配置寄存器GPIOx_CRH/CRL
3 操作IO口,输出高低电平。配置寄存器
GPIO_ODR或BSRR/BRR。
编写led.c
#include "sys.h"
#include "led.h"
//初始化PA8和PD2为输出口.并使能这两个口的时钟
//LED IO初始化
void LED_Init(void)
{
RCC->APB2ENR|=1<<2; //使能PORTA时钟
RCC->APB2ENR|=1<<5; //使能PORTD时钟
GPIOA->CRH&=0XFFFFFFF0;
GPIOA->CRH|=0X00000003;//PA8 推挽输出
GPIOA->ODR|=1<<8; //PA8 输出高
GPIOD->CRL&=0XFFFFF0FF;
GPIOD->CRL|=0X00000300;//PD.2推挽输出
GPIOD->ODR|=1<<2; //PD.2输出高
}
编写led.h
#ifndef __LED_H
#define __LED_H
#include "sys.h"
//LED端口定义
#define LED0 PAout(8) // PA8
#define LED1 PDout(2) // PD2
void LED_Init(void); //初始化
#endif
编写main.c
#include "sys.h"
#include "usart.h"
#include "delay.h"
#include "led.h"
int main(void)
{
Stm32_Clock_Init(9); //系统时钟设置
delay_init(72); //延时初始化
LED_Init(); //初始化与LED连接的硬件接口
while(1)
{
LED0=0;
LED1=1;
delay_ms(300);
LED0=1;
LED1=0;
delay_ms(300);
}
}
位带操作
1.1 位带操作的介绍及基本原理
位操作的本质目的就是操作寄存器
1 位操作比较方便操作IO口
2 位操作原理
把每个比特膨胀为一个32位的字,当访问这些字的时候就达到了访问
比特的目的,比如说BSRR寄存器有32个位,那么可以映射到32个地址
上,我们去访问(读-改-写)这32个地址就达到访问32个比特的目的。
3 哪些区域支持位操作
其中一个是 SRAM 区的最低 1MB 范围,
0x20000000 ‐ 0x200FFFFF(SRAM 区中的最低 1MB)
第二个则是片内外设区的最低 1MB范围,
0x40000000 ‐ 0x400FFFFF(片上外设区中最低 1MB)
4 sys.h里面对GPIO输入输出部分功能实现了位带操作
5 最终输出都操作了ODR寄存器
编写流程
1 使能IO口时钟。调用函数RCC_APB2PeriphphColckCmd();
2 初始化IO口模式。调用函数GPIO_Init();
3 操作IO口,输出高低电平(使用位带操作)
编写led.c
#include "led.h"
//初始化PA8和PD2为输出口.并使能这两个口的时钟
//LED IO初始化
void LED_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOD, ENABLE); //使能PA,PD端口时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8; //LED0-->PA.8 端口配置
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz
GPIO_Init(GPIOA, &GPIO_InitStructure); //根据设定参数初始化GPIOA.8
GPIO_SetBits(GPIOA,GPIO_Pin_8); //PA.8 输出高
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; //LED1-->PD.2 端口配置, 推挽输出
GPIO_Init(GPIOD, &GPIO_InitStructure); //推挽输出 ,IO口速度为50MHz
GPIO_SetBits(GPIOD,GPIO_Pin_2); //PD.2 输出高
}
编写main.c
#include "led.h"
#include "delay.h"
#include "sys.h"
int main(void)
{
delay_init(); //延时函数初始化
LED_Init(); //初始化与LED连接的硬件接口
while(1)
{
PAout(5)=1;
PDout(5)=1;
delay_ms(500); //延时500ms
PAout(5)=1;
PDout(5)=1;
}
}