1.按鍵模塊
????????以按鍵k1為例:兩個引腳被接到GND和P1_4引腳,當K1按鍵被按下時,P1_4引腳會和GND短路到一起,P1_4引腳會呈現低電平。
按鍵初始化:
//按鍵初始化
void Key_Init(void)
{P1 |= (0x0f << 4);P3 |= (1 << 5);
}
檢測那個按鍵按下:
int Key_Press(void)
{int ret = 0;if((P1 & (1 << 4)) == 0){ret = 1;}else if ((P1 & (1 << 5)) == 0){ret = 2;}else if ((P1 & (1 << 6)) == 0){ret = 3;}else if ((P1 & (1 << 7)) == 0){ret = 4;}else if ((P3 & (1 << 5)) == 0){ret = 5;}
}
我們可以以此寫一個函數:那個按鍵亮起就讓數碼管顯示那個數字,如k1亮起數碼管顯示1,如果沒有按鈕按下則顯示0(Diditer_Show函數在上一篇文章有展示)
#include <reg51.h>
#include <key.h>
#include <digiter.h>
#include <delay.h>
int main(void)
{int ret = 0;Key_Init();while(1){ret = Key_Press();Digiter_Show(ret);P0 = 0;}return 0;
}
2.中斷
????????中斷概念:CPU在執行一個任務時,被外界更為緊急的事件打斷,轉而去執行更為緊急的任務,執行完后再回到剛才的地方繼續向下執行,這一過程叫做中斷。
????????中斷源:打斷CPU執行當前任務的事件/源頭叫做中斷源。
????????中斷源分類:外部中斷0、外部中斷1、定時器0、定時器1、串口。
????????中斷優先級:CPU再去處理中斷任務時候,會去比較多個中斷的優先級,優先去處理優先級高的中斷
????????默認優先級:
?????????中斷嵌套:處理一個中斷時,再嵌套另外的中斷;51單片機只允許嵌套2層。
????????中斷處理流程:
?? ??? ?(1)中斷源發出中斷請求
?? ??? ?(2)檢查CPU是否響應中斷及該中斷源是否被屏蔽
?? ??? ?(3)比較中斷優先級
?? ??? ?(4)保護現場
?? ??? ?(5)執行中斷服務函數(回調函數)
?? ??? ?(6)恢復現場
2.1外部中斷
????????單片機上的引腳電平變化所引發的中斷(INT0(P3-2)、INT1(P3-3))
寄存器相關配置:
1. IE寄存器(中斷允許寄存器)
?? ??? ?(1)將IE寄存器中的bit7,EA置1,代表CPU能夠響應所有中斷
?? ??? ?(2)將IE寄存器中的bit0,EX0置1,代表允許外部中斷0產生中斷
2. TCON寄存器(定時器寄存器)
(1)將TCON寄存器的bit1,IE0置1,代表向CPU發起中斷請求,CPU響應完中斷請求后,硬件清“0”
?? ??? ?(2)將TCON寄存器的bit0,IT0置1,代表外部中斷0下降沿觸發中斷
知道相關寄存器內容后,我們來對外部中斷0進行配置:
//中斷配置
void int0_init(void)
{P3 |= (1 << 2);//將外部中斷0對應的引腳置1IE |= (1 << 7);//CPU能夠響應所有中斷 總開關IE |= (1 << 0);//外部中斷0能夠發起中斷 子開關TCON |= (1 << 0);//外部中斷0:P3_2引腳中斷觸發方式->下降沿觸發
}
再編寫中斷處理函數,即發生中斷后所執行的函數內容:
//外部中斷0的處理函數,每次發生中斷g_i++,無需聲明
unsigned int g_i = 0;
void Int0_Handler(void) interrupt 0
{g_i++;
}
每發生一次中斷,g_i都會進行自加,我們將g_i傳參進Digiter_Show函數中,使得中斷次數在數碼管上顯示:
#include <reg51.h>
#include <key.h>
#include <digiter.h>
#include <delay.h>
int main(void)
{int ret = 0;Key_Init();int0_init();while(1){Digiter_Show(g_i); }return 0;
}
????????用杜邦線短接P3.2和GND,每次短接,都會產生下降沿觸發外部中斷0,數碼管也會顯示中斷次數。
2.2定時器中斷
定時器:能夠產生一個精準的定時,不同外設對時序的要求高(高電平和低電平時間是精準的)
?? ??? ?51單片機內部有兩個定時器,分別為timer0、timer1,所使用自增型定時器(計數器 16位),因此其自增范圍為0~2^16=65535。
?????????晶振,晶體振蕩器(12MHZ / 11.0592MHZ)
? ? ? ? ?由于51單片機達不到12MHZ,將12MHZ進行12分頻,12MHZ/12 = 1MHZ
? ? ? ? ?51單片機完成一條指令運算:1/1MHZ = 1us。
因此我們要想定時1ms,需要51單片機完成1000次計時,由于其為自增型,因此我們需要將初始值設為65535-1000=64535。在執行1000次運算后定時器溢出,也就是1ms后中斷。
定時器相關寄存器配置:
TCON寄存器:
?? ??? ??? ?(1)bit4置1,TMOD寄存器中的Gate位清0, 代表允許定時器開始計數,
TMOD寄存器:
?? ??? ??? ?(1)定時器0->低四位清0
?? ??? ??? ?(2)將TMOD寄存器中的M0,bit0置1,代表定時器0工作在16位定時器/計數器模式
IE寄存器:
?? ??? ??? ?(1)將IE寄存器中的bit7置1,代表CPU能夠響應所有中斷
(2)將IE寄存器中的bit1置1,代表允許定時器0產生中斷
配置流程:
?? ??? ?1. 先配置TMOD模式選擇寄存器,將低四位清0,再將bit0置1代表工作在16位定時器
?? ??? ?2. 向TH0和TL0中裝入定時器的初值(1ms -> 64535)
3. ?將TCON寄存器中的bit6置1,代表允許定時器開始計數
?? ??? ?4. ?將IE寄存器中的bit7和bit1置1,開啟中斷總開關和定時器0的子開關
?? ??? ?5. 編寫定時器0的中斷服務函數
我們對定時器進行配置:
// 定時器0初始化函數
void Timer0_Init(void)
{TMOD &= ~(0x0F << 0); // TMOD寄存器低四位清0TMOD |= (1 << 0); // 定時器工作在16位定時器模式TH0 = 64535 >> 8;TL0 = 64535;TCON |= (1 << 4); // 允許定時器0開始計數IE |= (1 << 7) | (1 << 1); // 允許CPU響應中斷及定時器0產生中斷
}
中斷服務函數:每過1s對所有LED燈進行一次反轉。
void Timer0_handler(void) interrupt 1
{TH0 = 64535 >> 8;TL0 = 64535;g_i++;if (g_i >= 1000){LED_Nor();g_i = 0;}
}
寫入主函數:
#include <reg51.h>
#include "timer.h"
#include "led.h"
int main(void)
{Timer0_Init();while (1){}return 0;
}
3.蜂鳴器模塊
????????????????????????
蜂鳴器:
?? ??? ??? ?震蕩源 ?-> 聲音(波)-> 音調不同 -> 波的頻率發生變化 -> 高音 高頻 ?低音 低頻 ? 音量不同 -> 波的振幅 -> 能量
?? ??? ??? ?有源蜂鳴器:存在震蕩源,通電后蜂鳴器會發出持續頻率的聲音。
?? ??? ??? ?無源蜂鳴器:不存在震蕩源,通電后蜂鳴器不會發出聲音,需要給蜂鳴器一個震蕩。
PWM:脈沖寬度調制,能夠讓引腳產生一個方波,周期性的讓引腳的電平發生翻轉。
????????PWM周期:一個方波所經歷的周期。(從上升沿到上升沿所經歷的時間/從下降沿到下降沿所經歷的時間)
?? ??? ?PWM占空比:在一個周期內高電平所占的比例。
我們分別調制200,400,600,800,1000hz的蜂鳴器發聲頻率
以200為例:
????????????????PWM蜂鳴器按照頻率200HZ,占空比50%工作
頻率:200HZ
時間:17公0==0.005s
定時:0.005s/2-0.0025s
定時器初值:
品振:12MHZ*10^6=12,000,000HZ分頻:12,000,000HZ/12=1000000HZ
時間:1/1000000HZ=0.000001s
定時器初值:
0.0025/0.000001=2500
65535-2500=63035
TH0=63035 >> 8;TL0=63035;
調制好的頻率對應的計數器初始值:
#ifndef TIMER_H__
#define TIMER_H__
extern void Timer0_Init(void);
extern unsigned short g_i1;
#define HZ200 63035
#define HZ400 64285
#define HZ600 64703
#define HZ800 64910
#define HZ1000 65035
#endif
定時器初始化以及中斷服務:
#include <reg51.h>
#include "led.h"
unsigned short g_i1 = 0;
// 定時器0中斷服務函數
void Timer0_handler(void) interrupt 1
{TH0 = g_i1 >> 8;TL0 = g_i1;P2 ^= (1 << 1); //蜂鳴器反轉信號
}// 定時器0初始化函數
void Timer0_Init(void)
{TMOD &= ~(0x0F << 0); // TMOD寄存器低四位清0TMOD |= (1 << 0); // 定時器工作在16位定時器模式TH0 = g_i1 >> 8;TL0 = g_i1;TCON |= (1 << 4); // 允許定時器0開始計數IE |= (1 << 7) | (1 << 1); // 允許CPU響應中斷及定時器0產生中斷
}
主函數調用:當按鍵按下后蜂鳴器會發出對應聲音:
#include <reg51.h>
#include "timer.h"
#include "led.h"
#include "key.h"
int main(void)
{int set = 0;Key_Init();Timer0_Init();while (1){set = Key_Press();if (set ==0){TCON = 0;}else if(set == 1){TCON |= (1 << 4);g_i1 = HZ200;}else if(set == 2){TCON |= (1 << 4);g_i1 = HZ400;}else if(set == 3){TCON |= (1 << 4);g_i1 = HZ600;}else if(set == 4){TCON |= (1 << 4);g_i1 = HZ800;}else if(set == 5){TCON |= (1 << 4);g_i1 = HZ1000;}}return 0;
}