首页 > 分享 > STM32单片机智能桌面宠物

STM32单片机智能桌面宠物

项目简介

本项目是基于STM32单片机的智能小桌宠,具有简单的与人交互功能,支持语音与蓝牙同时控制。视频教程发布于哔哩哔哩,抖音平台。

STM32智能桌面宠物新电路板

项目资料位置:

 物料,代码,模型,PCB文件已在立创开源硬件平台进行了开源,各位可以直接去取。STM32智能桌面宠物 - 立创开源硬件平台,搭配我的哔哩哔哩的教程

哔哩哔哩出了一期详细的开源教程,也可以在我视频下方直接购买整理好的文件资料包,这样更容易上手制作,减少些繁琐的步骤。

项目图片

 当前最新:

 

 以往:

 

 

项目功能

一些简单的交流互动,立正,前进,后退,左转,右转,摇尾巴,趴下,蹲下,睡觉,向前跳,一般用于放置桌面上。语音可以自定义设置,需要到智能公元网站配置。

项目学习

单片机小狗的灵感来自于UP主有出息的男孩,让我明白了舵机也能这样玩。STM32单片机是跟着UP主江科大老师学习的OLED的使用看的是江科大老师的OLED教程,也可进行自定义设置表情嘉立创PCB画板跟着UP主Expert电子实验室学习的SOLIDWORKS软件是跟着阿奇老师学习的语音模块用的是机芯智能的su-03t1,可进行自定义设置唤醒词命令词

原理解析

一、硬件说明

详细请转至我的立创开源硬件平台:STM32智能桌面宠物 - 立创开源硬件平台

本项目使用的是嘉立创专业版绘制电路板,硬件比较简单,采用外部3.7V锂电池供电,通过5V充放电模块输出5V给电路板上的stm32最小开发板供电,因开发板自带稳压芯片可得3.3V给单片机供电。

二、代码说明

由于单片机知识我是跟着江科大老师学习的,所以代码采用的是标准库,也进行了模块封装。

主函数代码

主函数里的Action_Mode是全局变量,值是进串口中断更改的,主循环遍历这个值来切换动作模式

#include "stm32f10x.h"

#include "Delay.h"

#include "OLED.h"

#include "BlueTooth.h"

#include "Servo.h"

#include "PetAction.h"

#include "Face_Config.h"

#include "PWM.h"

uint16_t Time;

uint16_t HuXi;

uint16_t PanDuan=1;

uint16_t Wait=0;

int main(void)

{

Servo_Init();

OLED_Init();

BlueTooth_Init();

OLED_ShowImage(0,0,128,64,Face_sleep);

OLED_Update();

while(1)

{

if(Action_Mode==0){Action_relaxed_getdowm();WServo_Angle(90);}

else if(Action_Mode==1){Action_sit();}

else if(Action_Mode==2){Action_upright();}

else if(Action_Mode==3){Action_getdowm();}

else if(Action_Mode==4){Action_advance();}

else if(Action_Mode==5){Action_back();}

else if(Action_Mode==6){Action_Lrotation();}

else if(Action_Mode==7){Action_Rrotation();}

else if(Action_Mode==8){Action_Swing();}

else if(Action_Mode==9){Action_SwingTail();}

else if(Action_Mode==10){Action_JumpU();}

else if(Action_Mode==11){Action_JumpD();}

else if(Action_Mode==12){Action_upright2();}

else if(Action_Mode==13){Action_Hello();}

else if(Action_Mode==14){Action_stretch();}

else if(Action_Mode==15){Action_Lstretch();}

}

}

 定时中断(配置呼吸灯)

 因为TIM3的通道1给了尾巴舵机上,所以设置的ARR为20000,PSC=72,

根据计算得72000000/72/20000=50,1/50=0.02s,所以每20ms进一次中断,

因为ARR为20000,所以灯最亮时CCR需为20000,每次进中断,让CCR减100。

void TIM3_IRQHandler(void)

