以stm32f10x.h为头文件在keil创建一个STM32F103C8T6代码:赛博钢琴,初始状态蜂鸣器不响,两个按键让蜂鸣器发出两种不同音量不同音调的声音,即第一个按键按下,与第二个按键按下蜂鸣器发出的声音的大小与音调不同。
时间: 2024-12-08 13:24:42 浏览: 18
首先,为了创建一个简单的 STM32F103C8T6 赛博钢琴程序,你需要按照以下步骤操作:
1. **包含头文件**:
在`main.c`文件顶部,添加`stm32f10x.h`和其他必要的库头文件:
```c
#include "stm32f10x.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_tim.h"
```
2. **初始化硬件**:
- 首先,初始化GPIO,包括设置按键输入模式、蜂鸣器输出模式等。
```c
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
// 初始化GPIO
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA | RCC_AHBPeriph_GPIOB, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1; // 按键
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; // 输入浮空
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; // 蜂鸣器
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT_PP; // 输出推挽
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
```
3. **定时器配置**:
使用TIM(定时器)生成周期性的脉冲信号,控制蜂鸣器的频率和音调。例如,使用定时器1的下降沿触发,可以产生不同频率的声音。
```c
TIM_TimeBaseStructure.TIM_Period = (uint16_t)(49152 / 2); // 产生50Hz声音,调整这个值改变频率
TIM_TimeBaseStructure.TIM_Prescaler = 839; // 根据系统时钟计算正确的预分频
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);
TIM_Cmd(TIM1, ENABLE); // 启动定时器
// 为每个按键分配不同的定时器通道
uint16_t channel1 = TIM_CHANNEL_1;
uint16_t channel2 = TIM_CHANNEL_2;
```
4. **按键中断处理**:
设置按键中断,当按键按下时进入回调函数,通过调整定时器的频率和持续时间来改变蜂鸣器的声音。
```c
EXTI_InitTypeDef EXTI_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
EXTI_InitStructure.EXTI_Line = EXTI_Line0 | EXTI_Line1; // 按键线
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
// 键盘中断服务函数
void EXTI0_IRQHandler(void) {
if (EXTI_GetITStatus(EXTI_Line0) != RESET) {
EXTI_ClearITPendingBit(EXTI_Line0); // 清除中断标志
ChangeSound(channel1, LOW); // 发出低音量声音
}
if (EXTI_GetITStatus(EXTI_Line1) != RESET) {
EXTI_ClearITPendingBit(EXTI_Line1); // 清除中断标志
ChangeSound(channel2, HIGH); // 发出高音量声音
}
}
// 添加中断到NVIC
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
```
5. **改变声音函数**:
这里只是一个简化版本,实际应用可能需要更复杂的音乐理论支持。
```c
void ChangeSound(uint16_t channel, bool highVolume) {
TIM_SelectOutputChannel(TIM1, channel, TIM_OCMode_PWM1);
TIM_ARRPreloadConfig(TIM1, ENABLE);
if (highVolume) {
TIM_PWMPulseWidthModulationConfig(TIM1, channel, TIM_PWMCmp1, 2 * TIM_TimeBaseStructure.TIM_Period);
} else {
TIM_PWMPulseWidthModulationConfig(TIM1, channel, TIM_PWMCmp1, TIM_TimeBaseStructure.TIM_Period);
}
}
```
6. **主循环和启动中断服务**
```c
int main(void)
{
// ... 其他必要的设置 ...
while (1)
{
// 主循环...
}
}
```
7. **记得添加`#pragma once`防止宏重复声明,并包含`delay.h`或其他延时库以便在调试时使用暂停功能。**
```c
#pragma once
#include "delay.h"
// ... 代码主体 ...
```
阅读全文