实操之STM32 F103C8T6 控制舵机TS90A/SG90(PWM驱动)

一、TS90A/SG90三个引脚

信号线接单片机IO引脚,用来接收单片机发送的PWM。
注意:由于舵机需要较大电压/电流(直接用单片机供电无法正常工作),一般采用外接电源,也可以用micro usb给单片机供电。

TS90A/SG90引脚功能
红线VCC5V
棕线GND共地
橙线信号线PWM

外接电源法:电源负极与单片机GND连接,再将舵机GND与单片机GND相连——达到共地,这样做可以确保电路中的电压和电流能够正确流动,避免因电压差异导致的电路问题。(本文即采用此法)

二、C8T6引脚分布

在这里插入图片描述

三、 接线说明(另:串口下载–USB转TTL接线

舵机、电源和单片机接线:

TS90A/SG90单片机c8t6外部电源
红线VCC5V
棕线GNDGND单片机GND 接 电源负极
橙线PWMPA0

四、代码部分

main.c

#include "TIMER.h"
#include "delay.h"

int main(void)
{
  delay_init();
  TIM2_PWM_Init(9999, 143); //TIM2_Int_Init(u16 arr, u16 psc),初始化定时器TIM2--20ms
	                        //定时时间=(arr+1)(psc+1)/Tclk,Tclk为内部通用定时器时钟,本例程默认设置为72MHZ
  while(1)
	{
		delay_ms(100);
//		TIM_SetCompare1(TIM2, PWM); //设置待装入捕获比较寄存器的脉冲值,相当于不断设置TIM_Pulse
//		                            //也即设置占空比,输出的PWM值
//  	                            //在本例程中PWM值即为一个周期(20ms)内引脚A0输出的高电平时长(单位2^-3ms)
		

		/*计数arr=10000-1,所以一个周期计数10000次,
		0度    250/10000=2.50%
		45度   500/10000=5.00%
		90度   750/10000=7.50%
		135度  1000/10000=10.00%
		180度  1250/10000=12.50%
		*/
		TIM_SetCompare1(TIM2, 250);//0
		delay_ms(5000);
		TIM_SetCompare1(TIM2, 500);//45
		delay_ms(5000);
		TIM_SetCompare1(TIM2, 700);//90
		delay_ms(5000);
		TIM_SetCompare1(TIM2, 1000);//135
		delay_ms(5000);
		TIM_SetCompare1(TIM2, 1250);//180
		delay_ms(5000);
	}
}

TIMER.c

#include "TIMER.h"

//通用定时器2初始化函数,arr:自动重装载值,psc:预分频系数,默认定时时钟为72MHZ时,两者共同决定定时中断时间
void TIM2_Int_Init(u16 arr, u16 psc)
{
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStrue; //定义一个定时中断的结构体
	NVIC_InitTypeDef NVIC_InitStrue; //定义一个中断优先级初始化的结构体
	
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //使能通用定时器2时钟
	
	TIM_TimeBaseInitStrue.TIM_Period=arr; //计数模式为向上计数时,定时器从0开始计数,计数超过到arr时触发定时中断服务函数
	TIM_TimeBaseInitStrue.TIM_Prescaler=psc; //预分频系数,决定每一个计数的时长
	TIM_TimeBaseInitStrue.TIM_CounterMode=TIM_CounterMode_Up; //计数模式:向上计数
	TIM_TimeBaseInitStrue.TIM_ClockDivision=TIM_CKD_DIV1; //一般不使用,默认TIM_CKD_DIV1
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStrue); //根据TIM_TimeBaseInitStrue的参数初始化定时器TIM2
	
	TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); //使能TIM2中断,中断模式为更新中断:TIM_IT_Update
	
	NVIC_InitStrue.NVIC_IRQChannel=TIM2_IRQn; //属于TIM2中断
	NVIC_InitStrue.NVIC_IRQChannelCmd=ENABLE; //中断使能
	NVIC_InitStrue.NVIC_IRQChannelPreemptionPriority=1; //抢占优先级为1级,值越小优先级越高,0级优先级最高
	NVIC_InitStrue.NVIC_IRQChannelSubPriority=1; //响应优先级为1级,值越小优先级越高,0级优先级最高
	NVIC_Init(&NVIC_InitStrue); //根据NVIC_InitStrue的参数初始化VIC寄存器,设置TIM2中断
	
	TIM_Cmd(TIM2, ENABLE); //使能定时器TIM2
}

void TIM2_IRQHandler()
{
  if(TIM_GetITStatus(TIM2, TIM_IT_Update)==1) //当发生中断时状态寄存器(TIMx_SR)的bit0会被硬件置1
	{
		PCout(13)=!PCout(13); //LED灯(C13引脚)状态取反,该函数封装在库函数"sys.h"中
		TIM_ClearITPendingBit(TIM2, TIM_IT_Update); //状态寄存器(TIMx_SR)的bit0置0
	}
}

