基于江科大STM32的桌宠小狗

接线图

在这里插入图片描述
在这里插入图片描述

PWM部分

PWM.c

#include "stm32f10x.h"                  // Device header

void PWM_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;//GPIO初始化
	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_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	TIM_InternalClockConfig(TIM2);//定时器2初始化
	
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInitStructure.TIM_Period = 2000-1;   //ARR
	TIM_TimeBaseInitStructure.TIM_Prescaler = 720-1;  //PSC
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
	TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);
	
	TIM_OCInitTypeDef TIM_OCInitTypeDefStructure1; 
	TIM_OCStructInit(&TIM_OCInitTypeDefStructure1);
	TIM_OCInitTypeDefStructure1.TIM_OCMode = TIM_OCMode_PWM1;
	TIM_OCInitTypeDefStructure1.TIM_OCPolarity = TIM_OCPolarity_High;
	TIM_OCInitTypeDefStructure1.TIM_OutputState = TIM_OutputState_Enable;
	TIM_OCInitTypeDefStructure1.TIM_Pulse = 0;  //CCR值
	TIM_OC1Init(TIM2,&TIM_OCInitTypeDefStructure1);	
	
	TIM_OCInitTypeDef TIM_OCInitTypeDefStructure2;
	TIM_OCStructInit(&TIM_OCInitTypeDefStructure2);
	TIM_OCInitTypeDefStructure2.TIM_OCMode = TIM_OCMode_PWM1;
	TIM_OCInitTypeDefStructure2.TIM_OCPolarity = TIM_OCPolarity_High;
	TIM_OCInitTypeDefStructure2.TIM_OutputState = TIM_OutputState_Enable;
	TIM_OCInitTypeDefStructure2.TIM_Pulse = 0;
	TIM_OC2Init(TIM2,&TIM_OCInitTypeDefStructure2);
	
	
	TIM_OCInitTypeDef TIM_OCInitTypeDefStructure3;
	TIM_OCStructInit(&TIM_OCInitTypeDefStructure3);
	TIM_OCInitTypeDefStructure3.TIM_OCMode = TIM_OCMode_PWM1;
	TIM_OCInitTypeDefStructure3.TIM_OCPolarity = TIM_OCPolarity_High;
	TIM_OCInitTypeDefStructure3.TIM_OutputState = TIM_OutputState_Enable;
	TIM_OCInitTypeDefStructure3.TIM_Pulse = 0;
	TIM_OC3Init(TIM2,&TIM_OCInitTypeDefStructure3);	
	
	
	TIM_OCInitTypeDef TIM_OCInitTypeDefStructure4;
	TIM_OCStructInit(&TIM_OCInitTypeDefStructure4);
	TIM_OCInitTypeDefStructure4.TIM_OCMode = TIM_OCMode_PWM1;
	TIM_OCInitTypeDefStructure4.TIM_OCPolarity = TIM_OCPolarity_High;
	TIM_OCInitTypeDefStructure4.TIM_OutputState = TIM_OutputState_Enable;
	TIM_OCInitTypeDefStructure4.TIM_Pulse = 0;
	TIM_OC4Init(TIM2,&TIM_OCInitTypeDefStructure4);		
	
	TIM_Cmd(TIM2,ENABLE); //开启定时器
}

void PWM_SetCompare1(uint16_t Compare)
{
	TIM_SetCompare1(TIM2, Compare);		//设置CCR1的值
}

void PWM_SetCompare2(uint16_t Compare)
{
	TIM_SetCompare2(TIM2, Compare);		//设置CCR2的值
}

void PWM_SetCompare3(uint16_t Compare)
{
	TIM_SetCompare3(TIM2, Compare);		//设置CCR3的值
}

void PWM_SetCompare4(uint16_t Compare)
{
	TIM_SetCompare4(TIM2, Compare);		//设置CCR4的值
}

可以参考江科大的:PWM驱动舵机

舵机角度的封装

void Servo_SetAngle1(float Angle)		
{
	PWM_SetCompare1(Angle / 180 * 2000 + 500);   
	
}

void Servo_SetAngle2(float Angle)		
{
	PWM_SetCompare2(Angle / 180 * 2000 + 500);   
	
}