{

if(TIM_GetITStatus(TIM3,TIM_IT_Update)==SET)

{

if(AllLed==1 && BreatheLed==0)

{

PWM_LED1(20000);

PWM_LED2(20000);

}

else if(AllLed==1 && BreatheLed==1)

{

if(PanDuan==1)

{

HuXi+=100;

PWM_LED1(HuXi);

PWM_LED2(HuXi);

if(HuXi==20000)

PanDuan=2;

}

else if(PanDuan==2)

{

HuXi-=100;

PWM_LED1(HuXi);

PWM_LED2(HuXi);

if(HuXi==0)

{

PanDuan=3;

}

}

else if(PanDuan==3)

{

Wait+=1000;

if(Wait==20000)

{

PanDuan=1;

Wait=0;

}

}

}

else if(AllLed==0)

{

PWM_LED1(0);

PWM_LED2(0);

}

TIM_ClearITPendingBit(TIM3,TIM_IT_Update);

}

}

输出比较PWM模式

由于一个计时器只能开启4个输出比较模式,对应四条腿,但我们还需要一个尾巴,所以只能再开启一个定时器了

#include "stm32f10x.h"

void PWM_Init(void)

{

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);

GPIO_InitTypeDef GPIO_InitStructure;

GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;

GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_6;

GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;

GPIO_Init(GPIOA,&GPIO_InitStructure);

GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;

GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0|GPIO_Pin_1;

GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;

GPIO_Init(GPIOB,&GPIO_InitStructure);

TIM_InternalClockConfig(TIM2);

TIM_InternalClockConfig(TIM3);

TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;

TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;

TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;

TIM_TimeBaseInitStructure.TIM_Period=20000-1;

TIM_TimeBaseInitStructure.TIM_Prescaler=72-1;

TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0;

TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);

TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStructure);

NVIC_InitTypeDef NVIC_InitStructure;

NVIC_InitStructure.NVIC_IRQChannel=TIM3_IRQn;

NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;

NVIC_InitStructure.NVIC_IRQChannelSubPriority=0;

NVIC_Init(&NVIC_InitStructure);

TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE);

TIM_OCInitTypeDef TIM_OCInitStructure;

TIM_OCStructInit(&TIM_OCInitStructure);

TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;

TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High;

TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;

TIM_OCInitStructure.TIM_Pulse=0;

TIM_OC1Init(TIM2,&TIM_OCInitStructure);

TIM_OC2Init(TIM2,&TIM_OCInitStructure);

TIM_OC3Init(TIM2,&TIM_OCInitStructure);

TIM_OC4Init(TIM2,&TIM_OCInitStructure);

TIM_OC1Init(TIM3,&TIM_OCInitStructure);

TIM_OC3Init(TIM3,&TIM_OCInitStructure);

TIM_OC4Init(TIM3,&TIM_OCInitStructure);

TIM_Cmd(TIM2,ENABLE);

TIM_Cmd(TIM3,ENABLE);

}

void PWM_SetCompare1(uint16_t Compare)

{

TIM_SetCompare1(TIM2, Compare);

}

void PWM_SetCompare2(uint16_t Compare)

{

TIM_SetCompare2(TIM2, Compare);

}

void PWM_SetCompare3(uint16_t Compare)

{

TIM_SetCompare3(TIM2, Compare);

}

void PWM_SetCompare4(uint16_t Compare)

{

TIM_SetCompare4(TIM2, Compare);

}

void PWM_WSetCompare(uint16_t Compare)

{

TIM_SetCompare1(TIM3, Compare);

}

void PWM_LED1(uint16_t Compare)

{

TIM_SetCompare3(TIM3,Compare);

}

void PWM_LED2(uint16_t Compare)

{

TIM_SetCompare4(TIM3,Compare);

}

头文件

#ifndef __PWM_H

#define __PWM_H

void PWM_Init(void);

void PWM_SetCompare1(uint16_t Compare);

void PWM_SetCompare2(uint16_t Compare);

void PWM_SetCompare3(uint16_t Compare);

void PWM_SetCompare4(uint16_t Compare);

void PWM_WSetCompare(uint16_t Compare);

void PWM_LED1(uint16_t Compare);

void PWM_LED2(uint16_t Compare);

#endif

舵机设置

为了统一角度,比如设置0度,那么所有舵机执行的方向朝向一致。所以舵机2和舵机4的Angle取补角

#include "stm32f10x.h"

#include "PWM.h"

void Servo_Init()

{

PWM_Init();

}

void Servo_Angle1(float Angle)

{

PWM_SetCompare1(Angle / 180 * 2000 + 500);

}

void Servo_Angle2(float Angle)

{

PWM_SetCompare2((180-Angle) / 180 * 2000 + 500);

}

void Servo_Angle3(float Angle)

{

PWM_SetCompare3(Angle / 180 * 2000 + 500);

}

