定时器(3)代码部分


写在前头

9/28 昨天接受了xxx的一连串的良心拷问 花了我一晚上的时间

昨天学习了呼吸灯 控制舵机 以及 控制直流电机

现在在这里放放代码

呼吸灯

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#include "stm32f10x.h"                  // Device header


void PWM_Init(void)
{
//1. rcc开启时钟 TIM GPIO
//2. 配置时基单元
//3. 配置输出比较单元
//4. 配置GPIO 把PWM对应的GPIO口 初始化为复用推挽输出模式
//5. 运行控制
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
GPIO_InitTypeDef Gpioa_InitStruct;
// 模式需要设置为复用推挽输出 才能把控制权交给片上外设 PWM波形才能通过引脚输出
Gpioa_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
Gpioa_InitStruct.GPIO_Pin = GPIO_Pin_0;
Gpioa_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &Gpioa_InitStruct);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
// 选择时基单元的时钟
// 定时器上电默认使用内部时钟
TIM_InternalClockConfig(TIM2);
TIM_TimeBaseInitTypeDef TIM_InitStruct;
// 时钟分频
TIM_InitStruct.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_InitStruct.TIM_CounterMode = TIM_CounterMode_Up;
// ARR 自动重装器
TIM_InitStruct.TIM_Period = 100 - 1 ;
// PSC 预分频器
TIM_InitStruct.TIM_Prescaler = 720 - 1;
// CNT 计数器的值 高级计数器才有 这里不需要使用
TIM_InitStruct.TIM_RepetitionCounter = 0x0000;
// 这里是 时基单元的初始化
TIM_TimeBaseInit(TIM2, &TIM_InitStruct);

// 由于时基单元初始化 会触发一次更新事件
//
// 在这里需要重新清理一下 更新的标志位
TIM_ClearFlag(TIM2, TIM_FLAG_Update);
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;
// 设置CCR值
// 呈现呼吸效果 修改ccr的值就行了
// 这里的ccr 是控制占空比
Tim_OCInitStructure.TIM_Pulse = 0;
// 这里的OC1 需要查询引脚功能表才能查到
TIM_OC1Init(TIM2, &Tim_OCInitStructure);
// 定时器使能中断 中断输出控制
TIM_Cmd(TIM2,ENABLE);
}

void PWM_setCompare1(uint16_t Compare)
{
TIM_SetCompare1(TIM2, Compare);
}

注意细节

  1. gpio输出端口 需要设置成复用推挽输出模式 才能将控制权交给片上外设

  2. 当时基单元初始化时 会出发更新时间 在这里需要清理一下更新的标志位

  3. 在输出比较功能 由于结构体的赋值过多 可以先通过TIM_OCStructInit(&Tim_OCInitStructure)。给结构体赋初值然后修改我们需要的初值。

  4. TIM_OC1Init 需要通过查引脚参考表才能知道是通道1

  5. PWM_setCompare1 该函数为设置通道1内CCR的值,PWM是什么通道就用什么通道的函数

针对于 舵机的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include "stm32f10x.h"                  // Device header
#include "pwm.h"

void Servo_init(void)
{
PWM_Init();
}

void Servo_SetAngle(float Angle)
{

TIM_SetCompare2(TIM2, Angle/180 *2000 + 500);
}

一种针对于PWM的模块的封装

学习下

针对于直流电机的代码

由于直流电机功率高 且电压超过了3.3v

需要通过电机驱动电路来完成任务功能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#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_SetBits(GPIOA,GPIO_Pin_5);
GPIO_ResetBits(GPIOA,GPIO_Pin_4);
PWM_setCompare3(-speed);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "pwm.h"
#include "motor.h"
#include "Key.h"
uint8_t KeyNum;
// 这里的speed 要设置为一个有符号的数字
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;
}
}
OLED_ShowSignedNum(1,7,Speed,3);
motor_SetSpeed(Speed);
}
}

注意细节

  1. PWM_setCompare3 中的speed只能放入正值,其中速度为负 是通过电机正反装实现的
  2. 在写到main函数中 发现代码中的speed 应该设置成有符号数字 (bug查了一会)