1 裸機(jī)
1.1工程建立
使用STM32CubeMX來(lái)生成工程,基本使用也可見(jiàn)鏈接
-
選擇外部時(shí)鐘
image.png -
選擇SW調(diào)試
image.png -
串口1作為打印
image.png -
配置時(shí)鐘,8M外部輸入,32M系統(tǒng)時(shí)鐘
image.png -
選擇PA2為PWM的通道
image.png -
配置對(duì)于的時(shí)鐘TIM2,選擇通道3
image.png -
配置該P(yáng)WM通道,系統(tǒng)時(shí)鐘32M
image.png -
生產(chǎn)工程的配置
image.png
image.png 最后生成的工程(GENERATE CODE)
1.2 分析生產(chǎn)的代碼
主函數(shù)中初始化了GPIO和TIM,前者僅僅打開(kāi)了GPIO的時(shí)鐘,主要初始化在TIM中。
//main.h
MX_GPIO_Init();
MX_TIM2_Init();
在tim.c則進(jìn)行了對(duì)于通道引腳初始化和定時(shí)器PWM初始化
//初始化PA2對(duì)于定時(shí)器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);
}
}
定時(shí)器初始化的時(shí)候?qū)⑦M(jìn)行時(shí)鐘配置,這決定了PWM的頻率,Prescaler表示分頻數(shù),表示如果最終分頻到TIM的時(shí)鐘是32M,那么實(shí)際使用時(shí)鐘則是32/Prescaler。Period代表定時(shí)器計(jì)數(shù)達(dá)到多少后重新裝填,對(duì)于PWM來(lái)說(shuō)就代表了一個(gè)周期,所以PWM的頻率就等于48M/Prescaler/Period。Pulse就對(duì)應(yīng)占空比了,他代表當(dāng)前計(jì)數(shù),占空比 = 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;//向上計(jì)數(shù)
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初始計(jì)數(shù)值 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);
}
之后的啟動(dòng)和占空比修改就需要自己調(diào)用stm32l1xx_hal.time.c中的函數(shù)來(lái)執(zhí)行了
| 函數(shù) | 說(shuō)明 |
|---|---|
| HAL_StatusTypeDef HAL_TIM_PWM_Start(TIM_HandleTypeDef *htim, uint32_t Channel) | 啟動(dòng)對(duì)應(yīng)通道的PWM |
| HAL_StatusTypeDef HAL_TIM_PWM_Stop(TIM_HandleTypeDef *htim, uint32_t Channel) | 停止對(duì)應(yīng)通道的PWM |
| 宏 | 說(shuō)明 |
|---|---|
| __HAL_TIM_SET_COMPARE(HANDLE, CHANNEL, COMPARE) | 配置對(duì)于通道占空比 |
下面是在tim.c中添加的函數(shù)
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是因?yàn)橛?jì)數(shù)閾值被設(shè)置成了1千
{
duty=1000;
}
__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_3, duty);
}
最后在主函數(shù)中調(diào)用進(jìn)行測(cè)試
先添加打印定向,使其能夠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;
}
然后啟動(dòng)PWM,設(shè)置占空比50%
USR_TIM_PWM_OpenTim2Ch3();
USR_TIM_PWM_SetCompare(500); //50%
1.3 STM32L系列定時(shí)器通道對(duì)應(yīng)關(guān)系
| 引腳號(hào) | 定時(shí)器通道 |
|---|---|
| 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 相關(guān)文件導(dǎo)入
這里不使用scons,而是手動(dòng)添加,第一步是加入HAL庫(kù)文件
stm32l1xx_hal_gpio.c
stm32l1xx_hal_gpio_ex.c
stm32l1xx_hal_tim.c
stm32l1xx_hal_time_ex.c
然后在stm32l1xx_hal_conf.h中打開(kāi)宏定義,關(guān)于這里,如果是使用cube生成的工程,這些是根據(jù)配置自動(dòng)生成的。
#define HAL_GPIO_MODULE_ENABLED
#define HAL_TIM_MODULE_ENABLED
第二步,引入rtthread的PWM框架,該文件位于rt-thread-master\components\drivers\misc的rt_drv_pwm.c,無(wú)需修改,也沒(méi)有頭文件。底層驅(qū)動(dòng)將會(huì)根據(jù)該框架來(lái)實(shí)現(xiàn)。
第三步是添加PWM的底層驅(qū)動(dòng),這部分使用STM系列新品是無(wú)需編寫(xiě)的,在libraries/HAL_Drivers中drv_pwm.c,該文件有一個(gè)pwm_config.h用來(lái)基本配置,里面可以看出設(shè)備名和定時(shí)器之間的關(guān)系,例
#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 */
關(guān)于設(shè)備的注冊(cè)是在rtconfig.h中用宏來(lái)決定的,例如需要初始化定時(shí)器3的PWM,則需要定義
#define BSP_USING_PWM
#define BSP_USING_PWM3
實(shí)際上該宏決定了stm32_pwm_obj數(shù)組的內(nèi)容,在stm32_pwm_init函數(shù)中,會(huì)根據(jù)該數(shù)組來(lái)注冊(cè)PWM設(shè)備。
文件末尾能夠看到初始化被自啟動(dòng),也表明pwm3這個(gè)設(shè)備我們可以直接find了
INIT_DEVICE_EXPORT(stm32_pwm_init);
3 下載
裸機(jī)代碼9zqy
rt_thread代碼








