當(dāng)前位置:首頁 > 單片機(jī) > 單片機(jī)
[導(dǎo)讀]一般教科書上提供的UART收發(fā)的程序往往是一段采用輪循(Polling)方式完成收發(fā)的簡(jiǎn)單代碼。但對(duì)于高速的AVR來講,采用這種方式大大降低了MUC的效率。在使用AVR時(shí),應(yīng)根據(jù)芯片本身的特點(diǎn)(片內(nèi)大容量數(shù)據(jù)存儲(chǔ)器RAM,更

一般教科書上提供的UART收發(fā)的程序往往是一段采用輪循(Polling)方式完成收發(fā)的簡(jiǎn)單代碼。但對(duì)于高速的AVR來講,采用這種方式大大降低了MUC的效率。在使用AVR時(shí),應(yīng)根據(jù)芯片本身的特點(diǎn)(片內(nèi)大容量數(shù)據(jù)存儲(chǔ)器RAM,更適合采用高級(jí)語言編寫系統(tǒng)程序),編寫高效可靠的UART收發(fā)接口(低層)程序。下面是一個(gè)典型的USART的接口程序。

//usart.h


//常量定義

#define BAUDRATE 9600 //波特率

//#define F_CPU 4000000 //晶振頻率4.0MHz


#define RXB8 1

#define TXB8 0

#define PE 2 //M16

//#define UPE 2 //M128

#define OVR 3

#define FE 4

#define UDRE 5

#define RXC 7


//宏定義

#define FRAMING_ERROR (1<

#define PARITY_ERROR (1<

//#define PARITY_ERROR (1<

#define DATA_OVERRUN (1<

#define DATA_REGISTER_EMPTY (1<

#define RX_COMPLETE (1<


// USART Receiver buffer

// 全局變量,會(huì)在中斷服務(wù)程序中被修改,須加volatile限定,不要就會(huì)出錯(cuò)啦

#define RX_BUFFER_SIZE 16 // 接收緩沖區(qū)大小,可根據(jù)需要修改

volatile char rx_buffer[RX_BUFFER_SIZE]; // 接收緩沖區(qū),為char型變量組成的數(shù)組,該數(shù)組構(gòu)成環(huán)形隊(duì)列,個(gè)數(shù)為RX_BUFFER_SIZE

volatile unsigned char rx_wr_index,rx_rd_index,rx_counter;

// This flag is set on USART Receiver buffer overflow

volatile char rx_buffer_overflow; //接收緩沖區(qū)溢出標(biāo)志


// USART Transmitter buffer

#define TX_BUFFER_SIZE 16

volatile char tx_buffer[TX_BUFFER_SIZE];

volatile unsigned char tx_wr_index,tx_rd_index,tx_counter;


// 函數(shù)聲明

char get_c(void);

void put_c(char c);

void put_s(char *ptr);

void init_USART(void);

//usart.c


#include

#include

#include

#include "usart.h"


/*接收中斷*/

ISR(USART_RXC_vect)

{

char status,data;

status=UCSRA; //讀取接收狀態(tài)標(biāo)志位,必須先讀,當(dāng)讀了UDR后,UCSRA便自動(dòng)清零了

data=UDR; //讀取USART數(shù)據(jù)寄存器,這句與上句位置不能顛倒的

if ((status & (FRAMING_ERROR | PARITY_ERROR | DATA_OVERRUN))==0) //判斷本接收到的數(shù)據(jù)是否有數(shù)據(jù)幀、校驗(yàn)或數(shù)據(jù)溢出錯(cuò)誤(此處指USART的硬件接收溢出)

{

rx_buffer[rx_wr_index]=data; // 將數(shù)據(jù)填充到接收緩沖隊(duì)列中

if (++rx_wr_index == RX_BUFFER_SIZE) //寫指針指向下一個(gè)單元,并判斷是否到了隊(duì)列的尾部,(不表示接受緩沖區(qū)是否滿?。?/p>

rx_wr_index=0; //到了尾部,則指向頭部(構(gòu)成環(huán)狀)

if (++rx_counter == RX_BUFFER_SIZE) //隊(duì)列中收到字符加1,并判斷是否隊(duì)列已滿

{

rx_counter=0; // 隊(duì)列滿了,隊(duì)列中收到字符個(gè)數(shù)為0,表示隊(duì)列中所有以前的數(shù)據(jù)作廢,因?yàn)樽詈蟮臄?shù)據(jù)已經(jīng)把最前邊的數(shù)據(jù)覆蓋了

rx_buffer_overflow=1; //置緩沖區(qū)溢出標(biāo)志。在主程序中必要的地方需要判斷該標(biāo)志,以證明讀到數(shù)據(jù)的完整性

};

};

}

/*接收單個(gè)字符*/

char get_c(void)

{

char data;

while (rx_counter==0); //接收數(shù)據(jù)隊(duì)列中沒有數(shù)據(jù)可以讀取,等待......(注2)

data=rx_buffer[rx_rd_index]; //讀取緩沖隊(duì)列中的數(shù)據(jù)

if (++rx_rd_index == RX_BUFFER_SIZE) rx_rd_index=0; //讀取指針指向下一個(gè)未讀的數(shù)據(jù),如果指到了隊(duì)列尾部,則指回到隊(duì)列頭步

cli(); // 關(guān)中斷!非常重要

--rx_counter; //隊(duì)列中未讀數(shù)據(jù)個(gè)數(shù)減1。因?yàn)樵撟兞吭诮邮罩袛嘀幸淖兊模瑸榱朔乐箾_突,所以改動(dòng)前臨時(shí)關(guān)閉中斷。程序相當(dāng)可靠了。

sei(); // 開中斷

return data;

}


//發(fā)送中斷

ISR(USART_TXC_vect)

{

if (tx_counter)

{

--tx_counter;

UDR=tx_buffer[tx_rd_index];

if (++tx_rd_index == TX_BUFFER_SIZE) tx_rd_index=0;

};

}

/*發(fā)送單個(gè)字符*/

void put_c(char c)

{

while (tx_counter == TX_BUFFER_SIZE); //發(fā)送數(shù)據(jù)隊(duì)列中還有數(shù)據(jù)沒有發(fā)送完,等待

cli();

if (tx_counter || ((UCSRA & DATA_REGISTER_EMPTY)==0)) //若發(fā)送數(shù)據(jù)隊(duì)列有數(shù)據(jù)或者數(shù)據(jù)寄存器UDR非空時(shí)執(zhí)行(因?yàn)殛?duì)列先進(jìn)先出的原因,所以,c要放進(jìn)非空的發(fā)送數(shù)據(jù)隊(duì)列里面)

{

tx_buffer[tx_wr_index]=c;

if (++tx_wr_index == TX_BUFFER_SIZE) tx_wr_index=0;

++tx_counter;

}

else

UDR=c;

sei();

}

/*發(fā)送字符串*/

void put_s(char *ptr)

{

while (*ptr)

{

put_c(*ptr++);

}

put_c(0x0D);

put_c(0x0A); //結(jié)尾發(fā)送回車換行

}


/*USART 初始化*/

void init_USART(void)

{


//USART 9600 8, n,1 PC上位機(jī)軟件(超級(jí)終端等)也要設(shè)成同樣的設(shè)置才能通訊

UCSRC = (1<

UBRRL= (F_CPU/BAUDRATE/16-1)%256;

UBRRH= (F_CPU/BAUDRATE/16-1)/256;

UCSRA = 0x00;

//接收使能,發(fā)送使能,接收中斷使能,發(fā)送中斷使能

UCSRB=(1<

}


/***********************************************

**** 名 稱:AVR USART(RS232)低層驅(qū)動(dòng)+中間層軟件示例

****

**** 作 者:zhiyu

**** 編譯器:WINAVR20070525

****

**** 參 考:http://www.ouravr.com/bbs/bbs_content.jsp?mother_form=bbs_content.jsp&bbs_id=1000&bbs_page_no=1&bbs_sn=147242

《高檔8位單片機(jī)ATmega128原理與開發(fā)應(yīng)用指南(上)》--馬潮 P320

《嵌入式C編程與ATMEL AVR》-- 國外計(jì)算機(jī)經(jīng)典教材 P141

**** 日 期:2007.07.19

****

**** 芯 片:M16L

**** 時(shí)鐘源:外部4M晶振

****

**** 結(jié) 果:測(cè)試成功

**** 問 題:暫無

***********************************************/

//#include

//#include

#include

#include "usart.h"


int main(void)

{

init_USART();

sei(); //總中斷允許

put_s("Hello!");

put_s("這是一個(gè)簡(jiǎn)單的高速的串口驅(qū)動(dòng)程序");

put_s("請(qǐng)你輸入任意的字符,單片機(jī)將返回你輸入的字符");

while (1)

{

put_c(get_c());

}

}

//Makefile,主要的幾項(xiàng),只是針對(duì)我這里的程序,要靈活運(yùn)用哦


MCU = atmega16


F_CPU = 4000000


TARGET = main


SRC = $(TARGET).c usart.c //多文件編譯才會(huì)用到這一項(xiàng),可以參考這個(gè)帖子:


http://www.mcublog.com/blog/user1/4266/archives/2006/6145.html


*****************************************************/

這段由CVAVR程序生成器產(chǎn)生的UART接口代碼是一個(gè)非常好的、高效可靠,并且值得認(rèn)真學(xué)習(xí)和體會(huì)的。其特點(diǎn)如下:

l.它采用兩個(gè)8字節(jié)的接收和發(fā)送緩沖器來提高M(jìn)CU的效率.當(dāng)主程序調(diào)用getchar()函數(shù)時(shí),按順序執(zhí)行到while (rx_counter==0)處,接收數(shù)據(jù)隊(duì)列里面就沒有數(shù)據(jù),如果再?zèng)]有數(shù)據(jù)輸入,那么就只能死在那里等待.如果有數(shù)據(jù)輸入的話,中斷很快就響應(yīng),數(shù)據(jù)就會(huì)迅速地填充接收數(shù)據(jù)隊(duì)列,rx_counter!=0,這個(gè)死等待也就給瓦解了,讓程序執(zhí)行接下來的那句data=rx_buffer[rx_rd_index]了.最后return data;,返回輸入的值;如當(dāng)主程序調(diào)用Putchar()發(fā)送數(shù)據(jù)時(shí),如果UART口不空閑,就將數(shù)據(jù)放入發(fā)送緩沖器中,MCU不必等待,可以繼續(xù)執(zhí)行其它的工作。而UART的硬件發(fā)送完一個(gè)數(shù)據(jù)后,產(chǎn)生中斷,由中斷服務(wù)程序負(fù)責(zé)將發(fā)送緩沖器中數(shù)據(jù)依次自動(dòng)送出。

C語言書本里有其中一段:

getchar()函數(shù)(字符輸入函數(shù))的作用是從終端(或系統(tǒng)隱含指定的輸入設(shè)備)輸入一個(gè)字符.getchar()函數(shù)沒有參數(shù).當(dāng)你輸入一個(gè)字符時(shí)候,比如'a'后,要按'Enter'鍵,字符才能送到內(nèi)存!你一旦按了這個(gè)'Enter',上面的程序就會(huì)執(zhí)行中斷響應(yīng)了,

2.數(shù)據(jù)緩沖器結(jié)構(gòu)是一個(gè)線性的循環(huán)隊(duì)列,由讀、寫和隊(duì)列計(jì)數(shù)器3個(gè)指針控制,用于判斷隊(duì)列是否空、溢出,以及當(dāng)前數(shù)據(jù)在

本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請(qǐng)聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請(qǐng)及時(shí)聯(lián)系本站刪除。
換一批
延伸閱讀

9月2日消息,不造車的華為或?qū)⒋呱龈蟮莫?dú)角獸公司,隨著阿維塔和賽力斯的入局,華為引望愈發(fā)顯得引人矚目。

