本文是对stm32mini单片机跑马灯实验的一个总结。小白发文,如有疏漏,还请大神赐教。
一,所用寄存器说明
首先是对IO口模式的说明:IO口分为8种模式
1,输入浮空(GPIO_Mode_IN_FLOATING)
2,输入上拉(GPIO_Mode_IPU)
3,输入下拉(GPIO_Mode_IPD)
4,模拟输入(GPIO_Mode_AIN)
5,开漏输出(GPIO_Mode_Out_OD)
6,推挽输出(GPIO_Mode_Out_PP)
7,推挽式复用功能(GPIO_Mode_AF_PP)
8,开漏复用功能(GPIO_Mode_AF_OD)
stm32的每个IO口都由7个寄存器来控制。其中,CRL和CRH两个32位的寄存器负责配置模式(mode)及输出速率(speed),也是本次实验的主力寄存器。CRL控制每组IO口的低8位的模式,每个IO口占CRL的4个位,高两位为CNF,低两位为MODE。CRH则控制高8位的模式,其他与CRL相同。
在本次的实验中,操控CRL和CRH控制IO口模式和速率的任务则交由GPIO初始化函数来完成。
void GPIO_Init(GPIO_TypeDef*GPIOx,GPIO_InitTypeDef*GPIO_InitStruct);
其中第一个变量是选定IO口组,第二个变量则是初始化参赛结构体指针,其定义包括了选定该端口组的第几个端口,该端口的模式和速率。
IDR 是一个端口输入数据寄存器,为只读寄存器,并且只能以 16 位的形式读出,我们可以通过读它来判断某个IO口的电平状态。
固件库中操作IDR寄存器是通过操作GPIO_ReadInputDataBit函数实现的。
uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
第一个变量也是选定IO口组,第二个选定端口,读出该端口的电平数据。返回值是1(高电平)和0(低电平)。
ODR 是一个端口输出数据寄存器,为可读写寄存器,我们既可以通过读该寄存器的值判断IO口的输出状态,也可以通过向该寄存器写入数据来控制IO口的输出电平。
BSRR 寄存器是端口位设置/清除寄存器,可 以用来设置 GPIO 端口的输出位是 1 还是 0。BRR 寄存器是端口位清除w寄存器。
我们通过函数 GPIO_SetBits(G)和函数 PIO_ResetBits()来控制BSRR和BRR寄存器设置GPIO端口的输出
void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
两个变量含义同上。
二,跑马灯实验
接下来就是跑马灯实验的实战了。
首先是跑马灯的硬件连接
本实验在正点原子Template工程模板的基础上进行修改
首先创建如下工程(led,c是之后创建的)
可以看出与工程模板的不同是FWLib文件夹中只保留了led.c需要用到的固件库。也即
stm32f10x_gpio.c /stm32f10x_gpio.h
stm32f10x_rcc.c/stm32f10x_rcc.h
misc.c/ misc.h
stm32f10x_usart /stm32f10x_usart.h
之后新建一个文件夹HARDWARE,在其中再建LED文件夹,在里面建立led.c,内容为
#include "led.h"
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 输出高
}
这段代码的作用是初始化PA8和PD2为输出口,使能PA,PD端口时钟,并使LED IO初始化。
尤其要注意的是配置stm32外设时,必须先要初始化该外设的时钟。
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|
RCC_APB2Periph_GPIOD, ENABLE); //使能 PA,PD 端口时钟
配置时钟后的代码就是设置两端口的初始模式。因为两端口的初始化参数都设置在变量GPIO_InitStructure中,且两端口的模式和速度一致,所以我们只初始化一次。最后用
GPIO_SetBits将两IO口的初始输出电平都设为1.
然后我们在LED文件夹下再建一个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
头文件的作用就是宏定义了PA8和PD2,这里是通过位带操作实现的。
注意要将头文件的路径添加上
最后在main.c中输入如下代码
#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
}
}
上面的delay.h和sys.h都可以在SYSTEM文件夹中找到。
先是用delay_init初始化延时,然后LED_init初始化PA8和PD2,使其为输出端。
最后用while(1)使两个LED灯每隔300毫秒交替闪烁。
之后编译即可。