機電之家資源網(wǎng)
單片機首頁|單片機基礎|單片機應用|單片機開發(fā)|單片機文案|軟件資料下載|音響制作|電路圖下載 |嵌入式開發(fā)
培訓信息
贊助商
單片機串口發(fā)送接收程序模塊程序
單片機串口發(fā)送接收程序模塊程序
 更新時間:2010-1-26 16:29:49  點擊數(shù):0
【字體: 字體顏色

/************************************************************************  
;* 公 司: xx  
;* 模 塊: serial.c  
;* 功 能: 串口中斷服務程序,僅需做簡單調用即可完成串口輸入輸出的處理;  
;* 出入均設有緩沖區(qū),大小可任意設置  
;* 芯 片: AMEGA16  
;* 說 明: 未利用串口發(fā)送硬件BUFF  
;* 設 計: 李耀峰  
;* 時 間: 2005-11-24  
;* 版 本: V1.0  
;* 記 錄:  
;************************************************************************/  


/************************************************************************  
可供使用的函數(shù)名:  
extern void PutByte(byte c); //放入一個字節(jié)到發(fā)送緩沖區(qū)  
extern void PutString(byte *puts); //發(fā)送一個定義在程序存儲區(qū)的字符串到串口  
extern void PutBytes(byte *outplace,byte j); //發(fā)送一串數(shù)據(jù)  
extern void PutHEX(byte c); //發(fā)送一個字節(jié)的hex碼,分成兩個字節(jié)發(fā)  
extern byte GetByte (void); //從接收緩沖區(qū)取一個byte  
extern void SerialInit (word baud); //串口初始化  

extern byte inbufsign; //接收緩沖區(qū)數(shù)據(jù),有數(shù)據(jù)=1。  

#define CR PutString("\r\n") //發(fā)送一個回車換行  
#define NUL putstring("\0") //發(fā)送一個空格  
*************************************************************************/  

#include <iom16V.h>  
#include <macros.h>  

#define byte unsigned char  
#define word unsigned int  

#define OLEN 20 //串口發(fā)送緩沖大小  
#define ILEN 20 //串口接收緩沖大小  

byte outbuf[OLEN]; //發(fā)送緩沖  
byte inbuf[ILEN]; //接收數(shù)據(jù)緩沖  
byte *outlast=outbuf; //最后由中斷傳輸出去的字節(jié)位置  
byte *putlast=outbuf; //最后放入發(fā)送緩沖區(qū)的字節(jié)位置  
byte *inlast=inbuf; //最后接收到接收緩沖區(qū)的字節(jié)位置  
byte *getlast=inbuf; //最后從發(fā)送緩沖區(qū)取走的字節(jié)位置  

struct data //位定義  
{  
unsigned bit0:1;  
unsigned bit1:1;  
unsigned bit2:1;  
unsigned bit3:1;  
unsigned bit4:1;  
unsigned bit5:1;  
unsigned bit6:1;  
unsigned bit7:1;  
}bit_flag;  
#define outbufsign0 bit_flag.bit0 //緩沖區(qū)數(shù)據(jù)發(fā)完標志 發(fā)完=0  
#define outbufsign bit_flag.bit1 //發(fā)送緩沖區(qū)非空標志 有=1  
#define inbufful bit_flag.bit2 //接收緩沖區(qū)滿標志 滿=1  

//#define inbufsign bit_flag.bit3 //接收緩沖區(qū)非空標志 有=1  
//byte outbufsign0; //緩沖區(qū)數(shù)據(jù)發(fā)完標志 發(fā)完=0  
//byte outbufsign; //發(fā)送緩沖區(qū)非空標志 有=1  
//byte inbufful; //接收緩沖區(qū)滿標志 滿=1  

byte inbufsign; //接收緩沖區(qū)非空標志 有=1  


#define CR PutString("\r\n") //CR=回車換行  
#define SPACE PutByte(0x20) //發(fā)送一個空格。  

