基于STM32的宠物喂养系统设计

主要硬件连接约定如下

  • STM32F103C8T6(72 MHz)

  • SU-03T 语音识别模块

    -- VCC 3.3 V

    -- GND

    -- TX → MCU RX1 (PA10)

    -- RX → MCU TX1 (PA9)

  • 步进电机(28BYJ-48 + ULN2003 驱动板)

    -- IN1: PB0

    -- IN2: PB1

    -- IN3: PB2

    -- IN4: PB10

  • DHT11

    -- DATA: PA1,上拉 10 kΩ

  • 调试/状态 LED

    -- PC13(板载 LED)

  • 喂食按键 KEY1(手动触发)

    -- PA0,下拉 10 kΩ

  • 蜂鸣器 BEEP

    -- PB11

cpp 复制代码
/*------------------  main.c  ------------------*/
#include "stm32f10x.h"          // CMSIS
#include <string.h>
#include <stdio.h>
/*---------------- 设计加V:Niumajiuhao  ----------------*/
/*----------------  用户可调区  ----------------*/
#define SYSCLK    72000000UL
#define DHT_PIN     GPIO_Pin_1
#define DHT_PORT    GPIOA
#define STEP_PORT   GPIOB
#define IN1_PIN     GPIO_Pin_0
#define IN2_PIN     GPIO_Pin_1
#define IN3_PIN     GPIO_Pin_2
#define IN4_PIN     GPIO_Pin_10
#define LED_PIN     GPIO_Pin_13
#define LED_PORT    GPIOC
#define KEY_PIN     GPIO_Pin_0
#define KEY_PORT    GPIOA
#define BEEP_PIN    GPIO_Pin_11
#define BEEP_PORT   GPIOB

/*  SU-03T UART  */
#define SU_UART     USART1
/*----------------------------------------------*/
/*---------------- 设计加V:Niumajiuhao  ----------------*/
/*--------------  步进电机 8 拍序列  -------------*/
static const uint8_t phase[8] = {
    0b0001, 0b0011, 0b0010, 0b0110,
    0b0100, 0b1100, 0b1000, 0b1001
};

/*------------  全局变量 & 原型  ---------------*/
volatile uint32_t tick = 0;
uint8_t  DHT_data[5];
char     uartRxBuf[32];
uint8_t  uartRxIdx = 0;

void delay_ms(uint32_t ms);
void SysTick_Handler(void);
void GPIO_Config(void);
void TIM2_Config(void);
void USART1_Config(void);
void DHT11_Start(void);
uint8_t DHT11_ReadByte(void);
uint8_t DHT11_Get(void);
void Stepper_Run(uint16_t steps, uint8_t dir);
void feed(void);
void beep(uint16_t ms);
/*----------------------------------------------*/

/*----------------  主函数  --------------------*/
int main(void)
{
    SystemInit();               // 72 MHz
    SysTick_Config(SYSCLK/1000);
    GPIO_Config();
    USART1_Config();
    TIM2_Config();
    
    printf("Pet Feeder STM32+SU-03T\r\n");
    
    while(1)
    {
        /* 1. 语音指令监听(SU-03T 固定返回"FEED"字符串) */
        if(strstr(uartRxBuf, "FEED") != NULL)
        {
            memset(uartRxBuf, 0, sizeof(uartRxBuf));
            feed();
        }
        
        /* 2. 手动按键 */
        if(GPIO_ReadInputDataBit(KEY_PORT, KEY_PIN) == Bit_SET)
        {
            while(GPIO_ReadInputDataBit(KEY_PORT, KEY_PIN) == Bit_SET);
            feed();
        }
        
        /* 3. 每 5 s 采集一次温湿度并打印(可扩展为自动喂食) */
        static uint32_t last = 0;
        if(tick - last >= 5000)
        {
            last = tick;
            if(DHT11_Get())
            {
                printf("T=%d H=%d\r\n", DHT_data[2], DHT_data[0]);
            }
        }
    }
}
/*--------------  功能实现  --------------------*/
void feed(void)
{
    beep(100);
    Stepper_Run(512, 1);        // 512 步约一圈,可自行调整
    beep(200);
    GPIO_SetBits(LED_PORT, LED_PIN);
    delay_ms(1000);
    GPIO_ResetBits(LED_PORT, LED_PIN);
}

