PWM的说明

PWM有三个关键指标: PWM频率, 占空比, 区分度

对于同一个时钟频率下工作的单片机, 区分度是和PWM工作频率相关的, 因为总频率是固定的, PWM工作频率越高, 留下给区分度的部分就越低, 因此区分度就越低. 对于STM32, 如果时钟是72MHz, 在PWM频率为1KHz时, 区分度为16bit, 在281KHz时, 为8bit, 在4.5MHz时, 就是4bit了.

STM32F4 Timers

STM32的PWM功能是定时器功能的一部分, STM32F4系列完整的定时器是14个

Timer Type Resolution Prescaler Channels MAX INTERFACE CLOCK MAX TIMER CLOCK* APB
TIM1, TIM8 Advanced 16bit 16bit 4 SysClk/2 SysClk 2
TIM2, TIM5 General purpose 32bit 16bit 4 SysClk/4 SysClk, SysClk/2 1
TIM3, TIM4 General purpose 16bit 16bit 4 SysClk/4 SysClk, SysClk/2 1
TIM9 General purpose 16bit 16bit 2 SysClk/2 SysClk 2
TIM10, TIM11 General purpose 16bit 16bit 1 SysClk/2 SysClk 2
TIM12 General purpose 16bit 16bit 2 SysClk/4 SysClk, SysClk/2 1
TIM13, TIM14 General purpose 16bit 16bit 1 SysClk/4 SysClk, SysClk/2 1
TIM6, TIM7 Basic 16bit 16bit 0 SysClk/4 SysClk, SysClk/2 1

F401属于低端系列, 定时器只有一部分, 内置的定时器为

  • 1个高级定时器TIM1

    • 三相 PWM 输出, 4个独立通道(如果正反算两个的话有8个). It has complementary PWM outputs with programmable inserted dead times
  • 7个通用定时器
    • 全功能的: TM2&5, TIM3&4, 4个独立通道 for input capture/output compare, PWM or one-pulse mode output.
    • 普通的: TIM9, TIM10,11. TIM10和TIM11有1个独立通道, TIM9有2个独立通道 for input capture/output compare, PWM or one-pulse mode output.
  • 2个watchdog timers

每个定时器都有对应的通道数, 一般都有CH1 - CH4, 对于TIM1, 还有CH1N - CH4N

关于CH1和CH1N

后者输出相对于前者反相的PWM信号, CH1和CH1N两个通道互补输出. 在设置这两个通道输出的时候如果开启了互补输出, 那么这两个引脚的输出电平始终相反, 也就是一个引脚输出低电平, 另一个引脚自动输出高电平, 反之亦然. 这样的输出方式一般用于电机驱动控制.

STM32F4的TIMx PIN脚输出映射关系

TIM1 TIM2 TIM3 TIM9
CH1 PA8 PA0 PA5 PA15 PA6 PB4 PA2
CH2 PA9 PA1 PB3 PA7 PB5 PA3
CH3 PA10 PA2 PB10 PB0
CH4 PA11 PA3 PB11 PB1
CH1N PB13 PA7
CH2N PB14 PB0
CH3N PB15 PB1

设置PWM输出电平的模式

PWM输出模式的配置主要有两个

1. TIM_OCMode: TIM输出比较和PWM模式

  • TIM_OCMode_Timing 在比较成功后不在对应输出管脚上产生输出, TIM_OCMode_Timing does not produce output on the corresponding output pin after a successful comparison
  • TIM_OCMode_Active
  • TIM_OCMode_Inactive
  • TIM_OCMode_Toggle 计数达到比较值时翻转对应输出管脚上的电平, TIM_OCMode_Toggle is to flip the level on the corresponding output pin after a successful comparison
  • TIM_OCMode_PWM1 常用的模式, CNT < CRRx时为有效电平, CNT > CRRx为无效电平
  • TIM_OCMode_PWM2 与PWM1相反, CNT小于时为无效电平, 高于时为有效电平, 配合TIM_OCPolarity可以做到和PWM1一样的输出

2. TIM_OCPolarity: PWM的有效电平

与TIM_OCMode_PWM1和TIM_OCMode_PWM2配合, TIM_OCPolarity_High表示有效电平是高电平, TIM_OCPolarity_Low是低电平. 一般使用PWM1+HIGH的组合.

