520到了,看着朋友圈里的花式秀恩爱,平常午餐最爱吃的泡面都变得不那么香了。于是!突发奇想,突然就来了更新的想法,今天用32来做一个非常简单的小程序:
 
因为基本只用到两个外设,程序容量也很小,所以用c8t6就刚刚好
 
这里要用的是无源蜂鸣器,其音调是可调的。
我们先声明要用到的引脚以及相应的函数:
#define BeeGpio	GPIO自选
#define Bee 	GPIO_Pin_自选	
void Bee_Init(void); //蜂鸣器初始化
void Bee_test(void); //蜂鸣器测试
void Play_Music(void);//播放音乐
这个也非常好理解,和初始化引脚是一样的 。
void Bee_Init(void){
	GPIO_InitTypeDef  GPIO_InitStructure; 	
    GPIO_InitStructure.GPIO_Pin = Bee; 
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; 
	GPIO_Init(BeeGpio, &GPIO_InitStructure);	
	
	GPIO_WriteBit(BeeGpio,Bee,(BitAction)(1)); 
}
在主函数演奏之前,我们先测试一下蜂鸣器好不好使,让它先响一声:
void Bee_test(void){ 
	u16 i;
	for(i=0;i<200;i++){
		GPIO_WriteBit(BeeGpio,Bee,(BitAction)(0));
		delay_us(500); 
		GPIO_WriteBit(BeeGpio,Bee,(BitAction)(1));
		delay_us(500);
	}
}
为了给下文的演奏做铺垫,发出声响的原理现在要着重强调一下:
 (delay函数是已经写好的,有us、ms、s等等单位,这里用的是us)
以一个非常简单的粉刷匠为例:(希望我没有记错谱子哈哈哈)
 
以“2432|5-”为例,我们把音调与对应的时间 两两一组,放到一个数组里:
uc16 m_24325[10]={//奇数项为频率,偶数项为持续时间(ms)
	587,300,
	698,300,
	659,300,
	587,300,
	784,750,
};
我在测试的时候发现如果严格按照音调对应频率的话,听起来反而与想象中的音乐差了不少(难道是蜂鸣器的事?)所以稍微改了一下频率。
 void Play_Music(void){ 
	u16 i,j;
	for(i=0;i<5;i++){
		for(j=0;j<m_24325[i*2]*m_24325[i*2+1]/1000;j++){
			GPIO_WriteBit(BeeGpio,Bee,(BitAction)(0));
			delay_us(500000/m_24325[i*2]);
			GPIO_WriteBit(BeeGpio,Bee,(BitAction)(1)); 
			delay_us(500000/m_24325[i*2]); 
		}	
	}
}
演算一下:以“523Hz”响750ms为例:
 
 如此,我们便能演奏一些基本的曲子了,只需要自己写一个乐谱就好了。
 void Play_Music(void)也可以写为有输入参数的函数,这样便于我们用同一个函数调用不同的乐谱。
