新聞中心

EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > 51單片機(jī)學(xué)習(xí)總結(jié)實(shí)例

51單片機(jī)學(xué)習(xí)總結(jié)實(shí)例

作者: 時(shí)間:2016-11-19 來源:網(wǎng)絡(luò) 收藏
馬上大四了,即將找工作。所以便把我學(xué)過的東西總結(jié)一下,系統(tǒng)一下。

接下來,就把我總結(jié)的結(jié)果跟大家分享下。

本文引用地址:http://butianyuan.cn/article/201611/318259.htm

這一章是51單片機(jī),主要是程序?qū)嵗4a參考郭天祥的單片機(jī)教材。

是總括性的,適合于有一定單片機(jī)基礎(chǔ)的同學(xué),也可以給初學(xué)者做一個(gè)系統(tǒng)的學(xué)習(xí)主線。

這個(gè)博客里的涉及的源代碼大家可以在這里下載http://download.csdn.net/detail/zhaole20094463/4427745

1.流水燈

/流水燈/
#include
#include//包含_crol_函數(shù)所在的頭文件
#define uint unsigned int //宏定義 定義uint 在大項(xiàng)目中更加的方便
#define uchar unsigned char
void delayms(uint);
uchar aa;
void main()
{
aa=0xfe;
while(1)
{
P1=aa;
delayms(500);
aa=_crol_(aa,1);//aa左移一位
}
}
void delayms(uint xms)//延時(shí)時(shí)間約為1ms通過程序單步執(zhí)行,看運(yùn)行時(shí)間可得到
{
uint i,j;
for(i=xms;i>0;i--)
for(j=110;j>0;j--);
}

通過調(diào)用系統(tǒng)函數(shù)的方式使流水燈實(shí)現(xiàn)循環(huán)左移。

2.數(shù)碼管顯示程序

/*鎖存器用的是74HC573高電平通,低電平鎖存*/
/*作用:高阻態(tài) ,數(shù)據(jù)鎖存 ,數(shù)據(jù)緩沖 (加強(qiáng)驅(qū)動(dòng)能力)*/
/*循環(huán)顯示1-A的數(shù)據(jù)*/
#include
#define uint unsigned int
#define uchar unsigned char
sbit dula=P2^6;
sbit wela=P2^7;
uchar num;
uchar code table[]={數(shù)碼管段碼表};
void main()
{
wela=1;//打開鎖存器
P0=0xc0;//送入鎖存信號
wela=0;//關(guān)閉鎖存器
while(1)
{
for(num=0;num<16;num++)
dula=1;
P0=table[num];
delayms(500);
}
}
void delayms(uint xms)
{
uint i,j;
for(i=xms;i>0;i--)
for(j=110;j>0;j--);
}

3.獨(dú)立鍵盤檢測