void Stepper_Run(uint16_t steps, uint8_t dir)
{
    static uint8_t pos = 0;
    for(uint16_t i=0; i<steps; i++)
    {
        if(dir) pos++; else pos--;
        pos &= 0x07;
        
        uint8_t out = phase[pos];
        GPIO_WriteBit(STEP_PORT, IN1_PIN, (out & 0x01) ? Bit_SET : Bit_RESET);
        GPIO_WriteBit(STEP_PORT, IN2_PIN, (out & 0x02) ? Bit_SET : Bit_RESET);
        GPIO_WriteBit(STEP_PORT, IN3_PIN, (out & 0x04) ? Bit_SET : Bit_RESET);
        GPIO_WriteBit(STEP_PORT, IN4_PIN, (out & 0x08) ? Bit_SET : Bit_RESET);
        delay_ms(2);            // 2 ms/步 ≈ 250 rpm
    }
    /* 关闭线圈 */
    GPIO_ResetBits(STEP_PORT, IN1_PIN | IN2_PIN | IN3_PIN | IN4_PIN);
}

void DHT11_Start(void)
{
    GPIO_InitTypeDef  gpio;
    gpio.GPIO_Pin = DHT_PIN;
    gpio.GPIO_Mode = GPIO_Mode_Out_PP;
    gpio.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(DHT_PORT, &gpio);
    
    GPIO_ResetBits(DHT_PORT, DHT_PIN);
    delay_ms(18);
    GPIO_SetBits(DHT_PORT, DHT_PIN);
    delay_us(30);
    
    gpio.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_Init(DHT_PORT, &gpio);
}

uint8_t DHT11_ReadByte(void)
{
    uint8_t i, dat = 0;
    for(i=0;i<8;i++)
    {
        while(GPIO_ReadInputDataBit(DHT_PORT, DHT_PIN) == Bit_RESET);
        delay_us(40);
        if(GPIO_ReadInputDataBit(DHT_PORT, DHT_PIN) == Bit_SET)
            dat |= (1<<(7-i));
        while(GPIO_ReadInputDataBit(DHT_PORT, DHT_PIN) == Bit_SET);
    }
    return dat;
}

uint8_t DHT11_Get(void)
{
    uint8_t sum;
    DHT11_Start();
    if(GPIO_ReadInputDataBit(DHT_PORT, DHT_PIN) == Bit_RESET)
    {
        while(GPIO_ReadInputDataBit(DHT_PORT, DHT_PIN) == Bit_RESET);
        while(GPIO_ReadInputDataBit(DHT_PORT, DHT_PIN) == Bit_SET);
        
        DHT_data[0] = DHT11_ReadByte();
        DHT_data[1] = DHT11_ReadByte();
        DHT_data[2] = DHT11_ReadByte();
        DHT_data[3] = DHT11_ReadByte();
        sum         = DHT11_ReadByte();
        
        if((DHT_data[0]+DHT_data[1]+DHT_data[2]+DHT_data[3]) == sum)
            return 1;
    }
    return 0;
}

void beep(uint16_t ms)
{
    GPIO_SetBits(BEEP_PORT, BEEP_PIN);
    delay_ms(ms);
    GPIO_ResetBits(BEEP_PORT, BEEP_PIN);
}

