单片机的工厂模式

记录下单片机使用工厂模式

在STM32上使用简单工厂模式(Simple Factory Pattern)的示例,以传感器为例。

简单工厂模式:定义一个工厂类(或函数),根据传入的参数决定创建哪一种具体的产品对象。在嵌入式系统中,对象通常通过结构体和函数指针来模拟。

我们将以传感器为例:假设有多个传感器类型(比如温度传感器、湿度传感器),每个传感器有初始化、读取数据等方法。工厂根据传感器类型返回对应的传感器对象(结构体指针)。

需要提供:

1.传感器抽象接口(结构体,包含函数指针)

2.具体传感器实现(温度传感器、湿度传感器)

3.工厂函数:根据类型创建对应的传感器实例,并返回接口指针。

sensor.h

c 复制代码
#ifndef __DRV_SENSOR_H
#define __DRV_SENSOR_H

#include <stdint.h>

/* 传感器类型枚举 */
typedef enum {
    SENSOR_DS18B20,
    SENSOR_DHT22,
    SENSOR_TYPE_MAX
} SensorType_t;

/* 传感器对象结构体(类似于抽象类) */
typedef struct {
    void     (*Init)(void *pPrivate);          // 初始化函数
    float    (*Read)(void *pPrivate);           // 读取数据函数
    void     *pPrivate;                          // 私有数据(具体传感器需要的硬件信息)
    const char *name;                            // 传感器名称
} Sensor_t;

/* 工厂函数:创建传感器对象(返回常量指针,避免外部修改) */
const Sensor_t* Sensor_Create(SensorType_t type);

#endif

sensor.c

c 复制代码
#include "drv_sensor.h"

#include "drv_DHT22.h"
#include "drv_DS18B20.h"



/* DHT22 私有数据 */
static DHT22_Private_t dht22_priv = 
{
    .port = GPIOB,
    .pin  = GPIO_PIN_1
};


static const Sensor_t dht22_sensor = 
{
    .Init     = DHT22_Init,
    .Read     = DHT22_Read,
    .pPrivate = &dht22_priv,
    .name     = "DHT22"
};



/* 静态私有数据实例(假设使用固定的引脚:例如 GPIOA, GPIO_PIN_0) */
static DS18B20_Private_t ds18b20_priv = {
    .port = GPIOA,
    .pin  = GPIO_PIN_0
};

/* DS18B20 传感器对象 */
static const Sensor_t ds18b20_sensor = {
    .Init     = DS18B20_Init,
    .Read     = DS18B20_Read,
    .pPrivate = &ds18b20_priv,
    .name     = "DS18B20"
};




/* 工厂函数:根据类型返回对应的传感器对象 */
const Sensor_t* Sensor_Create(SensorType_t type) {
    switch (type) {
        case SENSOR_DS18B20:
            return &ds18b20_sensor;   // 需要外部声明
        case SENSOR_DHT22:
            return &dht22_sensor;
        default:
            return NULL;
    }
}

DS18B20.h

c 复制代码
#ifndef __DRV_DS18B20_H
#define __DRV_DS18B20_H

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "stm32f4xx_hal.h"
#include "drv_sensor.h"

typedef struct {
    GPIO_TypeDef *port;
    uint16_t pin;
} DS18B20_Private_t;

static void DS18B20_DelayUs(uint32_t us);
static uint8_t DS18B20_Reset(void *pPrivate);
static void DS18B20_WriteByte(void *pPrivate, uint8_t data);
static uint8_t DS18B20_ReadByte(void *pPrivate);
void DS18B20_Init(void *pPrivate);
float DS18B20_Read(void *pPrivate);

#endif

DS18B20.c

c 复制代码
#include "drv_DS18B20.h"





/* 模拟单总线时序的函数(实际工程需精确延时) */
static void DS18B20_DelayUs(uint32_t us) 
{
    // 简单循环延时,建议使用定时器或HAL_Delay微秒级实现
    for (uint32_t i = 0; i < us * 10; i++) { __NOP(); }
}

/* 复位脉冲和存在检测 */
static uint8_t DS18B20_Reset(void *pPrivate) 
{
    DS18B20_Private_t *priv = (DS18B20_Private_t *)pPrivate;
    // 拉低总线 480us
    HAL_GPIO_WritePin(priv->port, priv->pin, GPIO_PIN_RESET);
    DS18B20_DelayUs(480);
    HAL_GPIO_WritePin(priv->port, priv->pin, GPIO_PIN_SET);
    DS18B20_DelayUs(70);
    // 读取存在脉冲
    uint8_t presence = HAL_GPIO_ReadPin(priv->port, priv->pin);
    DS18B20_DelayUs(410);
    return presence;
}