/*通過按鍵控制led亮滅*/
#include
#define uint unsigned int
#define uchar unsigned char
sbit key1=P3^4;
sbit led=P1^0;
void delay(uint z)
{
uint x,y;
for(x=z;x>0;x--)
for(y=110;y>0;y--);
}
void main()
{
P3=0xff;//在對51單片機(jī)進(jìn)行按鍵檢測時(shí),先要將引腳置1;
while(1)
{
if(key1==0)
{
delay(5);
if(key1==0)//按鍵消抖
{
led=0;
num++;
if(num==2)
num=0;
led=1;
}
}

4.矩陣鍵盤檢測

/*檢測矩陣鍵盤數(shù)碼管顯示0-F/
矩陣鍵盤的四列與P3.4~P3.7相連
4行與P3.0~P3.3
#include
#define uchar unsinged char
#define uint unsigned int
sbit dula=P2^6;
sbint wela=P2^7;
uchar code table[]={段碼表};
void delayms(uint xms);
{
uint i,j;
for(i=xms;i>0;i--)
for(j=110;j>0;j--);
}
void display(uchar num)顯示函數(shù)
{
P0=table[num];
dula=1;
dula=0;
}
void matrixkeyscan()//矩陣鍵盤的檢測
{
uchar temp,key;
P3=0xfe;//打開P3.7,P3.7置0.檢測高四位
temp=P3;
temp=temp&0xf0;
if(temp!=0xf0)//是否有鍵被按下
{
delayms(10);
temp=P3;
temp=temp&0xf0;
if(temp!=0xf0)//按鍵消抖
{
temp=P3;
switch(temp)
{
case 0xee:key=0;break;
case 0xde:key=1;break;
case 0xbe:key=2;break
case 0x7e:key=3:break;
}
while(temp!=0xf0)//檢測按鍵是否彈起,如果沒有彈起循環(huán)停在這里。
{
temp=P3;
temp=temp&0xf0;
}
display(key);
}
}
。。。。。。。。。。。。。。。。。。。
如下程序依次增加
令P3=0xfd,打開P3.6,P3.6置低,檢測高四位 依次為 4,5,6,7
然后令P3= 0xfb 0xf7
}
void main()
{
P0=0;//關(guān)閉所有數(shù)碼管的段選
dula=1;
dula=0;
P0=0xc0;
wela=1;
wela=0;
while(1)
{
matrixkeyscan();//不停調(diào)用鍵盤掃描程序
此程序關(guān)鍵在于這個(gè)函數(shù),矩陣鍵盤的掃描算法
}
}

5.1602液晶屏顯示子函數(shù)

//
這個(gè)程序主要是有這樣幾個(gè)子函數(shù),關(guān)于lcd寫命令和寫數(shù)據(jù)的
#include
#define uchar unsigned char
#define uint unsigned int
uchar code table[]="zhaole20094463";
uchar code table1[]="love Embedded systems";
sbit lcden=P3^4;//lcd使能端
sbit lcdrs=P3^5;//lcd數(shù)據(jù)命令選擇端
uchar num;
void delay(uint z)
{
uint x,y;
for(x=z;x>0;x--)
for(y=110;y>0;y--);
}
void write_com(uchar com)//lcd寫命令函數(shù)
{
lcdrs=0;
P0=com;
delay(5);
lcden=1;
delay(5);
lceen=0;
}


void write_data(uchar date)//lcd寫數(shù)據(jù)
{
lcdrs=1;
P0=date;
delay(5);
lcden=1;
delay(5);
lcden=0;
}


void init()
{
lcden=0;
write_com(0x38);//設(shè)置16*2顯示,5*7點(diǎn)陣,8位數(shù)據(jù)接口
write_com(0x0c);//設(shè)置開顯示,不顯示光標(biāo)
write_com(0x06);//寫第一個(gè)字符后地址指針加1
write_com(0x01);//顯示清0,數(shù)據(jù)指針清0
}
void main()
{
init();
write_com(0x80);//數(shù)據(jù)指針定位在第一行的第一個(gè)字處
for(num=0;num<14;num++)
{
write_data(table[num]);
delay(5);
}
write_com(0x80+0x40);//數(shù)據(jù)指針定位在第二行的第一個(gè)字處
for(num=0;num<21;num++)
{
write_data(table1[num]);
delay(5);
}
while(1);
}

5.2 12864顯示子函數(shù)

#include
#include
#include


#define uchar unsigned char
#define uint unsigned int


#define LCD_data P0;//數(shù)據(jù)口


sbit LCD_RS=P3^5; //數(shù)據(jù)選擇輸入
sbit LCD_RW=P3^6; //液晶讀寫控制
sbit LCD_EN=P3^4; //液晶使能控制端
sbit LCD_PSB=P3^7; //串并方式控制


void delay_1ms(uint )
{
uint i,j;
for(j=0j for(i=0;i<110;i++);
}
/*PS=L,RW=L,E=高脈沖,D0~D7=指令碼*/
void write_cmd(uchar cmd)
{
LCD_RS=0;
LCD_RW=0;
LCD_EN=0;
P0=cmd;
delay_1ms(5);
LCD_EN=0;
}
/*寫顯示數(shù)據(jù)到LCD*/
/*RS=H,RW=L,E=高脈沖,D0~D7=數(shù)據(jù)
void write_dat(uchar dat)
{
LCD_RS=1;
LCD_RW=0;
LCD_EN=0;
P0=dat;
delay_1ms(5);
LCD_EN=1;
dealy_1ms(5);
LCD_EN=0;
}
/*設(shè)定顯示位置*/
void LCD_pos(uchar X,uchar Y)
{
uchar pos;
if(X==0)
{X=0x80;}
else if(X==1);
{X=0x90;}
else if(x==2)
{X=0x88;}
else if(X==3)
{X=0x98;}
pos=X+Y;
write_cmd(pos);//顯示地址
}


/*LCD初始化設(shè)置*/
void lcd_init()
{
LCD_PSB=1; //并口方式
write_cmd(0x30);//基本指令操作
delay_1ms(5);
write_cmd(0x0C);//先是開,關(guān)光標(biāo)
delay_1ms(5);
write_cmd(0x01);//清除LCD的顯示內(nèi)容
delay_1ms(5);
}

6.定時(shí)器中斷

/*用定時(shí)器0的方式1實(shí)現(xiàn)第一個(gè)發(fā)光管以1s亮滅*/
定時(shí)器/計(jì)數(shù)器4種工作方式
1,方式0 13位計(jì)數(shù)器 高8位和低5位
2,方式1 16位計(jì)數(shù)器
3,方式2 自動(dòng)恢復(fù)初值 8位
4,方式3 只適用于T0,不適用于T1 8位

45872初值的計(jì)算
晶振:11.0592M
機(jī)器周期:計(jì)數(shù)一次的時(shí)間=12*(1/11.0592M)51單片機(jī)是12個(gè)時(shí)鐘周期為一個(gè)機(jī)器周期
=1.09US 指令周期由整數(shù)個(gè)機(jī)器周期組成
45872 =50Ms/1.09us


//
#include
#define uchar unsigned char
#define uint unsigned int
sbit led1=P1^0;
uchar num;
void main()
{
TMOD=0x01;//設(shè)置定時(shí)器0工作方式1
TH0=(65535-45872)/256;//裝初值11.0592M晶振定時(shí)50ms為45872
TL0=(65535-45872)%256;
EA=1; //開總中斷
ET0=1; //開定時(shí)器0中斷
TR0=1; //啟動(dòng)定時(shí)器0
while(1) //程序停在這里等待中斷的發(fā)生
}


void T0_time() interrupt 1
{
TH0=(65535-45872)/256;
TL0=(65535-45872)%256;
num++;
if(num==20)
{
num=0;
led1=~led1;
}
}

7.串口通信

//
上位機(jī)通過串口調(diào)試助手發(fā)送一個(gè)字符x,單片機(jī)收到字符后返回給上位機(jī)“I get x”
串口波特率設(shè)置為9600bps。
#include
#define uchar unsigned char
#define uint unsigned int
uchar flag,a,i;
uchar code table[]="I get";
void init()
{
TMOD=0x20;//設(shè)置T1定時(shí)器工作方式為2 8位初值自動(dòng)重裝的8位定時(shí)器
TH1=0xfd;//T1定時(shí)器裝初值(高八位) 控制串口通信的波特率(由定時(shí)器1的溢出率控制)
TL1=0xfd;///T1定時(shí)器裝入初值(低八位)
TR1=1; //定時(shí)器1運(yùn)行控制位 置一啟動(dòng)定時(shí)器
REN=1; //允許串口接收
SM0=0;
SM1=1; //設(shè)置串口工作方式為一
EA=1; //全局中斷允許位 置一開全局中斷
ES=1; //串口中斷允許位
}


void main()
{
init();
` while(1)
{
if(flag==1)
{
ES=0;
for(i=0;i<6;i++)
{
SBUF=table[i];
while(!TI)
TI=0;//發(fā)送中斷標(biāo)志 發(fā)送數(shù)據(jù)完成后觸發(fā)中斷 硬件置一 必須軟件清零
}
SBUF=a;// 串口發(fā)送數(shù)據(jù)
while(!TI);
TI=0;
ES=1;
flag=0;
}

}


void ser() interrupt 4 //串口中斷服務(wù)程序
{
RI=0; // 收到數(shù)據(jù)硬件置一,由軟件清零
a=SBUF; //將寄存器的值 賦給a
flag=1; //標(biāo)志位
}
注意:51單片機(jī)的特殊之處在于,SBUF既是串口接收寄存器也是串口發(fā)送寄存器,取決于
SBUF所在賦值符號“=”左右的位置


此程序中共用的串口中斷,


定時(shí)器1中斷 特殊功能寄存器SBUF


中斷響應(yīng)的條件


中斷源有中斷請求 此中斷源允許位為1 cpu開中斷(即EA=1)以上三個(gè)條件同時(shí)滿足


串口通信設(shè)置


確定串口通信波特率(編程TMOD寄存器定時(shí)器工作方式寄存器)

計(jì)算定時(shí)器初值轉(zhuǎn)載THX TLX

確定串行口工作方式(編程SCON寄存器串行口控制方式寄存器)

串行口工作在中斷方式時(shí),要進(jìn)行中斷設(shè)置如TI,RI軟件清零

8.I2C總線通信模擬子函數(shù)

/*/
因?yàn)?1單片機(jī)沒有I2C總線,所以采用模擬I2C通信
1,總線初始化
void init()
{
SCL=1;
delay();
SDA=1;
delay();
}
2,啟動(dòng)信號
void start()
{
SDA=1;
delay(1);
SCL=1;
delay();
SDA=0;
delay();
}
3,應(yīng)答信號
void respons()
{
uchar i=0;
SCL=1;
delay();
while((SDA==1)&&(i<255))
i++;
SCL=0;
delay();
}
4,停止信號
void stop()
{
SDA=0;
delay();
SCL=1;
delay();
SDA=1;
delay();
}
5,寫一個(gè)字節(jié)
void writebyte(uchar date)
{
uchar i,temp;
temp=date;
for(i=0;i<8;i++)
{
temp=temp<<1;
SCL=0;
delay();
SDA=CY;
delay();
SCL=1;
delay();
}
SCL=0;
delay();
SDA=1;
delay();
}
6,讀一個(gè)字節(jié)
uchar readbyte()
{
uchar i,k;
SCL=0;
delay();
SDA=1;
for(i=0;i<8;i++)
{
SCL=1;
delay();
k=(k<<1)|SDA;
SCL=0;
delay();
}
delay();
return k;
}

9.看門狗

//
關(guān)于51單片機(jī)中的看門狗寄存器
D5 EN_WDT 看門狗允許位
D4 CLK_WDT 看門狗清零
D3 IDLE_WDT 看門狗IDLE模式位
PS0 PS1 PS2 看門狗定時(shí)器預(yù)分頻值
這三個(gè)寄存器置不同的值決定不同的看門狗溢出時(shí)間
看門狗溢出時(shí)間=(N*預(yù)分頻數(shù)*32768)/晶振頻率
#include
#define uchar unsigned char
#define uint unsigned int
sfr WDT_CONTR=0xe1;//定義看門狗寄存器 reg52.h中沒有對它進(jìn)行定義
sbit led1=P1^0;
void delayms(uint xms)
{
uint i,j;
for(i=xms;j>0;j--)
for(j=110;j>0;j--);
}

void main()
{
WDT_CONTR=0x35;//0x35=0011 0101設(shè)置預(yù)分頻數(shù)為 64 溢出時(shí)間為2.0971s
led1=0;
delayms(500);
led1=1;
while(1)
{
delayms(1000);
WDT_CONTR=0x35;//喂狗語句將D4不斷置1,一旦D4被清零則看門狗復(fù)位
}
}

10.軟件實(shí)現(xiàn)系統(tǒng)復(fù)位

STC ISP/IAP控制寄存器(ISP_CONTR)
D7 ISPEN 功能允許位 0禁止編程改變flash 1允許
D6 SWBS 0軟件選擇從用戶應(yīng)用程序區(qū)啟動(dòng) 1從ISP程序區(qū)啟動(dòng)
D5 SWRST 不操作 1產(chǎn)生系統(tǒng)軟件復(fù)位,硬件自動(dòng)清零
D2 WT2
D1 WT1
D0 WT0 編程設(shè)定CPU等待的最長時(shí)間,對flash進(jìn)行讀操作,寫操作,擦除操作必須在這個(gè)時(shí)間內(nèi)
SWBS=0 SWRST=1(軟復(fù)位) 從用戶應(yīng)用程序區(qū)(AP區(qū))軟件復(fù)位并切換到用戶應(yīng)用程序區(qū)開始執(zhí)行程序
從哪里復(fù)位取決于程序在哪里執(zhí)行
SWBS=1 SWRST=1 從ISP監(jiān)控程序區(qū)軟件復(fù)位并切換ISP監(jiān)控程序區(qū)開始執(zhí)行程序
使用方法:
進(jìn)行軟件復(fù)位時(shí)
首先
sfr ISP_CONTR=0xe7;定義ISP/IAP控制寄存器
然后再需要軟件復(fù)位的地方加入如下語句即可
ISP_CONTR=0x20//用軟件復(fù)位到用戶應(yīng)用程序區(qū)(AP),重新開始執(zhí)行程序

11.DS18B20編程應(yīng)用子函數(shù)

//
Ds18B20的編程子函數(shù)
DS18B20是單總線接口的溫度傳感器,應(yīng)用范圍很廣泛

#include
#include
#define uchar unsigned char
#define uint unsigned int
sbit ds=P2^2;//溫度傳感器信號線
uint temp;//定義整型的溫度數(shù)據(jù)
float temp;//定義浮點(diǎn)型的溫度數(shù)據(jù)
void delay(uint z)
{
uint x,y;
for(x=z;x>0;x--)
for(y=110;y>0;y--);
}




void dsreset(void)//DS18B20復(fù)位,初始化函數(shù)
{
uint i;
ds=0;
i=103;
while(i>0)i--;
ds=1;
i=4;
while(i>0)i--;
}


bit tempreadbit(void)//讀1位數(shù)據(jù)函數(shù)
{
uint i;
bit dat;
ds=0;i++;//i++起延時(shí)作用
ds=1;i++;i++;
dat=ds;
i=8;while(i>0)i--;
return(dat);
}


uchar tempread(void)//讀1個(gè)字節(jié)數(shù)據(jù)函數(shù)
{
uchar i,j,dat;
dat=0;
for(i=1;i<=8;i++)
{
j=tempreadbit();
dat=(j<<7)|(dat>>1);//讀出的數(shù)據(jù)最低位在最前面,這樣剛好一個(gè)字節(jié)在dat里
}
return(dat);
}
void tempwritebyte(uchar dat)//向DS18B20寫一個(gè)字節(jié)數(shù)據(jù)函數(shù)
{
uint i;
uchar j;
bit testb;
for(j=1;j<=8;j++)
{
testb=dat&0x01;
dat=dat>>1;
if(testb)//寫1
{
ds=0;
i++;i++;
ds=1;
i=8;while(i>0)i--;
}
else//寫0
{
ds=0;
i=8;while(i>0)i--;
ds=1;
i++;i++;
}
}
}


void tempchange(void)//DS18B20 開始獲取溫度并轉(zhuǎn)換
{
dsreset();
delay(1);
tempwritebyte(0xcc);//寫 跳過讀ROM指令
tempwritebyte(0x44);//寫 溫度轉(zhuǎn)換指令
}


uint get_temp()
{
uchar a,b;
dsreset();
delay(1);
tempwritebyte(0xcc);
tempwritebyte(0xbe);//讀內(nèi)部ram中的9字節(jié)
a=tempread();//讀低8位
b=tempreda();//讀高8位
temp=b;
temp<<=8;
temp=temp | a;//兩個(gè)字節(jié)組合為1個(gè)字
f_temp = temp*0.0625;//溫度在寄存器中為12位,分辨率為0.0625 廠家出廠時(shí)默認(rèn)精度為12位,所以乘以0.0625
temp=f_temp*10+0.5; //乘以10表示小數(shù)點(diǎn)后面只取一位,加0.5是為了四舍五入
f_temp=f_temp+0.05;
return temp;
}

12.內(nèi)部ram的擴(kuò)展

51單片機(jī)存儲器模式一共有三種
small模式 默認(rèn)變量存儲在單片機(jī)內(nèi)部的128B RAM中
無聲明均以這個(gè)模式存儲
compact模式 默認(rèn)變量存儲在單片機(jī)內(nèi)部的 256B RAM中
關(guān)鍵字 pdata :unsinged char pdata a[100]
large 模式 默認(rèn)變量均存儲在64K的RAM區(qū)包括內(nèi)部ram和外部ram
關(guān)鍵字 xdata:unsingned char xdata a[100]
三種模式的不同:訪問速度由快到慢

這個(gè)博客里的涉及的源代碼大家可以在這里下載http://download.csdn.net/detail/zhaole20094463/4427745



評論


技術(shù)專區(qū)

關(guān)閉