概要
利用stm32最小系统板制作一个智能风琴,要求使用矩阵键盘,不同键盘按下蜂鸣器会发出不同音调,并用OLED显示音调。实现视频可在主页观看
所需器件:stm32f103c8t6、有源分蜂鸣器、矩阵按键、OLED
整体架构流程
使用模块化编程,所有模块如图:
其中key文件包含矩阵键盘的控制,oled文件包含oled的控制,pwm文件则是蜂鸣器的控制。
1.矩阵键盘模块
本次矩阵键盘采用4x4矩阵键盘,其行列引脚如图所示
详细教程可·看这个大佬:STM32 4*4矩阵键盘实现原理(附程序)_矩阵键盘原理图-优快云博客
#include "stm32f10x.h"
#ifndef __KEY_H
#define __KEY_H
void Matrix_ssKey_Pin_Init(void);
int Matrix_Key_Scan(void);
#endif
#include "key.h"
#include "stm32f10x.h" // Device header
#include "delay.h"
void Matrix_ssKey_Pin_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU ;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
GPIO_Init(GPIOB,&GPIO_InitStructure);
}
int Matrix_Key_Scan(void)
{
u8 temp = 0;
int key_val = -1;
GPIO_ResetBits(GPIOB,GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_10|GPIO_Pin_11); //拉低行线
delay_us(10);
temp=(GPIO_ReadInputData(GPIOB) >> 8)&0xff;
//没有按键按下时扫描
if (temp == 0xf0)
{
delay_ms(50);
GPIO_ResetBits(GPIOB,GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_10|GPIO_Pin_11); //拉低行线
delay_us(10);
temp=(GPIO_ReadInputData(GPIOB) >> 8)&0xff;
if (temp != 0xf0) //按键按下时,对键值进行赋值
{
//第一行
GPIO_Write(GPIOB,0);
delay_ms(5);
GPIO_Write(GPIOB,(uint16_t)(0xFE << 8));
if(((GPIO_ReadInputData(GPIOB) >> 8) & 0XF0) != 0XF0)
{
delay_ms(20);//消抖
if(((GPIO_ReadInputData(GPIOB) >> 8) & 0XF0) != 0XF0)
{
temp=((GPIO_ReadInputData(GPIOB) >> 8) & 0XFE); //对列进行扫描
switch(temp)
{
case 0xEE: key_val = 1; break;
case 0xDE: key_val = 2; break;
case 0xBE: key_val = 3; break;
case 0x7E: key_val = 4; break;
default: key_val = -1; break;
}
}
}
//第二行
GPIO_Write(GPIOB,0);
delay_ms(5);
GPIO_Write(GPIOB,(uint16_t)(0xFD << 8));
if(((GPIO_ReadInputData(GPIOB) >> 8) & 0XF0)!= 0XF0)
{
delay_ms(20);
if(((GPIO_ReadInputData(GPIOB) >> 8) & 0XF0) != 0XF0)
{
temp=((GPIO_ReadInputData(GPIOB) >> 8) & 0XFD);
switch(temp)
{
case 0xED: key_val = 5; break;
case 0xDD: key_val = 6; break;
case 0xBD: key_val = 7; break;
case 0x7D: key_val = 8; break;
default: key_val = -1; break;
}
}
}
//第三行
GPIO_Write(GPIOB,0);
delay_ms(5);
GPIO_Write(GPIOB,(uint16_t)(0xFB << 8));
if(((GPIO_ReadInputData(GPIOB) >> 8) & 0XF0) != 0XF0)
{
delay_ms(20);
if(((GPIO_ReadInputData(GPIOB) >> 8) & 0XF0) != 0XF0)
{
temp=((GPIO_ReadInputData(GPIOB) >> 8) & 0XFB);
switch(temp)
{
case 0xEB: key_val = 9; break;
case 0xDB: key_val = 10; break;
case 0xBB: key_val = 11; break;
case 0x7B: key_val = 12; break;
default: key_val = -1; break;
}
}
}
//第四行
GPIO_Write(GPIOB,0);
delay_ms(5);
GPIO_Write(GPIOB,(uint16_t)(0xF7 << 8));
if(((GPIO_ReadInputData(GPIOB) >> 8) & 0XF0) !=0XF0)
{
delay_ms(20);
if(((GPIO_ReadInputData(GPIOB) >> 8) & 0XF0) != 0XF0)
{
temp=((GPIO_ReadInputData(GPIOB) >> 8) & 0XF7);
switch(temp)
{
case 0xE7: key_val = 13; break;
case 0xD7: key_val = 14; break;
case 0xB7: key_val = 15; break;
case 0x77: key_val = 16; break;
default: key_val = -1; break;
}
}
}
}
}
return key_val;
}
连线方式:
R1——PB8 C1——PB12
R2——PB9 C2——PB13
R3——PB10 C3——PB14
R4——PB11 C4——PB15
2.蜂鸣器模块
要控制蜂鸣器输出不同音调,就要改变蜂鸣器输出引脚的输出占空比,即输出PWM波。
本次PWM波输出采用TIME2的CH3通道,即PA2、
I/O——PA2
详细原理可看:STM32 使用STM32F103控制无源蜂鸣器发声播放音乐_stm32 无源蜂鸣器 音阶-优快云博客
#ifndef _PWM_H
#define _PWM_H
#include "stm32f10x.h"
void Pwm_Gpio_Init(void);
void Tim4_Pwm_Set(int Period, int Pulse);
#endif
#include "pwm.h"
//PA2
void Pwm_Gpio_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//使能GPIOA的时钟
//GPIO配置 PA2 TIM2_CH3
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure); //引脚初始化
}
void Tim4_Pwm_Set(int Period, int Pulse)
{
TIM_TimeBaseInitTypeDef TIM_BaseInitStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);//使能TIM3的时钟
//TIM2的基本配置
TIM_BaseInitStructure.TIM_Prescaler = 7200-1;//预分频
TIM_BaseInitStructure.TIM_Period = Period;//计数周期
TIM_BaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;//向上计数
TIM_BaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; //时钟分割 输入滤波
TIM_TimeBaseInit(TIM2, &TIM_BaseInitStructure);//初始化TIM3
//配置TIM2的通道1输出PWM脉冲
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;//TIM 脉冲宽度调制模式 1
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;//定时器输出使能
TIM_OCInitStructure.TIM_Pulse = Pulse;//设置装入捕获比较寄存器的脉冲值
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;//TIM 输出比较极性:高即周期内低于TIM_Pulse这个阈值的时间,都是高电平,其他时间都是低;
TIM_OC3Init(TIM2,&TIM_OCInitStructure);//初始化TIM3的Channel1
TIM_Cmd(TIM2,ENABLE);//使能TIM2
}
3.oled模块,oled模块大都为封装好的文件,可直接移植调用\
SCL——PA6
SDA——PA7
#ifndef __OLED_H
#define __OLED_H
#include "sys.h"
#include "stdlib.h"
//-----------------OLED IIC端口定义----------------
#define OLED_SCLK_Clr() GPIO_ResetBits(GPIOA,GPIO_Pin_6)//SCL IIC接口的时钟信号
#define OLED_SCLK_Set() GPIO_SetBits(GPIOA,GPIO_Pin_6)
#define OLED_SDIN_Clr() GPIO_ResetBits(GPIOA,GPIO_Pin_7)//SDA IIC接口的数据信号
#define OLED_SDIN_Set() GPIO_SetBits(GPIOA,GPIO_Pin_7)
#define OLED_CMD 0 //写命令
#define OLED_DATA 1 //写数据
//OLED控制用函数
void OLED_WR_Byte(unsigned dat,unsigned cmd);
void OLED_Display_On(void);
void OLED_Display_Off(void);
void OLED_Init(void);
void OLED_Clear(void);
void OLED_Fill(unsigned char fill_Data);
void OLED_ShowString(u8 x,u8 y, u8 *p,u8 Char_Size);
void OLED_Set_Pos(unsigned char x, unsigned char y);
void IIC_Start(void);
void IIC_Stop(void);
void IIC_Wait_Ack(void);
void Write_IIC_Command(unsigned char IIC_Command);
void Write_IIC_Data(unsigned char IIC_Data);
#endif
#include "oled.h"
#include "stdlib.h"
#include "oledfont.h"
#include "delay.h"
//PA6.7
//OLED的显存
//存放格式如下.
//[0]0 1 2 3 ... 127
//[1]0 1 2 3 ... 127
//[2]0 1 2 3 ... 127
//[3]0 1 2 3 ... 127
//[4]0 1 2 3 ... 127
//[5]0 1 2 3 ... 127
//[6]0 1 2 3 ... 127
//[7]0 1 2 3 ... 127
/**********************************************
//IIC Start
**********************************************/
/**********************************************
//IIC Start
**********************************************/
void IIC_Start(void)
{
OLED_SCLK_Set() ;
OLED_SDIN_Set();
OLED_SDIN_Clr();
OLED_SCLK_Clr();
}
/**********************************************
//IIC Stop
**********************************************/
void IIC_Stop(void)
{
OLED_SCLK_Set() ;
OLED_SDIN_Clr();
OLED_SDIN_Set();
}
void IIC_Wait_Ack(void)
{
OLED_SCLK_Set() ;
OLED_SCLK_Clr();
}
/**********************************************
// IIC Write byte
**********************************************/
void Write_IIC_Byte(unsigned char IIC_Byte)
{
unsigned char i;
unsigned char m, da;
da = IIC_Byte;
OLED_SCLK_Clr();
for(i = 0; i < 8; i++)
{
m = da;
m = m & 0x80;
if(m == 0x80)
{
OLED_SDIN_Set();
}
else OLED_SDIN_Clr();
da = da << 1;
OLED_SCLK_Set();
OLED_SCLK_Clr();
}
}
/**********************************************
// IIC Write Command
**********************************************/
void Write_IIC_Command(unsigned char IIC_Command)
{
IIC_Start();
Write_IIC_Byte(0x78); //Slave address,SA0=0
IIC_Wait_Ack();
Write_IIC_Byte(0x00); //write command
IIC_Wait_Ack();
Write_IIC_Byte(IIC_Command);
IIC_Wait_Ack();
IIC_Stop();
}
/**********************************************
// IIC Write Data
**********************************************/
void Write_IIC_Data(unsigned char IIC_Data)
{
IIC_Start();
Write_IIC_Byte(0x78); //D/C#=0; R/W#=0
IIC_Wait_Ack();
Write_IIC_Byte(0x40); //write data
IIC_Wait_Ack();
Write_IIC_Byte(IIC_Data);
IIC_Wait_Ack();
IIC_Stop();
}
/***********************Delay****************************************/
//坐标设置
void OLED_Set_Pos(unsigned char x, unsigned char y)
{
Write_IIC_Command(0xb0 + y);
Write_IIC_Command(((x & 0xf0) >> 4) | 0x10);
Write_IIC_Command((x & 0x0f) | 0x01);
}
void OLED_Fill(unsigned char fill_Data)//全屏填充
{
unsigned char m, n;
for(m = 0; m < 8; m++)
{
Write_IIC_Command(0xb0 + m); //page0-page1
Write_IIC_Command(0x02); //low column start address
Write_IIC_Command(0x10); //high column start address
for(n = 0; n < 128; n++)
{
Write_IIC_Data(fill_Data);
}
}
}
//清屏函数,清完屏,整个屏幕是黑色的!和没点亮一样!!!
void OLED_Clear(void)
{
OLED_Fill(0x00);
}
//--------------------------------------------------------------
// Prototype : void OLED_ON(void)
// Calls :
// Parameters : none
// Description : 将OLED从休眠中唤醒
//--------------------------------------------------------------
void OLED_On(void)
{
Write_IIC_Command(0X8D); //设置电荷泵
Write_IIC_Command(0X14); //开启电荷泵
Write_IIC_Command(0XAF); //OLED唤醒
}
//--------------------------------------------------------------
// Prototype : void OLED_OFF(void)
// Calls :
// Parameters : none
// Description : 让OLED休眠 -- 休眠模式下,OLED功耗不到10uA
//--------------------------------------------------------------
void OLED_OFF(void)
{
Write_IIC_Command(0X8D); //设置电荷泵
Write_IIC_Command(0X10); //关闭电荷泵
Write_IIC_Command(0XAE); //OLED休眠
}
//--------------------------------------------------------------
// Prototype : void OLED_ShowChar(unsigned char x, unsigned char y, unsigned char ch[], unsigned char TextSize)
// Calls :
// Parameters : x,y -- 起始点坐标(x:0~127, y:0~7); ch[] -- 要显示的字符串; TextSize -- 字符大小(1:6*8 ; 2:8*16)
// Description : 显示codetab.h中的ASCII字符,有6*8和8*16可选择
//--------------------------------------------------------------
void OLED_ShowString(unsigned char x, unsigned char y, unsigned char ch[], unsigned char TextSize)
{
unsigned char c = 0,i = 0,j = 0;
switch(TextSize)
{
case 8:
{
while(ch[j] != '\0')
{
c = ch[j] - 32;
if(x > 122)
return;
OLED_Set_Pos(x,y);
for(i=0;i<6;i++)
Write_IIC_Data(F6x8[c][i]);
x += 6;
j++;
}
}break;
case 16:
{
while(ch[j] != '\0')
{
c = ch[j] - 32;
if(x > 120)
return;
OLED_Set_Pos(x,y);
for(i=0;i<8;i++)
Write_IIC_Data(F8X16[c*16+i]);
OLED_Set_Pos(x,y+1);
for(i=0;i<8;i++)
Write_IIC_Data(F8X16[c*16+i+8]);
x += 8;
j++;
}
}break;
}
}
//初始化OLED屏幕
void OLED_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能PB端口时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7| GPIO_Pin_6; //PB6,PB7推挽输出
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//速度50MHz
GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化GPIOD3,6
delay_ms(100); //这里的延时很重要
Write_IIC_Command(0xAE); //display off
Write_IIC_Command(0x20); //Set Memory Addressing Mode
Write_IIC_Command(0x10); //00,Horizontal Addressing Mode;01,Vertical Addressing Mode;10,Page Addressing Mode (RESET);11,Invalid
Write_IIC_Command(0xb0); //Set Page Start Address for Page Addressing Mode,0-7
Write_IIC_Command(0xc8); //Set COM Output Scan Direction
Write_IIC_Command(0x00); //---set low column address
Write_IIC_Command(0x10); //---set high column address
Write_IIC_Command(0x40); //--set start line address
Write_IIC_Command(0x81); //--set contrast control register
Write_IIC_Command(0xff); //亮度调节 0x00~0xff
Write_IIC_Command(0xa1); //--set segment re-map 0 to 127
Write_IIC_Command(0xa6); //--set normal display
Write_IIC_Command(0xa8); //--set multiplex ratio(1 to 64)
Write_IIC_Command(0x3F); //
Write_IIC_Command(0xa4); //0xa4,Output follows RAM content;0xa5,Output ignores RAM content
Write_IIC_Command(0xd3); //-set display offset
Write_IIC_Command(0x00); //-not offset
Write_IIC_Command(0xd5); //--set display clock divide ratio/oscillator frequency
Write_IIC_Command(0xf0); //--set divide ratio
Write_IIC_Command(0xd9); //--set pre-charge period
Write_IIC_Command(0x22); //
Write_IIC_Command(0xda); //--set com pins hardware configuration
Write_IIC_Command(0x12);
Write_IIC_Command(0xdb); //--set vcomh
Write_IIC_Command(0x20); //0x20,0.77xVcc
Write_IIC_Command(0x8d); //--set DC-DC enable
Write_IIC_Command(0x14); //
Write_IIC_Command(0xaf); //--turn on oled panel
OLED_Clear();
}
4.mian函数部分
#include "stm32f10x.h" // Device header
#include "pwm.h"
#include "key.h"
#include "led.h"
#include "oled.h"
#include "stdio.h"
#include "delay.h"
void my_delay(int n);
#define proport 10000 //Tclk/(psc+1)=72000000/(7199+1) Tclk=72MHz 预分频后的频率
//根据 Tout = ((arr+1)*(psc+1))/Tclk Tout为音调频率的倒数, 推出arr值就是define定义的值
#define L1 ((proport/131)-1)//低调 do 的周期
#define L2 ((proport/147)-1)//低调 re 的周期
#define L3 ((proport/165)-1)//低调 mi 的周期
#define L4 ((proport/176)-1)//低调 fa 的周期
#define L5 ((proport/196)-1)//低调 sol的周期
#define L6 ((proport/220)-1)//低调 la 的周期
#define L7 ((proport/247)-1)//低调 si 的周期
#define M1 ((proport/262)-1)//中调 do 的周期
#define M2 ((proport/296)-1)//中调 re 的周期
#define M3 ((proport/330)-1)//中调 mi 的周期
#define M4 ((proport/349)-1)//中调 fa 的周期
#define M5 ((proport/392)-1)//中调 sol的周期
#define M6 ((proport/440)-1)//中调 la 的周期
#define M7 ((proport/494)-1)//中调 si 的周期
#define H1 ((proport/523)-1)//高调 do 的周期
#define H2 ((proport/587)-1)//高调 re 的周期
#define H3 ((proport/659)-1)//高调 mi 的周期
#define H4 ((proport/699)-1)//高调 fa 的周期
#define H5 ((proport/784)-1)//高调 sol的周期
#define H6 ((proport/880)-1)//高调 la 的周期
#define H7 ((proport/988)-1)//高调 si 的周期
#define Z0 0
unsigned int keyValue;
int music[]=
{
H2,50,H1,25,M6,25,M6,25,H1,50, M6,25,H2,25,H1,25,M6,50,M6,25,H1,50,H1,50, H3,100,H3,25,H4,25,H3,50,H3,25,H2,50,H2,50,Z0,25,
//我曾将青春翻涌成她 也曾指尖弹出盛夏 心之所动且就随缘去吧
H1,50,H2,50,H3,50,H6,25,H5,25,H5,50,H6,25,H5,25,H5,50,H6,25,H5,25,H5,50,H2,50, H3,50,H6,25,H5,25,H5,50,H6,25,H5,25,H5,50,H6,25,H5,25,H5,50,H3,50,H3,50, H2,50,H1,25,M6,25,M6,25,H3,50,H3,50, H2,50,H1,25,M6,25,M6,25,H1,50,H1,50,H1,100,H1,100,Z0,10,
//短短的路走走停停 也有了几分的距离
M2,50,M2,50,M1,25,M2,50,M2,50,M1,25,M2,50,M3,50,M5,50,M3,50, M2,50,M2,50,M1,25,M2,50,M2,50,M1,25,M2,25,M3,25,M2,25,M1,25,L6,100,Z0,10,
//不知抚摸的是故事还是段心情
M2,50,M2,50,M1,25,M2,50,M2,50,M1,25,M2,50,M3,50,M5,50,M3,50, M2,50,M2,50,M3,25,M2,50,M1,50,M2,100,Z0,50,
//也许期待的不过是与时间为敌
M2,50,M2,50,M1,25,M2,50,M2,50,M1,25,M2,50,M3,50,M5,50,M3,50, M2,50,M2,50,M3,25,M2,50,M1,50,L6,100,Z0,10,
//再次见到你 微凉晨光里 笑的很甜蜜
M3,25,M2,25,M1,25,M2,25,M1,100, M3,25,M2,25,M1,25,M2,25,M1,50,M1,50, M5,25,M3,25,M2,25,M1,25,M2,25,M1,100,M1,150,Z0,30,
//从前初识这世间 万般留恋 看着天边似在眼前 也甘愿赴汤蹈火去走它一遍
M1,50,M2,50,M3,50,M1,50,M6,50,M5,25,M6,25,M6,50,M6,50, M1,25,M7,50,M6,25,M7,25,M7,100,Z0,5, M7,50,M6,25,M7,25,M7,50,M3,50,H1,25,H2,25,H1,25,M7,25,M6,50,M5,50, M6,50,M5,25,M6,25,M6,25,M5,25,M6,25,M5,25,M6,50,M5,25,M2,25,M2,25,M5,50,M5,50,M3,100,M3,100,Z0,25,
//如今走过这世间 万般留恋 翻过岁月不同侧脸 措不及防闯入你的笑颜
M1,50,M2,50,M3,50,M1,50,M6,50,M5,25,M6,25,M6,50,M6,50, M1,25,M7,50,M6,25,M7,25,M7,100,Z0,5, M7,50,M6,25,M7,25,M7,50,M3,50,H1,25,H2,25,H1,25,M7,25,M6,50,M5,50, M6,50,H3,25,H3,25,H3,50,M5,50,M6,50,H3,25,H3,25,H3,25,M5,50,M6,25,M6,100,M6,100,M6,100,Z0,25,
//我曾难自拔于世界之大 也沉溺于其中梦话
H1,50,H2,50,H3,50,H6,25,H5,25,H5,50,H6,25,H5,25,H5,50,H6,25,H5,25,H5,50,H2,25,H3,25,H3,50, H6,25,H5,25,H5,50,H6,25,H5,25,H5,50,H6,25,H5,25,H5,25,H3,50,H3,50,
//不得真假 不做挣扎 不惧笑话
H2,50,H1,25,M6,25,M6,25,H1,50, M6,25,H2,25,H1,25,M6,50,M6,25,H1,50,H1,50, H3,100,H3,25,H4,25,H3,50,H3,25,H2,50,H2,50,Z0,25,
//我曾将青春翻涌成她 也曾指尖弹出盛夏 心之所动且就随缘去吧
H1,50,H2,50,H3,50,H6,25,H5,25,H5,50,H6,25,H5,25,H5,50,H6,25,H5,25,H5,50,H2,50, H3,50,H6,25,H5,25,H5,50,H6,25,H5,25,H5,50,H6,25,H5,25,H5,50,H3,50,H3,50, H2,50,H1,25,M6,25,M6,25,H3,50,H3,50, H2,50,H1,25,M6,25,M6,25,H1,50,H1,50,H1,100,H1,100,Z0,10,
//逆着光行走任风吹雨打吧
M6,25,H3,50,H3,50,H2,50,H1,25,M6,25,M6,25,H3,50,H2,50,H1,25,M6,25,M6,25,H1,50,H1,50,H1,50,H1,100,Z0,25,
//晚风吹起你鬓间的白发 抚平回忆留下的疤
H1,50,H2,50,H2,25,H3,50,H6,25,H5,25,H5,50,H6,25,H5,25,H5,50,H6,25,H5,25,H5,50,H2,25, H3,25,H3,50,H6,25,H5,25,H5,50,H6,25,H5,25,H5,50,H6,25,H5,25,H5,25,H3,50,H3,50,Z0,5,
//你的眼中明暗交杂 一笑生花 暮色遮住你蹒跚的步伐
H2,50,H1,25,M6,25,M6,25,H1,50,M6,25,H2,25,H1,25,M6,50,M6,50, H1,50,H1,50,H3,100,H3,25,H4,25,H3,50,H3,25,H2,50,H2,50,H1,100,H2,100,H3,100,H6,25,H5,25,H5,50,H6,25,H5,25,H5,50,H6,25,H5,25,H5,50,H2,50,
//走进床头藏起的画 画中的你(低着头说话)
};
int main()
{
int i = 2000;
int length = sizeof(music)/sizeof(music[0]);//计算数组长度
delay_init();
OLED_Init();
OLED_Clear();
delay_init();
Matrix_ssKey_Pin_Init();
while(1)
{
keyValue=Matrix_Key_Scan();;//获取按键的键值
switch(keyValue) //根据键值确定按下的按钮
{
case 1:
Pwm_Gpio_Init();
Tim4_Pwm_Set(L1, 25);
OLED_ShowString(0,0,(u8*)"do",16);
delay_ms(200);break; //按键1
case 2:
Pwm_Gpio_Init();
Tim4_Pwm_Set(M2, 25);
OLED_ShowString(0,0,(u8*)"re",16);
delay_ms(200);break; //按键2
case 3:
Pwm_Gpio_Init();
Tim4_Pwm_Set(L3, 25);
OLED_ShowString(0,0,(u8*)"mi",16);
delay_ms(200);break; //按键3
case 4:
Pwm_Gpio_Init();
Tim4_Pwm_Set(L4, 25);
OLED_ShowString(0,0,(u8*)"fa",16);
delay_ms(200);break; //按键4
case 5:
Pwm_Gpio_Init();
Tim4_Pwm_Set(L5, 25);
OLED_ShowString(0,0,(u8*)"sol",16);
delay_ms(200);break; //按键5
case 6:
Pwm_Gpio_Init();
Tim4_Pwm_Set(L6, 25);
OLED_ShowString(0,0,(u8*)"la",16);
delay_ms(200);break; //按键6
case 7:
Pwm_Gpio_Init();
Tim4_Pwm_Set(L7, 25);
OLED_ShowString(0,0,(u8*)"xi",16);
delay_ms(200);break; //按键7
case 8:
Pwm_Gpio_Init();
OLED_ShowString(0,0,(u8*)"qifengle ",16);
delay_ms(1000);
for(i=0; i<(length/2); i++)//取数组数据
{
Tim4_Pwm_Set(music[2*i], music[2*i]);//PWM波周期
my_delay(5*music[2*i+1]);//音长的时间都乘以5即一拍为500微秒,此值"5"可调整,只是播放的整个快慢而已,有点类似于视频快进和后退
}
my_delay(20000); //2S延时
break; //按键8
case 9:
OLED_ShowString(0,0,(u8*)"9",16);
delay_ms(2000);break; //按键9
case 10:
OLED_ShowString(0,0,(u8*)"10",16);
delay_ms(2000);break; //按键10
case 11:
OLED_ShowString(0,0,(u8*)"11",16);
delay_ms(2000);break; //按键11
case 12:
OLED_ShowString(0,0,(u8*)"12",16);
delay_ms(2000);break; //按键12
case 13:
OLED_ShowString(0,0,(u8*)"13",16);
delay_ms(2000);break; //按键13
case 14:
OLED_ShowString(0,0,(u8*)"14",16);
delay_ms(2000);break; //按键14
case 15:
OLED_ShowString(0,0,(u8*)"15",16);
delay_ms(2000);break; //按键15
case 16:
OLED_ShowString(0,0,(u8*)"16",16);
delay_ms(2000);break; //按键16
default:break;
}
}
技术细节
特别注意:delay_Init()函数一定要放在所有初始化函数前面!!!!否则整个代码都运行不了!
还有千万不要串口功能重定义!!!
小结
写代码前一定要想好不同模块功能的连接位置,合理规划引脚