本章介紹如何使用stdio.h庫函數仿真串口通訊,學會使用view下面的“serial window #1”,實現模擬串口通訊。
Keil C51中有一些關鍵字,需要牢記:
interrupt0:指定當前函數為外部中斷0;
interrupt1:指定當前函數為定時器0中斷;
interrupt2:指定當前函數為外部中斷1;
interrupt3:指定當前函數為定時器1中斷;
interrupt4:指定當前函數為串口中斷;
?using 0表示當前函數使用第0組寄存器;
using 1表示當前函數使用第1組寄存器;
using 2 表示當前函數使用第2組寄存器;
using 3 表示當前函數使用第3組寄存器;
51單片機內有4個工作組寄存器,每個工作組的寄存器是R0--R7。
R0-R7在數據存儲器里的實際地址是由特殊功能寄存器PSW里的RS1、RS0位決定的。
using 0表示設置 RS1=0,RS0 =0,用第0組寄存器,R0--R7的在數據存儲區里的實際地址是00H-07H。R0(00H)....R7(07H);
using 1表示設置 RS1=0,RS0 =1,用第1組寄存器,R0--R7的在數據存儲區里的實際地址是00H-07H。R0(08H)....R7(0FH);
using 2表示設置 RS1=1,RS0 =0,用第2組寄存器,R0--R7的在數據存儲區里的實際地址是08H-0FH。R0(10H)....R7(17H);
using 3表示設置 RS1=1,RS0 =1,用第3組寄存器,R0--R7的在數據存儲區里的實際地址是00H-07H。R0(18H)....R7(1FH);
#include <REG51.h> ???//包含頭文件REG51.h,使能51內部寄存器;
#include <intrins.h> ?//包含頭文件intrins.h,要放在stdio.h的頭文件之前;
//使能函數: _nop_(); ?相當于匯編的NOP指令;
//使能函數: bit ?_testbit_( bit bit_value ); 對bit_value進行測試,若bit_value=1,返回1,否則返回0;
//使能函數: _cror_( unsigned char x, unsigned char n ); 將字節型變量x的值,向右循環移動n位,然后將其
//值返回;
//使能函數: _iror_( unsigned int x, ?unsigned char n ); 將雙字節型變量x的值,向右循環移動n位,然后將
//其值返回;
//使能函數: _lror_( unsigned long x, unsigned char n ); 將4字節型變量x的值,向右循環移動n位,然后將
//其值返回;
//使能函數: _crol_( unsigned char x, unsigned char n ); 將字節型變量x的值,向左循環移動n位,然后將其
//值返回;
//使能函數: _irol_( unsigned int x, ?unsigned char n ); 將雙字節型變量x的值,向左循環移動n位,然后將
//其值返回;
//使能函數: _lrol_( unsigned long x, unsigned char n ); 將4字節型變量x的值,向左循環移動n位,然后將
//其值返回;
//以上的循環左移和循環右移,同C語言的左移和右移是不同的,使用時要小心;
#include <stdio.h> ?//包含頭文件stdio.h
????//_getkey();從串口讀入一個字符;
???//putchar();向串口發送一個字節;
???//printf();向串口發送一串字節;
#define OSC_FREQ ????11059200L
#define BAUD_Time 1
#if(BAUD_Time==1)
//若波特率加倍,則使用下面參數;
#define BAUD_57600 ??256 - (OSC_FREQ/192L)/57600L ???//255
#define BAUD_28800 ??256 - (OSC_FREQ/192L)/28800L ???//254
#define BAUD_19200 ??256 - (OSC_FREQ/192L)/19200L ???//253
#define BAUD_14400 ??256 - (OSC_FREQ/192L)/14400L ???//252
#define BAUD_9600 ???256 - (OSC_FREQ/192L)/9600L ????//250
#define BAUD_4800 ???256 - (OSC_FREQ/192L)/4800L ?//244
#define BAUD_2400 ???256 - (OSC_FREQ/192L)/2400L ?//232
#define BAUD_1200 ???256 - (OSC_FREQ/192L)/1200L ?//208
#else
//若波特率不加倍,則使用下面參數;
#define BAUD_9600 ???256 - (OSC_FREQ/384L)/9600L
#define BAUD_4800 ???256 - (OSC_FREQ/384L)/4800L
#define BAUD_1200 ???256 - (OSC_FREQ/384L)/1200L
#endif
#define receive_buffer_size ?40
unsigned char receive_buffer[receive_buffer_size];
unsigned char next_in,next_out;
//函數功能:接收和發送中斷服務函數;
void isr_UART(void) interrupt 4 using 1
{ unsigned char temp;
??if(RI)?//處理接收數據;
????{ temp=_getkey(); //從串口接收一個字節;?
??receive_buffer[next_in++]=temp;
??????if(next_in==receive_buffer_size) next_in=0;
}
}
//函數功能:初始化串口,設置波特率為9600bps@11.0592MHz,使能接收,使用8位UART,開中斷允許;
void Serial_Port_Initialization()
{ PCON = 0x80;
??SCON=0x50; //串行控制寄存器: SM0,SM1,SM2,REN,TB8,RB8,TI,RI
?????????????//SM1:SM0=01,選擇方式1,SM2=0,表示非多機通訊,8-bit UART;
?????//REN=1,使能接收;
??TMOD&=0x0f;
??TMOD|= 0x20;
//定時器方式控制寄存器:GATE1,C/T1,M11,M10,GATE0,C/T0,M01,M00
????????//GATE=0,TR置1便可以啟動Timer;GATE=1,TR置1,且INT腳輸入高電平,才可以啟動Timer;
???//M11:M10=10,選擇方式2,8位自動重裝載;
??TH1=BAUD_9600; ?//TH1: ?reload value for 9600 baud @11.0592MHz;
??TL1=TH1;
??TR1=1; ??//啟動Timer1;
??//TI=1; ???//發送UART的第一個字節,為下次發送做準備;
??TI=0; ???//為下次發送做準備;
??RI=0;
??next_in=0;
??next_out=0;
??ES=1; //使能串口接收和發送中斷;
??EA=1; //開總中斷
}
//函數功能: 將接收到的數據返回給PC;
void send_data_to_pc()
{ while(next_out!=next_in) ?//將接收到的數據返回給PC;
?????{ TI=1; //為調用printf()和putchar()內部函數做準備;
???printf("receive_buffer[%bd]=%c\n",next_out,receive_buffer[next_out]);
???TI=0; //結束調用printf()和putchar()內部函數
????next_out++;
?}
}
//函數功能: Delay 50us
void delay_50us(unsigned char _50us)
{ while(_50us--)
{ _nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();
??_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();
??_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();
??_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();
??_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();
??_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();
??_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();
??_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();
????}
}
void main(void)
{ Serial_Port_Initialization();
??//初始化串口,設置波特率為9600bps@11.0592MHz,使能接收,使用8位UART,開中斷允許;
??TI=1;?//為調用printf()和putchar()內部函數做準備;
??printf("Start:\n");
??TI=0;?//結束調用printf()和putchar()內部函數
??for(;;)
????{ _getkey();?//打開view下面的serial window #1,用鍵盤輸入一個字符;
??send_data_to_pc(); //將接收到的數據返回給PC;
??delay_50us(20); ???//延時1ms;
??TI=0;?//結束調用printf()和putchar()內部函數
}
}