由于我们前期的任务目标中,不做台灯,而改为环境检测了,对于PWM的应用就缺失了一部分,这样也会导致基本上没有下行的控制命令的必要的,这样可不行,所以有关PWM控制部分我们集成到板载的LED控制,来实现三个LED的多种控制模式,我们这里实现四种控制模式。
第一种就是循环灯,三个LED循环点亮;
第二种就是Blink,这里实现的事所有LED同亮和同灭;
第三种是循环呼吸灯,三个LED循环呼吸点亮;
第四个是同步呼吸灯,所有LED同频进行呼吸灯的实现;
这里我们就要看一下芯片的资源是不是能满足我们的要求,我们这里不去看手册,在STM32CubeMX中进行查看:
如上图,这样查看可以看到是不是是定时器CH口,如果可以,就能实现PWM呼吸灯的功能,LED1对应PB4,LED2对应PA9,LED3对应的是PB8,为了节约资源可以将其中PB4和PB8可以用同一个定时器(TIM1),PA9只能用定时器3了。
咱们先初步将PB4配置为普通GPIO输出,PB8和PA9配置为PWM输出:
上图可以看到配置为PWM输出的引脚是黄色,说明我们还没有配置完成,我们还要对对应的定时器进行配置例如PB8:
PWM输出不需要配置中断等内容,只要配置时钟源、通道、定时基准就可以了,其他的使用默认配置就可以了。
这里我们还添加了一个按键的控制,B1,作为还没有蓝牙控制的一个手动切换模式的控制按键:
B1对应的按键是PC13:
结合原理图,我们需要修改外部中断的配置,下降沿触发并且需要上拉,注意开启外部中断;
我们先测试一下按键的效果,添加外部中断的回调函数:
void HAL_GPIO_EXTI_Falling_Callback(uint16_t GPIO_Pin) { if(GPIO_Pin == B1_Pin) {/* KEY */ HAL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin); } }
LED1(蓝灯)的控制随着B1的按下进行翻转,加下来我们测试一下普通定时器16的,10ms定时功能:
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { if (htim->Instance == TIM16) { HAL_IncTick(); LED.TIMcnt ++; if(LED.TIMcnt>100){ LED.TIMcnt = 0; HAL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin); } } }
这样就实现了和之前创建初始工程时的效果一样了,1s实现一次LED(蓝灯的翻转),这里需要注意一下,对于定时器不会自动开启,我们需要使用HAL_TIM_Base_Start_IT(&htim16);才能真正的运转起来。
接下来我们看一下LED3(红灯)的呼吸灯效果,这也是加入定时器16的一个主要原因:
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { if (htim->Instance == TIM16) { HAL_IncTick(); LED.TIMcnt ++; LED.PWMcnt ++; __HAL_TIM_SET_COMPARE(&htim1,TIM_CHANNEL_1,LED.PWMcnt*50); if(LED.PWMcnt>100) LED.PWMcnt = 0; } }
注意启动PWM对应的定时器,使用HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_1)效果正常;
接下来就是一个整合了,由于我们对LED的控制分为不同的配置,这个我们是无法通过STM32CubeMX进行同步配置多以我们需要写两个不同状态的初始化程序,一个是三个LED都配置为GPIO输出:
void LED_GPIO_init(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; /* GPIO Ports Clock Enable */ __HAL_RCC_GPIOB_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); __HAL_RCC_GPIOC_CLK_ENABLE(); /*Configure GPIO pin : PtPin */ GPIO_InitStruct.Pin = LED1_Pin; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_PULLUP; HAL_GPIO_Init(LED1_GPIO_Port, &GPIO_InitStruct); GPIO_InitStruct.Pin = LED2_Pin; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_PULLUP; HAL_GPIO_Init(LED2_GPIO_Port, &GPIO_InitStruct); GPIO_InitStruct.Pin = LED3_Pin; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_PULLUP; HAL_GPIO_Init(LED3_GPIO_Port, &GPIO_InitStruct); }
另外一种模式就是PWM控制模式的初始化,这一部分我们是通过STM32CubeMX生成的,切换模式的时候直接使用系统生成的函数就可以,注意一点就是STM32CubeMX对引脚配置只能是一种,所以要想切换只能手动写一下。
接下来就是模式的切换,通过外部中断实现:
void HAL_GPIO_EXTI_Falling_Callback(uint16_t GPIO_Pin) { if(GPIO_Pin == B1_Pin) {/* KEY */ LED.Mode_Dis++; if(LED.Mode_Dis>=4) LED.Mode_Dis = 0; } }
重点是在定时器中对LED中间太的控制:
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { if (htim->Instance == TIM16) { HAL_IncTick(); switch(LED.Mode_OidDis) { case 0: LED.TIMcnt++; if(LED.TIMcnt>100){ LED.TIMcnt = 0; LEDRed_off; LEDBlue_off; LEDGreen_off; LED.state ++; switch(LED.state%3){ case 0: LEDRed_on; break; case 1: LEDBlue_on; break; case 2: LEDGreen_on; break; default: break; } } break; case 1: LED.TIMcnt++; if(LED.TIMcnt>100){ LED.TIMcnt = 0; LEDRed_Toggle; LEDBlue_Toggle; LEDGreen_Toggle; } break; case 2: LED.PWMcnt ++; if(LED.PWMcnt<100){ __HAL_TIM_SET_COMPARE(&htim1,TIM_CHANNEL_1,LED.PWMcnt*50); __HAL_TIM_SET_COMPARE(&htim1,TIM_CHANNEL_3,LED.PWMcnt*50); __HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_2,LED.PWMcnt*50); } else if(LED.PWMcnt>=100 && LED.PWMcnt<200){ __HAL_TIM_SET_COMPARE(&htim1,TIM_CHANNEL_1,(200-LED.PWMcnt)*50); __HAL_TIM_SET_COMPARE(&htim1,TIM_CHANNEL_3,(200-LED.PWMcnt)*50); __HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_2,(200-LED.PWMcnt)*50); } else LED.PWMcnt = 0; break; case 3: LED.PWMcnt ++; if(LED.PWMcnt<100){ __HAL_TIM_SET_COMPARE(&htim1,TIM_CHANNEL_1,LED.PWMcnt*50); } else if(LED.PWMcnt>=100 && LED.PWMcnt<200){ __HAL_TIM_SET_COMPARE(&htim1,TIM_CHANNEL_1,(200-LED.PWMcnt)*50); } else if(LED.PWMcnt>=200 && LED.PWMcnt<300){ __HAL_TIM_SET_COMPARE(&htim1,TIM_CHANNEL_3,(LED.PWMcnt-200)*50); } else if(LED.PWMcnt>=300 && LED.PWMcnt<400){ __HAL_TIM_SET_COMPARE(&htim1,TIM_CHANNEL_3,(400-LED.PWMcnt)*50); } else if(LED.PWMcnt>=400 && LED.PWMcnt<500){ __HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_2,(LED.PWMcnt-400)*50); } else if(LED.PWMcnt>=500 && LED.PWMcnt<600){ __HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_2,(600-LED.PWMcnt)*50); } else LED.PWMcnt = 0; break; default: break; } } }
效果如下: