【stm32c8t6多路舵机PWM输出】

stm32c8t6多路舵机PWM输出

对于舵机的简单使用大家都不陌生,在实验中使用的SG90舵机最大转动角度为180度,而对舵机控制的原理是我们每一个使用者都应该了解的,具体的可以从下面这张角度和占空比的关系看看出来。(本次实验基于前一篇多路串口使用改写)通过串口中断接收数据来控制不同的舵机转动,对串口使用不太会的小伙伴前看前面一篇文章

多路串口使用

舵机转动原理:
舵机的控制一般需要一个20ms的时基脉冲,该脉冲的高电平部分一般为0.5ms~2.5ms范围内的角度控制脉冲部分。以180度角度舵机为例,那么对应的控制关系是这样的:

在这里插入图片描述

 可以发现一个规律:角度每次增加45度,高电平时间相应增加0.5ms

 总周期 - 高电平脉冲 = 低电平脉冲

 舵机角度的转动就是通过高、低脉冲的变化实现的
硬件接线引脚对应关系

在这里插入图片描述

在这里插入图片描述

了解完舵机的基本原理后,下面我们就进行pwm的配置。在stm32c8t6最小系统中使用pwm的时候我们需要进行定时器相应的重映射,每个定时器有四路PWM输出,大家可以根据自己情况配置不同的定时器进行多路PWM的输出,下面是重映射对应关系。

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

本次实验中使用的是定时器34个通道
TIM3_CH1---------------------->PB4
TIM3_CH2---------------------->PB3
TIM3_CH3---------------------->PB0
TIM3_CH4---------------------->PB1

自己在实验的时候搞了很久,配置没问题一开始就是不能控制多路Pwm,在配置的四路中有时候只有两路,甚至一路可以,然后就改成其他定时器重新进行映射,结果还是一样不能同时控制,折腾了很久时间,后面突然又可以了,就挺离谱的,代码一模一样的有时候一下就成功,有时候要好久才成功。
所以各位小伙伴不管做什么都一定要有耐心哦

实验源码

/*--------------------servo.h-------------------*/
#ifndef __SERVO_H
#define __SERVO_H

#include "stm32f10x.h"

#define SERVO_GPIO_PORT GPIOB
#define SERVO_GPIO_CLK  RCC_APB2Periph_GPIOB
#define SERVO_GPIO_PIN  (GPIO_Pin_5 |GPIO_Pin_0 |GPIO_Pin_1| GPIO_Pin_4)

void servo_init(void);
void Servo_Run2(uint16_t angle);
void Servo_Run(uint16_t angle);
void Servo_Run3(uint16_t angle);

void Servo_Run4(uint16_t angle);

#endif /* __SERVO_H */

/*-----------------------servo.c---------------------*/
#include "./servo/servo.h"
/**
 * 功能:舵机初始化函数
 * 参数:None
 * 返回值:None
 */
void servo_init(void)
{
    GPIO_InitTypeDef GPIO_Init_Structure;                  //定义GPIO初始化结构体
    TIM_TimeBaseInitTypeDef Timer_Init_Structure;          //定义定时器初始化结构体
    TIM_OCInitTypeDef Timer_OC_Init_Structure;             //定义定时器输出PWM结构体
    
    RCC_APB2PeriphClockCmd(SERVO_GPIO_CLK, ENABLE);        //开Timer3通道2GPIO时钟
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);   //开定时器3时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);   //开复用时钟
    
    GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE);   //选择部分重映射
    
    //配置GPIO初始化结构体
    GPIO_Init_Structure.GPIO_Mode  = GPIO_Mode_AF_PP;
    GPIO_Init_Structure.GPIO_Pin   = SERVO_GPIO_PIN;
    GPIO_Init_Structure.GPIO_Speed = GPIO_Speed_50MHz;
    
    GPIO_Init(SERVO_GPIO_PORT, &GPIO_Init_Structure);
    
    //配置通用定时器初始化结构体
    Timer_Init_Structure.TIM_ClockDivision = TIM_CKD_DIV1;        //设置分频系数,通常采用默认的分频
    Timer_Init_Structure.TIM_CounterMode = TIM_CounterMode_Up;    //设置捕获模式为向上计数(基本定时器仅有向上计数)
    Timer_Init_Structure.TIM_Period = 200-1;                      //设置重装载值(在预分频值为72000下,10000为一秒)
    Timer_Init_Structure.TIM_Prescaler = 7200-1;                  //设置初始化预分频值为7200