關(guān)鍵字: 阿維塔 塞力斯 華為

倫敦2024年8月29日 /美通社/ -- 英國汽車技術(shù)公司SODA.Auto推出其旗艦產(chǎn)品SODA V,這是全球首款涵蓋汽車工程師從創(chuàng)意到認(rèn)證的所有需求的工具,可用于創(chuàng)建軟件定義汽車。 SODA V工具的開發(fā)耗時(shí)1.5...

關(guān)鍵字: 汽車 人工智能 智能驅(qū)動(dòng) BSP

北京2024年8月28日 /美通社/ -- 越來越多用戶希望企業(yè)業(yè)務(wù)能7×24不間斷運(yùn)行,同時(shí)企業(yè)卻面臨越來越多業(yè)務(wù)中斷的風(fēng)險(xiǎn),如企業(yè)系統(tǒng)復(fù)雜性的增加,頻繁的功能更新和發(fā)布等。如何確保業(yè)務(wù)連續(xù)性,提升韌性,成...

關(guān)鍵字: 亞馬遜 解密 控制平面 BSP

8月30日消息,據(jù)媒體報(bào)道,騰訊和網(wǎng)易近期正在縮減他們對(duì)日本游戲市場(chǎng)的投資。

關(guān)鍵字: 騰訊 編碼器 CPU