void Servo_SetAngle3(float Angle)		
{
	PWM_SetCompare3(Angle / 180 * 2000 + 500);   
	
}

void Servo_SetAngle4(float Angle)		
{
	PWM_SetCompare4(Angle / 180 * 2000 + 500);   
	
}

写舵机运动状态

在这里插入图片描述

具体的步态可以观看【步态详解】人人都可制作的WiFi遥控迷你四足机器人
可以根据他的步态来进行运动,下面是我按照我自己的连线以及代码来实现的状态

前进

void servo_advance(void)//前进
{
	static uint8_t advanceFlag = 1;
	if (advanceFlag == 1)
	{
		Servo_SetAngle1(135);
		Servo_SetAngle2(90);
		Servo_SetAngle3(90);
		Servo_SetAngle4(45);	
		Delay_ms(speed);
		advanceFlag++;
	}
	else if(advanceFlag == 2)
	{
		Servo_SetAngle1(135);
		Servo_SetAngle2(45);
		Servo_SetAngle3(135);
		Servo_SetAngle4(45);	
		Delay_ms(speed);
		advanceFlag++;
	}
	else if(advanceFlag == 3)
	{
		Servo_SetAngle1(90);
		Servo_SetAngle2(45);
		Servo_SetAngle3(135);
		Servo_SetAngle4(90);	
		Delay_ms(speed);
		advanceFlag++;
	}
	else if(advanceFlag == 4)
	{
		Servo_SetAngle1(90);
		Servo_SetAngle2(90);
		Servo_SetAngle3(90);
		Servo_SetAngle4(90);	
		Delay_ms(speed);	
		advanceFlag++;
	}
	else if(advanceFlag == 5)
	{
		Servo_SetAngle1(90);
		Servo_SetAngle2(135);
		Servo_SetAngle3(45);
		Servo_SetAngle4(90);	
		Delay_ms(speed);
		advanceFlag++;
	}
	else if(advanceFlag == 6)
	{
		Servo_SetAngle1(45);
		Servo_SetAngle2(135);
		Servo_SetAngle3(45);
		Servo_SetAngle4(135);	
		Delay_ms(speed);
		advanceFlag++;
	}
	else if(advanceFlag == 7)
	{
		Servo_SetAngle1(45);
		Servo_SetAngle2(90);
		Servo_SetAngle3(90);
		Servo_SetAngle4(135);	
		Delay_ms(speed);
		advanceFlag++;
	}
	else if(advanceFlag == 8)
	{
		Servo_SetAngle1(90);
		Servo_SetAngle2(90);
		Servo_SetAngle3(90);
		Servo_SetAngle4(90);	
		Delay_ms(speed);
		advanceFlag = 1;
	}

}

后退

void servo_retreat(void)//后退
{
	static uint8_t retreatFlag = 1;
	if (retreatFlag == 1)
	{
		Servo_SetAngle1(45);
		Servo_SetAngle2(90);
		Servo_SetAngle3(90);
		Servo_SetAngle4(135);	
		Delay_ms(speed);
		retreatFlag++;
	}
	else if(retreatFlag == 2)
	{
		Servo_SetAngle1(45);
		Servo_SetAngle2(135);
		Servo_SetAngle3(45);
		Servo_SetAngle4(135);	
		Delay_ms(speed);
		retreatFlag++;
	}
	else if(retreatFlag == 3)
	{
		Servo_SetAngle1(90);
		Servo_SetAngle2(135);
		Servo_SetAngle3(45);
		Servo_SetAngle4(90);	
		Delay_ms(speed);
		retreatFlag++;
	}
	else if(retreatFlag == 4)
	{
		Servo_SetAngle1(90);
		Servo_SetAngle2(90);
		Servo_SetAngle3(90);
		Servo_SetAngle4(90);	
		Delay_ms(speed);	
		retreatFlag++;
	}
	else if(retreatFlag == 5)
	{
		Servo_SetAngle1(90);
		Servo_SetAngle2(45);
		Servo_SetAngle3(135);
		Servo_SetAngle4(90);	
		Delay_ms(speed);
		retreatFlag++;
	}
	else if(retreatFlag == 6)
	{
		Servo_SetAngle1(135);
		Servo_SetAngle2(45);
		Servo_SetAngle3(135);
		Servo_SetAngle4(45);	
		Delay_ms(speed);
		retreatFlag++;
	}
	else if(retreatFlag == 7)
	{
		Servo_SetAngle1(135);
		Servo_SetAngle2(90);
		Servo_SetAngle3(90);
		Servo_SetAngle4(45);	
		Delay_ms(speed);
		retreatFlag++;
	}
	else if(retreatFlag == 8)
	{
		Servo_SetAngle1(90);
		Servo_SetAngle2(90);
		Servo_SetAngle3(90);
		Servo_SetAngle4(90);	
		Delay_ms(speed);
		retreatFlag = 1;
	}

}

