湖北天健建设集团有限公司网站,广元市住房与城乡建设厅网站,济南招考院网站,百度入口网页版要点亮LED#xff0c;需要完成LED的驱动#xff0c; 在工程模板上新建一个led.c和led.h文件#xff0c;将其存放在led文件夹内。这两个文件需要我们自己编写。 通常xxx.c文件用于存放编写的驱动程序#xff0c;xxx.h文件用于存放xxx.c内的stm32头文件、管脚定义、全局变量声…要点亮LED需要完成LED的驱动 在工程模板上新建一个led.c和led.h文件将其存放在led文件夹内。这两个文件需要我们自己编写。 通常xxx.c文件用于存放编写的驱动程序xxx.h文件用于存放xxx.c内的stm32头文件、管脚定义、全局变量声明、函数声明等内容。 因此在led.c文件内编写如下代码#include led.h/******************************************************************************** 函 数 名 : LED_Init* 函数功能 : LED 初始化函数* 输 入 : 无* 输 出 : 无*******************************************************************************/void LED_Init(){GPIO_InitTypeDef GPIO_InitStructure; //定义结构体变量RCC_APB2PeriphClockCmd(LED_PORT_RCC,ENABLE);GPIO_InitStructure.GPIO_PinLED_PIN; //选择你要设置的 IO 口GPIO_InitStructure.GPIO_ModeGPIO_Mode_Out_PP; //设置推挽输出模式GPIO_InitStructure.GPIO_SpeedGPIO_Speed_50MHz; //设置传输速率GPIO_Init(LED_PORT,GPIO_InitStructure); /* 初始化 GPIO */GPIO_SetBits(LED_PORT,LED_PIN); //将 LED 端口拉高熄灭所有 LED} 函数中的LED_PORT_RCC、LED_PIN和LED_PORT是我们定义的宏其存放在led.h头文件内 。LED_PORT_RCC定义的是LED端口时钟如RCC_APB2Periph_GPIOCLED_PIN定义的是LED的引脚如 GPIO_Pin_0LED_PORT定义的是LED的端口如GPIOC。这样定义宏的好处是有效提高了程序的移植性即使后续需要换其他端口只需简单修改这几个宏就可以完成对LED的控制。 在 led.h 文件内编写如下代码#ifndef _led_H#define _led_H#include stm32f10x.h/* LED 时钟端口、引脚定义 */#define LED_PORT GPIOC#define LED_PIN(GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7)#define LED_PORT_RCC RCC_APB2Periph_GPIOCvoid LED_Init(void);#endif LED_Init()函数就是对LED所接端口的初始化是按照GPIO初始化步骤完成这些内容在“寄存器点亮一个LED”章节中有介绍。下面我们主要看库函数是如何实现GPIO初始化的。 在库函数中实现 GPIO 的初始化函数是void GPIO_Init(GPIO_TypeDef*GPIOx,GPIO_InitTypeDef*GPIO_InitStruct); 这个函数具体有什么功能以及函数形参的意义我们可以通过库函数帮助文档来查阅。GPIO_Init函数内有两个形参第一个形参是GPIO_TypeDef类型的指针变量而GPIO_TypeDef是一个结构体类型封装了GPIO外设的所有寄存器所以给它传送GPIO外设基地址即可通过指针操作寄存器内容第一个参数值可以为GPIOA、GPIOB、...GPIOG等其实这些就是封装好的GPIO外设基地址在stm32f10x.h文件中可以找到。第二个形参是GPIO_InitTypeDef类型的指针变量而GPIO_InitTypeDef也是一个结构体类型里面封装了GPIO外设的寄存器配置成员。我们初始化GPIO其实就是对这个结构体配置。 如果想快速查看代码或参数可以用鼠标点击要查找的函数或者参数然后右键鼠标选择“Go To Definition Of ...”即可进入所要查找的函数或参数内。 查找函数内变量类型也是同样的方法但是如果发现此方法查找不出内容那可能就是你所查找的东西在 KEIL5 软件认为是不正确的。 在 LED 初始化函数中最开始调用的一个函数是RCC_APB2PeriphClockCmd(LED_PORT_RCC,ENABLE); 此函数功能是使能GPIOC外设时钟 在STM32中要操作外设必须将其外设时钟使能否则即使其他的内容都配置好也是徒劳无功。因为GPIO外设是挂接在APB2总线上所以是对APB2总线时钟进行使能函数内有两个参数一个是用来选择外设时钟一个是用来选择使能还是失能使能ENABLE失能DSIABLE。 在LED初始化函数内最后还调用了GPIO_SetBits(LED_PORT,LED_PIN)函数此函数功能是让GPIOC端口的第0-7个引脚输出高电平让LED处于熄灭状态如果要对同一端口的多个引脚输出高电平可以使用“|”运算符相应的在对结构体初始化配置时管脚设置那里也要使用“|”将管脚添加进去即在led.h文件内对LED引脚的定义。前提条件是要操作的多个引脚必须是配置同一种工作模式例如GPIO_InitStructure.GPIO_PinGPIO_Pin_0|GPIO_Pin_1;//管脚设置GPIO_SetBits(GPIOC,GPIO_Pin_0|GPIO_Pin_1); 其实从函数名我们大致就可以知道函数的功能。函数内有两个参数一个是端口的选择一个是端口管脚的选择。如果要输出低电平的话可以使用如下库函数GPIO_ResetBits(GPIOC,GPIO_Pin_0); 这个函数功能和GPIO_SetBits是相反的一个输出低电平一个输出高电平里面参数功能是一样的。 GPIO输出函数还有好几个例如void GPIO_WriteBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin,BitAction BitVal);void GPIO_Write(GPIO_TypeDef* GPIOx, uint16_t PortVal); 功能设置端口管脚输出电平这两个函数很少使用。 从 GPIO 内部结构可知STM32 的 GPIO 还可以读取输入或输出引脚电平状态。其函数如下读取输入引脚uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_tGPIO_Pin);功能读取端口中的某个管脚输入电平。底层是通过读取 IDR 寄存器。uint16_t GPIO_ReadInputData(GPIO_TypeDef* GPIOx);功能读取某组端口的输入电平。底层是通过读取 IDR 寄存器。读取输出引脚uint8_t GPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx, uint16_tGPIO_Pin);功能读取端口中的某个管脚输出电平。底层是通过读取 ODR 寄存器。uint16_t GPIO_ReadOutputData(GPIO_TypeDef* GPIOx);功能读取某组端口的输出电平。底层是通过读取 ODR 寄存器。 在 led.h 文件中可以看到使用了一个定义头文件的结构代码如下#ifndef _led_H#define _led_H//此处省略头文件定义的内容#endif 它的功能是防止头文件被重复包含避免引起编译错误。在头文件的开头使用“#ifndef”关键字判断标号“ _led_H”是否被定义若没有被定义则从“#ifndef”至“ #endif”关键字之间的内容都有效也就是说这个头文件若被其它文件“ #include”它就会被包含到其该文件中且头文件中紧接着使用“#define”关键字定义上面判断的标号“_led_H”。当这个头文件被同一个文件第二次“#include”包含的时候由于有了第一次包含中的“ #define _led_H”定义这时再判断“#ifndef _led_H”判断的结果就是假了从“#ifndef”至“#endif”之间的内容都无效从而防止了同一个头文件被包含多次编译时就不会出现“redefine重复定义”的错误了。 一般来说我们不会直接在C的源文件写两个“#include”来包含同一个头文件但可能因为头文件内部的包含导致重复这种代码主要是避免这样的问题。如“led.h”文件中调用了#include “stm32f10x.h”头文件可能我们写主程序的时候会在 main 文件开始处调用#include“stm32f10x.h”和“led.h”这个时候“stm32f10x.h”文件就被包含两次了如果在头文件中没有这种机制编译器就会报错。嵌入式开发直播课 - 深度剖析STM32DMA专题讲解 - 创客学院直播室www.makeru.com.cn