8月28日消息,今天上午,2024中國國際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)開幕式在貴陽舉行,華為董事、質(zhì)量流程IT總裁陶景文發(fā)表了演講。

關(guān)鍵字: 華為 12nm EDA 半導(dǎo)體

8月28日消息,在2024中國國際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)上,華為常務(wù)董事、華為云CEO張平安發(fā)表演講稱,數(shù)字世界的話語權(quán)最終是由生態(tài)的繁榮決定的。

關(guān)鍵字: 華為 12nm 手機(jī) 衛(wèi)星通信

要點(diǎn): 有效應(yīng)對(duì)環(huán)境變化,經(jīng)營業(yè)績(jī)穩(wěn)中有升 落實(shí)提質(zhì)增效舉措,毛利潤率延續(xù)升勢(shì) 戰(zhàn)略布局成效顯著,戰(zhàn)新業(yè)務(wù)引領(lǐng)增長 以科技創(chuàng)新為引領(lǐng),提升企業(yè)核心競(jìng)爭(zhēng)力 堅(jiān)持高質(zhì)量發(fā)展策略,塑強(qiáng)核心競(jìng)爭(zhēng)優(yōu)勢(shì)...

關(guān)鍵字: 通信 BSP 電信運(yùn)營商 數(shù)字經(jīng)濟(jì)

北京2024年8月27日 /美通社/ -- 8月21日,由中央廣播電視總臺(tái)與中國電影電視技術(shù)學(xué)會(huì)聯(lián)合牽頭組建的NVI技術(shù)創(chuàng)新聯(lián)盟在BIRTV2024超高清全產(chǎn)業(yè)鏈發(fā)展研討會(huì)上宣布正式成立。 活動(dòng)現(xiàn)場(chǎng) NVI技術(shù)創(chuàng)新聯(lián)...

關(guān)鍵字: VI 傳輸協(xié)議 音頻 BSP

北京2024年8月27日 /美通社/ -- 在8月23日舉辦的2024年長三角生態(tài)綠色一體化發(fā)展示范區(qū)聯(lián)合招商會(huì)上,軟通動(dòng)力信息技術(shù)(集團(tuán))股份有限公司(以下簡(jiǎn)稱"軟通動(dòng)力")與長三角投資(上海)有限...

關(guān)鍵字: BSP 信息技術(shù)
關(guān)閉
關(guān)閉