1.stm32之LED灯控制

接触嵌入式半年以来学习地非常零碎,没有一个系统的知识体系,因此决定进行一个系统的学习并做记录,如果有错误希望各位指出,不胜感激。
我使用的单片机系统的芯片为STM32f103zet6,这是一款144引脚的芯片,集成了STM32系列芯片的较多功能,适合用于学习。

嵌入式的知识结构

1.计算机硬件基础

编程语言
计算机组成原理
数据库

2.系统硬件层

数/模电路
嵌入式平台:ARM、DSP、FPGA
原理图及PCB设计

3.硬件抽象层

通用设备接口及协议:USB、TCP/IP、SPI
设备相关:信息监测、电机控制

4.系统软件层

文件系统
GUI
操作系统
应用程序

新建工程

1.新建工程文件夹

工程文件下的子文件夹.png

内部包含以下子文件夹:
Doc:内部包含程序说明文档 read me
Libraries:内部包含 CMSIS、FWLib 两个文件夹,内部为库文件,可从其他项目中拷贝。
Listing:建立工程时不用存放任何文件。
Output:编译工程时在这里生成USB烧写的 .hex 文件。
Project:放置新建工程时产生的工程文件。
USER:包含 main.c、stm32f10x_conf.h、stm32f10x_it.c、stm32f10x_it.h 四个文件,可从其他项目中拷贝。

2.在MDK中新建项目

新建项目时需要选择芯片,选择stm32f103ze系列,之后直接建立工程。
之后在Manage Project Items中添加 STARTUP、CMSIS、FWLib 以及 USER 这四个Group。
STARTUP这个Group中添加 CMSIS 中 startup 文件中的某一个,这个是根据芯片决定的,我在项目中添加的是 startup_stm32f10x_hd.s
CMSIS中添加除了 startup 的5个文件。
FWLib中添加FWLib文件夹中的src文件夹中的所有内容。
USER中添加对应文件夹下的内容。

keil内工程视图.png

3.项目配置

打开 options for target...串口

1.Target配置
将xtal(MHz)设置为8.0


Target配置.png

2.Output配置
在 create hex file 前打钩。
设置Output的文件路径,路径为工程文件夹下的Output文件夹。


Output配置.png

3.Listing配置
配置文件路径为Listing文件夹。

4.C/C++配置
添加USE_STDPERIPH_DRIVER, STM32F10X_HD这两句宏定义。
为 Include Paths 添加路径,具体如下图所示。


C/C++配置.png

在STM32F103中:
STM32F10X_LD 对应于 LowDensity ,即小容量的STM32F103芯片。
STM32F10X_MD 对应于 MediumDensity ,即中等容量的STM32F103芯片。
STM32F10X_HD 对应于 HighDensity ,即大容量的STM32F103芯片。
这次我所使用的stm32f103zet6就是大容量芯片。

5.Debug及Utilities配置
因为我使用的是USB下载程序,因此选择ULink调试。


Debug配置.png

LED灯的控制

1.目的

使单片机电路板的LED灯形成一个流水灯。

2.工程配置

为了操作LED灯,我们需要添加自己的库函数以便进行控制
在项目的user文件夹中,新建一个LED文件夹和一个INC文件夹。
LED文件夹中用于存放led.c,INC文件夹存放led.h。
以后每新建一个.c文件都应该建立一个专门的文件夹来存放,而.c文件对应的.h文件则都存放于INC文件夹中以便指定路径。因此需要在Options for Target...中的C/C++中添加一个这样的路径:..\USER\INC


添加用户自定义库文件路径.png

3.程序代码

led.h源代码:
//首先进行防卫声明
#ifndef __LED_H
#define __LED_H

#include "stm32f10x.h"

#define ON  0
#define OFF 1

/* 定义带参宏,使用方法类似C++中的内联函数 */
/* 本次使用的单片板有三个LED灯,其中一个是电源灯。
另外两个才是给用户使用的,因此定义两个灯开关的宏。 */
#define LED2(a) if(a) GPIO_SetBits( GPIOE, GPIO_Pin_5 ); else GPIO_ResetBits( GPIOE, GPIO_Pin_5 )
#define LED3(a) if(a) GPIO_SetBits( GPIOB, GPIO_Pin_5 ); else GPIO_ResetBits( GPIOB, GPIO_Pin_5 )

void LED_Init(void);

#endif

led.c源代码:
#include "stm32f10x.h"
#include "led.h"

//LED初始化函数
void LED_Init(void)
{
    
    /* 定义一个GPIO_InitTypeDef类型的结构体 */
    GPIO_InitTypeDef GPIO_InitStructure;
    
    /* 打开GPIOB和GPIOE的外设时钟 */
    RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOE, ENABLE );
    
    /* 选择要控制的GPIOB引脚;设置为推挽输出;最大速率设置为50MHz;初始化GPIOB */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init( GPIOB, &GPIO_InitStructure );
    
    /* 选择要控制的GPIOE引脚;设置为推挽输出;最大速率设置为50MHz;初始化GPIOE */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init( GPIOE, &GPIO_InitStructure );
    
    /* 关闭所有LED灯 */
    GPIO_SetBits( GPIOB, GPIO_Pin_5 );
    GPIO_SetBits( GPIOE, GPIO_Pin_5 );
}
led.c解释:

GPIO_InitTypeDef结构体在库函数里的定义如下。(可以选中它再按F12进入库函数查看。)

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口,需要指明它的引脚,速率以及输出方式。

首先打开它的外设时钟,这里涉及到stm32的时钟频率。可以在stm32f103的用户手册中查找时钟树,这个整体比较复杂,以后再细谈,这里选择APB2即可。

之后我们再根据电路原理图打开LED灯对应的引脚,如图为我所使用的板子的LED模块的原理图。因此打开PB5和PE5引脚。这个电路很简单,只要我们对PB5和PE5进行高低电平的控制就能改变LED灯的开关状态。


LED模块原理图

最后我们再通过结构体设置引脚的速率以及输出方式。

主函数main.c
#include "stm32f10x.h"
#include "led.h"

//一个不精确的延时函数,通过循环来延时
void Delay( __IO u32 nCount )
{
    for( ; nCount != 0; nCount-- );
}

//这里实现了两个LED灯的闪烁,如果有四五个就可以实现流水灯了
int main(void)
{
    LED_Init();
    
    while(1)
    {
        LED2( ON );
        Delay(0x0FFFFF);
        LED2( OFF );
        
        LED3( ON );
        Delay(0x0FFFFF);
        LED3( OFF );
    }
    
}

关于LED灯的操作基本就是这样,很多涉及到GPIO口的程序都是类似的,比如蜂鸣器
和一些传感器。之后会介绍蜂鸣器的开关代码。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,524评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,869评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,813评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,210评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,085评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,117评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,533评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,219评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,487评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,582评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,362评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,218评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,589评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,899评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,176评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,503评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,707评论 2 335

推荐阅读更多精彩内容