//    Timer_Init_Structure.TIM_RepetitionCounter = 0              //重复计数器,仅高级定时器需要设置
    
    TIM_TimeBaseInit(TIM3, &Timer_Init_Structure);
    
    //配置定时器输出PWM结构体
    Timer_OC_Init_Structure.TIM_OCMode = TIM_OCMode_PWM1;                 //定时器模式选择Timer脉冲宽度调制模式 1
    Timer_OC_Init_Structure.TIM_OutputState = TIM_OutputState_Enable;     //比较输出使能
    Timer_OC_Init_Structure.TIM_OCPolarity = TIM_OCPolarity_Low;          //选择有效输出为低电平
		
	TIM_OC1Init(TIM3, &Timer_OC_Init_Structure);  //PB4
    
    TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable);                     //使能预装载寄存器
    
    TIM_OC2Init(TIM3, &Timer_OC_Init_Structure); //PB5
    
    TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);                     //使能预装载寄存器
		
		
		 
    TIM_OC3Init(TIM3, &Timer_OC_Init_Structure); //PB0
    
    TIM_OC3PreloadConfig(TIM3, TIM_OCPreload_Enable);                     //使能预装载寄存器
		
		
	TIM_OC4Init(TIM3, &Timer_OC_Init_Structure); //PB1
    
    TIM_OC4PreloadConfig(TIM3, TIM_OCPreload_Enable);                     //使能预装载寄存器
    
    TIM_Cmd(TIM3, ENABLE);
}
/**
 * 功能:舵机驱动(可从0~180,每45度旋转一次)
 * 参数:angle  ;舵机旋转度数(相对角度)
 * 返回值:None
 */
void Servo_Run(uint16_t angle)
{
    switch(angle)
    {
		case 180 :TIM_SetCompare2(TIM3, 175); break;//对应180度
		case 135 :TIM_SetCompare2(TIM3, 180); break;//对应135度
		case 90  :TIM_SetCompare2(TIM3, 185); break;//对应90度
		case 45  :TIM_SetCompare2(TIM3, 190); break;//对应45度
		case 0   :TIM_SetCompare2(TIM3, 195); break;//对应0度
    }
}

void Servo_Run2(uint16_t angle)
{
    switch(angle)
    {
		case 180 :TIM_SetCompare3(TIM3, 175); break;//对应180度
		case 135 :TIM_SetCompare3(TIM3, 180); break;//对应135度
		case 90  :TIM_SetCompare3(TIM3, 185); break;//对应90度
		case 45  :TIM_SetCompare3(TIM3, 190); break;//对应45度
		case 0   :TIM_SetCompare3(TIM3, 195); break;//对应0度
    }
}


void Servo_Run3(uint16_t angle)
{
    switch(angle)
    {
		case 180 :TIM_SetCompare4(TIM3, 175); break;//对应180度
		case 135 :TIM_SetCompare4(TIM3, 180); break;//对应135度
		case 90  :TIM_SetCompare4(TIM3, 185); break;//对应90度
		case 45  :TIM_SetCompare4(TIM3, 190); break;//对应45度
		case 0   :TIM_SetCompare4(TIM3, 195); break;//对应0度
    }
}

void Servo_Run4(uint16_t angle)
{
    switch(angle)
    {
		case 180 :TIM_SetCompare1(TIM3, 175); break;//对应180度
		case 135 :TIM_SetCompare1(TIM3, 180); break;//对应135度
		case 90  :TIM_SetCompare1(TIM3, 185); break;//对应90度
		case 45  :TIM_SetCompare1(TIM3, 190); break;//对应45度
		case 0   :TIM_SetCompare1(TIM3, 195); break;//对应0度
    }
}

如果只有单路PWM输出(通道1TIM_OC1Init(TIM3, &Timer_OC_Init_Structure);  //PB4  
TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable);  //使能预装载寄存器
在上面初始化中写上述配置的任意一个都可以
一定要进行我们选择的通道要和pwm比较所对应
这里如果我们选择的通道1 则下面也选择1的比较
void TIM_SetCompare1(TIM_TypeDef* TIMx, uint16_t Compare1);

