记录下单片机使用工厂模式
在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)即可。