上面两个配置结合产生的效果

  • TIM_OCMode_PWM1模式下

    • 设置TIM_OCPolarity_High, TIMx_CNT > TIMx_CCR输出高电平, TIMx_CNT < TIMx_CCR输出低电平
    • 设置TIM_OCPolarity_Low, TIMx_CNT > TIMx_CCR输出低电平, TIMx_CNT < TIMx_CCR输出高电平
  • TIM_OCMode_PWM2模式下
    • 设置TIM_OCPolarity_High, TIMx_CNT > TIMx_CCR输出低电平, TIMx_CNT < TIMx_CCR输出高电平
    • 设置TIM_OCPolarity_Low, TIMx_CNT > TIMx_CCR输出高电平, TIMx_CNT < TIMx_CCR输出低电平

设置PWM频率

设置PWM频率, 即设置PWM完整周期的时钟计数次数. 这个是通过TIM_BaseStruct.TIM_Period(ARR寄存器)设置的, 要设置这个值, 首先你要知道这个值的上限, 即定时器的最大值, 例如 16bit 即 65535, 要计算出PWM频率, 可以这样计算

PWM_frequency = timer_tick_frequency / (TIM_Period + 1)

也可以通过PWM频率倒推时钟周期计数值

TIM_Period = timer_tick_frequency / PWM_frequency - 1

例如, 如果需要的PWM频率为10KHz, 则时钟的周期计数值为

TIM_Period = (84000000 / 10000) - 1; // 8399

如果需要17.57 Khz, 就是

TIM_Period = (SystemCoreClock / 17570 ) - 1;

如果通过这个式子算出来的计数值大于定时器长度(例如超过了65535), 你需要增大 prescaler, 降低系统时钟频率

如果需要在运行时修改, 可以使用函数TIM_PrescalerConfig(TIM2, 35999, TIM_PSCReloadMode_Immediate), 这个函数的作用就是在定时器工作时改变预分频器的值.

设置PWM占空比

设置占空比, 需要通过设置 TIM_Pulse 参数, 这个值就是用于比较的触发值CRR, TIM_OCInitStructure.TIM_Pulse = 100表示触发值为100, 这个值的计算要结合PWM周期总计数值TIM_Period和需要的占空比百分比, 例如

pulse_length = ((TIM_Period + 1) * DutyCycle) / 100 - 1
# 其中DutyCycle是一个百分比, 例如对于TIM_Period为8399, 如果需要25%占空比
pulse_length = (8399 + 1) * 0.25 - 1 = 2099

如果需要在运行时修改, 你可以:

  1. You just write the updated width to the TIMx_CCRy register. Changed the CCR value in the relevant timer register and this did the trick. In my case, the code used to change the duty cycle is 'TIM3 -> CCR4 = {required value}'
  2. 通过调用TIM_SetCompare[x](TIMx, Compare1)这个函数,修改CCR的值,改变输出占空比, 例如TIM_SetCompare1函数名中的数字1代表的是TIMx的通道1, 参数TIMx可以是TIM1, TIM2等, 第二个参数 Compare1, 是用于与TIMx计数值比较的数, 在TIMx达到这个计数值时将根据当前的模式和极性, 进行电平变换. TIM_SetCompareX这个函数有四个, 分别是TIM_SetCompare1, TIM_SetCompare2, TIM_SetCompare3, TIM_SetCompare4. 对应不同的CHx使用, 例如TIMx_CH1使用 TIM_SetCompare1, TIMx_CH2使用TIM_SetCompare2, 等等.
void TIM_SetCompare1(TIM_TypeDef* TIMx, uint16_t Compare1) {
/* Check the parameters */
assert_param(IS_TIM_LIST8_PERIPH(TIMx));
/* Set the Capture Compare1 Register value */
TIMx->CCR1 = Compare1;
}

控制直流马达的方向

控制直流马达的模块有两种, 一种是L293D这种三线输入的模块, AB线的电压差确定转向, E线输入PWM确定转速, 另一种是L298N和L9110s这种双线输入的模块, 根据两根线的电压差决定方向, 根据线上的PWM决定转速. 对于前者, 需要两根GPIO加一根PWM输出, 对于后者, 需要两根PWM输出, PWM加在正向的PIN脚上, 另一个PIN脚PWM设为0.

对于后者的控制代码例子如下

