1. 程式人生 > 實用技巧 >23 final關鍵字(完結器)

23 final關鍵字(完結器)

此文轉載自:https://blog.csdn.net/k_ksy/article/details/106233645

520到了,看著朋友圈裡的花式秀恩愛,平常午餐最愛吃的泡麵都變得不那麼香了。於是!突發奇想,突然就來了更新的想法,今天用32來做一個非常簡單的小程式:

簡單放個歌,再放個圖

stm32f103c8t6

因為基本只用到兩個外設,程式容量也很小,所以用c8t6就剛剛好

無源蜂鳴器

這裡要用的是無源蜂鳴器

,其音調是可調的。

庫函式

我們先宣告要用到的引腳以及相應的函式:

#define BeeGpio	GPIO自選
#define Bee 	GPIO_Pin_自選	

void Bee_Init(void); //蜂鳴器初始化
void Bee_test(void); //蜂鳴器測試
void Play_Music(void);//播放音樂

void Bee_Init(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)

在主函式演奏之前,我們先測試一下蜂鳴器好不好使,讓它先響一聲:

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)

  • 在這個for迴圈裡,先後兩次的delay_us(500)加在一起構成了一個週期,這個週期的時間長是1000us,也就是1ms。在這1ms的時間裡,一半的時間蜂鳴器不響,另一半的時間響,如此重複200次,就成為了我們人類耳朵聽到的一個時間約為200ms的響聲。

樂譜(簡譜)

以一個非常簡單的粉刷匠為例:(希望我沒有記錯譜子哈哈哈)

以“2432|5-”為例,我們把音調與對應的時間 兩兩一組,放到一個數組裡:

uc16 m_24325[10]={//奇數項為頻率,偶數項為持續時間(ms)
	587,300,
	698,300,
	659,300,
	587,300,
	784,750,
};

我在測試的時候發現如果嚴格按照音調對應頻率的話,聽起來反而與想象中的音樂差了不少(難道是蜂鳴器的事?)所以稍微改了一下頻率。

void Play_Music(void)

 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]); 
		}	
	}
}
  • 因為在前文的樂譜中,記了10個數據,5對音調與時間,所以令i=0;i<5
  • 在第二個for迴圈中,先後兩次delay_us(500000/music1[i*2]),使得週期變為1000 000/頻率
  • 而 j<m_24325[i*2]m_24325[i2+1]/1000 和 週期共同決定了蜂鳴器發出這個頻率對應音調的時間

演算一下:以“523Hz”響750ms為例:

如此,我們便能演奏一些基本的曲子了,只需要自己寫一個樂譜就好了。
void Play_Music(void)也可以寫為有輸入引數的函式,這樣便於我們用同一個函式呼叫不同的樂譜。

接下來就到了另一個模組:

OLED模組(7腳64*128)

買到OLED模組以後,商家往往都會附贈配套程式的,不過往往都會贈IIC的程式。這裡把我以前用的SPI程式放上。

模擬SPI

.h

#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); 

.c

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);
}

OLED

.h

void OLED_Init(void);
void OLED_ON(void);
void OLED_OFF(void);
void OLED_Refresh_Gram(void);
void OLED_Clear(void);

.c

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);
 		}
	}
}

顯示16*16的字元

這個是仿照商家的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); 
}
  • 第一個引數x:字元的行:0、2、4、6共4行(4*16=64,把64個畫素分為4行)
  • 第二個引數y:字元的列:共128列(畫素),但是因為字元是16*16的,所以用n * 16代替,便於計算
  • 第三個引數w:對應庫中的第幾個字元
  • 庫:M_16(在倒數第5行),這個內容馬上就講到

比如: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)
1262152311046
1#2771#5541#1109
2294258721175
2#3112#6222#1245
3330365931318
4349469841397
4#3704#7404#1480
5392578451568
5#4155#8315#1661
6440688061760
6#4666#9326#1865
7494798871976

  1. ↩︎