当前栏目
6.4 PWM驱动LED呼吸灯&PWM驱动舵机&PWM驱动直流电机
PWM驱动LED呼吸灯
1.1 电路连接示意图
![](https://img-blog.csdnimg.cn/img_convert/b9d840657adf74ab23b251976860af85.png)
PA0引脚上插一个LED,在PA0引脚输出一个PWM波,用于驱动LED呈现出不同亮度。
LED正极接在PA0引脚,负极接在GND(高电平电路,低电平熄灭),这样占空比越大,LED越亮,占空比越小,LED越暗。
1.2 设计思路
本设计采用模块化编程,在配置好的工程基础上在Hardware文件夹中加上PWM.c、PWM.h两部分。
灯的亮度与CCR的值有关,CCR值越大,灯越亮,CCR值越小,灯越暗
PWM初始化步骤
RCC开启时钟,把要用的TIM外设和GPIO外设的时钟打开。
配置时基单元,配置好时钟选择和时基单元。
配置输出比较单元,包含CCR的值、输出比较模式、极性选择、输出使能。
配置GPIO,把PWM对应的GPIO口,初始化为复用推挽输出的配置。
运行控制。
1.3 知识储备--输出比较常用库函数
配置输出比较函数
void TIM_OC1Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
void TIM_OC2Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
void TIM_OC3Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
void TIM_OC4Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
给输出比较结构体赋⼀个默认值函数
void TIM_OCStructInit(TIM_OCInitTypeDef* TIM_OCInitStruct);
配置强制输出模式函数
在运行中想要暂停输出波形并且强制输出高或者低电平,强制输出高电平和设置百分百占空比相同,强制输出低电平和设置百分百零低电平相同。
void TIM_ForcedOC1Config(TIM_TypeDef* TIMx, uint16_t TIM_ForcedAction);
void TIM_ForcedOC2Config(TIM_TypeDef* TIMx, uint16_t TIM_ForcedAction);
void TIM_ForcedOC3Config(TIM_TypeDef* TIMx, uint16_t TIM_ForcedAction);
void TIM_ForcedOC4Config(TIM_TypeDef* TIMx, uint16_t TIM_ForcedAction);
配置CCR寄存器的预装功能函数
预装功能就是影⼦寄存器:写⼊的值不会⽴即⽣效,⽽是在更新事件才会⽣效
void TIM_OC1PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload);
void TIM_OC2PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload);
void TIM_OC3PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload);
void TIM_OC4PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload);
配置快速使能函数
void TIM_OC1FastConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCFast);
void TIM_OC2FastConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCFast);
void TIM_OC3FastConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCFast);
void TIM_OC4FastConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCFast);
外部事件时清除REF信号函数
void TIM_ClearOC1Ref(TIM_TypeDef* TIMx, uint16_t TIM_OCClear);
void TIM_ClearOC2Ref(TIM_TypeDef* TIMx, uint16_t TIM_OCClear);
void TIM_ClearOC3Ref(TIM_TypeDef* TIMx, uint16_t TIM_OCClear);
void TIM_ClearOC4Ref(TIM_TypeDef* TIMx, uint16_t TIM_OCClear);
单独设置输出⽐较的极性函数
带N的是高级定时器互补通道的配置函数,OC4没有互补通道,无OC4N函数
void TIM_OC1PolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity);
void TIM_OC1NPolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCNPolarity);
void TIM_OC2PolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity);
void TIM_OC2NPolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCNPolarity);
void TIM_OC3PolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity);
void TIM_OC3NPolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCNPolarity);
void TIM_OC4PolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity);
单独修改输出使能参数函数
void TIM_CCxCmd(TIM_TypeDef* TIMx, uint16_t TIM_Channel, uint16_t TIM_CCx);
void TIM_CCxNCmd(TIM_TypeDef* TIMx, uint16_t TIM_Channel, uint16_t TIM_CCxN);
选择输出比较模式函数
void TIM_SelectOCxM(TIM_TypeDef* TIMx, uint16_t TIM_Channel, uint16_t TIM_OCMode);
单独更改CCR寄存器的值的函数
void TIM_SetCompare1(TIM_TypeDef* TIMx, uint16_t Compare1);
void TIM_SetCompare2(TIM_TypeDef* TIMx, uint16_t Compare2);
void TIM_SetCompare3(TIM_TypeDef* TIMx, uint16_t Compare3);
void TIM_SetCompare4(TIM_TypeDef* TIMx, uint16_t Compare4);
使用高级定时器输出PWM时调用使能主输出函数
void TIM_CtrlPWMOutputs(TIM_TypeDef* TIMx, FunctionalState NewState);
1.4 程序设计
PWM.h
#ifndef __PWM_H
#define __PWM_H
void PWM_Init(void);
void PWM_SetCompare1(uint16_t Compare);
#endif
PWM.c
#include "stm32f10x.h" // Device header
void PWM_Init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);//开启TIM2时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//开启GPIO时钟
// RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
// GPIO_PinRemapConfig(GPIO_PartialRemap1_TIM2, ENABLE);
// GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;//定义GPIO结构体
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//复用推挽输出
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; 开启引脚
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//配置响应速度
GPIO_Init(GPIOA, &GPIO_InitStructure);//写⼊参数
TIM_InternalClockConfig(TIM2);//使用内部时钟
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;//配置时基单元
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;//不分频
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;//向上计数
TIM_TimeBaseInitStructure.TIM_Period = 100 - 1; //ARR
TIM_TimeBaseInitStructure.TIM_Prescaler = 720 - 1; //PSC
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;//重复计数器
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);//写入参数
TIM_OCInitTypeDef TIM_OCInitStructure;//定义输出比较结构体
TIM_OCStructInit(&TIM_OCInitStructure);//给结构体赋默认值
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;//PWM1模式
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;//有效电平为高电平
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;//使能
TIM_OCInitStructure.TIM_Pulse = 0; //CCR
TIM_OC1Init(TIM2, &TIM_OCInitStructure);//写入参数
TIM_Cmd(TIM2, ENABLE);//开启时钟
}
//单独更改CCR的值 CCR越大 灯越亮 CCR值越小 灯越暗
void PWM_SetCompare1(uint16_t Compare)
{
TIM_SetCompare1(TIM2, Compare);//设置CCR3的值
}
main.c
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "PWM.h"
uint8_t i;
int main(void)
{
OLED_Init();
PWM_Init();
while (1)
{
for (i = 0; i <= 100; i++)
{
PWM_SetCompare1(i);//占空比从0--100 LED不断变亮
Delay_ms(10);
}
for (i = 0; i <= 100; i++)
{
PWM_SetCompare1(100 - i);//占空比从100-0 LED逐渐变暗
Delay_ms(10);
}
}
}
2. PWM驱动舵机
1.1 电路连接示意图
![](https://img-blog.csdnimg.cn/img_convert/c44e3dc31f6cad40d702a5c6c3dd289f.png)
三根线:棕色线GND 接GND
红色线5V接ST-LINK 5V输出引脚。
橙色线PWM接PA1引脚
PB1接一个按键用来控制舵机
1.2 设计思路
驱动舵机的关键输出PWM波形,通过控制占空比来控制转动角度,详情请看上一节。
设置按键,每按一次,舵机转动30度。
本设计采用模块化编程,在配置好的工程基础上在Hardware文件夹中加上PWM.c、PWM.h、Servo.c、Servo.h四部分。
1.3 程序设计
PWM.h
#ifndef __PWM_H
#define __PWM_H
void PWM_Init(void);
void PWM_SetCompare2(uint16_t Compare);
#endif
PWM.c
#include "stm32f10x.h" // Device header
void PWM_Init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);//开启TIM2时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//开启GPIO时钟
GPIO_InitTypeDef GPIO_InitStructure;//定义GPIO结构体
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//复用推挽输出
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;//开启引脚
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//配置响应速度
GPIO_Init(GPIOA, &GPIO_InitStructure);//写入参数
TIM_InternalClockConfig(TIM2);//使用内部时钟
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;//配置时基单元
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;//不分频
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;//向上计数
TIM_TimeBaseInitStructure.TIM_Period = 20000 - 1; //ARR 舵机要求的周期是20ms
TIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1; //PSC 舵机要求高电平时间0.5ms--2.5ms
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;//重复计数器
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);//写入参数
TIM_OCInitTypeDef TIM_OCInitStructure;//定义输出比较结构体
TIM_OCStructInit(&TIM_OCInitStructure);//给结构体赋默认值
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;//PWM1模式
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;//有效电平为高电平
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;//使能
TIM_OCInitStructure.TIM_Pulse = 0; //CCR
TIM_OC2Init(TIM2, &TIM_OCInitStructure);//写入参数
TIM_Cmd(TIM2, ENABLE);
}
//使用通道2 单独更改CCR的值
void PWM_SetCompare2(uint16_t Compare)
{
TIM_SetCompare2(TIM2, Compare);//设置CCR3的值
}
Servo.h
#ifndef __SERVO_H
#define __SERVO_H
void Servo_Init(void);
void Servo_SetAngle(float Angle);
#endif
Servo.c
#include "stm32f10x.h" // Device header
#include "PWM.h"
void Servo_Init(void)
{
PWM_Init();
}
//设置舵机角度
//0度对应 500
//180度对应 2500
void Servo_SetAngle(float Angle)
{
PWM_SetCompare2(Angle / 180 * 2000 + 500);
}
main.c
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "Servo.h"
#include "Key.h"
uint8_t KeyNum;//按键键码
float Angle;//角度变量
int main(void)
{
OLED_Init();
Servo_Init();
Key_Init();
OLED_ShowString(1, 1, "Angle:");
while (1)
{
KeyNum = Key_GetNum();
if (KeyNum == 1)
{
Angle += 30;//按一次加30度
if (Angle > 180)
{
Angle = 0;
}
}
Servo_SetAngle(Angle);
OLED_ShowNum(1, 7, Angle, 3);//显示角度值
}
}
3. PWM驱动直流电机
3.1电路连接示意图
![](https://img-blog.csdnimg.cn/img_convert/19264d8ff523191a24c36f8574a26f96.png)
TB6612电机驱动模块
VM点电机电源--ST-LINK 5V引脚
VCC逻辑电源--面包板3.3V
GND电源负极--面包板负极
AO1 AO2 电机输出端--接电机两根线
STBY待机控制脚--接逻辑电源3.3V
A1N1 A1N2方向控制--接任意两个GPIO口
PWMA速度控制--PWM输出脚 PA2对应的是TIM2通道3
按键--PB1口用于控制
3.2 设计思路
本设计采用模块化编程,在配置好的工程基础上在Hardware文件夹中加上PWM.c、PWM.h、Motor.c、Motor.h四部分。
3.3 程序设计
PWM.h
#ifndef __PWM_H
#define __PWM_H
void PWM_Init(void);
void PWM_SetCompare3(uint16_t Compare);
#endif
PWM.c
#include "stm32f10x.h" // Device header
void PWM_Init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);//开启TIM2时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//开启GPIO时钟
GPIO_InitTypeDef GPIO_InitStructure;//定义GPIO结构体
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//复用推挽输出
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;//开启引脚
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//配置响应速度
GPIO_Init(GPIOA, &GPIO_InitStructure);//写入参数
TIM_InternalClockConfig(TIM2);//使用内部时钟
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;//配置时基单元
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;//不分频
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;//向上计数
TIM_TimeBaseInitStructure.TIM_Period = 100 - 1; //ARR
TIM_TimeBaseInitStructure.TIM_Prescaler = 720 - 1; //PSC
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;//重复计数器
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);//写入参数
TIM_OCInitTypeDef TIM_OCInitStructure;//定义输出比较结构体
TIM_OCStructInit(&TIM_OCInitStructure);//给结构体赋默认值
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;//PWM1模式
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;//有效电平为高电平
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;//使能
TIM_OCInitStructure.TIM_Pulse = 0; //CCR
TIM_OC3Init(TIM2, &TIM_OCInitStructure);//写入参数
TIM_Cmd(TIM2, ENABLE);
}
//使用通道2 单独更改CCR的值
void PWM_SetCompare3(uint16_t Compare)
{
TIM_SetCompare3(TIM2, Compare);//设置CCR3的值
}
Motor.c
#include "stm32f10x.h" // Device header
#include "PWM.h"
void Motor_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//开启GPIOA时钟
GPIO_InitTypeDef GPIO_InitStructure;//定义GPIO结构体
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//设置开漏输出
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5;//开启引脚
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//配置响应速度
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA
PWM_Init();//初始化PWM
}
//设置速度-100--100代表反转正转
void Motor_SetSpeed(int8_t Speed)
{
if (Speed >= 0)//正转
{
GPIO_SetBits(GPIOA, GPIO_Pin_4);//方向
GPIO_ResetBits(GPIOA, GPIO_Pin_5);
PWM_SetCompare3(Speed);//速度
}
//反转
else
{
GPIO_ResetBits(GPIOA, GPIO_Pin_4);
GPIO_SetBits(GPIOA, GPIO_Pin_5);
PWM_SetCompare3(-Speed);
}
}
Motor.h
#ifndef __MOTOR_H
#define __MOTOR_H
void Motor_Init(void);
void Motor_SetSpeed(int8_t Speed);
#endif
main.c
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "Motor.h"
#include "Key.h"
uint8_t KeyNum;
int8_t Speed;
int main(void)
{
OLED_Init();
Motor_Init();
Key_Init();
OLED_ShowString(1, 1, "Speed:");
while (1)
{
KeyNum = Key_GetNum();
if (KeyNum == 1)
{
Speed += 20;//每按一次加20速度
if (Speed > 100)//如果速度大于100
{
Speed = -100;//反转
}
}
Motor_SetSpeed(Speed);
OLED_ShowSignedNum(1, 7, Speed, 3);
}
}
完
相关文章
- 前端面试 【JavaScript】— typeof 是否能正确判断类型?
- 前端面试 【JavaScript】— instanceof 能否判断基本数据类型?
- 前端面试 【JavaScript】— 能不能手动实现一下 instanceof 的功能?
- 前端面试 【JavaScript】— Object.is和=== 有什么区别?
- 前端面试 【JavaScript】— JS中类型转换有哪几种?
- 前端面试 【JavaScript】— == 和 ===有什么区别?
- 前端面试 【JavaScript】— 对象转原始类型是根据什么流程运行的?
- JavaScript 的 parseInt() 函数
- javascript实现两个数字进行组合
- JS监听键盘按键
- 大前端开发中的路由管理之五:Flutter篇
- Javascript的DOM操作
- 在Vue项目中使用WebSocket技术
- 新手向:前端程序员必学基本技能——调试JS代码
- React 毁了 Web 开发!
- 「JS 逆向百例」cnki 学术翻译 AES 加密分析
- 商标注册域名后缀用什么?商标和域名有哪些区别?
- 网站建设流程是怎样的?需要看重哪些细节?
- 网站域名商标注册流程是什么?网站域名商标有什么用?
- 如何建设一个实用性强的网站 网站上线后如何运营