本帖最后由 LiuDW091 于 2025-8-25 17:02 编辑
最近研究了下怎么输出波形,现在来呈现给大家
一、硬件
通过查找datasheet可以知道TMR1在PA8脚属于复位引脚。准备配置PA8为PWM输出脚
还可以得知在AF2,挂在APB2上,如果不知道在哪里,也可以通过程序查找
硬件原理图查到PA8在哪里,方便连线
二、代码
#include "apm32e030.h"
#include "apm32e030_gpio.h"
#include "apm32e030_tmr.h"
#include "apm32e030_rcm.h"
#include "delay.h"
/**
* @brief 初始化TIM1通道1输出PWM
* @param TIM1_CH1输出,产生1kHz PWM,初始占空比50%
*/
void PWM_Init_TMR1_CH1(void)
{
GPIO_Config_T gpioConfig;
TMR_TimeBase_T baseConfig;
TMR_OCConfig_T ocConfig;
/* 1. 开启外设时钟 */
RCM_EnableAHBPeriphClock(RCM_AHB_PERIPH_GPIOA); // 开启GPIOA时钟
RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_TMR1); // TMR1挂在APB2总线
/* 2. 配置GPIOA Pin8 为复用功能(AF) - TMR1_CH1 */
GPIO_ConfigStructInit(&gpioConfig); // 初始化结构体为默认值
gpioConfig.pin = GPIO_PIN_8;
gpioConfig.mode = GPIO_MODE_AF; // 复用功能模式
gpioConfig.speed = GPIO_SPEED_50MHz; // 高速
gpioConfig.outtype = GPIO_OUT_TYPE_PP; // 推挽输出
gpioConfig.pupd = GPIO_PUPD_NO; // 无上下拉
GPIO_Config(GPIOA, &gpioConfig);
// 配置PA8的复用功能为TIM1_CH1
// 根据APM32E030参考手册确认正确的AF编号,是GPIO_AF_PIN2
GPIO_ConfigPinAF(GPIOA, GPIO_PIN_SOURCE_8, GPIO_AF_PIN2);
/* 3. 配置TIM1时基单元 - 产生1kHz PWM */
// 系统时钟为72MHz
baseConfig.div = 72 - 1; // PSC = 71, 72分频 → 1MHz定时器时钟
baseConfig.period = 1000 - 1; // ARR = 999 → PWM周期1000个计数
baseConfig.counterMode = TMR_COUNTER_MODE_UP; // 向上计数模式
baseConfig.clockDivision = TMR_CKD_DIV1; // 时钟不分频
baseConfig.repetitionCounter = 0; // 重复计数寄存器(高级定时器必需)
TMR_ConfigTimeBase(TMR1, &baseConfig);
/* PWM频率计算:
* 定时器时钟 = 72MHz / (71+ 1) = 1MHz
* PWM频率 = 1MHz / (999 + 1) = 1000Hz = 1kHz
*/
/* 4. 配置TIM1通道1为PWM模式 */
TMR_OCConfigStructInit(&ocConfig);
ocConfig.OC_Mode = TMR_OC_MODE_PWM1;// 使用辅助函数初始化结构体
ocConfig.OC_OutputState = TMR_OUTPUT_STATE_ENABLE; // 使能主输出
ocConfig.OC_OutputNState = TMR_OUTPUT_NSTATE_DISABLE; // 禁用互补输出
ocConfig.Pulse = 500; // 初始占空比50% (500/1000)
ocConfig.OC_Polarity = TMR_OC_POLARITY_HIGH; // 高电平有效
ocConfig.OC_NPolarity = TMR_OC_NPOLARITY_HIGH; // 互补输出极性
ocConfig.OC_Idlestate = TMR_OCIDLESTATE_RESET; // 空闲状态输出低
ocConfig.OC_NIdlestate = TMR_OCNIDLESTATE_RESET; // 互补空闲状态输出低
TMR_OC1Config(TMR1, &ocConfig); // 应用配置到通道1
/* 5. 使能自动重装载预装载寄存器 */
TMR_EnableAUTOReload(TMR1);
/* 6. 【重要】对于高级定时器TMR1,必须使能主输出(MOE) */
TMR_EnablePWMOutputs(TMR1);
/* 7. 启动TMR1计数器 */
TMR_Enable(TMR1);
}
/**
* @brief 动态改变PWM占空比
* @param duty: 占空比值 (0-1000, 对应0%-100%)
* @retval 无
*/
void PWM_SetDuty(uint16_t duty)
{
// 确保duty值不超过ARR范围
if (duty > 1000) {
duty = 1000;
}
TMR_SetCompare1(TMR1, duty); // 使用TMR_SetCompare1
}
/**
* @brief 主函数示例
*/
int main(void)
{
// 系统时钟初始化
SystemInit();
// 初始化PWM
PWM_Init_TMR1_CH1();
// 设置初始占空比
// PWM_SetDuty(300); // 30%占空比
// 固定占空比变化
PWM_SetDuty(100); // 50%占空比
Delay_ms(10);
/*
while (1) {
// 在这里可以动态调整占空比
// 例如:呼吸灯效果
for (uint16_t i = 0; i <= 1000; i += 10) {
PWM_SetDuty(i);
Delay_ms(10);
}
for (uint16_t i = 1000; i > 0; i -= 10) {
PWM_SetDuty(i);
Delay_ms(10);
}
}
*/
}
/**
* @brief 简单延时函数
*/
延迟函数就不写了,这个网上都有,可以找到,或者看我前面的测评
注:不同的库版本对应的变量名可能不同,需要自己更改
注:可以输出固定占空比的方波,也可以输出占空比可变的方波
三、实验效果
视频:
代码:
PWM.zip
(39.88 KB, 下载次数: 0)
将PWM波通过转接板,接入电机,驱动电机效果如下:
视频:
|