接下来就到了另一个模块:
买到OLED模块以后,商家往往都会附赠配套程序的,不过往往都会赠IIC的程序。这里把我以前用的SPI程序放上。
#define OLED_CMD 0   
#define OLED_DATA 1 
#define OLED_CLK    PAout(4)  
#define OLED_MOSI   PAout(3)   
#define OLED_RST    PAout(2)   
#define OLED_DC     PAout(1)  
void OLED_SPI_Init(void); 
void SPI_WriteByte(uint8_t addr,uint8_t data); 
void WriteCmd(unsigned char cmd); 
void WriteData(unsigned char data); 
void OLED_SPI_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA ,ENABLE);
    GPIO_InitStructure.GPIO_Pin=GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4; 
    GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
    GPIO_Init(GPIOA,&GPIO_InitStructure);
}
void SPI_WriteByte(unsigned char data,unsigned char cmd)
{
    unsigned char i=0;
    OLED_DC =cmd;
    OLED_CLK=0;
    for(i=0;i<8;i++)
    {
        OLED_CLK=0;
        if(data&0x80)OLED_MOSI=1; 
        else OLED_MOSI=0;
        OLED_CLK=1;
        data<<=1;
    }
    OLED_CLK=1;
    OLED_DC=1;
}
void WriteCmd(unsigned char cmd)
{
    SPI_WriteByte(cmd,OLED_CMD);
}
void WriteData(unsigned char data)
{
    SPI_WriteByte(data,OLED_DATA);
}
void OLED_Init(void);
void OLED_ON(void);
void OLED_OFF(void);
void OLED_Refresh_Gram(void);
void OLED_Clear(void);
u8 OLED_GRAM[128][8];   
void OLED_DLY_ms(unsigned int ms)
{                         
  unsigned int a;
  while(ms)
  {
    a=1335;
    while(a--);
    ms--;
  }
}
void OLED_Init(void)
{
    OLED_SPI_Init();
    OLED_CLK = 1;
    OLED_RST = 0;
    OLED_DLY_ms(100);
    OLED_RST = 1;
      WriteCmd(0xae);
	  WriteCmd(0x00);
	  WriteCmd(0x10);
	  WriteCmd(0xd5);
	  WriteCmd(0x80);
	  WriteCmd(0xa8);
	  WriteCmd(0x3f);
	  WriteCmd(0xd3);
	  WriteCmd(0x00);
	  WriteCmd(0xB0);
	  WriteCmd(0x40);
	  WriteCmd(0x8d);
	  WriteCmd(0x14);
	  WriteCmd(0xa1);
	  WriteCmd(0xc8);
	  WriteCmd(0xda);
	  WriteCmd(0x12);
	  WriteCmd(0x81);
	  WriteCmd(0xff);
	  WriteCmd(0xd9);
	  WriteCmd(0xf1);
	  WriteCmd(0xdb);
	  WriteCmd(0x30);
	  WriteCmd(0x20);
	  WriteCmd(0x00);
	  WriteCmd(0xa4);
	  WriteCmd(0xa6);
	  WriteCmd(0xaf); 
    OLED_Clear(); 
}
void OLED_Refresh_Gram(void)
{
    u8 i,n;         
    for(i=0;i<8;i++)  
    {  
        WriteCmd(0xb0+i);   
        WriteCmd(0x00);      
        WriteCmd(0x10);      
        for(n=0;n<128;n++)WriteData(OLED_GRAM[n][i]); 
    }   
}
void OLED_Clear(void)  
{  
   	u8 j,t;
	for(t=0xB0;t<0xB8;t++){
	   WriteCmd(t);
		 WriteCmd(0x10);
		 WriteCmd(0x00);	
		for(j=0;j<132;j++){
 			    WriteData(0x11);
 		}
	}
}
这个是仿照商家的IIC例程改成SPI的写法,其实驱动OLED的方法都是一样的,只不过IIC和SPI略有不同而已(3个输入参数会在稍后讲到)
void OLED_DISPLAY_16x16(u8 x,u8 y, u16 w){ 
	u8 j,t,c=0;
	y=y-14;
	for(t=0;t<2;t++){
		WriteCmd(0xb0+x); 
		WriteCmd(y/16+0x10); 
		WriteCmd(y%16);
		for(j=0;j<16;j++){
 			WriteData(M_16[(w*32)+c]);
			c++;}x++;
	}
	WriteCmd(0xAF); 
}
比如:OLED_DISPLAY_16x16(4,8*16,8),在OLED屏幕第3行的第8列,显示库中的第9个字符
这个库是需要咱们自己建立的,可以由取模软件自动生成每个字符对应的16进制数据。
 我们用到的取模软件是:PCtoLCD2002
 配置如图:
 
 用它生成数据以后就可以把数据放到一个单独的.h文件中,作为我们自己的字符库。这里以两个16*16的空白为例
uc8 M_16[] = {
  //" "
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  //" "
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
};
这个软件还是很好用的,而且像素也可以自定,比如用64 * 128的图片铺满oled等等。详见生日快乐(b站投稿)。这里用的就是杜洋老师的开发板,我最初学32的时候就是学习杜洋老师的教程,虽然后来我又学了野火的32,正点原子的linux…(我很专一的/doge)
跑题了,这里只是举了一个16 * 16字符的例子,还有8 * 16字符、字符串、64 * 128图片等等,就请各位自己研究了/doge
我是康,希望做一名能帮助到各位的博主! 我不是本来要更机器学习的嘛? 在做了在做了(0%)预计下周会发布,欢迎感兴趣的小伙伴与我共同学习,一起进步!
| C调低音 | 频率(Hz) | C调中音 | 频率(Hz) | C调高音 | 频率(Hz) | 
|---|---|---|---|---|---|
| 1 | 262 | 1 | 523 | 1 | 1046 | 
| 1# | 277 | 1# | 554 | 1# | 1109 | 
| 2 | 294 | 2 | 587 | 2 | 1175 | 
| 2# | 311 | 2# | 622 | 2# | 1245 | 
| 3 | 330 | 3 | 659 | 3 | 1318 | 
| 4 | 349 | 4 | 698 | 4 | 1397 | 
| 4# | 370 | 4# | 740 | 4# | 1480 | 
| 5 | 392 | 5 | 784 | 5 | 1568 | 
| 5# | 415 | 5# | 831 | 5# | 1661 | 
| 6 | 440 | 6 | 880 | 6 | 1760 | 
| 6# | 466 | 6# | 932 | 6# | 1865 | 
| 7 | 494 | 7 | 988 | 7 | 1976 | 
原文:https://www.cnblogs.com/phyger/p/14072855.html