用途:短距離、波特率要求不高、環境干擾不大的場合
特點:
程序簡練、實用、移植方便
占用定時器T2
只消耗約600字節的ROM
有詳細的注釋
參數:
晶振:22.1184MHz
波特率:1200
起始位:1
數據位:8
校驗位:無
停止位:1
?
#include
//將T2定時器的自動重裝寄存器定義成16位SFR,以方便訪問
sfr16 RCAP2 = 0xCA;
//修改如下定義將方便程序移植
sbit RXD_pin = P3^0; //定義接收引腳
sbit TXD_pin = P3^1; //定義發送引腳
#define MAIN_CLK 22118400L //定義主頻
#define BAUD_RATE 1200L //定義波特率(數值不能太高,因為要給T2中斷服務程序留足執行時間)
#define HITS 8 //定義采樣率(應當是偶數;減少采樣率能提高波特率,但為保證可靠工作,最小不能少于6次)
#define RXD_BUF_LEN 32 //定義接收緩沖區大小
volatile unsigned char RXD_buf[RXD_BUF_LEN]; //定義接收緩沖區(循環隊列)
volatile unsigned char RXD_p1; //指向緩沖區,由中斷程序自動修改
volatile unsigned char RXD_p2; //指向緩沖區,由主程序修改
#define TXD_BUF_LEN 32 //定義發送緩沖區大小
volatile unsigned char TXD_buf[TXD_BUF_LEN]; //定義發送緩沖區(循環隊列)
volatile unsigned char TXD_p1; //指向TXD_buf,由主程序修改
volatile unsigned char TXD_p2; //指向TXD_buf,由中斷程序修改
//定時器T2初始化
extern void T2_init()
{
EA = 0;
T2CON = 0x00;
PT2 = 1; //將T2中斷設置成高級優先級
RCAP2 = 65536L - ( MAIN_CLK / 12 ) / ( BAUD_RATE * HITS ); //此公式值得你琢磨一下
TH2 = RCAP2H;
TL2 = RCAP2L;
ET2 = 1;
TR2 = 1;
EA = 1;
}
//接收初始化
extern void RXD_init()
{
unsigned char i;
RXD_pin = 1;
RXD_p1 = 0;
RXD_p2 = 0;
for ( i=0; i {
RXD_buf[i] = 0x00;
}
}
//發送初始化
extern void TXD_init()
{
unsigned char i;
TXD_pin = 1;
TXD_p1 = 0;
TXD_p2 = 0;
for ( i=0; i《 TXD_BUF_LEN; i++ )
{
TXD_buf[i] = 0x00;
}
}
//發送單個字符
extern void TXD_Send_Char(const unsigned char c)
{
unsigned char p; //臨時變量
p = TXD_p1 + 1;
if ( p 》= TXD_BUF_LEN ) p = 0;
while ( p == TXD_p2 ); //判斷發送緩沖隊列是否已滿,如果是,則暫時不能發送
TXD_buf[TXD_p1] = c; //先將c寫入隊列
TXD_p1 = p; //再修改TXD_p1
//在T2中斷服務程序里會自動完成發送
}
//發送字符串(不包括末尾的‘’)
extern void TXD_Send_String(const unsigned char s[])
{
unsigned char c;
unsigned int i = 0;
for (;;)
{
c = s[i++];
if ( c == ‘’ ) break;
TXD_Send_Char(c);
}
}
//定義接收緩沖字符
volatile unsigned char bdata RXD_ch;
sbit RXD_ch_MSB = RXD_ch^7;
//定義發送緩沖字符
volatile unsigned char bdata TXD_ch;
sbit TXD_ch_LSB = TXD_ch^0;
//T2中斷服務程序
//每中斷HITS次處理1位
static void T2INTSVC() interrupt 5 using 3
{
//定義接收所需要的變量
static bit RXD_doing = 0; //正在接收的標志
static unsigned char RXD_t = HITS/2; //接收時計數T2的中斷次數
static unsigned char RXD_cnt; //接收時bit位的計數器
//定義發送所需要的變量
static bit TXD_doing = 0; //正在發送的標志
static unsigned char TXD_t; //發送時計數T2的中斷次數
static unsigned char TXD_cnt; //發送時bit位的計數器
//先清除TF2
TF2 = 0;
//接收數據
if ( RXD_doing ) //正處于接收狀態
{
if ( --RXD_t == 0 ) //經過了HITS個采樣脈沖
{
if ( RXD_cnt == 0 ) //8個數據位接收完畢
{
if ( RXD_pin ) //檢測到停止位
{
RXD_t = RXD_p1 + 1; //在這里,RXD_t作為臨時變量
if ( RXD_t 》= RXD_BUF_LEN ) RXD_t = 0;
if ( RXD_t != RXD_p2 ) //如果接收緩沖隊列未滿
{
RXD_buf[RXD_p1] = RXD_ch;
RXD_p1 = RXD_t;
}
else
{
//如果接收緩沖隊列已滿,只好丟棄新收到數據
}
}
else //檢測停止位時出錯
{
//舍棄新收到的數據
}
RXD_doing = 0; //接收全部完畢,清除正在接收的標志
RXD_t = HITS/2; //恢復RXD_t的初始值
}
else //接收數據位
{
RXD_ch 》》= 1;
RXD_ch_MSB = RXD_pin;
//上面2條語句若用{CY=RXD_pin; CY=(RXD_ch&0x01); RXD_ch=ACC;}代替,效率更高
RXD_cnt--;
RXD_t = HITS;
}
}
}
else //檢測起始位
{
if ( RXD_pin )
{
RXD_t = HITS/2;
}
else
{
RXD_t--;
if ( RXD_t == 0 ) //連續HITS/2次采樣RXD_pin都是0,就可以確認起始位
{
//啟動接收
RXD_t = HITS;
RXD_cnt = 8;
RXD_doing = 1;
}
}
}
//發送數據
if ( TXD_doing ) //正處于發送狀態
{
TXD_t--;
if ( TXD_t == 0 )
{
if ( TXD_cnt == 0 ) //發送全部完畢
{
TXD_doing = 0; //清除正在發送的標志
}
else
{
if ( TXD_cnt == 1 ) //8個數據位發送完畢
{
TXD_pin = 1; //發送停止位
}
else //發送數據位
{
TXD_pin = TXD_ch_LSB;
TXD_ch 》》= 1;
//上面2條語句若用{CY=(TXD_ch&0x01); TXD_pin=CY; TXD_ch=ACC;}代替,效率更高
}
TXD_cnt--;
TXD_t = HITS;
}
}
}
else
{
if ( TXD_p2 != TXD_p1 ) //如果發送緩沖隊列不空
{
//從發送緩沖隊列中取出要發送的數據
TXD_ch = TXD_buf[TXD_p2++];
if ( TXD_p2 》= TXD_BUF_LEN ) TXD_p2 = 0;
//啟動發送
TXD_doing = 1;
TXD_cnt = 9;
TXD_t = HITS;
//先發送起始位
TXD_pin = 0;
}
else
{
//發送緩沖隊列是空的,不發送任何數據
}
}
}
//系統初始化
void SystemInit()
{
TXD_init();
RXD_init();
T2_init();
}
//主程序
void main()
{
unsigned char c;
SystemInit();
//
TXD_Send_String(“Hello!rn”);
TXD_Send_String(“The author is 21IC suda.rn”);
//以下是簡單的測試:從接收引腳接收數據,再通過發送引腳轉發出去
for (;;)
{
if ( RXD_p2 != RXD_p1 )
{
c = RXD_buf[RXD_p2++];
if ( RXD_p2 》= RXD_BUF_LEN ) RXD_p2 = 0;
TXD_Send_Char(c);
}
}
}
來源;21ic
評論
查看更多