/*--------------  外设初始化  ------------------*/
void GPIO_Config(void)
{
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB |
                           RCC_APB2Periph_GPIOC, ENABLE);
    
    GPIO_InitTypeDef gpio;
    
    /* LED */
    gpio.GPIO_Pin = LED_PIN;
    gpio.GPIO_Mode = GPIO_Mode_Out_PP;
    gpio.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(LED_PORT, &gpio);
    
    /* KEY */
    gpio.GPIO_Pin = KEY_PIN;
    gpio.GPIO_Mode = GPIO_Mode_IPD;
    GPIO_Init(KEY_PORT, &gpio);
    
    /* BEEP */
    gpio.GPIO_Pin = BEEP_PIN;
    gpio.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_Init(BEEP_PORT, &gpio);
    
    /* 步进电机 */
    gpio.GPIO_Pin = IN1_PIN | IN2_PIN | IN3_PIN | IN4_PIN;
    GPIO_Init(STEP_PORT, &gpio);
    GPIO_ResetBits(STEP_PORT, IN1_PIN | IN2_PIN | IN3_PIN | IN4_PIN);
    
    /* DHT11 默认为上拉输入 */
    gpio.GPIO_Pin = DHT_PIN;
    gpio.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_Init(DHT_PORT, &gpio);
}

void USART1_Config(void)
{
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);
    
    GPIO_InitTypeDef gpio;
    gpio.GPIO_Pin = GPIO_Pin_9;
    gpio.GPIO_Mode = GPIO_Mode_AF_PP;
    gpio.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &gpio);
    
    gpio.GPIO_Pin = GPIO_Pin_10;
    gpio.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_Init(GPIOA, &gpio);
    
    USART_InitTypeDef usart;
    usart.USART_BaudRate = 9600;
    usart.USART_WordLength = USART_WordLength_8b;
    usart.USART_StopBits = USART_StopBits_1;
    usart.USART_Parity = USART_Parity_No;
    usart.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
    USART_Init(SU_UART, &usart);
    USART_ITConfig(SU_UART, USART_IT_RXNE, ENABLE);
    USART_Cmd(SU_UART, ENABLE);
    
    NVIC_EnableIRQ(USART1_IRQn);
}

void TIM2_Config(void)          // 1 kHz 用于蜂鸣器 PWM(可选)
{
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
    TIM_TimeBaseInitTypeDef tim;
    tim.TIM_Period = 71;
    tim.TIM_Prescaler = 999;
    tim.TIM_ClockDivision = 0;
    tim.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInit(TIM2, &tim);
    TIM_Cmd(TIM2, ENABLE);
}

/*--------------  中断  ------------------------*/
void SysTick_Handler(void)
{
    tick++;
}

void USART1_IRQHandler(void)
{
    if(USART_GetITStatus(SU_UART, USART_IT_RXNE) != RESET)
    {
        uint8_t ch = USART_ReceiveData(SU_UART);
        if(ch == '\n' || uartRxIdx >= sizeof(uartRxBuf)-1)
        {
            uartRxBuf[uartRxIdx] = 0;
            uartRxIdx = 0;
        }
        else
            uartRxBuf[uartRxIdx++] = ch;
    }
}

/*--------------  延迟函数  --------------------*/
void delay_us(uint32_t us)
{
    us *= 8;
    while(us--);
}

void delay_ms(uint32_t ms)
{
    uint32_t start = tick;
    while(tick - start < ms);
}

/*--------------  printf 重定向  ---------------*/
#ifdef __GNUC__
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif

PUTCHAR_PROTOTYPE
{
    USART_SendData(USART1, (uint8_t)ch);
    while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
    return ch;
}
/*---------------- 设计加V:Niumajiuhao  ----------------*/

基于 STM32 单片机的宠物喂养系统设计

一、引言

1.1 研究背景与意义

在现代社会,随着人们生活节奏的加快,越来越多的家庭选择饲养宠物来丰富生活。然而,由于工作繁忙、出差等原因,宠物的喂养问题常常困扰着宠物主人。传统的宠物喂养方式需要人工定时投放食物,一旦主人无法按时照顾,宠物可能会面临饥饿的困境,甚至影响其健康。

基于此,设计一款智能化的宠物喂养系统具有重要的现实意义。该系统能够实现自动定时定量喂食,还可通过语音指令进行控制,同时能够监测饲养环境的温湿度,为宠物提供适宜的生活环境。本研究采用 STM32 单片机作为主控制器,结合 SU-03T 语音模块、步进电机和 DHT11 温湿度传感器等器件,设计出一款性能稳定、操作便捷、成本适中的智能宠物喂养系统,旨在解决宠物主人的喂养难题,保障宠物的健康成长,具有较好的市场应用前景。

