STM32学习笔记#3-面向对象编程思维
对于LED所用的GPIO口,PIN引脚等等进行宏定义,注意宏定义需要放在程序头部,否则会报错。然后将之前程序中的代码用宏定义取代,更改接口或是编程出错,都能很快修改,具备基础的项目思维。假如需要控制100个LED呢,不可能把每一组宏定义都写出来,非常容易出错也不容易管理,这简直是宏定义地狱。不仅要定义结构体,后续的函数调用中也要加上函数指针指向结构体,不清楚这部分的可以看一下b站郝斌C语言【郝斌】
将笔记#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.c,main.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项目需要涉及到多个外设,在函数结构中错综复杂,这样书写不仅易于管理还增加了代码的可读性。
更多推荐



所有评论(0)