void Servo_Angle4(float Angle)

{

PWM_SetCompare4((180-Angle) / 180 * 2000 + 500);

}

void WServo_Angle(float Angle)

{

PWM_WSetCompare(Angle / 180 * 2000 + 500);

}

头文件

#ifndef __SERVO_H

#define __SERVO_H

void Servo_Init(void);

void Servo_Angle1(float Angle);

void Servo_Angle2(float Angle);

void Servo_Angle3(float Angle);

void Servo_Angle4(float Angle);

void WServo_Angle(float Angle);

#endif

动作代码

【1】舵机的前进、后退、左转、右转比较难,这里我是参考了bilibili上的up主石桥北关于舵机步态的视频。

【2】代码里每一个动作中都带有一些延迟,目的是为了动作连贯性与供电稳定性而考虑到的,毕竟我们采用的是1000ma的锂电池接5V充放电模块,不只是给舵机供电,还要给蓝牙和语音模块供电。所以动作中只有两个舵机会同时供电(摇摆动作除外),这样能保障蓝牙与语音不会因瞬时电流减少而中断连接。

【3】25年2月16日进行了代码修改,将所有的连续动作添加了次数变量,将连续动作改为了半连续动作,目的就是减轻因舵机持续运动而导致语音模块供电不稳从而无法接收命令这个情况,蓝牙控制和原先一样,按住就是连续运动。

#include "stm32f10x.h"

#include "Servo.h"

#include "Delay.h"

#include "BlueTooth.h"

#define Chongfunumber 2

#define SwingRepeatnumber 3

#define HelloRepeatnumber 4

uint16_t PAnumbers=Chongfunumber;

uint16_t TiaoTurn=0;

uint16_t TiaoTurn2=0;

void Action_relaxed_getdowm(void)

{

Servo_Angle1(20);

Servo_Angle2(20);

Delay_ms(80);

Servo_Angle3(160);

Servo_Angle4(160);

}

void Action_upright(void)

{

Servo_Angle1(90);

Servo_Angle2(90);

Delay_ms(80);

Servo_Angle3(90);

Servo_Angle4(90);

if(WeiBa==1)

{

Action_Mode=9;

}

}

void Action_upright2(void)

{

Servo_Angle3(90);

Servo_Angle4(90);

Delay_ms(80);

Servo_Angle1(90);

Servo_Angle2(90);

if(WeiBa==1)

{

Action_Mode=9;

}

}

void Action_getdowm(void)

{

Servo_Angle1(20);

Servo_Angle2(20);

Delay_ms(80);

Servo_Angle3(20);

Servo_Angle4(20);

if(WeiBa==1)

{

Action_Mode=9;

}

}

void Action_sit(void)

{

Servo_Angle1(90);

Servo_Angle2(90);

Delay_ms(80);

Servo_Angle3(20);

Servo_Angle4(20);

if(WeiBa==1)

{

Action_Mode=9;

}

}

void Action_advance(void)

{

while(Action_Mode==4)

{

PAnumbers=Chongfunumber;

while((PAnumbers || Sustainedmove)&& Action_Mode==4)

{

Servo_Angle2(45);

Servo_Angle3(45);

Delay_ms(SpeedDelay);

if(Action_Mode!=4)break;

Servo_Angle1(135);

Servo_Angle4(135);

Delay_ms(SpeedDelay);

if(Action_Mode!=4)break;

Servo_Angle2(90);

Servo_Angle3(90);

Delay_ms(SpeedDelay);

if(Action_Mode!=4)break;

Servo_Angle1(90);

Servo_Angle4(90);

Delay_ms(SpeedDelay);

if(Action_Mode!=4)break;

Servo_Angle1(45);

Servo_Angle4(45);

Delay_ms(SpeedDelay);

if(Action_Mode!=4)break;

Servo_Angle2(135);

Servo_Angle3(135);

Delay_ms(SpeedDelay);

if(Action_Mode!=4)break;

Servo_Angle1(90);

Servo_Angle4(90);

Delay_ms(SpeedDelay);

if(Action_Mode!=4)break;

Servo_Angle2(90);

Servo_Angle3(90);

Delay_ms(SpeedDelay);

if(Action_Mode!=4)break;

PAnumbers--;

}

if(Sustainedmove!=1 && Action_Mode==4)

Action_Mode=2;

}

}

void Action_back(void)