/* 写一个字节 */
static void DS18B20_WriteByte(void *pPrivate, uint8_t data)
{
    DS18B20_Private_t *priv = (DS18B20_Private_t *)pPrivate;
	
    for (int i = 0; i < 8; i++) {
        HAL_GPIO_WritePin(priv->port, priv->pin, GPIO_PIN_RESET);
        DS18B20_DelayUs(2);
        if (data & 0x01) {
            HAL_GPIO_WritePin(priv->port, priv->pin, GPIO_PIN_SET);
        }
        DS18B20_DelayUs(60);
        HAL_GPIO_WritePin(priv->port, priv->pin, GPIO_PIN_SET);
        DS18B20_DelayUs(2);
        data >>= 1;
    }
}

/* 读一个字节 */
static uint8_t DS18B20_ReadByte(void *pPrivate)
{
    DS18B20_Private_t *priv = (DS18B20_Private_t *)pPrivate;
    uint8_t data = 0;
    for (int i = 0; i < 8; i++) {
        data >>= 1;
        HAL_GPIO_WritePin(priv->port, priv->pin, GPIO_PIN_RESET);
        DS18B20_DelayUs(2);
        HAL_GPIO_WritePin(priv->port, priv->pin, GPIO_PIN_SET);
        DS18B20_DelayUs(2);
        if (HAL_GPIO_ReadPin(priv->port, priv->pin)) {
            data |= 0x80;
        }
        DS18B20_DelayUs(60);
    }
    return data;
}

/* DS18B20 初始化函数(执行一次复位) */
void DS18B20_Init(void *pPrivate)
{
//    DS18B20_Reset(pPrivate);
	printf("DS18B20 Init is OK \n");
}

/* DS18B20 读取温度函数 */
float DS18B20_Read(void *pPrivate) 
{
//    // 启动温度转换
//    DS18B20_Reset(pPrivate);
//    DS18B20_WriteByte(pPrivate, 0xCC);  // 跳过ROM
//    DS18B20_WriteByte(pPrivate, 0x44);  // 启动转换

//    // 等待转换完成(通常750ms,这里简化)
//    HAL_Delay(750);

//    // 读取暂存器
//    DS18B20_Reset(pPrivate);
//    DS18B20_WriteByte(pPrivate, 0xCC);
//    DS18B20_WriteByte(pPrivate, 0xBE);

//    uint8_t lsb = DS18B20_ReadByte(pPrivate);
//    uint8_t msb = DS18B20_ReadByte(pPrivate);

//    int16_t raw = (msb << 8) | lsb;
//    return raw * 0.0625f;  // 12位精度,LSB=0.0625°C
	
	    return  10;
}

DHT22.h

c 复制代码
#ifndef __DRV_DHT22_H
#define __DRV_DHT22_H

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "stm32f4xx_hal.h"
#include "drv_sensor.h"

typedef struct 
{
    GPIO_TypeDef *port;
    uint16_t pin;
}DHT22_Private_t;

static void DHT22_DelayUs(uint32_t us);
static uint8_t DHT22_ReadData(void *pPrivate, int16_t *temp, int16_t *humi);
void DHT22_Init(void *pPrivate);
float DHT22_Read(void *pPrivate);

#endif

DHT22.c

c 复制代码
#include "drv_DHT22.h"








/* 微秒延时(同DS18B20,可共用) */
static void DHT22_DelayUs(uint32_t us) 
{
    for (uint32_t i = 0; i < us * 10; i++) 
{ __NOP(); }
}