串口代码在前一篇已经分享了这里就不重复了

/*---------------------main.c---------------------*/
#include "stm32f10x.h"
#include "usart.h"
#include "servo.h"
#include "delay.h"
int main()
{
    	Init_Usart();
		servo_init();
		led_init();
		Servo_Run(45);
		Servo_Run2(45);
		Servo_Run3(45);
		Servo_Run4(45);
		printf("====================串口测试=====================\n");
		USART_Send_String(USART1,"usart1 test\n");
		//USART_Send_String(USART2,"usart1 test\n");	
		//USART_Send_String(USART3,"usart1 test\n");
    while(1)
    {
			
    }
}

//串口1中断
void USART1_IRQHandler(void)
{
	char temp;
	//USART_Send_String(USART1,"\nUsart1 interrupt test\n");	
	if(USART_GetITStatus(USART1,USART_IT_RXNE)!= RESET)
	{
		temp = USART_ReceiveData(USART1);
		if(temp == '1')
		{
			//GPIO_ResetBits(GPIOC,GPIO_Pin_13);
			USART_Send_String(USART1,"servo1 open\n");		
			Servo_Run(0);
			//delay_ms(500);
			USART_Send_String(USART1,"servo1 over\n");		
		}
		else if(temp == '2')
		{
			//GPIO_ResetBits(GPIOC,GPIO_Pin_13);
			USART_Send_String(USART1,"servo1 close\n");		
			Servo_Run(45);
			//delay_ms(500);
			USART_Send_String(USART1,"servo1 over\n");	
			printf("------------servo1-----------\n");
		}
	
		else if(temp == '3')
		{
			//GPIO_SetBits(GPIOC,GPIO_Pin_13);
			USART_Send_String(USART1,"servo2 open\n");
			Servo_Run2(0);
			//delay_ms(500);
			USART_Send_String(USART1,"servo2 over\n");		
			
		}
		
		else if(temp == '4')
		{
			//GPIO_SetBits(GPIOC,GPIO_Pin_13);
			USART_Send_String(USART1,"servo2 close\n");
			Servo_Run2(45);
			//delay_ms(500);
			USART_Send_String(USART1,"servo2 over\n");
			printf("------------servo2-----------\n");			
			
		}
		
		else if(temp == '5')
		{
			//GPIO_SetBits(GPIOC,GPIO_Pin_13);
			USART_Send_String(USART1,"servo3 open\n");
			Servo_Run3(0);
			//delay_ms(500);
			USART_Send_String(USART1,"servo3 over\n");		
			
		}
		
		else if(temp == '6')
		{
			//GPIO_SetBits(GPIOC,GPIO_Pin_13);
			USART_Send_String(USART1,"servo3 close\n");
			Servo_Run3(45);
			//delay_ms(500);
			USART_Send_String(USART1,"servo3 over\n");
			printf("------------servo3-----------\n");				
			
		}
		
		else if(temp == '7')
		{
			//GPIO_SetBits(GPIOC,GPIO_Pin_13);
			USART_Send_String(USART1,"servo4 open\n");
			Servo_Run4(0);
			//delay_ms(500);
			USART_Send_String(USART1,"servo4 over\n");		
			
		}
		
		else if(temp == '8')
		{
			//GPIO_SetBits(GPIOC,GPIO_Pin_13);
			USART_Send_String(USART1,"servo4 open\n");
			Servo_Run4(45);
			//delay_ms(500);
			USART_Send_String(USART1,"servo4 over\n");		
			printf("------------servo4-----------\n");	
			
		}
		USART_ClearITPendingBit(USART1,USART_IT_RXNE); //清除中断
	}
}

实验结果

在这里插入图片描述

注意点

上述串口中断接收时我最开始在每接收完数据了进行短暂延时在打印相关信息,不过在实验的现象是,只能接收一次就卡在了延时的上面,最后就把延时去掉了,大家可以看看,自己哪里有没有这种现象,有错还望大佬指正。

工程源码链接需要自取
链接:https://pan.baidu.com/s/1AMKLH_A98tMibWFsJsN7sQ 
提取码:52x6 
--来自百度网盘超级会员V4的分享

在这里插入图片描述

  • 7
    点赞
  • 89
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小殷学长

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值