{

while(Action_Mode==5)

{

PAnumbers=Chongfunumber;

while((PAnumbers || Sustainedmove) && Action_Mode==5 )

{

Servo_Angle2(135);

Servo_Angle3(135);

Delay_ms(SpeedDelay);

if(Action_Mode!=5)break;

Servo_Angle1(45);

Servo_Angle4(45);

Delay_ms(SpeedDelay);

if(Action_Mode!=5)break;

Servo_Angle2(90);

Servo_Angle3(90);

Delay_ms(SpeedDelay);

if(Action_Mode!=5)break;

Servo_Angle1(90);

Servo_Angle4(90);

Delay_ms(SpeedDelay);

if(Action_Mode!=5)break;

Servo_Angle1(135);

Servo_Angle4(135);

Delay_ms(SpeedDelay);

if(Action_Mode!=5)break;

Servo_Angle2(45);

Servo_Angle3(45);

Delay_ms(SpeedDelay);

if(Action_Mode!=5)break;

Servo_Angle1(90);

Servo_Angle4(90);

Delay_ms(SpeedDelay);

if(Action_Mode!=5)break;

Servo_Angle2(90);

Servo_Angle3(90);

Delay_ms(SpeedDelay);

if(Action_Mode!=5)break;

PAnumbers--;

}

if(Sustainedmove!=1 && Action_Mode==5)

Action_Mode=2;

}

}

void Action_Lrotation(void)

{

while(Action_Mode==6)

{

PAnumbers=Chongfunumber;

PAnumbers=PAnumbers+Chongfunumber;

while((PAnumbers || Sustainedmove) && Action_Mode==6)

{

Servo_Angle2(45);

Servo_Angle3(135);

Delay_ms(SpeedDelay);

if(Action_Mode!=6)break;

Servo_Angle1(45);

Servo_Angle4(135);

Delay_ms(SpeedDelay);

if(Action_Mode!=6)break;

Servo_Angle2(90);

Servo_Angle3(90);

Delay_ms(SpeedDelay);

if(Action_Mode!=6)break;

Servo_Angle1(90);

Servo_Angle4(90);

Delay_ms(SpeedDelay);

if(Action_Mode!=6)break;

PAnumbers--;

}

if(Sustainedmove!=1 && Action_Mode==6)

Action_Mode=2;

}

}

void Action_Rrotation(void)

{

while(Action_Mode==7)

{

PAnumbers=Chongfunumber;

PAnumbers=PAnumbers+Chongfunumber;

while((PAnumbers || Sustainedmove) && Action_Mode==7)

{

Servo_Angle1(45);

Servo_Angle4(135);

Delay_ms(SpeedDelay);

if(Action_Mode!=7)break;

Servo_Angle2(45);

Servo_Angle3(135);

Delay_ms(SpeedDelay);

if(Action_Mode!=7)break;

Servo_Angle1(90);

Servo_Angle4(90);

Delay_ms(SpeedDelay);

if(Action_Mode!=7)break;

Servo_Angle2(90);

Servo_Angle3(90);

Delay_ms(SpeedDelay);

if(Action_Mode!=7)break;

PAnumbers--;

}

if(Sustainedmove!=1 && Action_Mode==7)

Action_Mode=2;

}

}

void Action_Swing(void)

{

uint16_t SwingNumber=SwingRepeatnumber;

while(SwingNumber && Action_Mode==8)

{

for(uint8_t i=30;i<150;i++)

{

Servo_Angle1(i);

Servo_Angle2(i);

Servo_Angle3(i);

Servo_Angle4(i);

Delay_ms(SwingDelay);

if(Action_Mode!=8)break;

}

if(Action_Mode!=8)break;

for(uint8_t i=150;i>30;i--)

{

Servo_Angle1(i);

Servo_Angle2(i);

Servo_Angle3(i);

Servo_Angle4(i);

Delay_ms(SwingDelay);

if(Action_Mode!=8)break;

}

if(Action_Mode!=8)break;

SwingNumber--;

}

for(uint8_t i=30;i<90;i++)

{

Servo_Angle1(i);

Servo_Angle2(i);

Servo_Angle3(i);

Servo_Angle4(i);

Delay_ms(SwingDelay);

if(Action_Mode!=8)break;

}

if(Action_Mode==8)

Action_Mode=2;

}

void Action_SwingTail(void)