1.2 国内外研究现状

国内外在智能宠物喂养领域已有一定的研究成果。国外的一些智能宠物喂养产品功能较为完善,例如能够通过手机 APP 远程控制喂食时间和食量,部分产品还具备视频监控功能,但这些产品价格较高,且在语音交互和本地化控制方面存在一定的局限性。

国内的研究则更注重性价比和实用性。许多研究以单片机为核心,实现了基本的自动喂食功能,但在语音控制的准确性、温湿度监测的集成以及喂食量的精确控制等方面还有提升空间。近年来,随着语音识别技术和传感器技术的发展,为智能宠物喂养系统的升级提供了可能。与现有研究相比,本设计引入 SU-03T 语音模块,提高了语音控制的响应速度和识别准确率;采用步进电机控制喂食量,实现了定量喂食的精确性;集成 DHT11 温湿度传感器,能够实时监测宠物生活环境,使系统功能更加完善。

1.3 研究目标与内容

本研究的目标是设计并实现一款基于 STM32 单片机的智能宠物喂养系统,该系统能够通过语音指令和定时设置实现自动喂食,精确控制喂食量,实时监测饲养环境的温湿度,并在温湿度异常时发出提醒。

研究内容主要包括以下几个方面:

  • 系统总体设计:确定系统的功能需求,设计系统的整体架构和技术方案。
  • 硬件设计:包括 STM32 最小系统设计、SU-03T 语音模块接口电路设计、步进电机驱动电路设计、DHT11 温湿度传感器接口电路设计以及电源电路设计等。
  • 软件设计:搭建软件开发环境,设计主程序流程,实现语音识别与指令解析程序、步进电机控制程序、DHT11 温湿度采集与处理程序以及定时喂食程序等。
  • 系统测试与优化:对系统的各项功能进行测试,根据测试结果进行优化,确保系统稳定可靠运行。

二、系统总体设计方案

2.1 需求分析