右转

void servo_trunright(void)//右转
{
	static uint8_t trunrightFlag = 1;
	if (trunrightFlag == 1)
	{
		Servo_SetAngle1(45);
		Servo_SetAngle2(90);
		Servo_SetAngle3(90);
		Servo_SetAngle4(45);	
		Delay_ms(speed);
		trunrightFlag++;
	}
	else if(trunrightFlag == 2)
	{
		Servo_SetAngle1(45);
		Servo_SetAngle2(135);
		Servo_SetAngle3(135);
		Servo_SetAngle4(45);	
		Delay_ms(speed);
		trunrightFlag++;
	}
	else if(trunrightFlag == 3)
	{
		Servo_SetAngle1(90);
		Servo_SetAngle2(135);
		Servo_SetAngle3(135);
		Servo_SetAngle4(90);	
		Delay_ms(speed);
		trunrightFlag++;
	}
	else if(trunrightFlag == 4)
	{
		Servo_SetAngle1(90);
		Servo_SetAngle2(90);
		Servo_SetAngle3(90);
		Servo_SetAngle4(90);	
		Delay_ms(speed);	
		trunrightFlag++;
		trunrightFlag = 1;
	}

}

左转

void servo_trunleft(void)//左转
{
	static uint8_t trunleftFlag = 1;
	if (trunleftFlag == 1)
	{
		Servo_SetAngle1(90);
		Servo_SetAngle2(135);
		Servo_SetAngle3(135);
		Servo_SetAngle4(90);	
		Delay_ms(speed);
		trunleftFlag++;
	}
	else if(trunleftFlag == 2)
	{
		Servo_SetAngle1(45);
		Servo_SetAngle2(135);
		Servo_SetAngle3(135);
		Servo_SetAngle4(45);	
		Delay_ms(speed);
		trunleftFlag++;
	}
	else if(trunleftFlag == 3)
	{
		Servo_SetAngle1(45);
		Servo_SetAngle2(90);
		Servo_SetAngle3(90);
		Servo_SetAngle4(45);	
		Delay_ms(speed);
		trunleftFlag++;
	}
	else if(trunleftFlag == 4)
	{
		Servo_SetAngle1(90);
		Servo_SetAngle2(90);
		Servo_SetAngle3(90);
		Servo_SetAngle4(90);	
		Delay_ms(speed);	
		trunleftFlag++;
		trunleftFlag = 1;
	}

}

跳舞

void servo_dance(void)//跳舞
{
	static uint8_t danceFlag = 1;
	if (danceFlag == 1)
	{
		Servo_SetAngle1(130);
		Servo_SetAngle2(130);
		Servo_SetAngle3(50);
		Servo_SetAngle4(50);
		Delay_ms(400);
		danceFlag++;
	}
	else if(danceFlag == 2)
	{
		Servo_SetAngle1(50);
		Servo_SetAngle2(50);
		Servo_SetAngle3(130);
		Servo_SetAngle4(130);
		Delay_ms(400);
		danceFlag = 1;
	}
}

USART

#include "stm32f10x.h"
#include <stdio.h>
#include <stdarg.h>

char Serial_RxPacket[100];
uint8_t Serial_RxFlag;

void Serial_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, 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);
	
	USART_InitTypeDef USART_InitStructure;
	USART_InitStructure.USART_BaudRate = 9600;
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
	USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
	USART_InitStructure.USART_Parity = USART_Parity_No;
	USART_InitStructure.USART_StopBits = USART_StopBits_1;
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;
	USART_Init(USART1, &USART_InitStructure);
	
	USART_ITConfig(USART1, 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);
	
	USART_Cmd(USART1, ENABLE);
}