#pragma interrupt_handler SerialIncept_handler:12 //串口接收中斷函數(shù)  
#pragma interrupt_handler SerialSend_handler:14 //串口發(fā)送中斷函數(shù)  
//**********************************************************************  
//函 數(shù) 名: void PutByte(byte c)  
//功 能: 放入一個字節(jié)到發(fā)送緩沖區(qū)  
//說 明:  
//參 數(shù):  
//返 回 值:  
//示 范: PutByte(0x00);  
//***********************************************************************  
void PutByte(byte c)  
{  
CLI(); //暫停串行中斷,以免數(shù)據(jù)比較時出錯  
while((((outlast-putlast)==2)&&(outlast > putlast ))||((outlast < putlast)&&(OLEN-(putlast-outlast)==2)))  
{  
SEI();  
c++;c--;  
CLI();  
}  
*putlast=c; //放字節(jié)進入緩沖區(qū)  
putlast++; //發(fā)送緩沖區(qū)指針加1  
if (putlast==outbuf+OLEN) putlast=outbuf; //指針到了頂部換到底部  
outbufsign=1;  
if (!outbufsign0) //緩沖區(qū)無數(shù)據(jù)  
{  
outbufsign0=1;  

UDR=*outlast; //未發(fā)送完繼續(xù)發(fā)送  
outlast++; //最后傳出去的字節(jié)位置加1  
if (outlast==outbuf+OLEN) outlast=outbuf;//地址到頂部回到底部  
if (putlast==outlast) outbufsign=0; //數(shù)據(jù)發(fā)送完置發(fā)送緩沖區(qū)空標志  
} //緩沖區(qū)開始為空置為有,啟動發(fā)送  
SEI();  
}  

//**********************************************************************  
//函 數(shù) 名: void PutString(byte *puts)  
//功 能: 發(fā)送字符串到串口  
//說 明:  
//參 數(shù): 發(fā)送的字符串  
//返 回 值:  
//示 范: putstring("\r\n")  
//***********************************************************************  
void PutString(byte *puts)  
{  
for(;*puts!=0;puts++) //遇到停止符0結束  
PutByte(*puts);  
}  

//**********************************************************************  
//函 數(shù) 名: void PutBytes(byte *outplace,byte j)  
//功 能: 放一串數(shù)據(jù)到發(fā)送緩沖區(qū),需要定義發(fā)送的字節(jié)數(shù)  
//說 明:  
//參 數(shù): *outplace:發(fā)送的字節(jié)數(shù)據(jù)首地址指針 j:發(fā)送的字節(jié)數(shù)量  
//返 回 值:  
//***********************************************************************  
void PutBytes(byte *outplace,byte j)  
{ int i;  
for(i=0;i<j;i++)  
{  
PutByte(*outplace);  
outplace++;  
}  
}  

//**********************************************************************  
//函 數(shù) 名: PutHEX(unsigned char c)  
//功 能: 發(fā)送一個字節(jié)的hex碼,分成兩個字節(jié)發(fā)。  
//說 明: 發(fā)送ASSIC碼  
//參 數(shù): 發(fā)送的數(shù)據(jù)  
//返 回 值: 無  
//示 范: PutHEX(i);  
//***********************************************************************  
const byte hex_[]={"0123456789ABCDEF"};  
void PutHEX(byte c)  
{  
word ch;  
ch=(c>>4)&0x0f;  
PutByte(hex_[ch]);  
ch=c&0x0f;  
PutByte(hex_[ch]);  
SPACE;  
}  

//**********************************************************************  
//函 數(shù) 名: byte GetByte (void)  
//功 能: 從接收緩沖區(qū)取一個byte  
//說 明: 如不想等待則在調用前檢測inbufsign是否為1  
//參 數(shù): 無  
//返 回 值: 接收到的數(shù)據(jù)  
//示 范: i=GetByte();  
//***********************************************************************  
byte GetByte (void)  
{  
char c ;  
while (!inbufsign); //緩沖區(qū)空等待  
CLI();  
c=*getlast; //取數(shù)據(jù)  
getlast++; //最后取走的數(shù)據(jù)位置加1  
inbufful=0; //輸入緩沖區(qū)的滿標志清零  
if (getlast==inbuf+ILEN) getlast=inbuf; //地址到頂部回到底部  
if (getlast==inlast) inbufsign=0; //地址相等置接收緩沖區(qū)空空標志,再取數(shù)前要檢該標志  
SEI();  
return (c); //取回數(shù)據(jù)  
}  

//**********************************************************************  
//函 數(shù) 名: void SerialSend_handler (void)  
//功 能: 串口發(fā)送中斷處理  
//說 明:  
//參 數(shù):  
//返 回 值:  
//***********************************************************************  
void SerialSend_handler (void)  
{  
UCSRA|=(1<<TXC); //清發(fā)送中斷標志  
if (outbufsign)  
{  
UDR=*outlast; //未發(fā)送完繼續(xù)發(fā)送  
outlast++; //最后傳出去的字節(jié)位置加1  
if (outlast==outbuf+OLEN) outlast=outbuf;//地址到頂部回到底部  
if (putlast==outlast) outbufsign=0; //數(shù)據(jù)發(fā)送完置發(fā)送緩沖區(qū)空標志  
}  
else  
{  
outbufsign0=0;  
}  
}  