/*
双轴摇杆: PIN脚朝左, X轴左小右大, Y轴上小下大
前进: X中,Y小
后退: X中,Y大
左转: X小,Y中
右转: X大,Y中
*/
void AdjustChannelPuls(u8 axis_x, u8 axis_y) {
int8_t l, r;
calc(axis_x, axis_y, &l, &r);
printf("X:%d, Y:%d, L:%d, R:%d\r\n", axis_x, axis_y, l, r);
if (l >= 0) {
Channel1Pulse = CalcPuls(l);
Channel3Pulse = CalcPuls(0);
} else {
Channel1Pulse = CalcPuls(0);
Channel3Pulse = CalcPuls(-l);
}
if (r >= 0) {
Channel2Pulse = CalcPuls(r);
Channel4Pulse = CalcPuls(0);
} else {
Channel2Pulse = CalcPuls(0);
Channel4Pulse = CalcPuls(-r);
}
TIM_ResetCounter(TIM3);
} void UpdatePWM(void) {
TIM_SetCompare1(TIM2, Channel1Pulse);
TIM_SetCompare2(TIM2, Channel2Pulse);
TIM_SetCompare3(TIM2, Channel3Pulse);
TIM_SetCompare4(TIM2, Channel4Pulse);
}

代码

启动对应输出口的定时器, 这里是TIM4

void TM_TIMER_Init(void) {
TIM_TimeBaseInitTypeDef TIM_BaseStruct; /* 开启TIM4时钟 */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
/*
TIM4连接的是 APB1 总线, 在F407上时钟是 42MHz, 但是有内部PLL, 将频率翻倍为 84MHz. 注意: 也有定时器是接在 APB2 总线上的, 默认工作在 84MHz, 通过内部PLL翻倍至 168MHz 设置预分频 timer prescaller
时钟被设置为 timer_tick_frequency = Timer_default_frequency / (prescaller_set + 1)
在这个例子中, 我们希望使用最大频率, 所以 prescaller 设置为 0, 所以时钟与总线时钟一致, 频率为
timer_tick_frequency = 84000000 / (0 + 1) = 84000000
*/
TIM_BaseStruct.TIM_Prescaler = 0;
/* 使用上升沿计数 */
TIM_BaseStruct.TIM_CounterMode = TIM_CounterMode_Up;
/*
设置一个PWM完整周期的时钟计数次数, 首先你要知道定时器的最大值, 在这个例子中是16bit, 即 65535, 要计算出你的PWM频率, 可以这样计算
PWM_frequency = timer_tick_frequency / (TIM_Period + 1)
通过这个算式也可以通过PWM频率倒推时钟周期计数值
TIM_Period = timer_tick_frequency / PWM_frequency - 1
在这个例子中, 如果需要的PWM频率为10KHz, 则时钟的周期计数值为
TIM_Period = 84000000 / 10000 - 1 = 8399 如果通过这个式子算出来的计数值大于定时器长度(例如超过了65535), 你需要增大 prescaler 降低系统时钟频率
*/
TIM_BaseStruct.TIM_Period = 8399; /* 10kHz PWM */
/* TIM_ClockDivision的设置不影响PWM频率 */
TIM_BaseStruct.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_BaseStruct.TIM_RepetitionCounter = 0;
/* TIM4 初始化 */
TIM_TimeBaseInit(TIM4, &TIM_BaseStruct);
/* TIM4 开始计数 */
TIM_Cmd(TIM4, ENABLE);
}

初始化PWM 4个通道

void TM_PWM_Init(void) {
TIM_OCInitTypeDef TIM_OCStruct; /* 通道的公用配置 */ /* PWM 模式 2 = Clear on compare match 达到预设值时拉低电平 */
/* PWM 模式 1 = Set on compare match 达到预设值时拉高电平 */
TIM_OCStruct.TIM_OCMode = TIM_OCMode_PWM2;
TIM_OCStruct.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCStruct.TIM_OCPolarity = TIM_OCPolarity_Low; /*
要得到期望的占空比(DutyCycle, 一个百分比), 通过这个式子计算定时器触发值
pulse_length = ((TIM_Period + 1) * DutyCycle) / 100 - 1
例如
25% 占空比: pulse_length = ((8399 + 1) * 25) / 100 - 1 = 2099
50% 占空比: pulse_length = ((8399 + 1) * 50) / 100 - 1 = 4199
75% 占空比: pulse_length = ((8399 + 1) * 75) / 100 - 1 = 6299
100% 占空比: pulse_length = ((8399 + 1) * 100) / 100 - 1 = 8399 注意: 如果触发值大于时钟周期总长度 TIM_Period, 这个PWM将一直输出同样的电平
*/
TIM_OCStruct.TIM_Pulse = 2099; /* 25% duty cycle */
TIM_OC1Init(TIM4, &TIM_OCStruct);
TIM_OC1PreloadConfig(TIM4, TIM_OCPreload_Enable); TIM_OCStruct.TIM_Pulse = 4199; /* 50% duty cycle */
TIM_OC2Init(TIM4, &TIM_OCStruct);
TIM_OC2PreloadConfig(TIM4, TIM_OCPreload_Enable); TIM_OCStruct.TIM_Pulse = 6299; /* 75% duty cycle */
TIM_OC3Init(TIM4, &TIM_OCStruct);
TIM_OC3PreloadConfig(TIM4, TIM_OCPreload_Enable); TIM_OCStruct.TIM_Pulse = 8399; /* 100% duty cycle */
TIM_OC4Init(TIM4, &TIM_OCStruct);
TIM_OC4PreloadConfig(TIM4, TIM_OCPreload_Enable);
}

