STM32中发出脉冲一般有两种方式:
1)利用定时中断输出脉冲,但是间隔的延时会影响其他主程序的进程,当控制多个电机的时候就非常不可取;
2)利用PWM脉宽调制,并通过主从定时器进行设定,好处是不占用主程序时钟,且能精准控制;
下面以定时器1为主,定时器2为从进行配置:
PWM.c文件
#include "stm32f10x.h" // Device header
/***定时器1主模式,定时器2从模式***/
void TIM1_config(u16 Cycle)
{
GPIO_InitTypeDef GPIO_InitStructure; //GPIO设置,创建结构体
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;//定时器设置结构体
TIM_OCInitTypeDef TIM_OCInitStructure; //pwm波对应设置结构体
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_TIM1 , ENABLE); //开启时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//
GPIO_Init(GPIOA, &GPIO_InitStructure);
TIM_TimeBaseStructure.TIM_Period = Cycle-1;
TIM_TimeBaseStructure.TIM_Prescaler =71; //设置用来作为TIMx时钟频率除数的预分频值
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS= Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0; //重复计数,一定要=0!!!
TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure); //装载
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //选择定时器模式:TIM脉冲宽度调制模式1
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
TIM_OCInitStructure.TIM_Pulse = Cycle/2-1; //设置待装入捕获寄存器的脉冲值
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; //输出极性
TIM_OC1Init(TIM1, &TIM_OCInitStructure); //装载通道1,PA8
TIM_SelectMasterSlaveMode(TIM1, TIM_MasterSlaveMode_Enable);
//设置或者重置 TIMx 主/从模式
//TIMx: x 可以是 2, 3 或者 4,来选择 TIM 外设
//TIM_MasterSlaveMode:定时器主/从模式,TIM 主/从模式使能
TIM_SelectOutputTrigger(TIM1, TIM_TRGOSource_Update);
//选择 TIMx 触发输出模式
//TIMx: x 可以是 2, 3 或者 4,来选择 TIM 外设
//TIM_TRGOSource:触发输出模式
//TIM_TRGOSource_Update:使用更新事件作为触发输出(TRGO)
// TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable); //使能或者失能 TIMx 在 CCR3 上的预装载寄存器
TIM_ARRPreloadConfig(TIM1, ENABLE); // 使能或者失能 TIMx 在 ARR 上的预装载寄存器
//允许或禁止在定时器工作时向ARR的缓冲器中写入新值,以便在更新事件发生时载入覆盖以前的值
}
/***定时器2从模式***/
void TIM2_config(u16 PulseNum)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; //对应结构体声明
NVIC_InitTypeDef NVIC_InitStructure; //NVIC 对应结构体声明
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
TIM_TimeBaseStructure.TIM_Period = PulseNum-1;
TIM_TimeBaseStructure.TIM_Prescaler =0;
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
TIM_SelectInputTrigger(TIM2, TIM_TS_ITR0);//选择 TIMx 输入触发源,TIM 内部触发 0
TIM_SelectSlaveMode(TIM2,TIM_SlaveMode_External1 );// 等同 TIM2->SMCR|=0x07 //设置从模式寄存器
// TIM2->SMCR|=0x07; //设置从模式寄存器
TIM_ITConfig(TIM2,TIM_IT_Update,DISABLE); //
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
//入口设定函数
void Pulse_output(u16 Cycle,u16 PulseNum)
{
TIM1_config(Cycle); //装载
TIM_Cmd(TIM1, ENABLE);//使能
TIM_CtrlPWMOutputs(TIM1, ENABLE); //高级定时器一定要加上,主输出使能
TIM2_config(PulseNum);//装载
TIM_Cmd(TIM2, ENABLE);//使能
TIM_ClearITPendingBit(TIM2,TIM_IT_Update);//清除TIMx 的中断待处理位
TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE); //使能或者失能指定的 TIMx 中断
}
//中断处理函数
void TIM2_IRQHandler(void)
{
if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET) // TIM_IT_CC1
{
TIM_ClearITPendingBit(TIM2, TIM_IT_Update); // 清除中断标志位
TIM_CtrlPWMOutputs(TIM1, DISABLE); //主输出使能
TIM_Cmd(TIM1, DISABLE); // 关闭定时器
TIM_Cmd(TIM2, DISABLE); // 关闭定时器
TIM_ITConfig(TIM2, TIM_IT_Update, DISABLE);
}
}
PWM.h文件
#ifndef __PWM_H
#define __PWM_H
void Pulse_output(u16 Cycle,u16 PulseNum);//入口函数
void TIM1_config(u16 Cycle);//1为主模式
void TIM2_config(u16 PulseNum);//2为从模式
#endif
主函数调用:
Pulse_output(1000,8000);//1KHZ,8000个脉冲
其中/TIM_SelectInputTrigger(TIM1, TIM_TS_ITR2);中的参数需要注意,参考手册查对应的可用连接,如下:
问题:
ARR的值最高只能是65535,所以这种方法最多只能输出65535个脉冲。有待改进。
解决方法:(2024.10.26)
将需要发送的脉冲数拆分为高16位和低16位,没进入中断前将低16位装载到从定时器的ARR,第一次进入中断再将高16位装载到从定时器ARR,第二次进入中断关闭脉冲输出和定时器。
完整代码:
#include "stm32f10x.h" // 包含STM32F10x系列的设备头文件
// 定义全局变量
volatile u16 PulseNum_High = 0; // 高16位脉冲计数
volatile u16 PulseNum_Low = 0; // 低16位脉冲计数
volatile int pulseStage = 0; // 脉冲阶段标志
/**
* @brief 配置TIM1定时器
*/
void TIM1_config(void)
{
GPIO_InitTypeDef GPIO_InitStructure; // 定义GPIO初始化结构体
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; // 定义TIM1时间基础初始化结构体
TIM_OCInitTypeDef TIM_OCInitStructure; // 定义TIM1输出比较初始化结构体
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE); // 使能TIM1时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // 使能GPIOA时钟
// 配置GPIOA的Pin8为复用推挽输出模式
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// 配置TIM1时间基础
TIM_TimeBaseStructure.TIM_Period = 100-1; // 定时周期为99,即100个计数周期
TIM_TimeBaseStructure.TIM_Prescaler = 720-1; // 预分频器为719,即720分频
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; // 时钟分频为1
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; // 向上计数模式
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0; // 重复计数器为0
TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure); // 初始化TIM1时间基础
// 配置TIM1输出比较模式
TIM_OCStructInit(&TIM_OCInitStructure); // 初始化输出比较结构体
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; // PWM模式1
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; // 输出使能
TIM_OCInitStructure.TIM_Pulse = 50; // 比较值为50
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; // 输出极性为高
TIM_OC1Init(TIM1, &TIM_OCInitStructure); // 初始化TIM1通道1的输出比较模式
TIM_SelectMasterSlaveMode(TIM1, TIM_MasterSlaveMode_Enable); // 使能主从模式
TIM_SelectOutputTrigger(TIM1, TIM_TRGOSource_Update); // 选择触发输出源为更新事件
TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable); // 使能通道1的CCR预装载
TIM_ARRPreloadConfig(TIM1, ENABLE); // 使能自动重装载寄存器预装载
TIM_CtrlPWMOutputs(TIM1, DISABLE); // 关闭TIM1的PWM输出
TIM_Cmd(TIM1, DISABLE); // 关闭TIM1
}
/**
* @brief 配置TIM2定时器
*/
void TIM2_config(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; // 定义TIM2时间基础初始化结构体
NVIC_InitTypeDef NVIC_InitStructure; // 定义NVIC初始化结构体
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); // 使能TIM2时钟
// 配置TIM2时间基础
TIM_TimeBaseStructure.TIM_Period = 65535; // 定时周期为65535
TIM_TimeBaseStructure.TIM_Prescaler = 0; // 预分频器为0
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; // 时钟分频为1
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; // 向上计数模式
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); // 初始化TIM2时间基础
TIM_SelectInputTrigger(TIM2, TIM_TS_ITR0); // 选择输入触发源为内部触发器0
TIM_SelectSlaveMode(TIM2, TIM_SlaveMode_External1); // 选择从模式为外部触发模式1
TIM_ITConfig(TIM2, TIM_IT_Update, DISABLE); // 禁用TIM2更新中断
TIM_ARRPreloadConfig(TIM2, ENABLE); // 使能自动重装载寄存器预装载
// 配置NVIC
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); // 配置优先级分组为2
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; // 中断通道为TIM2
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; // 抢占优先级为0
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; // 子优先级为0
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // 使能中断通道
NVIC_Init(&NVIC_InitStructure); // 初始化NVIC
TIM_Cmd(TIM2, DISABLE); // 关闭TIM2
}
/**
* @brief 输出指定周期和数量的脉冲
* @param Cycle 周期值,对应TIM1的ARR
* @param PulseNum 脉冲数量,最大为65535
*/
void Pulse_output(u16 Cycle, u32 PulseNum)
{
// 如果脉冲数量大于65535,则需要使用高位和低位计数
if(PulseNum >= 65536)
{
PulseNum_High = (PulseNum >> 16) * 65536 - 1; // 计算高16位计数值
PulseNum_Low = (PulseNum & 0xFFFF) - 1; // 计算低16位计数值
pulseStage = 0; // 设置脉冲阶段为高16位
}
else
{
PulseNum_High = 0; // 高16位计数值为0
PulseNum_Low = (PulseNum & 0xFFFF) - 1; // 计算低16位计数值
pulseStage = 1; // 设置脉冲阶段为低16位
}
TIM1_config(); // 配置TIM1
TIM2_config(); // 配置TIM2
TIM_Cmd(TIM2, DISABLE); // 关闭TIM2
TIM_SetAutoreload(TIM2, PulseNum_Low); // 设置TIM2的自动重装载寄存器为低16位计数值
TIM_GenerateEvent(TIM2, TIM_EventSource_Update); // 触发TIM2更新事件以更新ARR
TIM_Cmd(TIM2, ENABLE); // 开启TIM2
TIM_ClearITPendingBit(TIM2, TIM_IT_Update); // 清除TIM2更新中断标志
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); // 使能TIM2更新中断
TIM_SetAutoreload(TIM1, Cycle); // 设置TIM1的自动重装载寄存器为周期值
TIM_GenerateEvent(TIM1, TIM_EventSource_Update); // 触发TIM1更新事件以更新ARR
TIM_SetCompare1(TIM1, Cycle / 2); // 设置TIM1的比较值为周期值的一半,以生成50%占空比的PWM
TIM_GenerateEvent(TIM1, TIM_EventSource_CC1); // 触发TIM1捕获/比较事件
TIM_CtrlPWMOutputs(TIM1, ENABLE); // 开启TIM1的PWM输出
TIM_Cmd(TIM1, ENABLE); // 开启TIM1
}
/**
* @brief TIM2中断服务函数
*/
void TIM2_IRQHandler(void)
{
if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET) // 检查是否为TIM2更新中断
{
TIM_ClearITPendingBit(TIM2, TIM_IT_Update); // 清除TIM2更新中断标志
if (pulseStage == 0) // 如果处于高16位计数阶段
{
pulseStage = 1; // 切换到低16位计数阶段
TIM_Cmd(TIM2, DISABLE); // 关闭TIM2
TIM_SetAutoreload(TIM2, PulseNum_High); // 设置TIM2的自动重装载寄存器为高16位计数值
TIM_GenerateEvent(TIM2, TIM_EventSource_Update); // 触发TIM2更新事件以更新ARR
TIM_Cmd(TIM2, ENABLE); // 开启TIM2
TIM_ClearITPendingBit(TIM2, TIM_IT_Update); // 清除TIM2更新中断标志
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); // 使能TIM2更新中断
}
else // 如果处于低16位计数阶段
{
// 脉冲输出完成,停止定时器
TIM_CtrlPWMOutputs(TIM1, DISABLE); // 关闭TIM1的PWM输出
TIM_Cmd(TIM1, DISABLE); // 关闭TIM1
TIM_Cmd(TIM2, DISABLE); // 关闭TIM2
TIM_ITConfig(TIM2, TIM_IT_Update, DISABLE); // 禁用TIM2更新中断
}
}
}