{

uint16_t SwingTailNumber=3;

Delay_ms(60);

while(SwingTailNumber && Action_Mode==9)

{

for(uint8_t i=30;i<150;i++)

{

WServo_Angle(i);

Delay_ms(SwingDelay);

if(Action_Mode!=9)break;

}

if(Action_Mode!=9)break;

for(uint8_t i=150;i>30;i--)

{

WServo_Angle(i);

Delay_ms(SwingDelay);

if(Action_Mode!=9)break;

}

if(Action_Mode!=9)break;

SwingTailNumber--;

}

Delay_ms(60);

}

void Action_JumpU(void)

{

if(TiaoTurn==0)

{

Servo_Angle1(140);

Servo_Angle4(35);

Delay_ms(SpeedDelay);

Servo_Angle2(140);

Servo_Angle3(35);

Delay_ms(SpeedDelay+80);

Action_Mode=2;

TiaoTurn=1;

}

else

{

Servo_Angle2(140);

Servo_Angle3(35);

Delay_ms(SpeedDelay);

Servo_Angle1(140);

Servo_Angle4(35);

Delay_ms(SpeedDelay+80);

Action_Mode=2;

TiaoTurn=0;

}

}

void Action_JumpD(void)

{

if(TiaoTurn2==0){

Servo_Angle4(35);

Servo_Angle1(140);

Delay_ms(SpeedDelay);

Servo_Angle3(35);

Servo_Angle2(140);

Delay_ms(SpeedDelay);

Action_Mode=12;

TiaoTurn2=1;

}

else

{

Servo_Angle3(35);

Servo_Angle2(140);

Delay_ms(SpeedDelay);

Servo_Angle4(35);

Servo_Angle1(140);

Delay_ms(SpeedDelay);

Action_Mode=12;

TiaoTurn2=0;

}

}

void Action_Hello(void)

{

uint16_t HelloNumber=HelloRepeatnumber;

Servo_Angle3(20);

Servo_Angle4(45);

Delay_ms(80);

Servo_Angle1(90);

while(HelloNumber && Action_Mode==13)

{

if(Action_Mode!=13)break;

for(int i=0;i<=45;i++)

{

if(Action_Mode!=13)break;

Servo_Angle2(i);

Delay_ms(SwingDelay);

}

for(int i=45;i>0;i--)

{

if(Action_Mode!=13)break;

Servo_Angle2(i);

Delay_ms(SwingDelay);

}

if(Action_Mode!=13)break;

HelloNumber--;

}

if(Action_Mode==13)

Action_Mode=2;

}

void Action_stretch(void)

{

Servo_Angle3(90);

Servo_Angle4(90);

Delay_ms(80);

for(int i=90;i>10;i--)

{

Servo_Angle1(i);

Servo_Angle2(i);

if(Action_Mode!=14)break;

Delay_ms(15);

}

for(int i=10;i<90;i++)

{

Servo_Angle1(i);

Servo_Angle2(i);

if(Action_Mode!=14)break;

Delay_ms(15);

}

for(int i=90;i<170;i++)

{

Servo_Angle3(i);

Servo_Angle4(i);

if(Action_Mode!=14)break;

Delay_ms(15);

}

for(int i=170;i>90;i--)

{

Servo_Angle3(i);

Servo_Angle4(i);

if(Action_Mode!=14)break;

Delay_ms(15);

}

if(Action_Mode==14)

Action_Mode=15;

}

void Action_Lstretch(void)

{

int breakvalue=1;

int temp=3;

while(breakvalue)

{

Servo_Angle1(90);

Servo_Angle2(20);

Delay_ms(60);

Servo_Angle4(110);

for(int i=90;i<180;i++)

{

if(Action_Mode!=15)break;

Servo_Angle3(i);

Delay_ms(6);

}

while(temp && Action_Mode==15)

{

for(int i=180;i>150;i--)

{

if(Action_Mode!=15)break;

Servo_Angle3(i);

Delay_ms(15);

}

temp--;

}

if(Action_Mode!=15)break;

Delay_ms(100);

Servo_Angle1(90);

Servo_Angle2(90);

if(Action_Mode!=15)break;

Delay_ms(80);

Servo_Angle3(90);

Servo_Angle4(90);

Delay_ms(100);

if(Action_Mode!=15)break;

temp=3;

Servo_Angle2(90);

Servo_Angle1(20);

if(Action_Mode!=15)break;

Delay_ms(60);

Servo_Angle3(110);

for(int i=90;i<180;i++)

{

if(Action_Mode!=15)break;

Servo_Angle4(i);

Delay_ms(6);

}

while(temp && Action_Mode==15)

{

for(int i=180;i>150;i--)

{

if(Action_Mode!=15)break;

Servo_Angle4(i);

Delay_ms(15);

}

temp--;

}

if(Action_Mode==15)

Action_Mode=2;

breakvalue=0;

}

}

