笔记#2中例程直接引用,一步步开始面向对象编程思维讲解。

#include "stm32f4xx.h"
 
static void delay()
{
    for(uint32_t i = 0; i < 1000; i++)
    {
        for(uint32_t j = 0; j < 10000; j++)
            {
            __NOP();
            __NOP();
            __NOP();
            __NOP(); 
			__NOP();
            }
    }
}

static void leds_init(void)
{
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE | RCC_AHB1Periph_GPIOC, ENABLE);
    GPIO_InitTypeDef GPIO_InitStruct;
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 ;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_Init(GPIOE, &GPIO_InitStruct);

    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_13;
    GPIO_Init(GPIOC, &GPIO_InitStruct);
}
 
static void led_on()
{
    GPIO_WriteBit(GPIOE, GPIO_Pin_5 | GPIO_Pin_6, Bit_RESET);
    GPIO_WriteBit(GPIOC, GPIO_Pin_13, Bit_SET);
}

static void led_off()
{
    GPIO_WriteBit(GPIOE, GPIO_Pin_5 | GPIO_Pin_6, Bit_SET);
    GPIO_WriteBit(GPIOC, GPIO_Pin_13, Bit_RESET) ;
}
    
 
int main(void)
{
    leds_init();
 
    while (1)
    {
        delay();
        led_on();
        delay();
        led_off();
    }
}

1.增加宏定义(基础)

对于LED所用的GPIO口,PIN引脚等等进行宏定义,注意宏定义需要放在程序头部,否则会报错。

#define LED0_RCC RCC_AHB1Periph_GPIOE
#define LED0_GPIO GPIOE
#define LED0_PIN GPIO_Pin_5
#define LED0_ON_LVL Bit_RESET
#define LED0_OFF_LVL Bit_SET

#define LED1_RCC RCC_AHB1Periph_GPIOE
#define LED1_GPIO GPIOE
#define LED1_PIN GPIO_Pin_6
#define LED1_ON_LVL Bit_RESET
#define LED1_OFF_LVL Bit_SET

#define LED2_RCC RCC_AHB1Periph_GPIOC
#define LED2_GPIO GPIOC
#define LED2_PIN GPIO_Pin_13
#define LED2_ON_LVL Bit_RESET
#define LED2_OFF_LVL Bit_SET

然后将之前程序中的代码用宏定义取代,更改接口或是编程出错,都能很快修改,具备基础的项目思维。

2.定义结构体(进阶)

假如需要控制100个LED呢,不可能把每一组宏定义都写出来,非常容易出错也不容易管理,这简直是宏定义地狱。不仅要定义结构体,后续的函数调用中也要加上函数指针指向结构体,不清楚这部分的可以看一下b站郝斌C语言中结构体和指针的部分:【郝斌】-C语言自学入门教程(182集全 | 最新高清修复版)_哔哩哔哩_bilibili

以及这个视频:【强烈推荐】4小时彻底掌握C指针 - 顶尖程序员图文讲解 - UP主翻译校对 (已完结)_哔哩哔哩_bilibili

#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include "stm32f4xx.h"

typedef struct led_set {
    uint32_t clk_source;       // RCC时钟使能参数(如RCC_AHB1Periph_GPIOE)
    GPIO_TypeDef* gpio;        // GPIO端口指针(如GPIOE)
    uint16_t pin;              // 引脚号(如GPIO_Pin_5)
    BitAction lvl_on;          // 开启电平(Bit_RESET或Bit_SET)bitcation属于枚举类型
    BitAction lvl_off;         // 关闭电平
} led_ser_t;

static const led_ser_t led0 =
 {
    .clk_source = RCC_AHB1Periph_GPIOE,
    .gpio = GPIOE,
    .pin = GPIO_Pin_5,
    .lvl_on = Bit_RESET,
    .lvl_off = Bit_SET
 };
static const led_ser_t led1 =
 {
    .clk_source = RCC_AHB1Periph_GPIOE,
    .gpio = GPIOE,
    .pin = GPIO_Pin_6,
    .lvl_on = Bit_RESET,
    .lvl_off = Bit_SET

 };
static const led_ser_t led2 = 
{
    .clk_source = RCC_AHB1Periph_GPIOC,
    .gpio = GPIOC,
    .pin = GPIO_Pin_13,
    .lvl_on = Bit_RESET,
    .lvl_off = Bit_SET
};

static void delay()
{
    for(uint32_t i = 0; i < 1000; i++)
    {
        for(uint32_t j = 0; j < 10000; j++)
            {
            __NOP();
            __NOP();
            __NOP();
            __NOP(); 
			__NOP();
            }
    }
}
static void leds_init(const led_ser_t *led)
{
    RCC_AHB1PeriphClockCmd(led->clk_source, ENABLE);
    GPIO_InitTypeDef GPIO_InitStruct;
    GPIO_InitStruct.GPIO_Pin = led->pin;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_Init(led->gpio, &GPIO_InitStruct);

    GPIO_WriteBit(led->gpio, led->pin, led->lvl_off);
}
static void leds_deinit(const led_ser_t *led)
{
    RCC_AHB1PeriphClockCmd(led->clk_source, DISABLE);
    
}
static void leds_on(const led_ser_t *led)
{
    GPIO_WriteBit(led->gpio, led->pin, led->lvl_on);

}
static void leds_off(const led_ser_t *led)
{
    GPIO_WriteBit(led->gpio, led->pin, led->lvl_off);

}



