Stm32f103c8t6(proteus仿真)学习——7-2.PWM驱动SG90舵机
·
目录
一、proteus原理图绘制
proteus没有舵机的模块,只能类似的模拟
搜索:servo,选择PWMservo
双击改参数
180度的舵机(SG90)的控制需要产生一个周期为20ms的脉冲信号,以0.5ms到2.5ms的高电平来控制舵机转动的角度,对应关系如下:
二、代码的编写
1. PWM.c文件
配置舵机的PWM
#include "PWM.h"
void PWM_Init(void) //PWM初始化
{
//GPIO的结构体定义,定义一个GPIO类型的结构体,名字为GPIO_InitStructure
GPIO_InitTypeDef GPIO_InitStructure;
//TIM_TimeBase的结构体定义,定义一个TIM_TimeBase类型的结构体,名字为TIM_TimeBaseInitStructure
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
//TIM_OC的结构体定义,定义一个TIM_OC类型的结构体,名字为TIM_OCInitStructure
TIM_OCInitTypeDef TIM_OCInitStructure;
//开启定时器3的时钟,注意是APB1(GPIO的是APB2)
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
//开启GPIO的时钟,注意是APB2
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
//GPIO引脚的重映射,TIM3_CH1重映射引脚到PB4
//RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
//GPIO_PinRemapConfig(GPIO_PartialRemap1_TIM3, ENABLE);
//GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6; //GPIO_Pin_4;TIM3_CH1重映射引脚到PB4
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure); //GPIO_Init(GPIOB, &GPIO_InitStructure); //PB4
//选择定时器的内部时钟源 TIM3
TIM_InternalClockConfig(TIM3);
//配置定时器时基单元:TIM_TimeBase
//选择时钟分频,可以选择1分频、2分频和4分频
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; //TIM_CKD_DIV1:1分频
//选择定时器计数方式,可选择向上计数、向下计数、中心对齐计数
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM_CounterMode_Up:向上计数
//设置ARR,即定时器周期:TIM_Period,取值0-65535
TIM_TimeBaseInitStructure.TIM_Period = 20000 - 1; //ARR
//设置PSC,即定时器预分频器的值:TIM_Prescaler,取值0-65535
TIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1; //PSC
//高级定时器才用的到,重复计算器,先用不上赋值为0
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
//TIM_TimeBase初始化
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);
//初始化配置定时器输出比较单元:TIM_OC
//设置输出比较的模式:TIM_OCMode_PWM1,PWM1模式
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
//设置输出比较的极性:TIM_OCPolarity_High;高极性:有效电平为高电平
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
//设置输出使能
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
//设置捕获比较寄存器 CCR 的值
TIM_OCInitStructure.TIM_Pulse = 0; //CCR
//初始化定时器3通道1
TIM_OC1Init(TIM3, &TIM_OCInitStructure);
//使能定时器3
TIM_Cmd(TIM3, ENABLE);
}
void PWM_SetCompare1(uint16_t Compare)
{
TIM_SetCompare1(TIM3, Compare); //设置捕获比较寄存器 CCR 的值
}
注意:ARR设置为20000-1,PSC设置为72-1,正好对应舵机的周期20ms
公式:频率=72M / (PSC+1)(ARR+1)
代入ARR=20000-1、PSC=72-1,得频率=72x106/72x(2x104)=1/20
所以,周期=1/频率,得周期=20ms
具体ARR和PSC可以直接修改,只需要满足频率=1/20即可
2. PWM.h文件
头文件
#ifndef __PWM_H
#define __PWM_H
#include "stm32f10x.h" // Device header
void PWM_Init(void);
void PWM_SetCompare1(uint16_t Compare);
#endif
3. servo.c文件
servo.c需要用到PWM,直接调用pwm.h即可
#include "servo.h"
void Servo_Init(void) //舵机初始化
{
PWM_Init(); //直接调用PWM初始化
}
void Servo_SetAngle(float Angle) //输入需要设置的角度
{
PWM_SetCompare1(Angle / 180 * 2000 + 500); //舵机角度转换
}
4. servo.h文件
头文件
#ifndef __SERVO_H
#define __SERVO_H
#include "stm32f10x.h" // Device header
#include "PWM.h"
void Servo_Init(void);
void Servo_SetAngle(float Angle);
#endif
5. key.c文件
使用按键控制舵机转动角度,按一次角度+30
#include "key.h"
extern uint8_t KeyNum;
//按键 初始化函数
void Key_Init(void){
//声明一个结构体,名字是GPIO_InitStructure
GPIO_InitTypeDef GPIO_InitStructure;
//使能GPIOA的时钟,ENABLE代表使能
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//GPIOB
//按键需要设置引脚模式为上拉模式GPIO_Mode_IPU
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU; //上拉模式GPIO_Mode_IPU
//定义引脚为 15号引脚
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_15;
//设置引脚的速度50MHz
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
//初始化GPIO,初始化哪个引脚就对应哪个
GPIO_Init(GPIOB,&GPIO_InitStructure);//初始化GPIOB,所以引脚对应PB15
//初始化时LED应为熄灭状态,所以要拉高LED引脚的电平
GPIO_SetBits(GPIOB,GPIO_Pin_15); //PB15引脚拉高电平
}
uint8_t Key_GetNum(void){ //获取当前按键键值
//检测PB15引脚是否为低电平,按键按下时为低电平
if(GPIO_ReadInputDataBit(GPIOB , GPIO_Pin_15)==0){ //PB15为低电平,按键1已按下
delay_ms(20); //延时,消抖
//消抖,等待PB15重新变成高电平,如果一直为低电平则一直进入死循环
while(GPIO_ReadInputDataBit(GPIOB , GPIO_Pin_0)==0);
delay_ms(20); //延时,消抖
KeyNum=1; //键值赋值为1,代表按键1已按下
}
return KeyNum; //返回键值
}
6. key.h文件
#ifndef __KEY_H
#define __KEY_H
#include "stm32f10x.h" // Device header
#include "delay.h"
void Key_Init(void);
uint8_t Key_GetNum(void);
#endif
7. OLED文件
里面有三个文件:OLED.Font.h、OLED.c和OLED.h
其中OLED.Font.h是字库文件
百度网盘
链接:https://pan.baidu.com/s/1x2XtGtKYNEaTBEaUHLj5qw
提取码:69q1
8. main.c文件
#include "stm32f10x.h"
#include "key.h" //按键
#include "OLED.h" //OLED显示屏
#include "PWM.h" //PWM输出
#include "servo.h"
#include "delay.h"
uint8_t KeyNum = 0;
float Angle =0.0;
int main(void)
{
delay_init();
OLED_Init();
PWM_Init();
OLED_ShowString(1,1,"Angle: ");
while(1){
KeyNum=0;
KeyNum = Key_GetNum();
if (KeyNum == 1)
{
Angle += 30;
if (Angle > 180)
{
Angle = 0;
}
}
Servo_SetAngle(Angle);
OLED_ShowNum(1, 8, Angle, 3);
}
}
9. 效果展示
proteus无法准确仿真舵机,只能粗略模拟
三、项目(代码+仿真)分享链接
百度网盘
链接:https://pan.baidu.com/s/1pcVtAcER2mAwnQnyRL3aXQ
提取码:p8q4
更多推荐
已为社区贡献6条内容
所有评论(0)