初始化GPIO输出

void TM_LEDS_Init(void) {
GPIO_InitTypeDef GPIO_InitStruct; /* GPIOD 时钟 */
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE); /* 设置这些PIN脚的功能复用 */
GPIO_PinAFConfig(GPIOD, GPIO_PinSource12, GPIO_AF_TIM4);
GPIO_PinAFConfig(GPIOD, GPIO_PinSource13, GPIO_AF_TIM4);
GPIO_PinAFConfig(GPIOD, GPIO_PinSource14, GPIO_AF_TIM4);
GPIO_PinAFConfig(GPIOD, GPIO_PinSource15, GPIO_AF_TIM4); /* 设置PIN脚 */
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_Init(GPIOD, &GPIO_InitStruct);
}

完整的代码

#include "defines.h"
#include "stm32f4xx.h"
#include "stm32f4xx_rcc.h"
#include "stm32f4xx_gpio.h"
#include "stm32f4xx_tim.h" TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
u16 TimerPeriod = 0;
u16 Channel1Pulse = 0, Channel2Pulse = 0, Channel3Pulse = 0, Channel4Pulse = 0; void DecreasePuls() {
Channel1Pulse = (Channel1Pulse <= 10)? TimerPeriod : Channel1Pulse - 10;
Channel2Pulse = (Channel2Pulse <= 10)? TimerPeriod : Channel2Pulse - 10;
Channel3Pulse = (Channel3Pulse <= 10)? TimerPeriod : Channel3Pulse - 10;
Channel4Pulse = (Channel4Pulse <= 10)? TimerPeriod : Channel4Pulse - 10;
} void TIM_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure; /* GPIOA, GPIOB Clocks enable */
RCC_AHB1PeriphClockCmd( RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOB , ENABLE); /* GPIOA Configuration: Channel 1, 2, 3, 4 as alternate function push-pull */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP ;
GPIO_Init(GPIOA, &GPIO_InitStructure); GPIO_PinAFConfig(GPIOA, GPIO_PinSource0, GPIO_AF_TIM2);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource1, GPIO_AF_TIM2);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource2, GPIO_AF_TIM2);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource3, GPIO_AF_TIM2);
} int main(void)
{
Systick_Init();
USART1_Init(); TIM_Config(); /* Compute the value to be set in ARR register to generate signal frequency at 17.57 Khz */
TimerPeriod = (SystemCoreClock / 17570 ) - 1;
/* Compute CCR1 value to generate a duty cycle at 100% for channel 1 and 1N */
Channel1Pulse = (u16) (((u32) 10 * (TimerPeriod - 1)) / 10);
/* Compute CCR2 value to generate a duty cycle at 30% for channel 2 and 2N */
Channel2Pulse = (u16) (((u32) 300 * (TimerPeriod - 1)) / 1000);
/* Compute CCR3 value to generate a duty cycle at 20% for channel 3 and 3N */
Channel3Pulse = (u16) (((u32) 20 * (TimerPeriod - 1)) / 100);
/* Compute CCR4 value to generate a duty cycle at 10% for channel 4 */
Channel4Pulse = (u16) (((u32) 100 * (TimerPeriod- 1)) / 1000); /* TIM2 clock enable */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); /* Time Base configuration */
TIM_TimeBaseStructure.TIM_Prescaler = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseStructure.TIM_Period = TimerPeriod;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
//TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); /* Channel 1, 2,3 and 4 Configuration in PWM mode */
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; // PWM: trigger from valid -> invalid
// TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;
//TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;
// Specifies the TIM Output Compare pin state during Idle state, ## valid only for TIM1 and TIM8 ##
//TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;
//TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCIdleState_Reset; //Specifies the TIM Output Compare state
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStructure.TIM_Pulse = Channel1Pulse;
TIM_OC1Init(TIM2, &TIM_OCInitStructure);
// TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Enable); TIM_OCInitStructure.TIM_Pulse = Channel2Pulse;
TIM_OC2Init(TIM2, &TIM_OCInitStructure);
// TIM_OC2PreloadConfig(TIM2, TIM_OCPreload_Enable); TIM_OCInitStructure.TIM_Pulse = Channel3Pulse;
TIM_OC3Init(TIM2, &TIM_OCInitStructure);
// Enables or disables the TIMx peripheral Preload register on CCR1
// TIM_OC3PreloadConfig(TIM2, TIM_OCPreload_Enable); TIM_OCInitStructure.TIM_Pulse = Channel4Pulse;
TIM_OC4Init(TIM2, &TIM_OCInitStructure);
// TIM_OC4PreloadConfig(TIM2, TIM_OCPreload_Enable); // TIM_ARRPreloadConfig(TIM2, ENABLE); /* TIM2 counter enable */
TIM_Cmd(TIM2, ENABLE); /* TIM2 Main Output Enable */
TIM_CtrlPWMOutputs(TIM2, ENABLE); // Enables or disables the TIM peripheral Main Outputs. while (1)
{
printf("TP:%d, CH1:%d, CH2:%d, CH3:%d, CH4:%d\r\n", TimerPeriod, Channel1Pulse, Channel2Pulse, Channel3Pulse, Channel4Pulse);
DecreasePuls();
TIM_SetCompare1(TIM2, Channel1Pulse);
TIM_SetCompare2(TIM2, Channel2Pulse);
TIM_SetCompare3(TIM2, Channel3Pulse);
TIM_SetCompare4(TIM2, Channel4Pulse);
Systick_Delay_ms(100);
}