void TIM2_PWM_Init(u16 arr, u16 psc)
{
	GPIO_InitTypeDef GPIO_InitStructure; //定义一个引脚初始化的结构体
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStrue; //定义一个定时中断的结构体	
	TIM_OCInitTypeDef TIM_OCInitTypeStrue; //定义一个PWM输出的结构体
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能GPIOA时钟,在STM32中使用IO口前都要使能对应时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //使能通用定时器2时钟,A0引脚对应TIM2CHN1
	
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;//引脚0
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP; //复用推挽输出模式,定时器功能为A0引脚复用功能
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; //定义该引脚输出速度为50MHZ
  GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化引脚GPIOA0
	 
	TIM_TimeBaseInitStrue.TIM_Period=arr; //计数模式为向上计数时,定时器从0开始计数,计数超过到arr时触发定时中断服务函数
	TIM_TimeBaseInitStrue.TIM_Prescaler=psc; //预分频系数,决定每一个计数的时长
	TIM_TimeBaseInitStrue.TIM_CounterMode=TIM_CounterMode_Up; //计数模式:向上计数
	TIM_TimeBaseInitStrue.TIM_ClockDivision=0; //一般不使用,默认TIM_CKD_DIV1
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStrue); //根据TIM_TimeBaseInitStrue的参数初始化定时器TIM2
	
	TIM_OCInitTypeStrue.TIM_OCMode=TIM_OCMode_PWM1; //PWM模式1,当定时器计数小于TIM_Pulse时,定时器对应IO输出有效电平
	TIM_OCInitTypeStrue.TIM_OCPolarity=TIM_OCNPolarity_High; //输出有效电平为高电平
	TIM_OCInitTypeStrue.TIM_OutputState=TIM_OutputState_Enable; //使能PWM输出
	TIM_OCInitTypeStrue.TIM_Pulse = 0; //设置待装入捕获比较寄存器的脉冲值
	TIM_OC1Init(TIM2, &TIM_OCInitTypeStrue); //根TIM_OCInitTypeStrue参数初始化定时器2通道1

	TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Disable); //CH1预装载使能
	
	TIM_ARRPreloadConfig(TIM2, ENABLE); //CH1预装载使能
	
	TIM_Cmd(TIM2, ENABLE); //使能定时器TIM2
}

TIMER.h

#ifndef __TIMER_H
#define __TIMER_H	
#include "sys.h"
#include "stm32f10x_tim.h"

void TIM2_Int_Init(u16 arr, u16 psc);
void TIM2_PWM_Init(u16 arr, u16 psc);

#endif

sys.c

#include "sys.h"

//THUMB指令不支持汇编内联
//采用如下方法实现执行汇编指令WFI  
void WFI_SET(void)
{
	__ASM volatile("wfi");		  
}
//关闭所有中断
void INTX_DISABLE(void)
{		  
	__ASM volatile("cpsid i");
}
//开启所有中断
void INTX_ENABLE(void)
{
	__ASM volatile("cpsie i");		  
}
//设置栈顶地址
//addr:栈顶地址
__asm void MSR_MSP(u32 addr) 
{
    MSR MSP, r0 			//set Main Stack value
    BX r14
}

sys.h

#ifndef __SYS_H
#define __SYS_H	
#include "stm32f10x.h"

//0,不支持ucos
//1,支持ucos
#define SYSTEM_SUPPORT_OS		0		//定义系统文件夹是否支持UCOS
																	    
	 
//位带操作,实现51类似的GPIO控制功能
//具体实现思想,参考<<CM3权威指南>>第五章(87页~92页).
//IO口操作宏定义
#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2)) 
#define MEM_ADDR(addr)  *((volatile unsigned long  *)(addr)) 
#define BIT_ADDR(addr, bitnum)   MEM_ADDR(BITBAND(addr, bitnum)) 
//IO口地址映射
#define GPIOA_ODR_Addr    (GPIOA_BASE+12) //0x4001080C 
#define GPIOB_ODR_Addr    (GPIOB_BASE+12) //0x40010C0C 
#define GPIOC_ODR_Addr    (GPIOC_BASE+12) //0x4001100C 
#define GPIOD_ODR_Addr    (GPIOD_BASE+12) //0x4001140C 
#define GPIOE_ODR_Addr    (GPIOE_BASE+12) //0x4001180C 
#define GPIOF_ODR_Addr    (GPIOF_BASE+12) //0x40011A0C    
#define GPIOG_ODR_Addr    (GPIOG_BASE+12) //0x40011E0C    

