單片機(jī)通信是指單片機(jī)與計(jì)算機(jī)或單片機(jī)與單片機(jī)之間的信息交換,通常單片機(jī)與計(jì)算機(jī)之間的通信我們用的較多。通信有并行和串行兩種方式。串行通信又有兩種方式:異步串行通信和同步串行通信。 異步通信是以字符(構(gòu)成的幀)為單位進(jìn)行傳輸,字符與字符之間的間隙(時(shí)間間隔)是任意的,但每個(gè)字符中的各位是以時(shí)間傳送的,即字符之間不一定有“位間隔”的整數(shù)倍關(guān)系,但同一字符內(nèi)的各位之間的距離均為“位間隔”的整數(shù)倍。 DB25與DB9: 80C51串行口的結(jié)構(gòu): 有兩個(gè)物理上獨(dú)立的接受,發(fā)送寄存器SBUF,它們占用同一地址99H;接收器是雙緩沖結(jié)構(gòu);發(fā)送 緩沖器,因?yàn)榘l(fā)送時(shí)CPU是主動(dòng)的,不會(huì)產(chǎn)生重疊錯(cuò)誤。 RS232C標(biāo)準(zhǔn)接口主要引腳定義: 串行口控制寄存器SCON是一個(gè)特殊功能的寄存器,用以設(shè)定串行口的工作方式,接受發(fā)送控制及設(shè) 置狀態(tài)標(biāo)志。 SM0,SM1工作方式選擇位,SM2多機(jī)通信控制位,REN允許串行接收位,TI發(fā)送中斷標(biāo)志位,RI接 收中斷標(biāo)志位。串行發(fā)送停止位的開始時(shí),由內(nèi)部硬件使TI置1,向CPU發(fā)出中斷申請(qǐng)。在中斷服務(wù) 程序中,必須用軟件將其清0,取消此中斷申請(qǐng)。 電源管理寄存器PCON也是一個(gè)特殊功能寄存器,字節(jié)地址為87H,不能位尋址,PCON用來管理單片 機(jī)的電源部分,包括上電復(fù)位檢測(cè),掉電模式,空閑模式等。單片機(jī)復(fù)位時(shí)PCON全部被清0。 SMOD該位與串口波特率有關(guān),SMOD=0,串口方式1,2,3時(shí),波特率正常。SMOD=1,串口方式1,2,3時(shí),波特率加倍。 用軟件置REN為1時(shí),接收器會(huì)以所選擇波特率的16倍速采樣RXD引腳電平,檢測(cè)到RXD引腳輸入電平發(fā)生 負(fù)跳變時(shí),則說明起始位有效,將其移入輸入移位寄存器,并開始接受這一幀信息的其余位。接受過 程中,數(shù)據(jù)從輸入移位寄存器的右邊輸入,起始位移至輸入移位寄存器最左邊時(shí),控制電路進(jìn)行最后 一次移位。當(dāng)RI = 0,且SMOD = 0(或接受到的停止位為1)時(shí),將接收到的9位數(shù)據(jù)的前8位數(shù)據(jù) 裝入接受SBUF,第9位進(jìn)入RB8,并置RI=1,向CPU中斷請(qǐng)求。 在具體操作串行口之前,需要對(duì)單片機(jī)一些與串行口有關(guān)的特殊功能寄存器進(jìn)行初始化設(shè)置: 確定T1的工作方式(編程TMOD寄存器) 計(jì)算T1的初值,裝載TH1,TL1 開啟T1(編程TCON中的TR1位) 設(shè)置串口的工作方式(編程SCON寄存器) 串行口工作在中斷方式下,要進(jìn)行中斷設(shè)置(IE寄存器) 波特率計(jì)算公式: 方式0的波特率=fosc/12。 方式1的波特率=(2^smod/32)*(T1溢出率)。 方式2的波特率=(2smod/64)*fosc。 方式3的波特率=(2smod/32)*(T1溢出率)。 T1溢出率=fosc/{12*[256-(TH1)]} fosc為系統(tǒng)晶振頻率,通常為12MHZ或11.05926MHZ 異步串口通信兩種方式:輪詢和中斷 下面是一個(gè)中斷程序,使用串口調(diào)試工具發(fā)出什么返回什么。 #include <reg52.h> unsigned char a,flag; void main(){ TMOD = 0x20; //工作方式2,8位自動(dòng)重裝定時(shí)/計(jì)數(shù)器 TH1 = 0xfd; //波特率為9600bps,系統(tǒng)晶振頻率為11.0592MHZ時(shí)需要裝入的 TL1 = 0xfd; //TH1,TL1的值可以通過公式 T1溢出率=fosc/{12*[256-(TH1)]} EA = 1; //開啟CPU中斷允許位 ES = 1; //開始串口中斷允許位 SM1 = 1; //設(shè)置串口的工作方式為01即方式1,10位異步收發(fā)(8位數(shù)據(jù)) TR1 = 1; //T1開啟 REN = 1; //允許串行接受位 while(1){ if(flag == 1){ ES = 0; //關(guān)閉串口中斷,防止發(fā)送數(shù)據(jù)時(shí)產(chǎn)生中斷 SBUF = a; //將數(shù)據(jù)送到發(fā)送緩沖寄存器 while(!TI); //發(fā)送當(dāng)停止位開始時(shí),會(huì)產(chǎn)生中斷,把TI置1 TI = 0; flag = 0; ES = 1; //允許中斷 } } } void uart() interrupt 4{ a = SBUF; //當(dāng)產(chǎn)生RI中斷時(shí)說明數(shù)據(jù)接收完畢,把數(shù)據(jù)賦給變量a RI = 0; //軟件方法把RI置0 flag = 1; } 輪詢方式,如果有數(shù)據(jù)輸入發(fā)送給串口,當(dāng)停止位開始時(shí),蜂鳴器響起。 #include <reg52.h> #define uchar unsigned char sbit buzzer=P3^4; void delay(uchar z) { uchar x,y; for(x=1000;x>1;x--) for(y=z;y>1;y--); } void main(){ TMOD = 0x20; //工作方式2,8位自動(dòng)重裝定時(shí)/計(jì)數(shù)器 TH1 = 0xfd; //波特率為9600bps,系統(tǒng)晶振頻率為11.0592MHZ時(shí)需要裝入的 TL1 = 0xfd; //TH1,TL1的值可以通過公式 T1溢出率=fosc/{12*[256-(TH1)]} EA = 1; //開啟CPU中斷允許位 ES = 1; //開始串口中斷允許位 SM1 = 1; //設(shè)置串口的工作方式為01即方式1,10位異步收發(fā)(8位數(shù)據(jù)) TR1 = 1; //T1開啟 REN = 1; //允許串行接受位 while(1){ if(RI == 1){ //大循環(huán)進(jìn)行輪詢,如果串行發(fā)送停止位開始,則RI會(huì)被硬件置1 RI = 0; buzzer=0; delay(10); buzzer=1; delay(10); } } } 兩個(gè)糾結(jié)的程序: 由上位機(jī)發(fā)送1給單片機(jī)時(shí),蜂鳴器以400ms頻率發(fā)聲,發(fā)2時(shí)以200ms頻率發(fā)聲,發(fā)3時(shí)以100ms頻率發(fā)聲,發(fā)4時(shí)關(guān)閑蜂鳴器。 #include<reg52.h> unsigned char flag,a,num,benum; sbit beep=P3^4; void main() { TMOD=0x21;//設(shè)置定時(shí)器1為工作方式2 TH1=0xfd; TL1=0xfd; TH0=(65536-50000)/255; TL0=(65536-50000)%255; TR1=1; ET0=1; SM0=0; SM1=1; REN=1; EA=1; ES=1; while(1) { if(flag==1) { EA=0; flag=0; TR0=1; if(a==1) benum=4; if(a==2) benum=2; if(a==3) benum=1; if(a==4) { TR0=0; beep=1; } EA=1; } } } void ser() interrupt 4 { RI=0; a=SBUF; flag=1; } void time0() interrupt 1 { TH0=(65536-50000)/255; TL0=(65536-50000)%255; num++; if(num>=benum) { num=0; beep="beep; } } 以2400bps從計(jì)算機(jī)發(fā)送任一字節(jié)數(shù)據(jù),當(dāng)單片機(jī)收到該數(shù)據(jù)后,在此數(shù)據(jù)前加上一序號(hào)然后連同此數(shù)據(jù)一起發(fā)送至計(jì)算機(jī),當(dāng)序號(hào)超過255時(shí)歸零。 #include<reg52.h> unsigned char flag,a,num,num1; sbit beep=P3^4; void main() { TMOD=0x20;//設(shè)置定時(shí)器1為工作方式2 TH1=0xf4; TL1=0xf4; TR1=1; SM0=0; SM1=1; REN=1; EA=1; ES=1; while(1) { if(flag==1) { ES=0; flag=0; num1++; if(num1==255) num1=0; SBUF=num1; while(!TI); TI=0; SBUF=a; while(!TI); TI=0; ES=1; } } } void ser() interrupt 4 { RI=0; a=SBUF; flag=1; } 李萬(wàn)鵬 |