头文件

#ifndef __PET_ACTION_

#define __PET_ACTION

void Action_relaxed_getdowm(void);

void Action_upright(void);

void Action_getdowm(void);

void Action_sit(void);

void Action_Swing(void);

void Action_advance(void);

void Action_back(void);

void Action_Lrotation(void);

void Action_Rrotation(void);

void Action_SwingTail(void);

void Action_JumpD(void);

void Action_JumpU(void);

void Action_upright2(void);

void Action_Hello(void);

void Action_stretch(void);

void Action_Lstretch(void);

#endif

蓝牙与语音连接配置

USART1配置语音模块的串口,因为我用的语音模块是机芯智能商家的su-03t1模块,只能通过USART1串口通道

USART3配置蓝牙模块的串口(USART2被定时器2占用了)

中断函数中,是改变Action_Mode的值与Face_Mode的值,并进入Face_Config()函数来更改表情。主循环遍历根据Action_Mode的值来改变动作。

#include "stm32f10x.h"

#include "PWM.h"

#include "PetAction.h"

#include "Face_Config.h"

uint16_t AllLed=1;

uint16_t BreatheLed=0;

uint16_t Sustainedmove=0;

uint16_t Action_Mode=0;

uint16_t SpeedDelay=200;

uint16_t SwingDelay=6;

uint16_t Face_Mode=0;

uint8_t WeiBa=0;

void BlueTooth_Init(void)

{

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);

RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);

RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3,ENABLE);

GPIO_InitTypeDef GPIO_InitStructure;

GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;

GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9;

GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;

GPIO_Init(GPIOA,&GPIO_InitStructure);

GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;

GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10;

GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;

GPIO_Init(GPIOA,&GPIO_InitStructure);

GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;

GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10;

GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;

GPIO_Init(GPIOB,&GPIO_InitStructure);

GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;

GPIO_InitStructure.GPIO_Pin=GPIO_Pin_11;

GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;

GPIO_Init(GPIOB,&GPIO_InitStructure);

USART_InitTypeDef UASRT_InitStructure;

UASRT_InitStructure.USART_BaudRate=9600;

UASRT_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None;

UASRT_InitStructure.USART_Mode=USART_Mode_Rx|USART_Mode_Tx;

UASRT_InitStructure.USART_Parity=USART_Parity_No;

UASRT_InitStructure.USART_StopBits=USART_StopBits_1;

UASRT_InitStructure.USART_WordLength=USART_WordLength_8b;

USART_Init(USART1,&UASRT_InitStructure);

USART_Init(USART3,&UASRT_InitStructure);

USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);

USART_ITConfig(USART3,USART_IT_RXNE,ENABLE);

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);

NVIC_InitTypeDef NVIC_InitStructure;

NVIC_InitStructure.NVIC_IRQChannel=USART1_IRQn;

NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;

NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;

NVIC_Init(&NVIC_InitStructure);

NVIC_InitStructure.NVIC_IRQChannel=USART3_IRQn;

NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;

NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;

NVIC_Init(&NVIC_InitStructure);

USART_Cmd(USART1,ENABLE);

USART_Cmd(USART3,ENABLE);

}

void USART1_IRQHandler(void)