void led_toggle(void)
{
	
}

int main(void)
{
    leds_init(&led0);
    leds_init(&led1);
    leds_init(&led2);

    while (1)
    {
        delay();
        leds_on(&led0);
        leds_on(&led1);
        leds_on(&led2);
        delay();
        leds_off(&led0);
        leds_off(&led1);
        leds_off(&led2);
    }
}

3.项目化结构(高级)

2.中的关于引脚初始化的部分放入board.c,驱动程序放入led.cmain.c中只保留主循环。其余定义关系放入相关.h文件中。

main.c

#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include "main.h"


int main(void)
{
    led_init(&led0);
    led_init(&led1);
    led_init(&led2);

    while(1)
    {
        led_on(&led0);
        led_on(&led1);
        led_on(&led2);
        delay();

        led_off(&led0);
        led_off(&led1);
        led_off(&led2);
        delay();
    }
}

main.h

#ifndef __MAIN_H
#define __MAIN_H


#include "stm32f4xx.h"
#include "board.h"
#include "delay.h"


#endif /* __MAIN_H */

 board.c

#include "board.h"


const led_desc_t led0 =
{
    .clk_source = RCC_AHB1Periph_GPIOE,
    .port = GPIOE,
    .pin = GPIO_Pin_5,
    .on_lvl = Bit_RESET,
    .off_lvl = Bit_SET,
};

const led_desc_t led1 =
{
    .clk_source = RCC_AHB1Periph_GPIOE,
    .port = GPIOE,
    .pin = GPIO_Pin_6,
    .on_lvl = Bit_RESET,
    .off_lvl = Bit_SET,
};

const led_desc_t led2 =
{
    .clk_source = RCC_AHB1Periph_GPIOC,
    .port = GPIOC,
    .pin = GPIO_Pin_13,
    .on_lvl = Bit_RESET,
    .off_lvl = Bit_SET,
};

board.h

#ifndef __BOARD_H
#define __BOARD_H


#include "led.h"

extern const led_desc_t led0;
extern const led_desc_t led1;
extern const led_desc_t led2;


#endif /* __BOARD_H */

delay.h

#ifndef __DELAY_H
#define __DELAY_H


static void delay(void)
{
    for (unsigned int a = 0; a < 1000; a++)
    {
        for (unsigned int b = 0;b < 1000; b++)
        {
            __NOP();
            __NOP();
            __NOP();
            __NOP();
        }
    }
}

#endif /* __DELAY_H */

led.c

#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include "stm32f4xx.h"
#include "led.h"


void led_init(const led_desc_t *desc)
{
    RCC_AHB1PeriphClockCmd(desc->clk_source, ENABLE);

    GPIO_InitTypeDef ginit;
    memset(&ginit, 0, sizeof(GPIO_InitTypeDef));
    ginit.GPIO_Pin = desc->pin;
    ginit.GPIO_Mode = GPIO_Mode_OUT;
    ginit.GPIO_OType = GPIO_OType_PP;
    ginit.GPIO_Speed = GPIO_Medium_Speed;
    GPIO_Init(desc->port, &ginit);

    GPIO_WriteBit(desc->port, desc->pin, desc->off_lvl);
}

void led_deinit(const led_desc_t *desc)
{
    GPIO_WriteBit(desc->port, desc->pin, desc->off_lvl);
}

void led_on(const led_desc_t *desc)
{
    GPIO_WriteBit(desc->port, desc->pin, desc->on_lvl);
}

void led_off(const led_desc_t *desc)
{
    GPIO_WriteBit(desc->port, desc->pin, desc->off_lvl);
}

led.h

#ifndef __DRV_LED_H__
#define __DRV_LED_H__


#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include "stm32f4xx.h"


typedef struct led_desc
{
    uint32_t clk_source;
    GPIO_TypeDef *port;
    uint16_t pin;
    BitAction on_lvl;
    BitAction off_lvl;
} led_desc_t;


void led_init(const led_desc_t *desc);
void led_deinit(const led_desc_t *desc);
void led_on(const led_desc_t *desc);
void led_off(const led_desc_t *desc);


#endif /* __DRV_LED_H__ */

总结

项目化编程虽然在短时间内对于初学者不适应,并且降低效率,实际上很难出问题,磨刀不误砍柴工。完成一个STM32项目需要涉及到多个外设,在函数结构中错综复杂,这样书写不仅易于管理还增加了代码的可读性。

 

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