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