❤️ 专栏简介:本专栏记录了从零学习单片机的过程,其中包括51单片机和STM32单片机两部分;建议先学习51单片机,其是STM32等高级单片机的基础;这样再学习STM32时才能融会贯通。
☀️ 专栏适用人群 :适用于想要从零基础开始学习入门单片机,且有一定C语言基础的的童鞋。
🌙专栏目标:实现从零基础入门51单片机和STM32单片机,力求在玩好单片机的同时,能够了解一些计算机的基本概念,了解电路及其元器件的基本理论等。⭐️ 专栏主要内容: 主要学习STM32单片机的功能、各个模块、单片机的外设、驱动等,最终玩好单片机和单片机的外设,全程手敲代码,实现我们所要实现的功能。
🌴 专栏说明 :如果文章知识点有错误的地方,欢迎大家随时在文章下面评论,我会第一时间改正。让我们一起学习,一起进步。
💑专栏主页:http://t.csdn.cn/HCD8v
本学习过程参考:https://space.bilibili.com/383400717
STM3单片机安装软件、各种资料以及源码的路径:
链接:https://pan.baidu.com/s/1snD0uuTfMhchFqOMWvAiHA?pwd=asdf#list/path=%2F
提取码:asdf
链接里压缩包的解压密码:32
本大节主要学习TIM定时器的相关知识,包含八小节:
第一小节主要学习定时器基本定时的功能,第二小节是对第一小节的内容写两个程序进行练习,分别是定时器定时中断和定时器外部时钟;
第三小节主要学习定时器输出比较的功能,第四小节是对第三小节的内容写三个程序进行练习,分别是PWM驱动LED呼吸灯、PWM驱动舵机以及PWM驱动直流电机;
第五小节主要学习定时器输入捕获的功能,第六小节是对第五小节的内容写两个程序进行练习,分别是输入捕获模式测频率和PWMI模式测频率占空比;
第七小节主要学习定时器的编码器接口功能,第八小节是对第七小节的内容写一个程序进行练习,即编码器接口测速;
最终附上所有的源代码;
本小节是对第三小节TIM输出比较的内容写三个程序进行练习,分别是PWM驱动LED呼吸灯、PWM驱动舵机以及PWM驱动直流电机;也就是使用STM32输出PWM波形,来驱动舵机和直流电机;
文章目录
- 一、本节目标
- 目标1:PWM驱动LED呼吸灯
- 目标2:PWM驱动舵机
- 目标3:PWM驱动直流电机
- 二、示例1:PWM驱动LED呼吸灯
- 2.1 接线图
- 2.2 程序源码
- 三、示例2:PWM驱动舵机
- 3.1 接线图
- 3.2 程序源码
- 四、示例3:PWM驱动直流电机
- 4.1 接线图
- 4.2 程序源码
一、本节目标
目标1:PWM驱动LED呼吸灯
现象:LED灯不断变换亮度,实现一个呼吸灯的效果
目标2:PWM驱动舵机
现象:每按下一次按键,舵机输出轴的角度就变化一次,另外OLED上也显示当前的角度;
目标3:PWM驱动直流电机
OLED显示当前电机的速度值,按下按键,电机速度由0变为20,再按一下变为40;以此类推,等加到一百后,电机转速达到正向的最大值;如果继续按,则速度变为-100,即反向的最大值,再按,-80,再按-60,以此类推,直到0,电机停止;
二、示例1:PWM驱动LED呼吸灯
2.1 接线图
这里的LED,我们采用的是正极接在PA0引脚,负极接在GND的驱动方法,这样就是高电平点亮,低电平熄灭; 这种方法观察更直接一些,即占空比越大,LED越亮,占空比越小,LED就越暗;
实物图如下:
2.2 程序源码
代码路径:
STM32入门教程资料\程序源码\STM32Project\6-3 PWM驱动LED呼吸灯\User
STM32入门教程资料\程序源码\STM32Project\6-3 PWM驱动LED呼吸灯\Hardware
具体代码:
#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);
Delay_ms(10);
}
for (i = 0; i <= 100; i++)
{
PWM_SetCompare1(100 - i);
Delay_ms(10);
}
}
}
pwm.c
:
#include "stm32f10x.h" // Device header
void PWM_Init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
// RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
// GPIO_PinRemapConfig(GPIO_PartialRemap1_TIM2, ENABLE);
// GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //GPIO_Pin_15;
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;
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);//配置输出比较模块OC1,选择TIM2定时器;
TIM_Cmd(TIM2, ENABLE);
}
void PWM_SetCompare1(uint16_t Compare)
{
TIM_SetCompare1(TIM2, Compare);//用来单独更改CCR寄存器的值
}
代码解释:
整个开启PWM的流程也就是参考下图的流程:
- 第一步:RCC开启时钟,把我们要用的TIM外设和GPIO外设的时钟都打开;
- 第二步:配置时基单元,包括前面的时钟源选择和时基单元都配置好
- 第三步:配置输出比较单元,包括CCR的值、输出比较模式、极性选择、输出使能这些参数,在库函数里也都是用结构体来统一配置的
- 第四步,配置GPIO,把PWM对应的GPIO口,初始化为复用推挽输出的配置
具体每一步,及具体代码的解释,请参照代码中的注释。
三、示例2:PWM驱动舵机
3.1 接线图
第一个,黑线,GND,接在面包板的GND;第二个,红线,5V正极,接5V的电机电源,不要接面包板正极,面包板正极只有3.3V,带不动电机的;所以接在了STLINK的5V输出引脚;第三个,橙色线,PWM信号,接在PA1引脚;最后再在PB1接一个按键,用来控制舵机;
实物接线图如下:
3.2 程序源码
代码路径:
STM32入门教程资料\程序源码\STM32Project\6-4 PWM驱动舵机\User
STM32入门教程资料\程序源码\STM32Project\6-4 PWM驱动舵机\Hardware
具体代码:
#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;
if (Angle > 180)
{
Angle = 0;
}
}
Servo_SetAngle(Angle);
OLED_ShowNum(1, 7, Angle, 3);
}
}
Sero.c
:
#include "stm32f10x.h" // Device header
#include "PWM.h"
void Servo_Init(void)
{
PWM_Init();
}
void Servo_SetAngle(float Angle)
{
PWM_SetCompare2(Angle / 180 * 2000 + 500);
}
四、示例3:PWM驱动直流电机
4.1 接线图
- 红色的是TB6612电机驱动模块,第一个引脚VM,电机电源,同样的也是接在STLINK的5V引脚;第二个VCC,逻辑电源,接在面包板3.3V正极;第三个GNC,电源负极,接在面板吧的负极;之后AO1、AO2,电机输出端,接电机的两根线;STBY,待机控制脚,不需要待机,直接接逻辑电源正3.3V;剩下的三个是控制引脚,AIN1和AIN2是方向控制,任意接两个GPIO就行,这里我们接的是PA4和PA5两个脚;最后一个PWMA是速度控制,需要接PWM的输出脚,这里我们接在了PA2这个引脚;
硬件接线图如下:
4.2 程序源码
代码路径:
STM32入门教程资料\程序源码\STM32Project\6-5 PWM驱动直流电机\User
STM32入门教程资料\程序源码\STM32Project\6-5 PWM驱动直流电机\Hardware
具体代码:
#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;
if (Speed > 100)
{
Speed = -100;
}
}
Motor_SetSpeed(Speed);
OLED_ShowSignedNum(1, 7, Speed, 3);
}
}
Motor.c
:
#include "stm32f10x.h" // Device header
#include "PWM.h"
void Motor_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
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);
PWM_Init();
}
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);
}
}