{

if(USART_GetITStatus(USART1,USART_IT_RXNE)==SET)

{

Sustainedmove=0;

if(USART_ReceiveData(USART1)==0x29)

{

Face_Mode=0;

Face_Config();

Action_Mode=0;

}

else if(USART_ReceiveData(USART1)==0x30)

{

Face_Mode=1;

Face_Config();

Action_Mode=1;

}

else if(USART_ReceiveData(USART1)==0x31)

{

Face_Mode=5;

Face_Config();

Action_Mode=2;

}

else if(USART_ReceiveData(USART1)==0x32)

{

Face_Mode=1;

Face_Config();

Action_Mode=3;

}

else if(USART_ReceiveData(USART1)==0x33)

{

Face_Mode=2;

Face_Config();

Action_Mode=4;

}

else if(USART_ReceiveData(USART1)==0x34)

{

Face_Mode=2;

Face_Config();

Action_Mode=5;

}

else if(USART_ReceiveData(USART1)==0x35)

{

Face_Mode=2;

Face_Config();

Action_Mode=6;

}

else if(USART_ReceiveData(USART1)==0x36)

{

Face_Mode=2;

Face_Config();

Action_Mode=7;

}

else if(USART_ReceiveData(USART1)==0x37)

{

Face_Mode=4;

Face_Config();

Action_Mode=8;

}

else if(USART_ReceiveData(USART1)==0x38)

{

if(SpeedDelay==120){Face_Mode=3;Face_Config();}

if(SpeedDelay>100)

SpeedDelay-=20;

else

{

Face_Mode=2;

Face_Config();

SpeedDelay=200;

}

}

else if(USART_ReceiveData(USART1)==0x39)

{

if(SwingDelay==4){Face_Mode=3;Face_Config();}

if(SwingDelay>3)

SwingDelay--;

else

{

Face_Mode=4;

Face_Config();

SwingDelay=9;

}

}

else if(USART_ReceiveData(USART1)==0x40)

{

(WeiBa==0)?(WeiBa=1):(WeiBa=0);

Face_Mode=1;

Face_Config();

Action_Mode=9;

}

else if(USART_ReceiveData(USART1)==0x41)

{

Face_Mode=2;

Face_Config();

Action_Mode=10;

}

else if(USART_ReceiveData(USART1)==0x42)

{

Face_Mode=2;

Face_Config();

Action_Mode=11;

}

else if(USART_ReceiveData(USART1)==0x43)

{

Face_Mode=6;

Face_Config();

Action_Mode=13;

}

else if(USART_ReceiveData(USART1)==0x44)

{

AllLed=1;

}

else if(USART_ReceiveData(USART1)==0x45)

{

AllLed=0;

}

else if(USART_ReceiveData(USART1)==0x46)

{

BreatheLed=1;

}

else if(USART_ReceiveData(USART1)==0x47)

{

BreatheLed=0;

}

else if(USART_ReceiveData(USART1)==0x48)

{

Face_Mode=6;

Face_Config();

Action_Mode=14;

}

else if(USART_ReceiveData(USART1)==0x49)

{

Face_Mode=6;

Face_Config();

Action_Mode=15;

}

USART_ClearITPendingBit(USART1,USART_IT_RXNE);

}

}

void USART3_IRQHandler(void)

{

if(USART_GetITStatus(USART3,USART_IT_RXNE)==SET)

{

Sustainedmove=1;

if(USART_ReceiveData(USART3)==0x29)

{

Face_Mode=0;

Face_Config();

Action_Mode=0;

}

else if(USART_ReceiveData(USART3)==0x30)

{

Face_Mode=1;

Face_Config();

Action_Mode=1;

}

else if(USART_ReceiveData(USART3)==0x31)

{

Face_Mode=5;

Face_Config();

Action_Mode=2;

}

else if(USART_ReceiveData(USART3)==0x32)

{

Face_Mode=1;

Face_Config();

Action_Mode=3;

}

else if(USART_ReceiveData(USART3)==0x33)

{

Face_Mode=2;

Face_Config();

Action_Mode=4;

}

else if(USART_ReceiveData(USART3)==0x34)

{

Face_Mode=2;

Face_Config();

Action_Mode=5;

}

else if(USART_ReceiveData(USART3)==0x35)

{

Face_Mode=2;

Face_Config();

Action_Mode=6;

}

else if(USART_ReceiveData(USART3)==0x36)

{

Face_Mode=2;

Face_Config();

Action_Mode=7;

}

else if(USART_ReceiveData(USART3)==0x37)

{

Face_Mode=4;

Face_Config();

Action_Mode=8;

}

else if(USART_ReceiveData(USART3)==0x38)

{

if(SpeedDelay==120){Face_Mode=3;Face_Config();}

if(SpeedDelay>100)

SpeedDelay-=20;

else

{

Face_Mode=2;

Face_Config();

SpeedDelay=200;

}

}

else if(USART_ReceiveData(USART3)==0x39)

{

if(SwingDelay==4){Face_Mode=3;Face_Config();}

if(SwingDelay>3)

SwingDelay--;

else

{

Face_Mode=4;

Face_Config();

SwingDelay=9;

}

}

else if(USART_ReceiveData(USART3)==0x40)

{

(WeiBa==0)?(WeiBa=1):(WeiBa=0);

Face_Mode=1;

Face_Config();

Action_Mode=9;

}

else if(USART_ReceiveData(USART3)==0x41)

{

Face_Mode=2;

Face_Config();

Action_Mode=10;

}

else if(USART_ReceiveData(USART3)==0x42)

{

Face_Mode=2;

Face_Config();

Action_Mode=11;

}

else if(USART_ReceiveData(USART3)==0x43)

{

Face_Mode=6;

Face_Config();

Action_Mode=13;

}

else if(USART_ReceiveData(USART3)==0x44)

{

AllLed=1;

}

else if(USART_ReceiveData(USART3)==0x45)

{

AllLed=0;

}

else if(USART_ReceiveData(USART3)==0x46)

{

BreatheLed=1;

}

else if(USART_ReceiveData(USART3)==0x47)

{

BreatheLed=0;

}

else if(USART_ReceiveData(USART3)==0x48)

{

Face_Mode=6;

Face_Config();

Action_Mode=14;

}

else if(USART_ReceiveData(USART3)==0x49)

{

Face_Mode=6;

Face_Config();

Action_Mode=15;

}

USART_ClearITPendingBit(USART3,USART_IT_RXNE);

}

}

 头文件