代码中的几个函数的说明

TIM_OC4PreloadConfig

TIM_OC4PreloadConfig(TIM2, TIM_OCPreload_Enable);

使能TIM2 在 CCR4 上的预装载寄存器, 即 TIM2_CCR4 的预装载值在更新事件到来时才能被传送至当前寄存器中. 就是设置 CCR4 中的预装载值何时被传送到当前的CNT寄存器中, 设置为ENABLE, 表示仅当更新事件到来的时候才装载, 追踪寄存器的设置可知, 原来设置的是CCMR1的OC2PE, 其实还有一种方式是立即装载. OC1PE:输出比较1预装载使能(Output compare 1 preload enable)位3

  • 0:禁止TIMx_CCR1寄存器的预装载功能, 可随时写入TIMx_CCR1寄存器, 并且新写入的数值立即起作用
  • 1:开启TIMx_CCR1寄存器的预装载功能, 读写操作仅对预装载寄存器操作, TIMx_CCR1的预装载值在更新事件到来时被传送至当前寄存器中

TIM_ARRPreloadConfig

TIM_ARRPreloadConfig的作用, 是允许或禁止在定时器工作时向ARR的缓冲器中写入新值, 以便在更新事件发生时载入覆盖以前的值. 如果在初始化的时候设置了ARR的值TIM_TimeBaseStructure.TIM_Period=2000;, 后来也没更改(没有编写中断服务函数或者在中断服务函数中没有给ARR缓冲器重新写入新值), 那么设置为DISABLE 和ENABLE都没有影响, 这个方法可以不写.

参考