/* 读取DHT22数据,返回温度×10,湿度×10 */
static uint8_t DHT22_ReadData(void *pPrivate, int16_t *temp, int16_t *humi) 
{
    DHT22_Private_t *priv = (DHT22_Private_t *)pPrivate;
    uint8_t data[5] = {0};

    // 主机拉低至少18ms
    HAL_GPIO_WritePin(priv->port, priv->pin, GPIO_PIN_RESET);
    HAL_Delay(20);
    HAL_GPIO_WritePin(priv->port, priv->pin, GPIO_PIN_SET);
    DHT22_DelayUs(40);  // 等待DHT22响应

    // 检测响应
    if (HAL_GPIO_ReadPin(priv->port, priv->pin) == GPIO_PIN_RESET) {
        // 等待80us低电平结束
        while (HAL_GPIO_ReadPin(priv->port, priv->pin) == GPIO_PIN_RESET);
        // 等待80us高电平结束
        while (HAL_GPIO_ReadPin(priv->port, priv->pin) == GPIO_PIN_SET);

        // 读取40位数据
        for (int i = 0; i < 40; i++) {
            while (HAL_GPIO_ReadPin(priv->port, priv->pin) == GPIO_PIN_RESET);
            DHT22_DelayUs(40);
            if (HAL_GPIO_ReadPin(priv->port, priv->pin) == GPIO_PIN_SET) {
                data[i / 8] |= (1 << (7 - (i % 8)));
            }
            while (HAL_GPIO_ReadPin(priv->port, priv->pin) == GPIO_PIN_SET);
        }

        // 校验和
        if (data[4] == ((data[0] + data[1] + data[2] + data[3]) & 0xFF)) {
            *humi = (data[0] << 8) | data[1];
            *temp = (data[2] << 8) | data[3];
            return 1;
        }
    }
    return 0;
}

void DHT22_Init(void *pPrivate) 
{
    // DHT22 上电后需要1s稳定,初始化时不需要额外操作
    HAL_Delay(1000);
	printf("DHT22 Init is OK \n");
}

float DHT22_Read(void *pPrivate) 
{
//    int16_t temp, humi;
//    if (DHT22_ReadData(pPrivate, &temp, &humi)) 
//		{
//        // 返回温度值(保留一位小数)
//        return temp / 10.0f;
//    }
//    return -999.0f;  // 错误标志
	
	
	return 15;  // 
}

测试

c 复制代码
/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
	

  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */
	EventRecorderInitialize(EventRecordAll, 1U);
	EventRecorderStart();
  /* USER CODE END SysInit */
  DWT_Init();
  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  /* USER CODE BEGIN 2 */
	
// 创建温度传感器(DS18B20)
    const Sensor_t *temp_sensor = Sensor_Create(SENSOR_DS18B20);
    if (temp_sensor) {
        temp_sensor->Init(temp_sensor->pPrivate);
        printf("Sensor is  %s\n", temp_sensor->name);
    }

    // 创建湿度传感器(DHT22)
    const Sensor_t *humi_sensor = Sensor_Create(SENSOR_DHT22);
    if (humi_sensor) {
        humi_sensor->Init(humi_sensor->pPrivate);
        printf("Sensor is  %s\n", humi_sensor->name);
    }

    while (1) {
        if (temp_sensor) {
            float t = temp_sensor->Read(temp_sensor->pPrivate);
            printf("Temperature: %.2f°C\n", t);
        }
        if (humi_sensor) {
            float h = humi_sensor->Read(humi_sensor->pPrivate);
            printf("Humidity: %.2f%%\n", h);
        }
        HAL_Delay(2000);
    }
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
//  while (1)
//  {
//    /* USER CODE END WHILE */

//    /* USER CODE BEGIN 3 */
//		HAL_Delay(100);
//  }
  /* USER CODE END 3 */
}

可以看到正确显示了相应传感器和数值,而调用的是同一个函数。若替换了相应的温度传感器和湿度传感器,则只需要在Sensor_Create(xx)即可。

相关推荐
香水5只用六神2 小时前
【TIM】基本定时器定时实验(1)
c语言·git·stm32·单片机·嵌入式硬件·github
我在人间贩卖青春2 小时前
嵌入式mcu开发专业术语汇总
单片机·嵌入式硬件
fygfh.3 小时前
Linux外设之 串口(UART)的使用
linux·运维·单片机
搞机械的假程序猿3 小时前
STC32G学习笔记-FreeRTOS for STC32G12K128
笔记·单片机·学习
LCG元3 小时前
振动能量采集:STM32U5从振动启动,能量管理完整方案
stm32·单片机·嵌入式硬件
_探索_12 小时前
STM32U5F7VJT6Q (Cortex-M33, 160MHz) TouchGFX统计MCU占用率和FPS
stm32·单片机·嵌入式硬件
猫猫的小茶馆12 小时前
【Linux 驱动开发】Linux 内核启动过程详解
linux·c语言·arm开发·驱动开发·stm32·单片机·mcu
辰哥单片机设计12 小时前
STM32太阳能光伏板
stm32·单片机·嵌入式硬件
mftang12 小时前
MCU上应用的主流NVM技术: 嵌入式相变存储器(PCM) 和嵌入式磁阻随机存取存储器(MRAM)
单片机·嵌入式硬件·pcm