用户对智能宠物喂养系统的功能需求主要包括以下几个方面:

  • 语音控制功能:能够通过语音指令(如 "喂食""停止喂食""增加食量""减少食量" 等)控制喂食动作,语音识别应准确可靠,不受环境噪声的过多干扰。

  • 定时定量喂食功能:可以预先设置喂食时间和每次的喂食量,到设定时间后系统能够自动按照设定食量进行喂食。

  • 温湿度监测功能:实时监测宠物饲养环境的温度和湿度,并能在温湿度超出适宜范围时发出提示信息。

  • 手动控制功能:在语音控制和定时控制出现故障时,可通过手动按钮进行喂食操作,保证系统的可靠性。

  • 状态显示功能:能够显示当前的喂食状态、设定的喂食时间和食量以及温湿度数据等。

  • 基于以上需求,确定系统设计方向为:以 STM32 单片机为核心,通过 SU-03T 语音模块实现语音指令的接收与识别,利用步进电机控制喂食机构的动作以实现定量喂食,通过 DHT11 温湿度传感器采集环境温湿度数据,同时设计定时模块和手动控制模块,配合显示模块完成系统的各项功能。

    2.2 系统架构设计

    系统整体架构主要由 STM32 单片机、SU-03T 语音模块、步进电机及驱动模块、DHT11 温湿度传感器、按键模块、显示模块和电源模块等组成。

    STM32 单片机作为主控制器,负责协调各个模块的工作。它通过串口与 SU-03T 语音模块进行通信,接收语音指令;通过 GPIO 接口连接步进电机驱动器,控制步进电机的转动,从而实现喂食量的控制;通过单总线与 DHT11 温湿度传感器连接,采集环境温湿度数据;通过 GPIO 接口连接按键模块,接收手动控制指令;通过 I2C 或 SPI 接口连接显示模块,显示系统的各项状态信息。

    SU-03T 语音模块负责采集用户的语音指令,并进行识别和解析,将解析后的指令通过串口发送给 STM32 单片机。

    步进电机及驱动模块在 STM32 单片机的控制下,带动喂食机构的螺旋推进器或闸门等部件运动,实现食物的定量投放。

    DHT11 温湿度传感器用于实时采集宠物饲养环境的温度和湿度数据,并将数据传输给 STM32 单片机进行处理。

    按键模块包括设置键、增加键、减少键和手动喂食键等,用于手动设置喂食时间、食量以及进行手动喂食操作。

    显示模块采用 LCD1602 或 OLED 显示屏,用于显示当前的时间、设定的喂食时间、喂食量、环境温湿度以及系统的工作状态等信息。

    电源模块为系统中的各个组件提供稳定的工作电压,确保系统的正常运行。

    2.3 技术路线选择

  • 单片机选型:选择 STM32 单片机作为主控制器,原因在于其具有强大的处理能力,能够快速处理多模块的数据和指令;丰富的外设接口,便于与语音模块、电机驱动器、传感器、显示模块等进行连接;同时,STM32 系列单片机具有较低的功耗和较高的性价比,适合在嵌入式系统中应用。与 51 单片机相比,STM32 的性能更优,能够满足系统复杂控制的需求;与其他高端处理器相比,STM32 成本更低,更适合本系统的设计预算。

  • 语音模块选型:选用 SU-03T 语音模块,该模块具有识别准确率高、响应速度快、支持自定义唤醒词和指令集等优点,能够满足本系统对语音控制的需求。与其他语音模块相比,如 LD3320,SU-03T 的集成度更高,使用更加简便,无需复杂的外围电路设计,降低了系统的硬件复杂度。

  • 电机选型:选择步进电机作为执行机构,因为步进电机具有控制精度高、运行稳定的特点,能够精确控制转动角度,从而实现喂食量的精确控制。与直流电机相比,步进电机不需要位置传感器即可实现精确定位,简化了系统设计;与伺服电机相比,步进电机成本较低,适合本系统的成本要求。

  • 温湿度传感器选型:选用 DHT11 温湿度传感器,该传感器具有体积小、功耗低、精度能够满足室内环境监测需求等优点,且采用单总线通信方式,接口简单,便于与 STM32 单片机连接。与 SHT30 等传感器相比,DHT11 成本更低,虽然精度稍低,但足以满足宠物饲养环境的温湿度监测需求。

三、系统硬件设计

3.1 STM32 最小系统设计

本系统选用 STM32F103 系列单片机作为主控制器。STM32 最小系统主要由电源电路、时钟电路、复位电路和下载接口电路等组成。

电源电路:STM32 单片机需要 3.3V 的工作电压,系统采用外部 5V 直流电源供电,通过低压差线性稳压器(如 AMS1117-3.3)将 5V 电压转换为 3.3V,为单片机及其他需要 3.3V 电压的模块(如 SU-03T 语音模块、DHT11 温湿度传感器等)供电。电源电路中加入了电解电容和陶瓷电容进行滤波,以减小电源噪声对系统的影响。

时钟电路:STM32 单片机采用外部 8MHz 的晶体振荡器作为时钟源,通过锁相环(PLL)倍频后产生 72MHz 的系统时钟,保证系统各模块的高速运行。时钟电路中还配置了合适的负载电容,确保振荡器能够稳定起振。

复位电路:采用上电复位和手动复位相结合的方式。上电复位通过 RC 电路实现,当系统上电时,电容充电,产生复位信号;手动复位通过复位按钮实现,按下按钮时,单片机复位引脚接地,产生复位信号,确保系统在异常情况下能够重新启动。

下载接口电路:采用 SWD 接口,通过下载器将程序下载到 STM32 单片机中,便于系统的调试和程序更新。

3.2 SU-03T 语音模块电路设计

SU-03T 语音模块工作电压为 3.3V,通过串口与 STM32 单片机进行通信,实现语音指令的传输。

