• STM32笔记2-使用库函数点亮LED灯


    目录

    一、硬件电路设计

    二、软件设计

    1、工程配置

     2、程序编写

    (1)led头文件

    (2)Led_Init()函数编写

    三、实验测试

     四、使用宏定义

    1、修改后的led.h中程序

    2、修改后的Led_Init()初始化函数

    3、main函数中点亮LED灯

    五、使用位带方式

    1、创建system文件

    2、修改程序代码

    六、工程下载连接


    一、硬件电路设计

     电气原理图

    8个LED灯采用共阳极方式接在PC口的PC0-PC7引脚上,输出低电平为点亮、高电平熄灭。

    测试实物开发板

    二、软件设计

    复制第一节所创建的库函数模板空工程,重新编译没有错误没有警告。然后开始接下来的工程配置和代码编写等工作。

    1、工程配置

    在工程文件中新建文件夹取名APP,用来存放外部设备驱动程序。在APP文件夹中新建文件夹led,用以存放led灯相关的驱动程序。

    (1)led文件夹路径添加

    若不添加后面程序编译将报错。

    (2)创建led驱动程序文件

    分别创建led.c和led.h文件,保存在APP-led文件夹中

    (3)工程Project中新建APP分组

     (4)工程APP中添加led.c文件

     2、程序编写

    (1)led头文件

    1. #ifndef _LED_H_
    2. #define _LED_H_
    3. #include "stm32f10x.h"
    4. void Led_Init(void); //led Init Function
    5. #endif

    #ifndef _LED_H_

    #define _LED_H

    _ #endif

    的作用是:

    如果led.h第一次被引用,那么__LED_H没有被定义,所以#define __LED_H和#endif 中间的头文件内容就被执行,也就是头文件内容被定义。那么如果led.h第二次被引用,由于__LED_H已经被第一次引用时定义了,所以不会执行#define __LED_H和#endif 中间的头文件内容,也就是不会重复定义头文件内容。

    这样,可以避免头文件的内容被重复定义。头文件中定义的变量不存在重复声明或定义

    (2)Led_Init()函数编写

    ①GPIO_InitTypeDef结构体变量定义和赋值

    在STM32的GPIO的驱动文件上  找到GPIO_StructInit()。

     在Led_Init()中定义GPIO_InitTypeDef结构体变量,同时给结构体变量成员GPIO_Pin、GPIO_Speed、GPIO_Mode赋值

    GPIO_Pin:需要使用的IO引脚

    GPIO_Speed:IO输出最高带宽频率

    GPIO_Mode:IO输出模式,四种模式。一般常用为普通推挽输

    普通推挽输出(GPIO_Mode_Out_PP:电平匹配场合。低电平0V、高电平3.3V

    普通开漏输出(GPIO_Mode_Out_OD):电平不匹配场合,一般5V以上

    复用推挽输出(GPIO_Mode_AF_PP):用作串口的输出

    复用开漏输出(GPIO_Mode_AF_OD):用在IIC

     具体要赋什么值,鼠标分别放在GPIO_Pin_All、GPIO_Speed_2MHz、GPIO_Mode_IN_FLOATING上面右击,然后选择Go To Definition of 'XXX'跳转到其头文件中相应的宏、枚举定义,如下图所示

     GPIO_Pin

    GPIO_Speed

    GPIO_Mode

    结构体变量重新赋值后的程序如下

    ②时钟使能

    在STM32的rcc.c文件夹中找到RCC_APB2PeriphClockCmd(),使能或者失能 APB2 外设时钟

    第二个参数就是ENABLE或者DISENABLE,

    参数1选择如下:

    另外说明:

    (1)APB2负责AD,I/O,串口1,高级定时器TIM。如上图参数1表格所示。

    (2)APB1负责DA,串口2,3,4,5,普通定时器TIM, USB , IIC  , CAN。如下图所示

     最终的LED代码如下

    1. void Led_Init()
    2. {
    3. GPIO_InitTypeDef GPIO_InitTypeStruct; //结构体定义
    4. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE); //时钟使能
    5. GPIO_InitTypeStruct.GPIO_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;
    6. GPIO_InitTypeStruct.GPIO_Speed=GPIO_Speed_50MHz; //输出口的最高带宽频率:50MHz
    7. GPIO_InitTypeStruct.GPIO_Mode=GPIO_Mode_AF_PP; //普通推挽输出
    8. GPIO_Init(GPIOC,&GPIO_InitTypeStruct); //初始化GPIO的C口
    9. //设置IO高电平输出,LED在初始状态下都保持熄灭状态
    10. GPIO_SetBits(GPIOC,GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7);
    11. }

    (3)在Main.c主函数中点亮led灯

    首先引用led.h头文件,调用Led_Init()。

    Main程序

    1. #include "stm32f10x.h"
    2. #include "led.h"
    3. int main()
    4. {
    5. Led_Init();
    6. while(1)
    7. {
    8. //8个引脚都设置为低电平,将8个LED灯都点亮
    9. GPIO_ResetBits(GPIOC,GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7);
    10. }
    11. }

    三、实验测试

    编译没有错误,生成HEX文件。

    使用烧录软件,将HEX文件写到单片机中

     实验结果实物展示

     四、使用宏定义

    为了方便代码移植,将引脚、IO口和时钟等在头文件中使用宏定义,代码在移植到别的工程项目中,只需要修改宏定义文件即可。宏定义如下。

    1. #define LED_PORT_RCC RCC_APB2Periph_GPIOC
    2. #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
    3. #define LED_PORT GPIOC

    然后将程序中的原变量名,修改为定义的宏名称即可

    1、修改后的led.h中程序

    1. #ifndef _LED_H_
    2. #define _LED_H_
    3. #include "stm32f10x.h"
    4. #define LED_PORT_RCC RCC_APB2Periph_GPIOC
    5. #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)
    6. #define LED_PORT GPIOC
    7. void Led_Init(void); //led Init Function
    8. #endif

    2、修改后的Led_Init()初始化函数

    1. void Led_Init()
    2. {
    3. GPIO_InitTypeDef GPIO_InitStructure; //定义结构体变量
    4. RCC_APB2PeriphClockCmd(LED_PORT_RCC,ENABLE);
    5. GPIO_InitStructure.GPIO_Pin=LED_PIN; //选择要设置的IO口
    6. GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP; //设置推挽输出模式
    7. GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; //设置传输速率
    8. GPIO_Init(LED_PORT,&GPIO_InitStructure); /* 初始化GPIO */
    9. GPIO_SetBits(LED_PORT,LED_PIN); //设置IO口高电平输出,熄灭所有LED灯
    10. }

    3、main函数中点亮LED灯

    1. #include "stm32f10x.h"
    2. #include "led.h"
    3. int main()
    4. {
    5. Led_Init();
    6. while(1)
    7. {
    8. //
    9. GPIO_ResetBits(LED_PORT,GPIO_Pin_0); //点亮LED1
    10. GPIO_ResetBits(LED_PORT,GPIO_Pin_1); //点亮LED2
    11. GPIO_ResetBits(LED_PORT,GPIO_Pin_2); //点亮LED3
    12. //GPIO_ResetBits(GPIOC,GPIO_Pin_0); //点亮LED1
    13. }
    14. }

    五、使用位带方式

    1、创建system文件

    创建system.c源文件和system.h头文件,创建Public文件夹和Public文件组。使用前面讲解的方法添加文件

    将stm32f10x.h文件在system.h头文件中引用,其它文件中不在引用,只需要引用system.h即可。

    2、修改程序代码

    system.c中只调用system.h,没有其它代码操作。

    system.h中代码如下

    1. #ifndef _system_H
    2. #define _system_H
    3. #include "stm32f10x.h"
    4. //位带操作,实现类似于51单片机中IO口操作方式
    5. //IO口宏定义
    6. #define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2))
    7. #define MEM_ADDR(addr) *((volatile unsigned long *)(addr))
    8. #define BIT_ADDR(addr, bitnum) MEM_ADDR(BITBAND(addr, bitnum))
    9. //IO¿ÚµØÖ·Ó³Éä
    10. #define GPIOA_ODR_Addr (GPIOA_BASE+12) //0x4001080C
    11. #define GPIOB_ODR_Addr (GPIOB_BASE+12) //0x40010C0C
    12. #define GPIOC_ODR_Addr (GPIOC_BASE+12) //0x4001100C
    13. #define GPIOD_ODR_Addr (GPIOD_BASE+12) //0x4001140C
    14. #define GPIOE_ODR_Addr (GPIOE_BASE+12) //0x4001180C
    15. #define GPIOF_ODR_Addr (GPIOF_BASE+12) //0x40011A0C
    16. #define GPIOG_ODR_Addr (GPIOG_BASE+12) //0x40011E0C
    17. #define GPIOA_IDR_Addr (GPIOA_BASE+8) //0x40010808
    18. #define GPIOB_IDR_Addr (GPIOB_BASE+8) //0x40010C08
    19. #define GPIOC_IDR_Addr (GPIOC_BASE+8) //0x40011008
    20. #define GPIOD_IDR_Addr (GPIOD_BASE+8) //0x40011408
    21. #define GPIOE_IDR_Addr (GPIOE_BASE+8) //0x40011808
    22. #define GPIOF_IDR_Addr (GPIOF_BASE+8) //0x40011A08
    23. #define GPIOG_IDR_Addr (GPIOG_BASE+8) //0x40011E08
    24. //IO口操作,只对单一的IO口
    25. //确保n的值小于16
    26. #define PAout(n) BIT_ADDR(GPIOA_ODR_Addr,n) //输出
    27. #define PAin(n) BIT_ADDR(GPIOA_IDR_Addr,n) //输入
    28. #define PBout(n) BIT_ADDR(GPIOB_ODR_Addr,n) //输出
    29. #define PBin(n) BIT_ADDR(GPIOB_IDR_Addr,n) //输入
    30. #define PCout(n) BIT_ADDR(GPIOC_ODR_Addr,n) //输出
    31. #define PCin(n) BIT_ADDR(GPIOC_IDR_Addr,n) //输入
    32. #define PDout(n) BIT_ADDR(GPIOD_ODR_Addr,n) //输出
    33. #define PDin(n) BIT_ADDR(GPIOD_IDR_Addr,n) //输入
    34. #define PEout(n) BIT_ADDR(GPIOE_ODR_Addr,n) //输出
    35. #define PEin(n) BIT_ADDR(GPIOE_IDR_Addr,n) //输入
    36. #define PFout(n) BIT_ADDR(GPIOF_ODR_Addr,n) //输出
    37. #define PFin(n) BIT_ADDR(GPIOF_IDR_Addr,n) //输入
    38. #define PGout(n) BIT_ADDR(GPIOG_ODR_Addr,n) //输出
    39. #define PGin(n) BIT_ADDR(GPIOG_IDR_Addr,n) //输入
    40. #endif

    修改后的led.h代码如下

    1. #ifndef _LED_H_
    2. #define _LED_H_
    3. #include "system.h"
    4. #define LED_PORT_RCC RCC_APB2Periph_GPIOC
    5. #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)
    6. #define LED_PORT GPIOC
    7. #define led1 PCout(0) //D1灯连接引脚PC0
    8. #define led2 PCout(1) //D2灯连接引脚PC1
    9. #define led3 PCout(2) //D3灯连接引脚PC2
    10. void Led_Init(void); //led Init Function
    11. #endif

    修改后的main代码如下

    1. #include "system.h"
    2. #include "led.h"
    3. int main()
    4. {
    5. Led_Init();
    6. while(1)
    7. {
    8. //
    9. // GPIO_ResetBits(LED_PORT,GPIO_Pin_0); //点亮LED1
    10. // GPIO_ResetBits(LED_PORT,GPIO_Pin_1); //点亮LED2
    11. // GPIO_ResetBits(LED_PORT,GPIO_Pin_2); //点亮LED3
    12. // //GPIO_ResetBits(GPIOC,GPIO_Pin_0); //点亮LED4
    13. led1=0;
    14. led2=0;
    15. }
    16. }

    通过这种定义方式,这样就可以像在C51单片机中那样操作IO口了。

    若要取反,led1=~led1;

    六、工程下载连接

    https://download.csdn.net/download/panjinliang066333/86507279

  • 相关阅读:
    常见的SSH功能
    易云维®产业电商APP提供适合楼宇自动化应用的HMD/W80系列温湿度传感器资料介绍
    一文了解人工智能AI、大模型、AI大模型、ChatGPT、GPT-4、OpenAI、Claude 3...
    C++教学——从入门到精通 10.循环
    spark底层原理理解--高级进阶
    Redis安装及使用(Windows&&Linux)
    OpenCV入门(C++/Python)-使用OpenCV裁剪图像(四)
    【C++ 拷贝构造函数详解】
    【3D建模制作技巧分享】ZBrush模型制作流程:地精
    北斗导航系统为渔船保驾护航,助力海洋渔业发展
  • 原文地址:https://blog.csdn.net/panjinliang066333/article/details/126659513