基于江科大STM32的桌宠小狗

基于STM32C8T6的桌宠小狗

  • 接线图
  • PWM部分
  • 舵机角度的封装
  • 写舵机运动状态
  • 前进
  • 后退
  • 右转
  • 左转
  • 跳舞
  • USART
  • main.c
  • 连接蓝牙
  • 材料清单
  • 接线图


    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:这个橙子好辣【【教程】如何做一个可爱的桌面机器小猫小狗】

    材料清单


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

    作者:热爱学习的小c

    物联沃分享整理
    物联沃-IOTWORD物联网 » 基于江科大STM32的桌宠小狗

    发表回复