#ifndef __BLUE_TOOTH_H

#define __BLUE_TOOTH_H

extern uint16_t Action_Mode;

extern uint16_t Face_Mode;

extern uint16_t SpeedDelay;

extern uint16_t SwingDelay;

extern uint8_t WeiBa;

extern uint16_t AllLed;

extern uint16_t BreatheLed;

extern uint16_t Sustainedmove;

void BlueTooth_Init(void);

#endif

表情代码函数

OLED模块代码是用的江协老师的,OLED显示图片教程也是跟着这个老师学的,表情的图片是从网上找的。

#include "stm32f10x.h"

#include "OLED.h"

#include "BlueTooth.h"

void Face_Config(void)

{

if(Face_Mode==0)

{

OLED_Clear();

OLED_ShowImage(0,0,128,64,Face_sleep);

OLED_Update();

}

else if(Face_Mode==1)

{

OLED_Clear();

OLED_ShowImage(0,0,128,64,Face_stare);

OLED_Update();

}

else if(Face_Mode==2)

{

OLED_Clear();

OLED_ShowImage(0,0,128,64,Face_happy);

OLED_Update();

}

else if(Face_Mode==3)

{

OLED_Clear();

OLED_ShowImage(0,0,128,64,Face_mania);

OLED_Update();

}

else if(Face_Mode==4)

{

OLED_Clear();

OLED_ShowImage(0,0,128,64,Face_very_happy);

OLED_Update();

}

else if(Face_Mode==5)

{

OLED_Clear();

OLED_ShowImage(0,0,128,64,Face_eyes);

OLED_Update();

}

else if(Face_Mode==6)

{

OLED_Clear();

OLED_ShowImage(0,0,128,64,Face_hello);

OLED_Update();

}

}

头文件

#ifndef __FACE_CONFIG_H

#define __FACE_CONFIG_H

void Face_Config(void);

#endif

三、小狗模型

请去我立创开源硬件平台下方获取STM32智能桌面宠物 - 立创开源硬件平台

结束语

本开源项目整体并不难,其中涉及到的模块较少,五个舵机,一个OLED显示屏,蓝牙模块,语音模块。

同学们如果对哪个部分有所不懂的话可以在评论区询问,我有时间的话就回复。

相关知识

基于STM32单片机的宠物智能项圈设计
STM32单片机智能桌面宠物
STM32单片机做智能宠物狗项目
基于STM32单片机智能宠物穿戴设备设计.doc
基于STM32单片机的智能鱼缸设计
[DIY]用STM32实现桌面宠物功能#开源
基于STM32单片机的智能鱼缸控制系统设计
基于STM32单片机的智能宠物屋的设计与实现
一种基于STM32单片机的智能鱼缸控制系统设计
基于stm32智能图像宠物投喂喂养物联网单片机软硬件设计毕业生系统

网址: STM32单片机智能桌面宠物 https://m.mcbbbk.com/newsview1132402.html

所属分类:萌宠日常
上一篇: 介绍动物小狗
下一篇: 小型宠物狗品种有哪些 常见小型宠