用标准外设库方式使用GPIOA端口管脚控制八个LED灯,轮流闪烁,间隔时长1秒。
一、工程创建
1.创建一个新工程
点击project,new project,然后选择存放工程的文件夹
选择芯片STM32F103C8,点击ok
在刚刚创建的文件夹下新建三个文件夹:Start,Library,User
2.添加固件库启动文件
找到固件库的启动文件,将其放在刚刚建立的Start文件下
然后将stm32f10x和system的两个文件复制到Start文件下
再将core_cm3的两个文件复制到Start文件下
3.标准外设驱动
将inc和src文件夹下的文件全部复制到Library文件下(可以在官网找到这些文件)
将这几个文件添加到User下
将自己需要写的代码放进main.c里就可以了。
4.环境配置
回到keil,点击这个图标
建立三个文件夹,并把需要的文件添加进去
点击魔术棒
点击c/c++,选中Include Path,然后将Start,Library,User这三个文件添加进去
在Define栏填上USE_STDPERIPH_DRIVER
点击Debug,将Use选为ST_Link Debugger,并点击settings,勾选Reset and Run,点击确定
二、代码编写
1.操作STM32的三个步骤
(1)使用RCC开启GPIO时钟
(2)使用GPIO_Init函数初始化GIPO
(3)使用输出或输入的函数控制GPIO口
其中,涉及了RCC和GPIO这两个外设。
2.RCC和GPIO的库函数
(1)RCC库函数,开启时钟
AHB外设时钟控制的函数是使能或失能AHB外设时钟
void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState);
其中,第一个参数选择外设,第二个参数使能或失能。
我们要点亮PA0口的LED灯,因此选择RCC_APB2外设_GPIOA这一项,将其放到第一个参数上;第二个参数选择ENABLE使能 。
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
(2)GPIO库函数
void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct);
这个函数的作用是用结构体的参数来初始化GPIO口。需要先定义一个结构体变量,再对结构体进行赋值,最后再调用这个函数。这个函数的内部会自动读取结构体的值,然后自动把外设的参数配置好。
首先定义结构体类型:GPIO_InitTypeDef GPIO_InitStructure;
再设置结构体的三个成员:GPIO_Mode,GPIO_Pin,GPIO_Speed
GPIO_Mode有八个工作模式,我们选择推挽模式。
typedef enum
{ GPIO_Mode_AIN = 0x0, //模拟输入
GPIO_Mode_IN_FLOATING = 0x04, //浮空输入
GPIO_Mode_IPD = 0x28, //下拉输入
GPIO_Mode_IPU = 0x48, //上拉输入
GPIO_Mode_Out_OD = 0x14, //开漏输出
GPIO_Mode_Out_PP = 0x10, //推挽输输出
GPIO_Mode_AF_OD = 0x1C, //复用开漏输出
GPIO_Mode_AF_PP = 0x18 //复用推挽输出
}GPIOMode_TypeDef;
GPIO_Pin为选择的引脚,我们根据需要选择引脚。
GPIO_Speed为输出速度,我们选择50MHZ。
因此,创建的结构体如下:
GPIO_InitTypeDef GPIO_InitStructure; //定义结构体
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出模式
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All; //端口初始化
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //输出速度
3.延时函数
Delay.c
#include "stm32f10x.h"
/**
* @brief 微秒级延时
* @param xus 延时时长,范围:0~233015
* @retval 无
*/
void Delay_us(uint32_t xus)
{
SysTick->LOAD = 72 * xus; //设置定时器重装值
SysTick->VAL = 0x00; //清空当前计数值
SysTick->CTRL = 0x00000005; //设置时钟源为HCLK,启动定时器
while(!(SysTick->CTRL & 0x00010000)); //等待计数到0
SysTick->CTRL = 0x00000004; //关闭定时器
}
/**
* @brief 毫秒级延时
* @param xms 延时时长,范围:0~4294967295
* @retval 无
*/
void Delay_ms(uint32_t xms)
{
while(xms--)
{
Delay_us(1000);
}
}
/**
* @brief 秒级延时
* @param xs 延时时长,范围:0~4294967295
* @retval 无
*/
void Delay_s(uint32_t xs)
{
while(xs--)
{
Delay_ms(1000);
}
}
为了方便使用,将延时函数做成了Delay.h的头文件
Delay.h
#ifndef __DELAY_H
#define __DELAY_H
void Delay_us(uint32_t us); //微秒
void Delay_ms(uint32_t ms); //毫秒
void Delay_s(uint32_t s); //秒
#endif
在keil中再新建一个文件夹System,将延时函数的文件放进去。
将时间间隔设置为1秒,因此选择void Delay_s(uint32_t s)即可。
void Delay_s(1); //秒
4.设置灯的亮灭
使用GPIO_Write函数进行写入操作,实现流水灯。
void GPIO_Write(GPIO_TypeDef* GPIOx, uint16_t PortVal);
第一个参数是GPIOA,第二个参数写PA0-PA7对应的八个端口的16进制。
5.最终代码
#include "stm32f10x.h" //头文件
#include "Delay.h"
int main(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //开启时钟
GPIO_InitTypeDef GPIO_InitStructure; //定义结构体
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All; //端口初始化
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //设置输出速度为50MHZ
GPIO_Init(GPIOA, &GPIO_InitStructure); //将GPIO初始化的地址放在GPIO_Init的第二个参数上
while (1)
{
GPIO_Write(GPIOA, ~0x0001); //0000 0000 0000 0001 低电平点亮,需在前面加一个取反的符号
Delay_s(1);
GPIO_Write(GPIOA, ~0x0002); //0000 0000 0000 0010
Delay_s(1);
GPIO_Write(GPIOA, ~0x0004); //0000 0000 0000 0100
Delay_s(1);
GPIO_Write(GPIOA, ~0x0008); //0000 0000 0000 1000
Delay_s(1);
GPIO_Write(GPIOA, ~0x0010); //0000 0000 0001 0000
Delay_s(1);
GPIO_Write(GPIOA, ~0x0020); //0000 0000 0010 0000
Delay_s(1);
GPIO_Write(GPIOA, ~0x0040); //0000 0000 0100 0000
Delay_s(1);
GPIO_Write(GPIOA, ~0x0080); //0000 0000 1000 0000
Delay_s(1);
}
}
三、烧录结果
由于视频有点大,在做成动图时做了加速处理,实际效果灯亮的间隔基本为1s。
四、输出波形
五、总结
本次实验用标准外设库的方式通过GPIO口来控制LED灯。GPIO的工作模式有八种,我们在使用过程中可根据实际情况选择合适的工作模式;AHB外设时钟控制的函数是使能或失能AHB外设时钟;在点灯过程中,我们需要用到GPIO_Init函数来初始化GPIO端口,然后用输出或输入的函数控制GPIO口。