使用fifo的好處有:
?1:串口的數據發送的數據量較大時,使用fifo可以大大降低MCU的開銷。
(有點類似串入并出的cput處理模型,本質上還是串行收發)
?2:在某些特殊場合,例如制定較復雜的協議時,可以使用fifo特性來做協議簡化,比如一包
數據包含8個字節,(并且fifo設置的長度為8),這樣相當于把uart轉換為類似CAN/以太網模型,
這樣信息可擴展性得到了質的提高,當然,這里需要同步協調。
?fifo分析拓展:
? ? ? ? ?? 1. 如果要用中斷來處理接收到的數據,就是說,接收完數據然后產生中斷,再于中斷里處理接收的數據。如果要實現這個本意,要設置好觸發點。
? ??????? 至于超時中斷之類,那是另外一回事了。
?????????? 2. 就UART的中斷類型而言,還包括:RBR中斷使能、THRE中斷使能、RX線狀態中斷使能、自動波特率超時中斷使能等。
? ? ? ? ??
3.
FIFO定義說了,先入先出緩沖區,在UART中有什么用呢。我們可以用它來批量發送 數據(而非FIFO模式,只能一字節一字節的發,而且發每個字節都需要等待緩沖區變空才能發送下一字節),這樣能在一定程度上提高數據發送速度。還有就是 避免數據包的的丟失(這個問題,目前還沒體會)。
?需要了解的相關知識:
HCLK主要為 S3C2440 AHB 總線( Advanced High performance Bus )上掛接硬件提供工作頻率, AHB 總線主要掛接有內存, NAND , LCD 控制器等硬件
FCLK 主要為 ARM920T 內核提供工作頻率;
PCLK 主要為 APB 總線提供工作頻率, APB 總線主要掛接 UART 串口, Watchdog 等硬件控制器。 【所以在這里我們用PCLK作為UART的時鐘源】
外接設備 |
起始地址 |
結束地址 |
存儲控制器 |
0x48000000 |
0x48000030 |
USB Host控制器 |
0x49000000 |
0x49000058 |
中斷控制器 |
0x4A000000 |
0x4A00001C |
DMA |
0x4B000000 |
0x4B0000E0 |
時鐘和電源管理 |
0x4C000000 |
0x4C000014 |
LCD控制器 |
0x4D000000 |
0x4D000060 |
NAND FLASH控制器 |
0x4E000000 |
0x4E000014 |
攝像頭接口 |
0x4F000000 |
0x4F0000A0 |
UART |
0x50000000 |
0x50008028 |
脈寬調制計時器 |
0x51000000 |
0x51000040 |
USB設備 |
0x52000140 |
0x5200026F |
WATCHDOG計時器 |
0x53000000 |
0x53000008 |
IIC控制器 |
0x54000000 |
0x5400000C |
IIS控制器 |
0x55000000 |
0x55000012 |
I/O端口 |
0x56000000 |
0x560000B0 |
實時時鐘RTC |
0x57000040 |
0x5700008B |
A/D轉換器 |
0x58000000 |
0x58000010 |
SPI |
0x59000000 |
0x59000034 |
SD接口 |
0x5A000000 |
0x5A000040 |
AC97音頻編碼接口 |
0x5B000000 |
0x5B00001C
|
?
在start.s中完成對看門狗,內存等進行初始化: ?????
GPBCON???
? EQU????? 0x56000010
GPBDAT???????????? EQU????? 0x56000014
? AREA Init,CODE,READONLY? ? ? ? ? ??
//聲明一個只讀性質的代碼段Init.
ENTRY??????????????????? ? ? ? ? ? ??
//入口
start
close watchdog
??? ldr r0,=0x53000000;????????????
? //將看門狗控制寄存器地址放入r0
??? mov r1,#0????????????????????? ?
??? str r1,[r0];???????????????????
? //將r1的值0放到r0中,即設置看門/
??? 狗控制寄存器的值為0
??? bl initmem;??????????????????? ??
//跳轉到initmem代碼段,初始化內存
?? ?
??? IMPORT main;?????????? ? ? ? ? ??
//引入main.c中的main函數
??? ldr sp,=0x34000000;?????? ?? ?? ?
//調用c程序前先初始化桟指針
??? ldr lr,=loop;????????????????????
//設置main函數的返回地址
??? ldr pc,=main;????????????????? ??
//跳轉到c程序的main函數的入口處執行
loop
??? b loop????? ;??????????????? ?
?? //死循環
initmen????????????????????????? ??
? //內存初始化
??? ldr r0,=0x48000000;?????????????
? //加載內存相關寄存器首地址r0
??? ldr r1,=0x48000034;??????????????
//加載內存相關寄存器尾地址到r1
??? adr r2,memdata;???????????????? ?
//將寄存器配置數據地址段首地址加載到r2
?initmemloop
??? ldr r3,[r2],#4;??????????????????
//循環設置存寄存器
??? str r3,[r0],#4
??? teq r0,r1
??? bne initmemloop;????????????????
? //循環到最后一個寄存器時退出函數
??? mov pc,lr
?memdata?????????????????????????????
// 存放內存控制器設置數據
?????????? DCD 0x22000000???????????????? ;BWSCON
?????????? DCD 0x00000700???????????????? ;BANKCON0?? ?
?????????? DCD 0x00000700???????????????? ;BANKCON1?? ?
?????????? DCD 0x00000700???????????????? ;BANKCON2?? ?
?????????? DCD 0x00000700???????????????? ;BANKCON3??????????? ?
?????????? DCD 0x00000700???????????????? ;BANKCON4?? ?
?????????? DCD 0x00000700???????????????? ;BANKCON5?? ?
?????????? DCD 0x00018005???????????????? ;BANKCON6?? ?
?????????? DCD 0x00018005???????????????? ;BANKCON7?? ?
?????????? DCD 0x008e07a3???????????????? ;REFRESH?????? ?
?????????? DCD 0x000000b1???????????????? ;BANKSIZE???? ?
?????????? DCD 0x00000030???????????????? ;MRSRB6
?????????? DCD 0x00000030???????????????? ;MRSRB7
?????????? END
在uart.c中: ?
#define GPHCON? (*(volitile unsigned long *)0X56000070)
#define GPHDAT? (*(volitile unsigned long *)0X56000074)
#define GPHUP?? (*(volitile unsigned long *)0X56000078)
#define UFCON0? (*(volitile unsigned long *)0x50000008)
#define UMCON0? (*(volitile unsigned long *)0X5000000C)
#define UCON0?? (*(volitile unsigned long *)0X50000004)
#define ULCON0? (*(volitile unsigned long *)0X50000000)
#define UART_CLK??????????? PCKL??????? ? ? ??
//UART0的時鐘源為PCLK
#define UART_BAUD_DATE????? 115200???? ? ? ? ?
//波特率
#define UART_BRD?????????? ((UART_CLK/(UART_BAUD_DATE*16))-1)
void uart_init(void)
{
????????????????? ?
??
? UFCON0=0xbf;?????? ? ? ? ? ? ?
? ? ? ? ? ?
//使用fifo(發送fifo和接收fifo的觸發深度都為32字節)
【在中斷模式下的fifo要設置觸發方式(超時觸發或字節觸發)】
??? UMCON0=0x00;?????? ? ? ? ? ? ?? ? ? ? ? ??
//不使用流控
??? UBRDIV0=UART_BRD;???????????????? ? ? ?? ?
//波特率為115200
??? GPHCON? |=0xa0;????????? ? ? ? ? ? ? ? ???
//GPH2,GPH3用作TXD0,RXD0
??? GPHUP=0x0c;????????????????????? ? ? ? ? ?
//GPH2,GPH3內部上拉
??? UCON0=0X05
???????????????????????????????
?
//時鐘源為PCKL
??? ULCON0 &=0X03;???? ? ? ? ? ? ? ? ? ? ? ?
? //正常模式,數據格式:8個數據位,沒有流控,1個數據位
}
當發送緩沖區里有數據需要傳送時,我們就需要中斷,來完成發送數據的任務。這個中斷的產生,是由 s3c24xx_serial_start_tx()函數來完成的,具體來說,是它所調用的一個是中斷使能的函數 enable_irq(TX_IRQ(port))來完成的。而此中斷一旦使能,就會調用該中斷的服務函數 s3c24xx_serial_tx_chars()去做后續的工作。
其次,在響應函數中,要注意檢測TxFIFO是否已滿。
發 送FIFO,是串口傳送數據非常重要的機制。相當于提供了一個發送前的緩沖區,給我們的發送工作的多樣化的處理帶來了可能。我們的中斷響應函數需要把數據 從發送緩沖區先搬送到TxFIFO中,但搬送之前需要做的工作就是判斷FIFO是不是已經滿了,如果已經滿了,就不能再往里放數據了。
再次,在響應函數中,要注意檢測傳送緩沖區是否已空。
這一點也很重要,我們要發送的數據來源于數據緩沖區,如果該緩沖區的數據是空的,那我們就不需要去傳送了。
最后,如何做到連續不斷地傳送數據。
我們從數據緩沖區里把數據傳到TxFIFO中,要想持續地傳送數據,很顯然還需要有人往數據緩沖區里不斷地放入新的數據。
void putc(unsigned char c)
{
? while(UFSTAT0 & (UFSTAT0=0<<14))
{
? UTXH0=C;
}
unsigined char getc(void)
{
?while(UFSTAT0 &(UFSTAT0=0<<6)
)
{
return URXH0;
}
在main.c中:
#include "start.s"
#include "uart.h"
int main()
{
? unsigned char c;
? uart_init();
?while(1)
?{
?
c=getc();
??? if(isDigit(c)||isLetter(c))
??? putc(c);
?
??? return 0;
?? ?
??? }
?
??
?
用FIFO發送數據時,若所用為輪詢法(用在非高速場合,高速場合最好用BDMA或中 斷法,故此輪詢法很少用)需要保證接受FIFO不溢出,類似中斷法,通過軟件來設置觸發條件。例如 if(rUFSTAT0&0x000f>0x0008)觸發讀為FIFO內有8字節數據。但是我們同時還要考慮,不能空讀接收FIFO,例 如while((rUFSTAT0&0x000F)>0x0000){ 讀接收FIFO}。這種輪詢法比較山寨,穩定性不咋地,適用低速。不提倡使用。
?
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