void Serial_SendByte(uint8_t Byte)
{
	USART_SendData(USART1, Byte);
	while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
}

void Serial_SendArray(uint8_t *Array, uint16_t Length)
{
	uint16_t i;
	for (i = 0; i < Length; i ++)
	{
		Serial_SendByte(Array[i]);
	}
}

void Serial_SendString(char *String)
{
	uint8_t i;
	for (i = 0; String[i] != '\0'; i ++)
	{
		Serial_SendByte(String[i]);
	}
}

uint32_t Serial_Pow(uint32_t X, uint32_t Y)
{
	uint32_t Result = 1;
	while (Y --)
	{
		Result *= X;
	}
	return Result;
}

void Serial_SendNumber(uint32_t Number, uint8_t Length)
{
	uint8_t i;
	for (i = 0; i < Length; i ++)
	{
		Serial_SendByte(Number / Serial_Pow(10, Length - i - 1) % 10 + '0');
	}
}

int fputc(int ch, FILE *f)
{
	Serial_SendByte(ch);
	return ch;
}

void Serial_Printf(char *format, ...)
{
	char String[100];
	va_list arg;
	va_start(arg, format);
	vsprintf(String, format, arg);
	va_end(arg);
	Serial_SendString(String);
}

void USART1_IRQHandler(void)
{
	static uint8_t RxState = 0;
	static uint8_t pRxPacket = 0;
	if (USART_GetITStatus(USART1, USART_IT_RXNE) == SET)
	{
		uint8_t RxData = USART_ReceiveData(USART1);
		
		if (RxState == 0)
		{
			if (RxData == '@' && Serial_RxFlag == 0)
			{
				RxState = 1;
				pRxPacket = 0;
			}
		}
		else if (RxState == 1)
		{
			if (RxData == '\r')
			{
				RxState = 2;
			}
			else
			{
				Serial_RxPacket[pRxPacket] = RxData;
				pRxPacket ++;
			}
		}
		else if (RxState == 2)
		{
			if (RxData == '\n')
			{
				RxState = 0;
				Serial_RxPacket[pRxPacket] = '\0';
				Serial_RxFlag = 1;
			}
		}
		
		USART_ClearITPendingBit(USART1, USART_IT_RXNE);
	}
}

USART可以观看江科大的串口收发HEX数据包&串口收发文本数据包
(建议从9-3开始观看,有利于了解USART代码的各部分含义)

main.c

#include "stm32f10x.h"                 
#include "delay.h"
#include "Servo.h"
#include "PWM.h"
#include "control.h"
#include "UART.h"
#include <string.h>


float Angle;
uint8_t statu_falg=0;

int main (void)
{
	
	Servo_Init();
	Serial_Init();
	
	servo_up();
//	servo_down();

	while(1)
	{	

			if(Serial_RxFlag == 1)
		{
			if (strcmp(Serial_RxPacket, "advance") == 0)
			{

				statu_falg=1;
			}
			
			 if (strcmp(Serial_RxPacket,"fast") == 0)
			{
				statu_falg=2;
			}	
			
			 if (strcmp(Serial_RxPacket, "ret") == 0)
			{
				statu_falg=3;
			}
			

			 if (strcmp(Serial_RxPacket, "right") == 0)
			{
				statu_falg=4;
			}
			if (strcmp(Serial_RxPacket, "left") == 0)
			{
				statu_falg=5;
			}
			if (strcmp(Serial_RxPacket, "down") == 0)
			{
				statu_falg=6;
			}
			if (strcmp(Serial_RxPacket, "up") == 0)
			{
				statu_falg=7;
			}
			if (strcmp(Serial_RxPacket, "hard") == 0)
			{
				statu_falg=8;
			}
			if (strcmp(Serial_RxPacket, "dance") == 0)
			{
				statu_falg=9;
			}
			if (strcmp(Serial_RxPacket, "sit") == 0)
			{
				statu_falg=10;
			}
			if (strcmp(Serial_RxPacket, "sithard") == 0)
			{
				statu_falg=11;
			}
				
			Serial_RxFlag = 0;
		}
		switch(statu_falg)
		{
			case 1: servo_advance();break;
			case 2: servo_fastadvance();break;
			case 3: servo_retreat();break;
			case 4: servo_trunright();break;
			case 5: servo_trunleft();break;
			case 6: servo_down();break;
			case 7: servo_up();break;
			case 8: servo_hard();break;
			case 9: servo_dance();break;
			case 10: servo_sitdown();break;
			case 11: servo_sithard();break;

		}
		
	}

}


