首页 > 技术文章 > stm32打怪升级之再见闪烁灯

bebox 2017-07-27 15:59 原文

用的是普中开发板
在stm32中用官方库来实现通过操作i/o口,使i/o口产生信号,从而控制led的亮灭

首先我们发现在用户文件夹user中创建三个.c文件,一个main.c主要是存放我们编写的main函数
,一个stm32f10x_it.c,这个之后再说,它本身是个所有中断函数的入口,默认为空。当我们需要使用中断时在进行编写,还有一个项目.c,这个文件夹需要用户自己根据自己的项目需求进行编写,比如我现在写的是一个led控制的程序,所以我在此文件夹下编写对led的控制。
思考:.c和.h的区别,为什么同样是子程序有的定义在.c中也有的定义在.H里面?一般来说是这样的,所有函数定义和变量放在.c中,告诉使用者怎么运行。而.h只做声明,声明包括一些宏定义,变量,函数,这只是告诉使用者这个程序能干什么,该如何用,但是编译后不产生代码,实际上.h上可以放任何东西,但是为了结构清晰,得区别对待。
我们可以看到在.c文件开头,总会存在一个#include,这个#include就完全可以看作把#include后面的.h文件赋值到.c中。往往当一个.h文件被多个.c包含,就会出现重复定义的错误了,声明可以很多次,但定义只有一次,其实还有更深层次原因,这里就不过多介绍了
在main.c中编写控制程序,测试我们的程序
#include "public.h"//公共函数头文件
这是第一条语句,我们再看public.h里面声明了什么东西
#ifndef _public_H
#define _public_H

文件内容


#endif
重复包含(重复定义)
由于头文件包含可以嵌套,那么C文件就有可能包含多次同一个头文件,就可能出现重复定义的问题的。
通过条件编译开关来避免重复包含(重复定义)

反正也就是说这条语句已经定义了所有函数,变量
之后进入int main()编写主函数
里面就两句简单的命令。LED_Init();和led_display(),前者对led端口和时钟进行初始化,后者对led进行显示,查看初始化的内容发现里面写了好多东西,又臭又长。
翻阅stm32的固件库使用手册发现gpio初始化函数规范写法是
GPIO_InitTypeDef structure

typedef struct
{
u16 GPIO_Pin;//选择设置gpio管脚
GPIOSpeed_TypeDef GPIO_Speed;#设置管脚输出速率
GPIOMode_TypeDef GPIO_Mode;#设置模式
} GPIO_InitTypeDef;
以上是个数据结构
另外由于每个外设都要设置时钟,所以也要对时钟进行初始化,而用到时钟的外设库就是rcc,所以我们也要把stm32f10x_rcc.c添加到工程文件夹里
同样查阅了固件库使用手册知道关于复位和时钟设置是rcc
所以在led初始化的时候我们也要对始终进行初始化,并且开启gpioc的外设时钟,即用RCC_APB2PeriphClockCmd函数至于为什么使用apb2而不使用apb1,是由于两者的periph值不同,gpio口是放在apb2的描述内。

来缕一缕思路

我要想led亮灭,就得控制管脚,通过给管角高低电平,而查阅中文手册,gpio有这个用途,然后led是一个外设,我们知道,使用外设就需要使用外部时钟
因为我写的工程是关于led的,所以我建了一个led.c的文件告诉我怎么运行,并且建了一个led.h文件告诉我我需要用那些东西,怎么用定义了的函数以及我所需要的库。led.c中初始化了时钟和操控的led口,一些参数的修改,最后通过设置或消除指定的数据端口位,因为要造成亮灭效果,亮就是给端口数据,而灭就是不给端口数据,而gpio_setbits和gpio_resetbits函数有这功能,所以我们想的是亮和灭隔段时间,在其中加入延迟。可以这么理解,初始化的目的是为了完成我们理想中的效果,将所有参数都确定下来,并运行出来,而真正操作的时候我们给他数据并再删除数据。

理解了这些,那么实现流水灯就好写代码了

------------------------------*-*(7.28)-------------------------------------

排版有很大的问题,给大家造成阅读的不便,非常抱歉,下次一定改进

更新一个理解上的错误gpio_setbits和gpio_resetbits函数的功能确切的来说是控制输出电平,前者控制输出高电平,后者控制输出低电平

推荐阅读