该模块的接口电路主要包括电源接口、串口接口和麦克风接口。电源接口直接连接到系统的 3.3V 电源,为模块提供工作电压;串口接口的 TX 引脚连接到 STM32 单片机的 USART_RX 引脚,RX 引脚连接到 STM32 单片机的 USART_TX 引脚,实现模块与单片机之间的双向通信;麦克风接口连接外部驻极体麦克风,用于采集用户的语音指令。

为保证串口通信的稳定性,在模块的 TX 和 RX 引脚上分别串联一个 100Ω 左右的限流电阻,减少信号传输过程中的干扰。同时,在模块的电源引脚附近并联一个 10μF 的电解电容和一个 0.1μF 的陶瓷电容,进一步滤除电源噪声,提高模块工作的稳定性。

SU-03T 语音模块的工作原理是:麦克风采集到用户的语音信号后,经过模块内部的语音识别算法处理,将识别到的指令转换为相应的数字信号,通过串口发送给 STM32 单片机,单片机接收到指令后进行解析并执行相应的操作。

3.3 步进电机驱动电路设计

本系统选用四相八拍步进电机,步距角为 1.8 度,通过控制电机的转动角度来控制喂食量。驱动芯片选用 ULN2003,该芯片是一款高电压、大电流的达林顿晶体管阵列,能够为步进电机提供足够的驱动电流,适合驱动四相步进电机。

步进电机驱动电路的设计如下:STM32 单片机的四个 GPIO 引脚分别连接到 ULN2003 的四个输入引脚(IN1-IN4),ULN2003 的四个输出引脚(OUT1-OUT4)分别连接到步进电机的四个相绕组(A、B、C、D)。通过单片机输出不同时序的脉冲信号,控制 ULN2003 内部晶体管的导通与截止,从而改变步进电机各相绕组的通电顺序,实现电机的正转、反转和停止。

为保护驱动芯片和步进电机,在电机的各相绕组两端分别并联续流二极管(如 1N4001),以吸收电机绕组断电时产生的反向电动势,防止高电压损坏芯片。同时,在 ULN2003 的电源引脚(VCC)与地之间并联滤波电容,减少电源波动对驱动电路的影响。

步进电机的转速通过改变脉冲信号的频率来调节,脉冲频率越高,电机转速越快;反之则越慢。在喂食过程中,可根据需要设置合适的转速,以保证食物投放的均匀性。

3.4 DHT11 温湿度传感器接口电路设计

DHT11 温湿度传感器采用单总线通信方式,工作电压为 3.3V-5V,本系统中采用 3.3V 供电,与 STM32 单片机的电压兼容。

传感器的接口电路较为简单,其 DATA 引脚通过一个 4.7kΩ 的上拉电阻连接到 STM32 单片机的一个 GPIO 引脚,同时连接到 3.3V 电源。上拉电阻的作用是保证 DATA 引脚在空闲状态时为高电平,确保通信的稳定性。

DHT11 温湿度传感器的工作原理是:当 STM32 单片机发送起始信号后,传感器会响应并发送 40 位的数据,其中包括 8 位湿度整数数据、8 位湿度小数数据、8 位温度整数数据、8 位温度小数数据和 8 位校验位。单片机接收到数据后,通过校验位验证数据的正确性,然后对温度和湿度数据进行解析和处理。

3.5 其他辅助电路设计

  • 按键电路:设计了多个独立按键,包括设置键、增加键、减少键和手动喂食键等。每个按键的一端连接到 STM32 单片机的 GPIO 引脚,另一端接地,同时单片机的 GPIO 引脚通过内部上拉电阻或外部上拉电阻保持高电平。当按键按下时,GPIO 引脚变为低电平,单片机通过检测电平变化识别按键操作。
  • 显示电路:采用 OLED12864 显示屏,通过 I2C 接口与 STM32 单片机连接。显示屏用于显示当前时间、设定的喂食时间、喂食量、环境温湿度等信息。I2C 接口电路简单,只需要两根线(SDA 和 SCL)即可实现通信,节省了单片机的 IO 资源。
  • 报警电路:当环境温湿度超出设定的适宜范围时,系统通过蜂鸣器发出报警提示。蜂鸣器的驱动电路采用三极管放大电路,STM32 单片机的 GPIO 引脚通过控制三极管的导通与截止,实现蜂鸣器的发声与关闭。