//**********************************************************************  
//函 數(shù) 名: void SerialIncept_handler (void)  
//功 能: 串口接收中斷處理  
//說 明:  
//參 數(shù):  
//返 回 值:  
//***********************************************************************  
void SerialIncept_handler (void)  
{  
if(!inbufful) //接收緩沖區(qū)未滿  
{  
*inlast= UDR; //放入數(shù)據(jù)  
inlast++; //最后放入的位置加1  
inbufsign=1;  
if (inlast==inbuf+ILEN) inlast=inbuf; //地址到頂部回到底部  
if (inlast==getlast) inbufful=1; //接收緩沖區(qū)滿置滿標志  
}  
}  

/**********************************************************************  
函 數(shù) 名: void SerialInit (unsigned long)  
功 能: 串口初始化  
說 明: 串口初始化成指定波特率,開接收,發(fā)送并開相應中斷  
參 數(shù): 需要初始化的波特率  
返 回 值: 無  
示 范: SerialInit (38400);  
***********************************************************************/  
void SerialInit (word baud)  
{  
CLI();  
UCSRC&=(~(1<<URSEL));  
UBRRH=(byte)(baud>>8);  
UBRRL=(byte)baud;  

UCSRB=(1<<RXCIE)|(1<<TXCIE)|(1<<RXEN)|(1<<TXEN);  
//接收中斷使能,發(fā)送中斷使能,接收器與發(fā)送器使能  
UCSRC=(1<<URSEL)|(3<<UCSZ0); //設置幀格式: 8 個數(shù)據(jù)位, 1 個停止位*/  
SEI(); //開全局中斷  
}  





我來潑幾瓢冷水:  

1>用兩個指針和一個位域來記錄隊列的位置和狀態(tài)極其不合理,因為這需要9個字節(jié),而且最后的目標代碼會因為指針和位域的原因產生相當長的代碼。我個人只用了兩個字節(jié)表示讀寫指針的位置加一個隊列有效數(shù)據(jù)的計數(shù)器,一共3個字節(jié),簡單明了;  

2>上述幾個讀寫指針沒有加volatile,有可能在執(zhí)行讀寫時和中斷沖突;  

3>既然使用了隊列緩沖,就不應該在程序中使用while語句來死等,而應該讓程序體面的失敗退出;這一點尤其體現(xiàn)在這個函數(shù):  
byte GetByte (void)  
程序有可能在這個地方死掉!  
while (!inbufsign); //緩沖區(qū)空等待  

4>發(fā)送中斷函數(shù):  
void SerialSend_handler (void)  
這簡直是失敗中的失!當發(fā)送緩沖區(qū)為空的時候還產生多余的中斷。  

5>接收中斷函數(shù):  
void SerialIncept_handler (void)  
這個函數(shù)也很失!但數(shù)據(jù)接收緩沖區(qū)滿的時候,如果再來一個數(shù)據(jù),由于你沒有把硬件中的數(shù)據(jù)取走,同樣會再次產生中斷!也會死掉!  

6>初始化函數(shù)  
void SerialInit (word baud)  
你在程序中添加了CLI() / SEI()  
我知道你是為了在初始化的時候關掉中斷,初始化完畢后再打開,看似合理,但真的合理嗎?至少在我看來是很不合理!  
一個系統(tǒng),要初始化的模塊肯定不止一個,當你初始化這個模塊后就帶開了中斷,由于相應中斷的原因,也許過了n久,你其它模塊還沒有初始化!  
我個人的做法是:系統(tǒng)開始初始化前關掉中斷:CLI(),等所有模塊初始化完畢再打開中斷SEL()

  • 上一篇: AT89C2051時鐘DS1302程序
  • 下一篇: 沒有了
  • 發(fā)表評論   告訴好友   打印此文  收藏此頁  關閉窗口  返回頂部
    熱點文章
     
    推薦文章
     
    相關文章
    網(wǎng)友評論:(只顯示最新5條。)
    關于我們 | 聯(lián)系我們 | 廣告合作 | 付款方式 | 使用幫助 | 機電之家 | 會員助手 | 免費鏈接

    點擊這里給我發(fā)消息66821730(技術支持)點擊這里給我發(fā)消息66821730(廣告投放) 點擊這里給我發(fā)消息41031197(編輯) 點擊這里給我發(fā)消息58733127(審核)
    本站提供的機電設備,機電供求等信息由機電企業(yè)自行提供,該企業(yè)負責信息內容的真實性、準確性和合法性。
    機電之家對此不承擔任何保證責任,有侵犯您利益的地方請聯(lián)系機電之家,機電之家將及時作出處理。
    Copyright 2007 機電之家 Inc All Rights Reserved.機電之家-由機電一體化網(wǎng)更名-聲明
    電話:0571-87774297 傳真:0571-87774298
    杭州濱興科技有限公司提供技術支持

    主辦:杭州市高新區(qū)(濱江)機電一體化學會
    中國行業(yè)電子商務100強網(wǎng)站

    網(wǎng)站經(jīng)營許可證:浙B2-20080178-1