1 裸机
1.1工程建立
使用STM32CubeMX来生成工程,基本使用也可见链接
-
选择外部时钟
image.png -
选择SW调试
image.png -
串口1作为打印
image.png -
配置时钟,8M外部输入,32M系统时钟
image.png -
选择PA2为PWM的通道
image.png -
配置对于的时钟TIM2,选择通道3
image.png -
配置该PWM通道,系统时钟32M
image.png -
生产工程的配置
image.png
image.png -
最后生成的工程(GENERATE CODE)
1.2 分析生产的代码
主函数中初始化了GPIO和TIM,前者仅仅打开了GPIO的时钟,主要初始化在TIM中。
//main.h
MX_GPIO_Init();
MX_TIM2_Init();
在tim.c则进行了对于通道引脚初始化和定时器PWM初始化
//初始化PA2对于定时器TIM2的CH3
void HAL_TIM_MspPostInit(TIM_HandleTypeDef* timHandle)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(timHandle->Instance==TIM2)
{
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitStruct.Pin = GPIO_PIN_2;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF1_TIM2;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
}
定时器初始化的时候将进行时钟配置,这决定了PWM的频率,Prescaler表示分频数,表示如果最终分频到TIM的时钟是32M,那么实际使用时钟则是32/Prescaler。Period代表定时器计数达到多少后重新装填,对于PWM来说就代表了一个周期,所以PWM的频率就等于48M/Prescaler/Period。Pulse就对应占空比了,他代表当前计数,占空比 = Pulse/Period
void MX_TIM2_Init(void)
{
TIM_MasterConfigTypeDef sMasterConfig = {0};
TIM_OC_InitTypeDef sConfigOC = {0};
htim2.Instance = TIM2;
htim2.Init.Prescaler = 32-1;//分频
htim2.Init.CounterMode = TIM_COUNTERMODE_UP;//向上计数
htim2.Init.Period = 1000-1;//阈值
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
if (HAL_TIM_PWM_Init(&htim2) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = 0;//PWM初始计数值 0/1000
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_3) != HAL_OK)
{
Error_Handler();
}
HAL_TIM_MspPostInit(&htim2);
}
之后的启动和占空比修改就需要自己调用stm32l1xx_hal.time.c中的函数来执行了
函数 | 说明 |
---|---|
HAL_StatusTypeDef HAL_TIM_PWM_Start(TIM_HandleTypeDef *htim, uint32_t Channel) | 启动对应通道的PWM |
HAL_StatusTypeDef HAL_TIM_PWM_Stop(TIM_HandleTypeDef *htim, uint32_t Channel) | 停止对应通道的PWM |
宏 | 说明 |
---|---|
__HAL_TIM_SET_COMPARE(HANDLE, CHANNEL, COMPARE) | 配置对于通道占空比 |
下面是在tim.c中添加的函数
void USR_TIM_PWM_OpenTim2Ch3()
{
HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_3);
}
void USR_TIM_PWM_CloseTim2Ch3()
{
HAL_TIM_PWM_Stop(&htim2,TIM_CHANNEL_3);
}
//duty == 0~1000
void USR_TIM_PWM_SetCompare(uint16_t duty)
{
if(duty >1000) //这里1000是因为计数阈值被设置成了1千
{
duty=1000;
}
__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_3, duty);
}
最后在主函数中调用进行测试
先添加打印定向,使其能够printf输出
#include "stdio.h"
#ifdef __GNUC__
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif /* __GNUC__ */
PUTCHAR_PROTOTYPE
{
HAL_UART_Transmit(&huart1 , (uint8_t *)&ch, 1, 0xFFFF);
return ch;
}
然后启动PWM,设置占空比50%
USR_TIM_PWM_OpenTim2Ch3();
USR_TIM_PWM_SetCompare(500); //50%
1.3 STM32L系列定时器通道对应关系
引脚号 | 定时器通道 |
---|---|
PA0 | TIM2_CH1_ETR |
PA1 | TIM2_CH2 |
PA2 | TIM2_CH3 |
PA3 | TIM2_CH4 |
PA6 | TIM3_CH1 |
PA7 | TIM3_CH2 |
PB0 | TIM3_CH3 |
PB1 | TIM3_CH4 |
PB6 | TIM4_CH1 |
PB7 | TIM4_CH2 |
PB8 | TIM4_CH3 |
PB9 | TIM4_CH4 |
2 RT-thread
2.1 相关文件导入
这里不使用scons,而是手动添加,第一步是加入HAL库文件
stm32l1xx_hal_gpio.c
stm32l1xx_hal_gpio_ex.c
stm32l1xx_hal_tim.c
stm32l1xx_hal_time_ex.c
然后在stm32l1xx_hal_conf.h中打开宏定义,关于这里,如果是使用cube生成的工程,这些是根据配置自动生成的。
#define HAL_GPIO_MODULE_ENABLED
#define HAL_TIM_MODULE_ENABLED
第二步,引入rtthread的PWM框架,该文件位于rt-thread-master\components\drivers\misc的rt_drv_pwm.c,无需修改,也没有头文件。底层驱动将会根据该框架来实现。
第三步是添加PWM的底层驱动,这部分使用STM系列新品是无需编写的,在libraries/HAL_Drivers中drv_pwm.c,该文件有一个pwm_config.h用来基本配置,里面可以看出设备名和定时器之间的关系,例
#ifdef BSP_USING_PWM2
#ifndef PWM2_CONFIG
#define PWM2_CONFIG \
{ \
.tim_handle.Instance = TIM2, \
.name = "pwm2", \
.channel = 0 \
}
#endif /* PWM2_CONFIG */
#endif /* BSP_USING_PWM2 */
关于设备的注册是在rtconfig.h中用宏来决定的,例如需要初始化定时器3的PWM,则需要定义
#define BSP_USING_PWM
#define BSP_USING_PWM3
实际上该宏决定了stm32_pwm_obj数组的内容,在stm32_pwm_init函数中,会根据该数组来注册PWM设备。
文件末尾能够看到初始化被自启动,也表明pwm3这个设备我们可以直接find了
INIT_DEVICE_EXPORT(stm32_pwm_init);
3 下载
裸机代码9zqy
rt_thread代码
网友评论