用keil uVision5编写程序,实现流水灯8个 LED 全亮,LED从DI到D8逐个熄灭,每0.5秒 熄灭一个,最终8个LED 全灭。
时间: 2024-09-13 15:09:27 浏览: 39
在Keil uVision5中编写程序以控制流水灯实现这个效果,首先你需要确保已连接了支持PWM功能的LED驱动模块,比如GPIO口。下面是一个基本的流程:
1. **设置项目及配置**:
- 新建一个新的项目或者打开现有项目,选择适合的芯片库。
- 配置GPIO口为PWM输出模式。
2. **编写头文件**:
- 创建一个包含宏定义、函数声明等的头文件,例如`led_pwm.h`,定义一组用于控制LED的全局变量和函数原型。
```c
#ifndef LED_PWM_H
#define LED_PWM_H
#include "stm32f4xx_hal.h"
// 定义LED的数量和GPIO端口
#define NUM_LEDS 8
#define GPIO_PORT GPIOB
extern void led_init(void);
extern void led_on(int index);
extern void led_off(int index);
#endif // LED_PWM_H
```
3. **初始化函数** (`led_init.c`):
- 这里初始化GPIO为PWM输出,并设置每个LED的初始状态为全亮。
```c
#include "led_pwm.h"
#include "stm32f4xx_hal_pwm.h"
void led_init(void) {
GPIO_InitTypeDef GPIO_InitStruct;
for (int i = 0; i < NUM_LEDS; ++i) {
GPIO_PinAFConfig(GPIO_PORT, GPIO_PIN(index), GPIO_AF0_PWM); // 设置GPIO为PWM模式
GPIO_InitStruct.Pin = GPIO_PIN(index);
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
HAL_GPIO_Init(GPIO_PORT, &GPIO_InitStruct);
HAL_PWMMaster_EnableChannel(i); // 启动PWM通道
}
}
```
4. **开/关单个LED函数** (`led_pwm.c`):
- `led_on` 和 `led_off` 函数分别用来设置LED为全亮和熄灭。
```c
#include "led_pwm.h"
void led_on(int index) {
GPIO_SetBits(GPIO_PORT, GPIO_PIN(index)); // 设置LED为高电平,即全亮
}
void led_off(int index) {
GPIO_ResetBits(GPIO_PORT, GPIO_PIN(index)); // 设置LED为低电平,即熄灭
}
```
5. **定时器中断服务函数** (`tim_isr.c` 或者 `main.c`):
- 使用系统时钟频率创建一个延时函数,然后在定时器中断服务函数中调用`led_off`逐步关闭LED。
```c
#include "led_pwm.h"
#include "stm32f4xx_hal_tim.h"
void TIM9_IRQHandler(void) {
if (__HAL_TIM_GET_FLAG(&TIM9) & TIM_FLAG_UPDATE) {
__HAL_TIM_CLEAR_FLAG(&TIM9, TIM_FLAG_UPDATE); // 清除标志
static int led_index = NUM_LEDS - 1;
led_off(led_index--); // 熄灭当前LED
if (led_index >= 0) { // 如果还有LED未熄灭
HAL_Delay(500); // 延迟0.5秒
HAL_TIM_Base_Start_IT(&TIM9); // 继续下一个LED的关闭
} else {
HAL_TIM_Base_Stop_IT(&TIM9); // 当所有LED关闭后停止定时器
}
}
}
void setupTim(uint32_t prescaler, uint32_t period) {
TIM_HandleTypeDef htim;
htim.Instance = TIM9;
htim.Init.Prescaler = prescaler;
htim.Init.CounterMode = TIM_COUNTERMODE_UP;
htim.Init.Period = period;
htim.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim.Init.RepetitionCounter = 0;
if (HAL_TIM_Base_Init(&htim) != HAL_OK) {
// 处理错误...
}
HAL_NVIC_SetPriority(TIM9_IRQn, 0, 0); // 设置中断优先级
HAL_NVIC_EnableIRQ(TIM9_IRQn); // 开启中断
TIM_BaseStart_IT(&htim); // 启动定时器
}
```
6. **主函数** (`main.c`):
- 初始化LED和定时器,并在定时器中断服务函数中开始计时。
```c
int main(void) {
led_init();
setupTim(/* 输入适当的时钟预分频值和周期 */);
while (1) {
}
}
```