STM32F401的PWM输出的更多相关文章

  1. Arduino学习经验(一)之解决舵机库和pwm输出冲突

    一.前言 最近在公司学习Arduino uno ,用它实现小车超声波避障功能.实现的功能很简单,就是在小车前方挂一个超声波模块,当碰到障碍物时,会通过舵机进行摆头,判断两边的距离,进行左右转弯.但是碰 ...

  2. 关于普通定时器与高级定时器的 PWM输出的初始化的区别

    不管是普通定时器还是高级定时器,你用哪个通道,就在程序里用OC多少.比如CH3对应OC3 TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;  TIM_ ...

  3. (五)转载:通用定时器PWM输出

    1.     TIMER输出PWM基本概念 脉冲宽度调制(PWM),是英文“Pulse Width Modulation”的缩写,简称脉宽调制,是利用微处理器的数字输出来对模拟电路进行控制的一种非常有 ...

  4. 16路PWM输出的pca9685模块

    今天要介绍的就是该模块,该模块是16路pwm模块,使用I2C总线可以控制16路舵机(led). 接线OE空着就可以,其他VCC是芯片供电+5,SCL时钟线,SDA信号线,GND地线. 芯片介绍可以看: ...

  5. 关于STM32CubeMX使用LL库设置PWM输出

    HAL和LL库 HAL是ST为了实现代码在ST家族的MCU上的移植性,推出的一个库,称为硬件抽象层,很明显,这样做将会牺牲存储资源,所以项目最后的代码比较冗余,且运行效率大大降低,运行速度受制于fla ...

  6. TIMER门控模式控制PWM输出长度

    TIMER门控模式控制PWM输出长度 参照一些网友代码做了些修改,由TIM4来控制TIM2的PWM输出长度, 采用主从的门控模式,即TIM4输出高时候TIM2使能输出 //TIM2 PWM输出,由TI ...

  7. STM32 PWM输出(映射)

    STM32 的定时器除了 TIM6 和 7.其他的定时器都可以用来产生 PWM 输出.其中高级定时器 TIM1 和 TIM8 可以同时产生多达 7 路的 PWM 输出.而通用定时器也能同时产生多达 4 ...

  8. STM32 HAL库学习系列第4篇 定时器TIM----- 开始定时器与PWM输出配置

    基本流程: 1.配置定时器 2.开启定时器 3.动态改变pwm输出,改变值  HAL_TIM_PWM_Start(&htim4, TIM_CHANNEL_1); 函数总结: __HAL_TIM ...

  9. NUCLEO-L053R8 TIM定时器 PWM输出

    TIM2 PWM输出测试 今天给大伙分享一个TIM2 PWM输出小实验. 实验开发板:Nucleo-L053R8,即STM32L053R8T6. 开发环境:MDK5 图1 - 工程界面 本次实验测试的 ...

  10. STM32(7)——通用定时器PWM输出

    1.TIMER输出PWM基本概念         脉冲宽度调制(PWM),是英文“Pulse Width Modulation”的缩写,简称脉宽调制,是利用微处理器的数字输出来对模拟电路进行控制的一种 ...

随机推荐

  1. 修改Keil uvison4 字体样式

    1.点击扳手配置 2.点击Colors & Fonts,选择其中的8051:Editor C Files,选择Text,点击右侧的Courier New... 3.在里面就可以调节字体了

  2. 疯狂GC的第二种处理方式-ChatGPT的学习之四

    疯狂GC的第二种处理方式-ChatGPT的学习之四 摘要 上一个脚本太复杂了. 而且要改启动脚本. 课间休息跟人扯淡聊起来 chatGPT 发现他的语法很有用 但是思路不太对. 不过突然根据文档里写的 ...

  3. [转帖]企业nginx简单配置

    https://www.jianshu.com/p/6a3e298b31be 第五章 企业简单应用 网站访问方式 1.基于域名访问www.baidu.com 基于IP地址访问172.16.1.7配置文 ...

  4. 【转帖】JAVA GC日志分析

    https://zhuanlan.zhihu.com/p/613592552 ​ 目录 1. GC分类 针对HotSpot VM的实现,它里面的GC按照回收区域又分为两大种类型:一种是部分收集(Par ...

  5. [转帖]ELF文件详解

    一.ELF概述 1.ELF的定义 ELF(Executable and Linkable Format)文件是一种目标文件格式,常见的ELF格式文件包括:可执行文件.可重定位文件(.o).共享目标文件 ...

  6. [转帖]一个小技巧解决笔记本HDMI接口失灵

      https://baijiahao.baidu.com/s?id=1738289993804283647&wfr=spider&for=pc 现如今笔记本的接口是越来越多,哪怕是标 ...

  7. 一个PCI-E的硬盘参数

    看了下 HDD 随机 IOPS 在 100-200 之间 (读写) SATA的 SSD 随机IOPS 在 读 100k 写 20k 左右U.2的SSD 的随机IOPS 在 读 500k 写 50k 左 ...

  8. 分析fastcache和freecache(一)

    分析fastcache和freecache(一) fastcache和freecache是两个比较简单的缓存实现,下面分析一下各自的实现,并学习一下其实现中比较好的方式. fastcache 概述 f ...

  9. Liunx网络配置

    1.安装精简版:CentOS-7-x86_64-Minimal-2009.iso 2.进入配置文件:  vi /etc/sysconfig/network-scripts/ifcfg-ens33 3. ...

  10. go 1.21:cmp

    标准库 cmp 原文在这里 go 1.21 新增 cmp 包提供了与有序变脸比较相关的类型和函数. Ordered 定义如下: type Ordered interface { ~int | ~int ...