四、系统软件设计

4.1 软件开发环境搭建

本系统的软件开发环境采用 Keil MDK 5,它是一款针对 ARM 微控制器的集成开发环境,支持 STM32 系列单片机的程序开发。

搭建开发环境的步骤如下:

  • 安装 Keil MDK 5 软件:从官方网站下载 Keil MDK 5 安装包,按照安装向导进行安装,在安装过程中需要输入许可证信息。
  • 安装 STM32 芯片支持包:打开 Keil MDK 5 软件,进入 Pack Installer 界面,搜索并下载安装 STM32F103 系列芯片的支持包,以确保软件能够正确识别和配置所使用的单片机。
  • 配置编译器:在工程设置中,选择 ARMCC 编译器作为默认编译器,该编译器能够生成高效的机器代码。
  • 配置调试器:根据所使用的调试工具(如 ST-Link V2),在工程设置的 Debug 选项中选择相应的调试器,并配置调试接口和通信速率等参数,以便能够正常进行程序的下载和在线调试。

4.2 主程序流程设计

主程序是系统的核心,负责统筹协调各个模块的工作,其工作流程如下:

系统上电后,首先进行初始化操作,包括 STM32 单片机的初始化(时钟、GPIO、USART、I2C、定时器等)、SU-03T 语音模块的初始化、步进电机驱动模块的初始化、DHT11 温湿度传感器的初始化、按键模块的初始化、显示模块的初始化以及系统参数的初始化(如默认喂食时间、喂食量、温湿度阈值等)。

初始化完成后,系统进入主循环。在主循环中,系统不断检测各模块的状态:

  • 检测 SU-03T 语音模块是否接收到语音指令,若接收到指令,则对指令进行解析并执行相应的操作(如喂食、调整食量等)。

  • 检测定时器是否到达设定的喂食时间,若到达,则控制步进电机按照设定的喂食量进行喂食。

  • 周期性地通过 DHT11 温湿度传感器采集环境温湿度数据,并在显示模块上显示,若温湿度超出设定阈值,则控制蜂鸣器报警。

  • 检测按键是否被按下,若有按键操作,则根据按键功能进行相应的处理(如修改喂食时间、手动喂食等)。

  • 实时更新显示模块的信息,包括当前时间、喂食状态、温湿度数据等。

  • 在执行各项操作的过程中,系统还会进行错误检测和处理,如传感器通信错误、电机驱动故障等,确保系统的稳定运行。

    4.3 语音识别程序设计

    SU-03T 语音模块的配置和控制通过串口通信实现。首先需要使用官方提供的配置工具对模块进行参数设置,包括设置唤醒词(如 "小喂")、指令集(如 "喂食" 对应指令 0x01、"停止喂食" 对应指令 0x02、"增加食量" 对应指令 0x03、"减少食量" 对应指令 0x04 等),并将模块的波特率设置为 9600,与 STM32 单片机的 USART 接口波特率保持一致,同时启用串口输出模式,使模块在识别到有效指令后自动发送相应的指令代码。

    在 STM32 单片机的程序中,语音识别程序通过 USART 中断服务函数接收 SU-03T 语音模块发送的指令数据。当模块识别到用户的语音指令后,会将对应的指令代码通过串口发送给单片机,单片机接收到数据后,将其存储在接收缓冲区中,并设置指令接收标志位。

    主程序检测到指令接收标志位后,对接收缓冲区中的指令代码进行解析。例如,当接收到指令 0x01 时,判断为 "喂食" 指令,主程序控制步进电机按照当前设定的喂食量进行喂食操作;当接收到指令 0x02 时,判断为 "停止喂食" 指令,主程序控制步进电机停止转动;当接收到指令 0x03 时,判断为 "增加食量" 指令,主程序适当增加设定的喂食量,并在显示模块上更新;当接收到指令 0x04 时,判断为 "减少食量" 指令,主程序适当减少设定的喂食量,并更新显示。