#define GPIOA_IDR_Addr    (GPIOA_BASE+8) //0x40010808 
#define GPIOB_IDR_Addr    (GPIOB_BASE+8) //0x40010C08 
#define GPIOC_IDR_Addr    (GPIOC_BASE+8) //0x40011008 
#define GPIOD_IDR_Addr    (GPIOD_BASE+8) //0x40011408 
#define GPIOE_IDR_Addr    (GPIOE_BASE+8) //0x40011808 
#define GPIOF_IDR_Addr    (GPIOF_BASE+8) //0x40011A08 
#define GPIOG_IDR_Addr    (GPIOG_BASE+8) //0x40011E08 
 
//IO口操作,只对单一的IO口!
//确保n的值小于16!
#define PAout(n)   BIT_ADDR(GPIOA_ODR_Addr,n)  //输出 
#define PAin(n)    BIT_ADDR(GPIOA_IDR_Addr,n)  //输入 

#define PBout(n)   BIT_ADDR(GPIOB_ODR_Addr,n)  //输出 
#define PBin(n)    BIT_ADDR(GPIOB_IDR_Addr,n)  //输入 

#define PCout(n)   BIT_ADDR(GPIOC_ODR_Addr,n)  //输出 
#define PCin(n)    BIT_ADDR(GPIOC_IDR_Addr,n)  //输入 

#define PDout(n)   BIT_ADDR(GPIOD_ODR_Addr,n)  //输出 
#define PDin(n)    BIT_ADDR(GPIOD_IDR_Addr,n)  //输入 

#define PEout(n)   BIT_ADDR(GPIOE_ODR_Addr,n)  //输出 
#define PEin(n)    BIT_ADDR(GPIOE_IDR_Addr,n)  //输入

#define PFout(n)   BIT_ADDR(GPIOF_ODR_Addr,n)  //输出 
#define PFin(n)    BIT_ADDR(GPIOF_IDR_Addr,n)  //输入

#define PGout(n)   BIT_ADDR(GPIOG_ODR_Addr,n)  //输出 
#define PGin(n)    BIT_ADDR(GPIOG_IDR_Addr,n)  //输入

//以下为汇编函数
void WFI_SET(void);		//执行WFI指令
void INTX_DISABLE(void);//关闭所有中断
void INTX_ENABLE(void);	//开启所有中断
void MSR_MSP(u32 addr);	//设置堆栈地址

#endif

五、PWM控制舵机原理

建议详读这篇文章
[1.]单片机——SG90舵机工作原理–掏一淘哆啦A梦的奇妙口袋

### 关于TS90A舵机的电路设计 TS90A是一种高性能的模拟舵机,相较于普通的SG90舵机,在机械结构上进行了优化,例如采用了金属马达齿、金属电位器齿轮轴以及带限位功能的齿轮设计,从而提升了其运行平滑性和物理稳定性[^1]。 然而,具体的TS90A舵机电路原理图并未在提供的引用中明确提及。通常情况下,舵机内部主要由以下几个部分组成: 1. **直流电机**:负责提供动力输出。 2. **位置反馈电位器**:用于检测当前转子的角度并将其转换为电信号。 3. **控制芯片**:接收外部输入信号(通常是PWM信号),并与电位器返回的际角度进行比较,驱动电机调整至目标位置。 #### STM32TS90A舵机控制方式 对于TS90A舵机控制,可以通过STM32控制器生成精确的PWM波形来现对其转动角度的调节。具体而言,舵机接受标准的PWM信号作为输入,其中脉冲宽度决定了舵机的目标角度。常见的PWM周期为20ms,而有效高电平持续时间范围一般在0.5ms到2.5ms之间,分别对应舵机的不同旋转角度[^2]。 以下是基于STM32的一个简单PWM配置例代码片段,展示了如何通过定时器模块生成适合TS90A舵机工作的PWM信号: ```c #include "stm32f10x.h" #include "ts90a.h" #include "delay.h" int main(void) { PWM_TIM3CH2RE_Config(); while (1) { u16 i; // 控制舵机正向移动 for (i = 175; i < 195; i++) { TIM_SetCompare2(TIM3, i); delay_ms(100); } // 控制舵机反向移动 for (i = 195; i > 175; i--) { TIM_SetCompare2(TIM3, i); delay_ms(100); } } } ``` 上述代码现了舵机在一个固定范围内往复运动的功能,通过修改`TIM_SetCompare2()`函数参数可以灵活设定不同的目标角度[^4]。 由于际硬件层面的设计图纸可能涉及厂商专有权保护,公开获取完整的TS90A舵机电原理图较为困难。如果需要深入了解其内部电气连接细节,建议参考同类产品的通用设计方案或者联系制造商索取官方资料。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值