本帖最后由 刘洋讲单片机 于 2017-2-16 17:12 编辑
1.6.1 使用库函数方法实现LED控制在STM32F0开发板程序的设计我们采用库函数的方法实现LED1及RGB的控制。在电路设计中我们固定使用PC6控制LED1,PC7/PC8/PC9控制RGB。所有的库函数配置要围绕这个硬件条件展开。库函数参数部分一般顺序都是“端口-管脚-具体功能”。 GPIO_Init(LED_PORT, &GPIO_InitStructure);//初始化 注释:在这条程序语句中,括号内的内容是功能配置,现在逐项说明:“GPIOC”是PC端口;“LED_PORT”是前面规定端口的第6个管脚,在*.h文件中有详细描述; /*选择要控制的GPIOC引脚*/ GPIO_InitStructure.GPIO_Pin = LED_1_PIN|LED_B_PIN|LED_G_PIN|LED_R_PIN; /*输出模式*/ GPIO_InitStructure.GPIO_Mode=GPIO_Mode_OUT; /*设置引脚速度为50MHz*/ GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; /*设置引脚模式为通用推挽输出*/ GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; /*设置引脚模式为上拉*/ GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; #define LED_1_PIN GPIO_Pin_6 #define LED_B_PIN GPIO_Pin_7 #define LED_G_PIN GPIO_Pin_8 #define LED_R_PIN GPIO_Pin_9 LED_1_L GPIO_ResetBits(LED_PORT,LED_1_PIN);//PC6输出低电平 LED_1_H GPIO_SetBits(LED_PORT,LED_1_PIN);//PC6输出高电平 注释:在这条程序语句中,括号内的内容是功能配置,现在逐项说明:“LED_PORT”是PC端口;“LED_1_PIN”是前面规定端口的第6个管脚。 有人会问,我怎么知道这些程序代码的编写规则及功能书写格式呢?具体的都要查找《STM32F0库函数参考手册》,在这份文档中有非常详细的说明及书写格式,很多我们直接拿过来套用就可以。 1.6.2 库函数编程的优势 STM32库函数里把所有寄存器用结构体一一对应并且封装起来,而且提供了基本的配置函数。我们要去操作配置某个外设的时候不需要再去翻眼花缭乱的数据手册,直接找到库函数描述拿来就可以用,这样就能把精力放在逻辑代码的开发上,而不是去费力的研究一个芯片的外设要怎么配置寄存器才能驱动起来。 简单讲,库函数是为了让开发者从大量繁琐的寄存器操作中脱离出来的一个文件包。 1.7 工程模版的建立使用KEIL软件进行程序设计,要先建立一个工程,由于C语言程序设计的灵活性,使得每个人对于程序设计的工程文件有不同的分配,有人习惯于把主要工作都放在主程序呢,有人习惯把所有的程序都放在主程序中。根据这么多年的设计经验我们有着自己的一套程序设计思路,通过整理后认为这样规范合理,分类清楚,阅读方便。 图1.2 工程设计文件目录 在一个新的工程中我们建立了4个文件夹,分别是BSP\LIB\USR\Readme。BSP文件夹中存放自定义底层驱动程序文件;LIB文件夹中引入C语言自己的库函数文件;USR文件夹中存放自定义主程序及数据库头文件等;Readme文件夹中存放自定义程序设计说明文件。 以这个实验为例,目录树展开后如“图1.3 工程目录树展开内容”。 图10.3 工程目录树展开内容 1.8 程序文件设计 前文我们已经详细介绍了工程模版的建立,我们按照前文建立工程文件。按照我们的编程习惯,我们自己定义了main.c、pbdata.c和pbdata.h三个函数文件,全部放置在“USR”文件夹中。pbdata.c和pbdata.h函数文件主要存放我们自定义的公共函数和全局变量,以方便以后每个功能模块之间传递参数。 在这里我们自定义了BSP文件夹,在我们的设计规划中,把所有的底层驱动函数全部放在这个文件中,使程序的可读性很好。在本课节中把LED流水发光的执行过程子函数放在这个文件中。 下面详细说明此驱动函数书写规范。 1.8.1 lib文件中内容分析我们建立一个“Lib”文件夹,把引用系统本身定义好的库函数加在其中,我们使用到哪个外设功能,直接引用到此文件夹中即可。一般情况下下面这三个文件都得引用。 Stm32f0xx_gpio.c // 定义GPIO函数 Stm32f0xx_rcc.c // 定义时钟函数 Stm32f0xx_conf.h // 外设声明函数(头文件) 图1.4 Stm32f0xx_conf.h头文件内部选择 本节实验及以后的实验我们都是用到库文件,其中 Stm32f0xx_conf.h头文件包含了所有外设的声明头文件,在本试验中我们使用到时钟外设和GPIO端口外设。所以#include "Stm32f0xx__syscfg.h"、#include "Stm32f0xx__rcc.h"和#include "Stm32f0xx_gpio.h"需要“打开”(就是把语句前面的双斜线注释符号删除即可,参考图1.4)。Stm32f0xx_gpio.c库函数包含了所有管脚初始化功能和具体的执行操作;Stm32f0xx_rcc.c库函数主要包含了内部时钟和外部时钟设置,在主函数中规定了具体的执行方法,在这个函数中就有具体相关的执行步骤。 1.8.2 main.c文件中的程序主程序就实现初始化和调用驱动程序,这样主程序控制思路清晰,流程简单。在以后的课节中我们就不再描述主程序的书写过程,留出主要思路讲述驱动部分的编写过程。详情请大家参考光盘(网盘)中程序及程序注释。 /*********************************************************************** * 说 明: 发光二极管流水灯实验 * 开发平台: 独角兽STM32F0开发板 * 关注微信公众平台微信号:"众拳 或者 zxkj-ly",免费获取STM32F0和STM8资料。 * STM32技术交流QQ群【373645551】 * 哈尔滨卓恩科技开发有限公司 * 作 者: 刘洋 张殿东 * 版 本: V1.0 * 日 期: 2016-12-23 * KEIL5开发环境 版本 V5.20.0 ***********************************************************************/ #include"pbdata.h"//引入自定义公共头文件 void BSP_Configuration(void);//硬件初始化函数声明 void RCC_Configuration(void); int main(void) { BSP_Configuration();//硬件驱动初始化函数 while(1) { LED_Demo();//调用LED流水灯例程 } }
/*********************************************************************** * 函 数 名: BSP_Configuration * 功能说明: 初始化硬件设备。只需要调用一次。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。 * 形 参:无 * 返 回 值: 无 ***********************************************************************/ void BSP_Configuration(void)//硬件驱动初始化函数 { RCC_Configuration();//时钟初始化函数 LED_GPIO();//LED初始化函数 } void RCC_Configuration(void)//时钟初始化函数 { RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC, ENABLE); } 1.8.3 led.c文件中的程序#include "pbdata.h" /*************************************************************************** * 函 数 名: LED_Init * 功能说明: LED的GPIO管脚初始化 * 形 参:无 * 返 回 值: 无 ***************************************************************************/ void LED_GPIO(void) { /*定义一个GPIO_InitTypeDef类型的结构体*/ GPIO_InitTypeDef GPIO_InitStructure; /*选择要控制的GPIOC引脚*/ GPIO_InitStructure.GPIO_Pin = LED_1_PIN|LED_B_PIN|LED_G_PIN|LED_R_PIN; /*设置要控制的GPIOC引脚为输出模式*/ GPIO_InitStructure.GPIO_Mode=GPIO_Mode_OUT; /*设置引脚速率为50MHz */ GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; /*设置引脚模式为通用推挽输出*/ GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; /*设置引脚模式为上拉*/ GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; /*调用库函数,初始化GPIOB*/ GPIO_Init(LED_PORT, &GPIO_InitStructure); LED_1_H;//拉高熄灭 LED_B_H;//拉高熄灭 LED_G_H;//拉高熄灭 LED_R_H;//拉高熄灭 } /*************************************************************************** * 函 数 名: LED_Demo2 * 功能说明: 闪烁例程,间隔时间为0.5秒。 * 形 参:无 * 返 回 值: 无 **************************************************************************/ void LED_Demo(void) { LED_1_L; //拉低PC6引脚,LED1发光二极管(发光) delay_ms(500);// LED_1_H; //拉高PC6引脚,LED1发光二极管(熄灭) delay_ms(500); LED_R_L; //拉低PC9引脚,RGB发光二极管(发红色光) delay_ms(500); LED_R_H; //拉高PC9引脚,RGB发光二极管(红色熄灭) delay_ms(500); LED_G_L; //拉低PC8引脚,RGB发光二极管(发绿色光) delay_ms(500); LED_G_H; //拉低PC8引脚,RGB发光二极管(绿色熄灭) delay_ms(500); LED_B_L; //拉低PC7引脚,RGB发光二极管(发蓝色光) delay_ms(500); LED_B_H; //拉高PC7引脚,RGB发光二极管(蓝色熄灭) delay_ms(500); } 1.8.4 led.h文件中的程序#ifndef _LED_H //宏定义,定义文件名称 #define _LED_H #include "stm32f0xx.h"//引用STM32F0头文件 #define LED_1_PIN GPIO_Pin_6 //定义GPIO_Pin_6引脚为LED_1_PIN,相当于重新命名。 #define LED_B_PIN GPIO_Pin_7 //定义GPIO_Pin_7引脚为LED_B_PIN,相当于重新命名。 #define LED_G_PIN GPIO_Pin_8 //定义GPIO_Pin_8引脚为LED_G_PIN,相当于重新命名。 #define LED_R_PIN GPIO_Pin_9 //定义GPIO_Pin_9引脚为LED_R_PIN,相当于重新命名。 #define LED_PORT GPIOC //定义GPIOC端口为LED_PORT,相当于重新命名。
//如果想用其他管脚控制LED,那么只需更改上面对应的端口与引脚编号即可 //定义LED_1_L,调用LED_1_L命令,PC6引脚输出低电平 #define LED_1_L GPIO_ResetBits(LED_PORT,LED_1_PIN); //定义LED_1_H,调用LED_1_H命令,PC6引脚输出低高平 #define LED_1_H GPIO_SetBits(LED_PORT,LED_1_PIN); //定义LED_1_T,调用LED_1_T命令,PC6引脚输出电平反转 #define LED_1_T GPIO_WriteBit(LED_PORT,LED_1_PIN,(BitAction)(1 - GPIO_ReadOutputDataBit(LED_PORT, LED_1_PIN))); //定义LED_B_L,调用LED_B_L命令,PC7引脚输出低电平 #define LED_B_L GPIO_ResetBits(LED_PORT,LED_B_PIN); //定义LED_B_H,调用LED_B_H命令,PC7引脚输出低高平 #define LED_B_H GPIO_SetBits(LED_PORT,LED_B_PIN); //定义LED_1_T,调用LED_1_T命令,PC7引脚输出电平反转 #define LED_B_T GPIO_WriteBit(LED_PORT,LED_B_PIN,(BitAction)(1 - GPIO_ReadOutputDataBit(LED_PORT, LED_B_PIN))); //定义LED_G_L,调用LED_G_L命令,PC8引脚输出低电平 #define LED_G_L GPIO_ResetBits(LED_PORT,LED_G_PIN); //定义LED_G_H,调用LED_G_H命令,PC8引脚输出低高平 #define LED_G_H GPIO_SetBits(LED_PORT,LED_G_PIN); //定义LED_1_T,调用LED_1_T命令,PC8引脚输出电平反转 #define LED_G_T GPIO_WriteBit(LED_PORT,LED_G_PIN,(BitAction)(1 - GPIO_ReadOutputDataBit(LED_PORT, LED_G_PIN))); //定义LED_R_L,调用LED_R_L命令,PC9引脚输出低电平 #define LED_R_L GPIO_ResetBits(LED_PORT,LED_R_PIN); //定义LED_R_H,调用LED_R_H命令,PC9引脚输出低高平 #define LED_R_H GPIO_SetBits(LED_PORT,LED_R_PIN); //定义LED_1_T,调用LED_1_T命令,PC9引脚输出电平反转 #define LED_R_T GPIO_WriteBit(LED_PORT,LED_R_PIN,(BitAction)(1 - GPIO_ReadOutputDataBit(LED_PORT, LED_R_PIN))); void LED_GPIO(void); //LED初始化函数 void LED_Demo(void); #endif //定义文件名称结束
在这里我们对程序的主要部分做了详细的说明,如果想了解全部程序,请使用KEIL软件打开我们的”独角兽开发板-参考程序/01.LED/MDK-ARM/LY-STM32F0”(位置以光盘内容为主)。以后的试验程序中主程序功能都是一样的,在后续课节中我们就不再详细介绍主程序部分。 图1.5 实验程序所在位置
|