標(biāo)題:
MSP430單片機(jī)串口通訊程序庫(精簡版)
[打印本頁]
作者:
51hei單片
時(shí)間:
2016-3-14 20:05
標(biāo)題:
MSP430單片機(jī)串口通訊程序庫(精簡版)
本程序是《MSP430系列單片機(jī)系統(tǒng)工程設(shè)計(jì)與實(shí)踐》書里面的源碼,(包含工程文件(例4.1.6) )完整例程下載:
http://www.torrancerestoration.com/bbs/dpj-46245-1.html
關(guān)于本程序的詳細(xì)解說大家可以點(diǎn)擊上圖下載電子書
這個(gè)串口庫文件的調(diào)用方法可先下載完整代碼然后找到(例4.1.6)這一節(jié),里面有調(diào)用方法
uart.c :
/*
MSP430F4XX單片機(jī)串口通訊程序庫(精簡版)
說明:該程序庫包括串口初始化、串口單字節(jié)收/發(fā)函數(shù),以及串口終端設(shè)備接口
函數(shù)。可以作為各種程序的底層驅(qū)動(dòng)使用。
要使用該庫函數(shù),需要將本文件(UART.c)添加進(jìn)工程,并在需要調(diào)用
串口函數(shù)的文件開頭處包含"UART.h"
本程序庫中的串口初始化函數(shù)會(huì)根據(jù)波特率為串口收發(fā)模塊自動(dòng)選擇最
合適的時(shí)鐘源,自動(dòng)配置波特率分頻系數(shù),用戶不需要了解串口底層寄存器。
對(duì)于4800bps及以下的波特率,會(huì)選擇ACLK作為時(shí)鐘;對(duì)于4800bps以上設(shè)置,
會(huì)選擇SMCLK作時(shí)鐘。若串口一直打開,為了降低功耗,盡量使用4800以下波
特率;若使用4800以上波特率,推薦間歇使用串口。使用38400bps以上波特率
最好適當(dāng)提高CPU主頻(2~4MHz)。
串口收發(fā)的等待過程中會(huì)將CPU置于休眠模式(LPM0或LPM3),以降低耗電。
但要注意某些應(yīng)用中可能不允許關(guān)閉時(shí)鐘(比如TimerA用SMCLK作時(shí)鐘,若串
口等待過程中進(jìn)入LPM3,關(guān)閉了SMCLK,造成計(jì)時(shí)錯(cuò)誤),遇到這類情況請(qǐng)修
改UART_LPM()函數(shù),刪除休眠語句或降低休眠深度,但功耗會(huì)有所增加。
程序后半部分是標(biāo)準(zhǔn)終端輸入輸出函數(shù),對(duì)標(biāo)準(zhǔn)終端設(shè)備輸入的數(shù)據(jù)流進(jìn)
行解析。通過串口與PC機(jī)相連;在PC機(jī)運(yùn)行超級(jí)終端程序,從而將PC的屏幕和鍵
盤映射成單片機(jī)的輸入/輸出終端。這樣在單片機(jī)程序中可以使用格式化輸入/
輸出函數(shù),如printf/scanf等。詳細(xì)的原理請(qǐng)參考《超級(jí)終端人機(jī)對(duì)話范例》
程序。終端輸入函數(shù)帶有退格功能,因此有輸入緩沖區(qū)。請(qǐng)根據(jù)需要自行修改
輸入行緩沖區(qū)大小(LINE_LENGTH),該值限定了終端設(shè)備每行最大能輸入的字符數(shù)。
(C)西安電子科技大學(xué) 測控技術(shù)與儀器教研中心 編寫:謝楷 2008/02/21
*/
//******************************************************************************
//
//
// MSP430FE425
// +-----------------+
// /|\| XIN|-
// | | | 32kHz
// --|RST XOUT|-
// | |
// | (TXD)P2.4|-----------> // ----> RXD(2)
// | | 300~115200 bps
// | (RXD)P2.5|<----------- // <---- TXD(3) PC(DB9)
// | |
// | GND |------------------------GND(5)
//
//******************************************************************************
#include "msp430x42x.h"
#define F_ACLK (32768) /*ACLK對(duì)應(yīng)晶體頻率,勿修改*/
char TxFlag=1;
char RxFlag=0;
/****************************************************************************
* 名 稱:UART_Init()
* 功 能:初始化串口。設(shè)置其工作模式及波特率。
* 入口參數(shù):
* Baud 波特率 (300~115200)
Parity 奇偶校驗(yàn)位('n'=無校驗(yàn) 'p'=偶校驗(yàn) 'o'=奇校驗(yàn))
DatsBits 數(shù)據(jù)位位數(shù) (7或8)
StopBits 停止位位數(shù) (1或2)
* 出口參數(shù):返回值為1時(shí)表示初化成功,為0表示參數(shù)出錯(cuò)
* 范 例: UART_Init(9600,'n',8,1) //設(shè)成9600bps,無校驗(yàn),8位數(shù)據(jù),1位停止位
UART_Init(2400,'p',7,2) //設(shè)成2400bps,偶校驗(yàn),7位數(shù)據(jù),2位停止位
****************************************************************************/
char UART_Init(long int Baud,char Parity,char DataBits,char StopBits)
{
unsigned long int BRCLK; //波特率發(fā)生器時(shí)鐘頻率
int FreqMul,FLLDx,BRDIV,BRMOD; //倍頻系數(shù)、DCO倍頻、波特率分頻系數(shù)、分頻尾數(shù)
int i;
unsigned char const ModTable[8]={0x00,0x08,0x88,0x2A,0x55,0x6B,0xdd,0xef};
//分頻尾數(shù)所對(duì)應(yīng)的調(diào)制系數(shù)(將0~7個(gè)"1"均勻分布在一個(gè)字節(jié)的8bit中)
//-------------設(shè)置波特率發(fā)生器時(shí)鐘源,并計(jì)算波特率時(shí)鐘頻率--------------
UTCTL0 &=~(SSEL0+SSEL1); //清除之前的時(shí)鐘設(shè)置
if(Baud<=4800)
{
UTCTL0 |= SSEL0; //低于4800的波特率,用ACLK,降低功耗
BRCLK=F_ACLK; //波特率發(fā)生器時(shí)鐘頻率=ACLK
}
else
{
UTCTL0 |= SSEL1; //高于4800的波特率,用SMCLK,保證速度
FreqMul=(SCFQCTL&0x7F)+1; //獲得倍頻系數(shù)
FLLDx=((SCFI0&0xC0)>>6)+1; //獲得DCO倍頻系數(shù)(DCOPLUS所帶來的額外倍頻)
BRCLK=F_ACLK*FreqMul; //計(jì)算波特率發(fā)生器時(shí)鐘頻率=ACLK*倍頻系數(shù)
if(FLL_CTL0&DCOPLUS) BRCLK*=FLLDx; //若開啟了DCOPLUS,還要計(jì)算額外倍頻
}
//------------------------設(shè)置波特率-------------------------
if((Baud<300)||(Baud>115200)) return(0); //波特率范圍300-115200bps
BRDIV=BRCLK/Baud; //計(jì)算波特率分頻系數(shù)(整數(shù)部分)
BRMOD=((BRCLK*8)/Baud)%8; //計(jì)算波特率分頻尾數(shù)(除不盡的余數(shù))
UBR00 = BRDIV%256;
UBR10 = BRDIV/256; //整數(shù)部分系數(shù)
UMCTL0 = ModTable[BRMOD]; //余數(shù)部分系數(shù)
//------------------------設(shè)置校驗(yàn)位-------------------------
switch(Parity)
{
case 'n':case'N': U0CTL&=~PENA; break; //無校驗(yàn)
case 'p':case'P': U0CTL|= PENA+PEV ;break; //偶校驗(yàn)
case 'o':case'O': U0CTL|= PENA; U0CTL&=~PEV;break;//奇校驗(yàn)
default : return(0); //參數(shù)錯(cuò)誤
}
//------------------------設(shè)置數(shù)據(jù)位-------------------------
switch(DataBits)
{
case 7:case'7': U0CTL&=~CHAR; break; //7位數(shù)據(jù)
case 8:case'8': U0CTL|= CHAR; break; //8位數(shù)據(jù)
default : return(0); //參數(shù)錯(cuò)誤
}
//------------------------設(shè)置停止位-------------------------
switch(StopBits)
{
case 1:case'1': U0CTL&=~SPB; break; //1位停止位
case 2:case'2': U0CTL|= SPB; break; //2位停止位
default : return(0); //參數(shù)錯(cuò)誤
}
P2SEL |= 0x30; // P2.4,5 = USART0 TXD/RXD
ME1 |= UTXE0 + URXE0; // Enable USART0 TXD/RXD
UCTL0 &= ~SWRST; // Initialize USART state machine
IE1 |= URXIE0+UTXIE0; // Enable USART0 RX interrupt
_EINT();
for(i=0;i<4000;i++); //略延遲,等待波特率分頻穩(wěn)定
return(1); //設(shè)置成功
}
/****************************************************************************
* 名 稱:UART_LPM()
* 功 能:串口收/發(fā)等待過程中,將CPU及時(shí)鐘系統(tǒng)關(guān)閉,休眠省電
* 入口參數(shù):無
* 出口參數(shù):無
* 說 明: 若與其他外設(shè)的時(shí)鐘沖突,可注釋掉該函數(shù),但會(huì)增加功耗。
****************************************************************************/
void UART_LPM()
{
if(UTCTL0&SSEL0) LPM3; //若以ACLK 作時(shí)鐘,進(jìn)入LPM3休眠(僅打開ACLK)
else LPM0; //若以SMCLK作時(shí)鐘,進(jìn)入LPM0休眠(不關(guān)閉SMCLK)
}
/****************************************************************************
* 名 稱:UART_PutChar()
* 功 能:從串口發(fā)送1字節(jié)數(shù)據(jù)
* 入口參數(shù):Chr: 待發(fā)送的一字節(jié)數(shù)據(jù)
* 出口參數(shù):無
* 說 明: 在等待發(fā)送完畢的過程中,CPU會(huì)休眠
****************************************************************************/
void UART_PutChar(char Chr)
{
while (TxFlag==0) UART_LPM(); // 等待上一字節(jié)發(fā)完,并休眠
TxFlag=0; //小技巧:等上一字節(jié)發(fā)完,再發(fā)本字節(jié),把字節(jié)間隔等待的時(shí)間讓給計(jì)算
TXBUF0=Chr;
}
/****************************************************************************
* 名 稱:UART_GetChar()
* 功 能:從串口接收1字節(jié)數(shù)據(jù)
* 入口參數(shù):無
* 出口參數(shù):收到的一字節(jié)數(shù)據(jù)
* 說 明: 如果串口沒有數(shù)據(jù),會(huì)一直等待。等待過程中,CPU會(huì)休眠
****************************************************************************/
char UART_GetChar(void)
{
while (RxFlag==0) UART_LPM(); // 收到一字節(jié)?
RxFlag=0;
return(RXBUF0);
}
/****************************************************************************
* 名 稱:UART_IsRcvChar()
* 功 能:判斷串口是否收到1字節(jié)數(shù)據(jù)
* 入口參數(shù):無
* 出口參數(shù):1表示有數(shù)據(jù),0表示無數(shù)據(jù)
* 說 明: 配合UART_GetChar()函數(shù)使用,先檢查到有數(shù)據(jù)再接收,可以消除阻塞
****************************************************************************/
char UART_IsRcvChar()
{
return(RxFlag);
}
/****************************************************************************
* 名 稱:UART_RX()
* 功 能:串口接收中斷,每接收到1字節(jié)會(huì)發(fā)生一次中斷
****************************************************************************/
#pragma vector=UART0RX_VECTOR
__interrupt void UART_RX (void)
{
RxFlag=1;
/*在這里添加用戶中斷服務(wù)程序代碼,如將數(shù)據(jù)壓入接收緩沖等*/
__low_power_mode_off_on_exit();
}
/****************************************************************************
* 名 稱:UART_TX()
* 功 能:串口發(fā)送中斷,每發(fā)完1字節(jié)會(huì)發(fā)生一次中斷
****************************************************************************/
#pragma vector=UART0TX_VECTOR
__interrupt void UART_TX (void)
{
TxFlag=1;
/*在這里添加用戶中斷服務(wù)程序代碼,如將數(shù)據(jù)從緩沖取出等*/
__low_power_mode_off_on_exit();
}
/*===================以下是串口終端設(shè)備接口函數(shù)庫==========================*/
#define LINE_LENGTH 20 /* 行緩沖區(qū)大小,決定每行最多輸入的字符數(shù)*/
/*標(biāo)準(zhǔn)終端設(shè)備中,特殊ASCII碼定義,請(qǐng)勿修改*/
#define In_BACKSP 0x08 /* ASCII <-- (退格鍵) */
#define In_DELETE 0x7F /* ASCII <DEL> (DEL 鍵) */
#define In_EOL '\r' /* ASCII <CR> (回車鍵) */
#define In_SKIP '\3' /* ASCII control-C */
#define In_EOF '\x1A' /* ASCII control-Z */
#define Out_DELETE "\x8 \x8" /* VT100 backspace and clear */
#define Out_SKIP "^C\n" /* ^C and new line */
#define Out_EOF "^Z" /* ^Z and return EOF */
#include "stdio.h"
/****************************************************************************
* 名 稱:putchar()
* 功 能:向標(biāo)準(zhǔn)終端設(shè)備發(fā)送一字節(jié)數(shù)據(jù)(1個(gè)字符)
* 入口參數(shù):ch: 待發(fā)送的字符
* 出口參數(shù):發(fā)出的字符
* 說 明: printf函數(shù)會(huì)調(diào)用該函數(shù)作為底層輸出。這里從串口輸出字符到PC機(jī)的超
級(jí)終端軟件上,printf的結(jié)果將打印到超級(jí)終端上。若修改該函數(shù),將字
符以其他方式輸出,如顯示到LCD上,printf的結(jié)果將顯示在LCD上。
****************************************************************************/
int putchar(int ch)
{
if (ch == '\n') // '\n'(回車)擴(kuò)展成 '\n''\r' (回車+換行)
{
UART_PutChar(0x0d) ; //'\r'
}
UART_PutChar(ch); //從串口發(fā)出數(shù)據(jù)
return (ch);
}
/****************************************************************************
* 名 稱:put_message()
* 功 能:向標(biāo)準(zhǔn)終端設(shè)備發(fā)送一個(gè)字符串
* 入口參數(shù):*s: 字符串(數(shù)組)頭指針(數(shù)組名)
* 出口參數(shù):無
****************************************************************************/
static void put_message(char *s)
{
while (*s) //當(dāng)前字符不為空 (字符串以0x00結(jié)尾)
putchar(*s++); //輸出一個(gè)字符,指針指向下一字符
}
/****************************************************************************
* 名 稱:getchar()
* 功 能:從標(biāo)準(zhǔn)終端設(shè)備接收一字節(jié)數(shù)據(jù)(1個(gè)字符)
* 入口參數(shù):無
* 出口參數(shù):收到的字符
* 說 明: scanf函數(shù)會(huì)調(diào)用該函數(shù)作為底層輸入。這里從PC機(jī)鍵盤借助超級(jí)終端軟
件通過串口輸入字符到單片機(jī)上。scanf函數(shù)的輸入即源自PC機(jī)鍵盤。若
修改該函數(shù),將字符以其他方式輸入,如單片機(jī)IO口,可用按鈕向scanf
函數(shù)輸入數(shù)據(jù)。本函數(shù)帶有緩存,能夠處理退格等刪除操作。若不需要?jiǎng)h
除操作,可直接調(diào)用UART_GetChar()函數(shù)。
****************************************************************************/
int getchar(void)
{
static char io_buffer[LINE_LENGTH + 2]; /* Where to put chars */
static int ptr; /* Pointer in buffer */
char c;
for (;;)
{
if (io_buffer[ptr]) //如果緩沖區(qū)有字符
return (io_buffer[ptr++]); //則逐個(gè)返回字符
ptr = 0; //直到發(fā)送完畢為止,清空緩沖區(qū)指針
while(1) //緩沖區(qū)沒有字符,才會(huì)執(zhí)行到這里,開始等待字符輸入
{ c = UART_GetChar(); //等待串口接收一個(gè)字符
if (c == In_EOF && !ptr) //----EOF鍵(Ctrl+Z)----
{ //EOF符只能在未輸入其他字符時(shí)才有效
put_message(Out_EOF); //讓終端顯示EOF符
return EOF; //返回EOF符
}
if ((c == In_DELETE)||(c==In_BACKSP)) //----退格或DEL鍵----
{
if (ptr)
{
ptr--; //從緩沖區(qū)刪掉一個(gè)字符
put_message(Out_DELETE); //讓終端顯示也刪掉一個(gè)字符
}
}
else if (c == In_SKIP) //-----取消鍵 Ctrl + C----
{
put_message(Out_SKIP); //讓終端顯示放棄本行跳到下一行
ptr = LINE_LENGTH + 1; /* 這里永遠(yuǎn)是0(結(jié)束符) */
break;
}
else if (c == In_EOL) //--------遇到回車鍵------
{
putchar(io_buffer[ptr++] = '\n'); //讓終端顯示換行
io_buffer[ptr] = 0; //末尾增添字符串結(jié)束字符NULL
ptr = 0; //指針清空
break; //跳出后開始返回?cái)?shù)據(jù)
}
else if (ptr < LINE_LENGTH) //----正常ASCII碼字符----
{
if (c >= ' ') //刪除0x20以下的其他ASCII碼
{
putchar(io_buffer[ptr++] = c); //存入緩沖區(qū)
}
}
else //--------沖區(qū)已滿--------
{
putchar('\7'); //向終端發(fā)送鳴響符,PC會(huì)響一聲,提示已滿
}
}
}
}
復(fù)制代碼
歡迎光臨 (http://www.torrancerestoration.com/bbs/)
Powered by Discuz! X3.1