在开始我写代码的时候,没有配置单独的关于小狗行动的标志位,直接运行行为,导致蓝牙控制下的小狗不能在指令下连续运动,经过高人指点,定义一个标志位,将持续运动的用标志位取代,用switch函数查询标志位,执行程序。(我犯了同志们就能避开了)
在这里插入图片描述

连接蓝牙

我使用的蓝牙是JDY-3x,蓝牙APP是B站上一位up的开源【蓝牙调试器App开源】,使用什么蓝牙APP无所谓。
连接线路如下:
RX-----P9;
TX-----P10;
GND—GND;
VCC----3.3V;
在这里插入图片描述
手机蓝牙app:

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
配置好后就可以试试能不能用蓝牙控制小狗了。我的小狗属于有线款,不能脱离面包板,条件允许,同志们可以购买这份材料清单,来源于B站up:这个橙子好辣【【教程】如何做一个可爱的桌面机器小猫小狗】

材料清单

在这里插入图片描述
到这个地方,一个桌面宠物就算做好了。。。如果可以也能加入智能语音控制模块,对宠物进行语音控制,我尚在摸索当中,感谢。

### STM32结合AI小狗小智的开发方案 #### 1. 系统架构设计 为了实现STM32与AI技术(如小狗小智)的集成,可以采用分层模块化的设计方法。整个系统可分为硬件部分和软件部分。 - **硬件部分**:主要由STM32单片机为核心控制器,外接传感器、语音识别模块以及蓝牙通信模块组成[^1]。 - **软件部分**:通过固件编程实现数据采集、处理逻辑以及与云端AI服务的交互功能。 #### 2. 主要组件选型 以下是几个关键组件的选择建议: - **微控制器单元 (MCU)** 使用高性能版本的STM32系列芯片作为核心处理器,例如STM32F4或STM32H7,这些型号具备足够的计算能力和内存资源来运行复杂的算法。 - **语音识别模块** 集成专用的离线/在线语音识别模组,用于解析用户的命令并触发相应的动作响应。可以选择市场上成熟的解决方案,比如科大讯飞提供的SDK或者百度DuerOS平台接口。 - **无线通讯模块** 蓝牙模块负责短距离内的设备连接;Wi-Fi模块则允许访问互联网从而调用远程服务器上的深度学习模型来进行更高级别的图像分类或其他形式的人工智能运算。 #### 3. 功能实现细节 具体到“小狗小智”的应用场景下,可能涉及以下几个方面的功能开发: - **运动控制** 编写程序使机械结构能够模仿真实动物的动作行为模式,这通常涉及到步态规划算法的研究应用。 - **情感表达** 利用人脸表情合成技术和声音变化调节机制让虚拟角色展现出不同的情绪状态给用户带来更加生动有趣的互动体验效果。 - **环境感知能力增强** 安装多种类型的传感装置如温度湿度计、光线强度探测仪等收集周围物理参数信息反馈至中央控制系统以便做出及时调整适应当前状况下的最佳表现方式。 ```c // 示例代码片段展示如何初始化I2C总线以读取外部传感器的数据 void I2C_Init(void){ GPIO_InitTypeDef GPIO_InitStruct = {0}; __HAL_RCC_GPIOB_CLK_ENABLE(); HAL_NVIC_SetPriority(I2Cx_IRQn, 0, 0); HAL_NVIC_EnableIRQ(I2Cx_IRQn); /* Configure SCL pin as alternate function */ GPIO_InitStruct.Pin = GPIO_PIN_8; GPIO_InitStruct.Mode = GPIO_MODE_AF_OD; GPIO_InitStruct.Pull = GPIO_PULLUP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; GPIO_InitStruct.Alternate = GPIO_AF4_I2C1; HAL_GPIO_Init(GPIOB,&GPIO_InitStruct); /* Configure SDA pin as alternate function */ GPIO_InitStruct.Pin = GPIO_PIN_9; HAL_GPIO_Init(GPIOB,&GPIO_InitStruct); } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值