请编写一个STM32的控制程序,要求用最小系统实现流水灯,并通过一个按键控制速度变化并用数码管显示速度
时间: 2024-06-10 10:10:38 浏览: 201
STM32按键控制4位流水灯
这里提供一种基于STM32F103C8T6的流水灯控制程序,使用GPIO控制LED灯的亮灭,使用外部中断控制按键,使用定时器控制速度变化,并使用数码管显示速度。
首先需要在Keil中创建一个工程,选择STM32F103C8T6作为芯片型号,并选择最小系统作为硬件平台。接下来编写以下代码:
```c
#include "stm32f10x.h"
#include "delay.h"
#include "led.h"
#include "key.h"
#include "timer.h"
#include "display.h"
int main(void)
{
LED_Init(); // 初始化LED
Key_Init(); // 初始化按键
Timer_Init(); // 初始化定时器
Display_Init(); // 初始化数码管
uint8_t speed = 0; // 定义速度变量,初始值为0
while(1)
{
if(Key_Scan() == KEY_ON) // 如果按键按下
{
speed++; // 速度加1
if(speed > 9) speed = 0; // 如果速度超过9,则重置为0
}
Display_Show(speed); // 显示速度
Delay_ms(100); // 延时100ms
}
}
```
在main函数中,首先初始化LED、按键、定时器和数码管。然后定义一个速度变量speed,并将其初始值设为0。在while循环中,不断检测按键是否按下,如果按下,则将速度加1,如果速度超过9,则重置为0。然后调用Display_Show函数显示速度,并延时100ms。
接下来编写LED、按键、定时器和数码管的初始化和控制函数。
LED控制函数:
```c
void LED_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); // 使能GPIOC时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // 推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC, &GPIO_InitStructure); // 初始化GPIO
}
void LED_On(void)
{
GPIO_SetBits(GPIOC, GPIO_Pin_13); // LED亮
}
void LED_Off(void)
{
GPIO_ResetBits(GPIOC, GPIO_Pin_13); // LED灭
}
void LED_Toggle(void)
{
GPIO_WriteBit(GPIOC, GPIO_Pin_13, (BitAction)(1 - GPIO_ReadOutputDataBit(GPIOC, GPIO_Pin_13))); // LED翻转
}
```
按键控制函数:
```c
void Key_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
EXTI_InitTypeDef EXTI_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); // 使能GPIOB时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); // 使能AFIO时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; // 上拉输入
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure); // 初始化GPIO
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource0); // 将PB0连接到中断线0
EXTI_InitStructure.EXTI_Line = EXTI_Line0; // 中断线0对应PB0
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; // 下降沿触发
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure); // 初始化外部中断
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn; // 外部中断0对应中断向量表中的IRQ6
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02; // 抢占优先级为2
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x00; // 子优先级为0
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure); // 初始化中断向量表
}
uint8_t Key_Scan(void)
{
if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0) == KEY_OFF) // 如果按键按下
{
Delay_ms(10); // 延时10ms
if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0) == KEY_OFF) // 再次检测按键是否按下
{
while(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0) == KEY_OFF); // 等待按键释放
return KEY_ON; // 返回按键按下状态
}
}
return KEY_OFF; // 返回按键未按下状态
}
void EXTI0_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line0) != RESET) // 如果中断线0产生了中断
{
EXTI_ClearITPendingBit(EXTI_Line0); // 清除中断标志位
}
}
```
定时器控制函数:
```c
void Timer_Init(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); // 使能TIM3时钟
TIM_TimeBaseStructure.TIM_Period = 19999; // 自动重载值为20000-1
TIM_TimeBaseStructure.TIM_Prescaler = 71; // 预分频系数为72-1
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); // 初始化定时器
NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; // TIM3对应中断向量表中的IRQ15
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x01; // 抢占优先级为1
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x00; // 子优先级为0
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure); // 初始化中断向量表
TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE); // 使能定时器溢出中断
TIM_Cmd(TIM3, ENABLE); // 启动定时器
}
void TIM3_IRQHandler(void)
{
if(TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) // 如果定时器溢出
{
LED_Toggle(); // LED翻转
TIM_ClearITPendingBit(TIM3, TIM_IT_Update); // 清除中断标志位
}
}
```
数码管控制函数:
```c
void Display_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB, ENABLE); // 使能GPIOA、GPIOB时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // 推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure); // 初始化GPIOA
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // 推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure); // 初始化GPIOB
}
void Display_Show(uint8_t num)
{
uint8_t i;
uint8_t digit[4] = {0, 0, 0, 0};
digit[0] = num / 1000;
digit[1] = num % 1000 / 100;
digit[2] = num % 100 / 10;
digit[3] = num % 10;
for(i = 0; i < 4; i++)
{
switch(i)
{
case 0:
GPIO_SetBits(GPIOB, GPIO_Pin_12);
break;
case 1:
GPIO_SetBits(GPIOB, GPIO_Pin_13);
break;
case 2:
GPIO_SetBits(GPIOB, GPIO_Pin_14);
break;
case 3:
GPIO_SetBits(GPIOB, GPIO_Pin_15);
break;
default:
break;
}
GPIO_Write(GPIOA, (GPIO_ReadOutputData(GPIOA) & 0xFF00) | digit[i]); // 设置数码管的数码
Delay_us(100); // 延时100us
switch(i)
{
case 0:
GPIO_ResetBits(GPIOB, GPIO_Pin_12);
break;
case 1:
GPIO_ResetBits(GPIOB, GPIO_Pin_13);
break;
case 2:
GPIO_ResetBits(GPIOB, GPIO_Pin_14);
break;
case 3:
GPIO_ResetBits(GPIOB, GPIO_Pin_15);
break;
default:
break;
}
}
}
```
在程序编写完成后,需要在Keil中进行编译和下载,最后在STM32最小系统上进行调试测试。
阅读全文