目录
1 博客内容
博客内容基于STM32F103 RET6芯片,使用系统通用定时器实现占空比输出。TIM2对于引脚 PA0、PA1、 PA2、PA3,TIM4四个通道对应的 PA6、PA7、 PA8、PA9引脚输出。增加VehcCtrl程序输出电机芯片DRV8848使能(PA15/PC0),通过Debug模式观察PWM输出。
2 主程序(Main.c)
//================================================
// 名称: Main.c
// 作者: Morven_X
// 版本: 1.1
// 编制: 2021/01/25 22:10
// 更新: 2021/01/30 23:01
// 功能: 基于STM32F103 RET6芯片,使用通用TIM2/4通道1/2/3/4输出PWM并测试引脚电压
// 简介: TIM3带输出引脚用于测试电压,TIM2/4通道用于控制电机(Keil 5.28)
// Email: morven_xie@163.com
//================================================
# include "stm32f10x.h"
# include "LED1.h"
# include "Delay.h"
# include "PWM.h"
# include "SPI.h"
# include "VehCtrl.h"
/***************************************************
TIM2通道1/2控制前左轮电机正反转,CCR1>CCR2时正传
TIM2通道3/4控制前右轮电机正反转,CCR3>CCR4时正传
TIM4通道1/2控制后左轮电机正反转,3/4后右轮电机正反转
***************************************************/
int main(void)
{
JTAG_Init();
Stm32_Clock_Init(9); //=====系统时钟设置
Delay_Init(); //=====延时初始化
LED_Init(); //===== LED 连接的硬件接口
uart_init(72,9600); //=====串口1初始化
VehCtrl_MotorEn_Int();
Delay_ms(100);
Motor_EN();
PWM_TIM2_Init(); //TIM2_PWM输出初始化
PWM_TIM4_Init(); //TIM4_PWM输出初始化
Delay_ms(1000); //=====延时等待初始化稳定
PS2_Init(); //=====ps2驱动端口初始化
PS2_SetInit(); //=====ps2配置初始化,配置“红绿灯模式”,并选择是否可以修改
GPIO_SetBits(GPIOC, GPIO_Pin_3); //设置LED高电平输出
Delay_ms(100);
GPIO_ResetBits(GPIOC, GPIO_Pin_3); //设置LED高电平输出
Delay_ms(100);
GPIO_SetBits(GPIOC, GPIO_Pin_3); //设置LED高电平输出
while(1)
{
GPIO_SetBits(GPIOC, GPIO_Pin_3); //设置LED高电平输出
Delay_us(20); //延时500毫秒
TIM_SetCompare1(TIM2,750); //设置TIM2 CH1占空比输出 PA0
TIM_SetCompare2(TIM2,0); //设置TIM2 CH2占空比输出 PA1
TIM_SetCompare3(TIM2,1000); //设置TIM2 CH1占空比输出 PA2
TIM_SetCompare4(TIM2,0); //设置TIM2 CH2占空比输出 PA3
TIM_SetCompare1(TIM4,0); //设置TIM4 CH1占空比输出 PB6
TIM_SetCompare2(TIM4,1500); //设置TIM4 CH2占空比输出 PB7
TIM_SetCompare3(TIM4,0); //设置TIM4 CH3占空比输出 PB8
TIM_SetCompare4(TIM4,2000); //设置TIM4 CH4占空比输出 PB9
}
}
3 PWM头文件(PWM.h)
# ifndef _PWM_H
# define _PWM_H
# include "stm32f10x.h"
#define TIM2_Reload_Num_ARR 1999 //自动重装载寄存器值
#define TIM2_Frequency_Divide_PSC 35 //TIM时钟预分频值
#define TIM4_Reload_Num_ARR 1999 //自动重装载寄存器值
#define TIM4_Frequency_Divide_PSC 35 //TIM时钟预分频值
void JTAG_Init(void);
void PWM_TIM2_Init(void); //TIM2_PWM输出初始化
void PWM_TIM4_Init(void); //TIM4_PWM输出初始化
#endif
4 PWM程序(PWM.c)
# include "PWM.h"
void JTAG_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE); //先开启开启AFIO复用时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); //使能GPIOA外设时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE); //使能GPIOB外设时钟
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);//关闭JTAG,保留SWD(同时关闭SWD,芯片作废)
}
void PWM_TIM2_Init(void)
{
/* 初始化结构体定义 */
GPIO_InitTypeDef GPIO_InitStructure; //GPIO初始化结构体
TIM_TimeBaseInitTypeDef TIM_TimeBaseSrtructure; //TIM时间基数初始化结构体
TIM_OCInitTypeDef TIM_OCInitStructure; //TIM输出比较功能结构体
/* 时钟线(RCC)设置 */
//RCC 为 Reset and Clock Control 时钟配置寄存器
//APB2 外设复位寄存器(RCC_APB2_RSTR,32位,用低16为位),偏移地址OxOC,复位地址 0x0000 0000。位2用于IO端口A复位(IOPARST),位0用于AFIO端口复位(AFIORST)
//APB1 外设复位寄存器(RCC_APB1_RSTR,32位,用全32为位),偏移地址0x10,复位地址 0x0000 0000。位0用于定时器2复位(TIM2RST)
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE); //重映射需开启AFIO复用时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); //使能GPIOA外设时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE); //使能TIM2时钟
/* 端口(GPIO)设置 */
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3; //TIM2 Ch1/2/3/4
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_10MHz; //速度 10MHz
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP; //复用推挽输出
GPIO_Init(GPIOA,&GPIO_InitStructure); //初始化 GPIOA
/* TIM时间基数初始化 */
TIM_TimeBaseSrtructure.TIM_Period= TIM2_Reload_Num_ARR; //计数器 TIMx_CNT计数 从0累加到ARR次后溢出,设置自动重装载值
TIM_TimeBaseSrtructure.TIM_Prescaler=TIM2_Frequency_Divide_PSC; //设置预分频系数 PSC
TIM_TimeBaseSrtructure.TIM_ClockDivision=0; //采用时钟分割,见库函数。TIM_Clock_Division_CKD定义,查手册 00:Tdts=Tck_int:01:Tdts=2*Tck_int(2分频)
TIM_TimeBaseSrtructure.TIM_CounterMode=TIM_CounterMode_Up; //TIM 向上计数模式溢出
TIM_TimeBaseInit(TIM2,&TIM_TimeBaseSrtructure); //初始化TIM2的时钟参数
/* TIM外设初始化 */
TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1; //选择定时器模式:TIM 脉冲宽度调制模式1,模式1为比较低输出。
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
TIM_OCInitStructure.TIM_Pulse =(TIM2_Reload_Num_ARR+1)*0; //比较输出脉冲宽度,设置占空比(初始化用),即CCR
TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High; //输出极性:TIM输出比较极性高
TIM_OC1Init(TIM2,&TIM_OCInitStructure); //初始化TIM2 CH1的时钟,下同
TIM_OC2Init(TIM2,&TIM_OCInitStructure);
TIM_OC3Init(TIM2,&TIM_OCInitStructure);
TIM_OC4Init(TIM2,&TIM_OCInitStructure);
/* 初始化CH1/2/3/4 */
TIM_OC1PreloadConfig(TIM2,TIM_OCPreload_Enable); //CH1 预装载使能,功能在ARR和CCR1改变时,等他们计数完一个周期再修改
TIM_OC2PreloadConfig(TIM2,TIM_OCPreload_Enable); //CH2 预装载使能
TIM_OC3PreloadConfig(TIM2,TIM_OCPreload_Enable); //CH3 预装载使能
TIM_OC4PreloadConfig(TIM2,TIM_OCPreload_Enable); //CH4 预装载使能
TIM_ARRPreloadConfig(TIM2,ENABLE); //使能 TIMx在ARR上的预装载寄存器
// TIM_ClearFlag(TIM2,TIM_IT_CC1);
// TIM_ClearFlag(TIM2,TIM_IT_CC2);
// TIM_ClearFlag(TIM2,TIM_IT_CC3);
// TIM_ClearFlag(TIM2,TIM_IT_CC4);
TIM_Cmd(TIM2, ENABLE); //使能 TIM2
// NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0); //设定中断优先级分组0,这个是我自加的
}
void PWM_TIM4_Init(void)
{
/* 初始化结构体定义 */
GPIO_InitTypeDef GPIO_InitStructure; //GPIO初始化结构体
TIM_TimeBaseInitTypeDef TIM_TimeBaseSrtructure; //TIM时间基数初始化结构体
TIM_OCInitTypeDef TIM_OCInitStructure; //TIM输出比较功能结构体
/* 时钟线(RCC)设置 */
//RCC 为 Reset and Clock Control 时钟配置寄存器
//APB2 外设复位寄存器(RCC_APB2_RSTR,32位,用低16为位),偏移地址OxOC,复位地址 0x0000 0000。位2用于IO端口A复位(IOPARST),位0用于AFIO端口复位(AFIORST)
//APB1 外设复位寄存器(RCC_APB1_RSTR,32位,用全32为位),偏移地址0x10,复位地址 0x0000 0000。位2用于定时器4复位(TIM2RST)
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE); //使能GPIOB外设时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE); //重映射需开启AFIO复用时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4,ENABLE); //使能TIM4时钟
/* 端口(GPIO)设置 */
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9; //TIM4 Ch1/2/3/4
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_10MHz; //速度 10MHz
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP; //复用推挽输出
GPIO_Init(GPIOB,&GPIO_InitStructure); //初始化 GPIOB
TIM_TimeBaseSrtructure.TIM_Period= TIM4_Reload_Num_ARR; //计数器 TIMx_CNT计数 从0累加到ARR次后溢出,设置自动重装载值
TIM_TimeBaseSrtructure.TIM_Prescaler=TIM4_Frequency_Divide_PSC; //设置预分频系数 PSC
TIM_TimeBaseSrtructure.TIM_ClockDivision=0; //采用时钟分割,见库函数。TIM_Clock_Division_CKD定义,查手册 00:Tdts=Tck_int:01:Tdts=2*Tck_int(2分频)
TIM_TimeBaseSrtructure.TIM_CounterMode=TIM_CounterMode_Up; //TIM 向上计数模式溢出
TIM_TimeBaseInit(TIM4,&TIM_TimeBaseSrtructure); //初始化TIM4的时钟参数
/* TIM外设初始化 */
TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1; //选择定时器模式:TIM 脉冲宽度调制模式1,模式1为比较低输出。
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
TIM_OCInitStructure.TIM_Pulse =(TIM2_Reload_Num_ARR+1)*0.5; //比较输出脉冲宽度,设置占空比(初始化用),即CCR
TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High; //输出极性:TIM输出比较极性高
TIM_OC1Init(TIM4,&TIM_OCInitStructure); //初始化TIM4 CH1的时钟,下同
TIM_OC2Init(TIM4,&TIM_OCInitStructure);
TIM_OC3Init(TIM4,&TIM_OCInitStructure);
TIM_OC4Init(TIM4,&TIM_OCInitStructure);
/* 初始化CH1/2/3/4 */
TIM_OC1PreloadConfig(TIM4,TIM_OCPreload_Enable); //CH1 预装载使能,功能在ARR和CCR1改变时,等他们计数完一个周期再修改
TIM_OC2PreloadConfig(TIM4,TIM_OCPreload_Enable); //CH2 预装载使能
TIM_OC3PreloadConfig(TIM4,TIM_OCPreload_Enable); //CH3 预装载使能
TIM_OC4PreloadConfig(TIM4,TIM_OCPreload_Enable); //CH4 预装载使能
TIM_ARRPreloadConfig(TIM4,ENABLE); //使能 TIMx在ARR上的预装载寄存器
TIM_Cmd(TIM4, ENABLE); //使能 TIM2
// NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); //设定中断优先级分组1,这个是我自加的
}
}
5 VehCtrl头文件(VehCtrl.h)
#ifndef _VehCtrl_H
#define _VehCtrl_H
# include "stm32f10x.h"
void VehCtrl_MotorEn_Int(void);
void Motor_EN(void);
#endif
6 VehCtrl程序(VehCtrl.c)
# include "stm32f10x_gpio.h"
# include "VehCtrl.h"
void VehCtrl_MotorEn_Int(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE); //使能C口GPIO时钟
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_PP; //选择推挽输出
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_0; //指定引脚PC0,MotEn2
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_10MHz; //设置输出速率50MHz//
GPIO_Init(GPIOC,&GPIO_InitStruct); //初始化外设GPIOC寄存器
GPIO_ResetBits(GPIOC, GPIO_Pin_0);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); //使能A口GPIO时钟
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_PP; //选择推挽输出
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_15; //指定引脚PA15,MotEn1
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_10MHz; //设置输出速率50MHz
GPIO_Init(GPIOA,&GPIO_InitStruct); //初始化外设GPIOA寄存器
GPIO_ResetBits(GPIOA, GPIO_Pin_15);
}
void Motor_EN(void)
{
GPIO_SetBits(GPIOA, GPIO_Pin_15); //PA15_MotorAB_EN
GPIO_SetBits(GPIOC, GPIO_Pin_0); //PC0_MotorAB_EN
}
#endif
6 输出结果
留意视频中小车状态与Debug Mode状态显示非同步。