自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

如何基于Cortex-A9的UART從頭實(shí)現(xiàn)printf函數(shù)

開發(fā)
本文將以Exynos4412的UART控制器為基礎(chǔ),講解UART的原理以及驅(qū)動(dòng)程序如何編寫。

[[361172]]

 0. 前言

Uart在一個(gè)嵌入式系統(tǒng)中是一個(gè)非常重要的模塊,他承擔(dān)了CPU與用戶交互的橋梁。用戶輸入信息給程序、CPU要打印一些信息給終端都要依賴UART。

本文將以Exynos4412的UART控制器為基礎(chǔ),講解UART的原理以及驅(qū)動(dòng)程序如何編寫。

1. UART是什么

UART是通用異步收發(fā)傳輸器(Universal Asynchronous Receiver/Transmitter),通常稱作UART,是一種異步收發(fā)傳輸器,是設(shè)備間進(jìn)行異步通信的關(guān)鍵模塊。UART負(fù)責(zé)處理數(shù)據(jù)總線和串行口之間的串/并、并/串轉(zhuǎn)換,并規(guī)定了幀格式;通信雙方只要采用相同的幀格式和波特率,就能在未共享時(shí)鐘信號(hào)的情況下,僅用兩根信號(hào)線(Rx 和Tx)就可以完成通信過程,因此也稱為異步串行通信。UART總線雙向通信,可以實(shí)現(xiàn)全雙工傳輸和接收。在嵌入式設(shè)計(jì)中,UART用于主機(jī)與輔助設(shè)備通信,如汽車音響與外接AP之間的通信,與PC機(jī)通信包括與監(jiān)控調(diào)試器和其它器件,如EEPROM通信。

通常需要加入一個(gè)合適的電平轉(zhuǎn)換器,如SP3232E、SP3485,UART還能用于RS-232、RS-485 通信,或與計(jì)算機(jī)的端口連接。UART 應(yīng)用非常廣泛,手機(jī)、工業(yè)控制、PC 等應(yīng)用中都要用到UART。

[[361173]]

在這里插入圖片描述

2. UART通信方式

UART使用的是 異步,串行通信方式。

串行通信

串行通信是指利用一條傳輸線將資料一位位地順序傳送。好比是一列縱隊(duì),每個(gè)數(shù)據(jù)元素依次縱向排列。如下圖所示,傳輸時(shí)一個(gè)比特一個(gè)比特的串行傳輸,每個(gè)時(shí)鐘周期傳輸一個(gè)比特,這種傳輸方式相對(duì)比較簡(jiǎn)單,速度較慢,但是使用總線數(shù)較少,通常一根接收線,一根發(fā)送線即可實(shí)現(xiàn)串行通信。

它的缺點(diǎn)是要增加額外的數(shù)據(jù)來控制一個(gè)數(shù)據(jù)幀的開始和結(jié)束。特點(diǎn)是通信線路簡(jiǎn)單,利用簡(jiǎn)單的線纜就可實(shí)現(xiàn)通信,降低成本,適用于遠(yuǎn)距離通信,但傳輸速度慢的應(yīng)用場(chǎng)合。

并行通信

并行通信好比一排橫隊(duì),齊頭并進(jìn)同時(shí)傳輸。這種通信方式每個(gè)時(shí)鐘周期傳輸?shù)臄?shù)據(jù)量和其總線寬度成正比,但是實(shí)現(xiàn)較為復(fù)雜。

在這里插入圖片描述

異步通信

異步通信以一個(gè)字符為傳輸單位,通信中兩個(gè)字符間的時(shí)間間隔多少是不固定的,然而在同一個(gè)字符中的兩個(gè)相鄰位間的時(shí)間間隔是固定的。

在異步通信技術(shù)中,數(shù)據(jù)發(fā)送方和數(shù)據(jù)接收方?jīng)]有同步時(shí)鐘,只有數(shù)據(jù)信號(hào)線,只不過發(fā)送端和接收端會(huì)按照協(xié)商好的協(xié)議(固定頻率)來進(jìn)行數(shù)據(jù)采樣。數(shù)據(jù)發(fā)送方以每秒鐘57600bits的速度發(fā)送數(shù)據(jù),接收方也以57600bits的速度去接收數(shù)據(jù),這樣就可以保證數(shù)據(jù)的有效和正確。通常異步通信中使用波特率(Baud-Rate)來規(guī)定雙方傳輸速度,其單位為bps(bits per second每秒傳輸位數(shù))。

同步通信

在發(fā)送數(shù)據(jù)信號(hào)的時(shí)候,會(huì)同時(shí)送出一根同步時(shí)鐘信號(hào), 用來同步發(fā)送方和接收方的數(shù)據(jù)采樣頻率。如下圖所示,同步通信時(shí),信號(hào)線1是一根同步時(shí)鐘信號(hào)線,以固定的頻率進(jìn)行電平的切換,其頻率周期為t,在每個(gè)電平的上升沿之后進(jìn)行對(duì)同步送出的數(shù)據(jù)信號(hào)線2進(jìn)行采樣(高電平代表1,低電平代表0),根據(jù)采樣數(shù)據(jù)電平高低取得輸出數(shù)據(jù)信息。如果雙方?jīng)]有同步時(shí)鐘的話,那么接收方就不知道采樣周期,也就不能正常的取得數(shù)據(jù)信息。

在這里插入圖片描述

3. 幀格式

數(shù)據(jù)傳送速率用波特率來表示,即每秒鐘傳送的二進(jìn)制位數(shù)。例如數(shù)據(jù)傳送速率為120字符/秒,而每一個(gè)字符為10位(1個(gè)起始位,7個(gè)數(shù)據(jù)位,1個(gè)校驗(yàn)位,1個(gè)結(jié)束位),則其傳送的波特率為10×120=1200字符/秒=1200波特。數(shù)據(jù)通信格式如下圖:

在這里插入圖片描述

其中各位的意義如下:

  • 起始位:先發(fā)出一個(gè)邏輯”0”信號(hào),表示傳輸字符的開始。
  • 數(shù)據(jù)位:可以是5~8位邏輯”0”或”1”。如ASCII碼(7位),擴(kuò)展BCD碼(8位)。小端傳輸
  • 校驗(yàn)位:數(shù)據(jù)位加上這一位后,使得“1”的位數(shù)應(yīng)為偶數(shù)(偶校驗(yàn))或奇數(shù)(奇校驗(yàn))
  • 停止位:它是一個(gè)字符數(shù)據(jù)的結(jié)束標(biāo)志??梢允?位、1.5位、2位的高電平。
  • 空閑位:處于邏輯“1”狀態(tài),表示當(dāng)前線路上沒有資料傳送。

注:異步通信是按字符傳輸?shù)?,接收設(shè)備在收到起始信號(hào)之后只要在一個(gè)字符的傳輸時(shí)間內(nèi)能和發(fā)送設(shè)備保持同步就能正確接收。

下一個(gè)字符起始位的到來又使同步重新校準(zhǔn)(依靠檢測(cè)起始位來實(shí)現(xiàn)發(fā)送與接收方的時(shí)鐘自同步的)

關(guān)于RS-232、RS-422、RS-485等標(biāo)準(zhǔn),大家可以參考文章《一篇文章了解什么是串口,UART、RS-232、RS-422、RS-485 》

4. Exynos4412 Uart

本文討論UART 是基于Cortex-A9架構(gòu)的Exynos4412 為例。

1)特性

  • Exynos4412 中UART,有4 個(gè)獨(dú)立的通道,每個(gè)通道都可以工作于中斷模式或DMA 模式,即UART 可以發(fā)出中斷或 DMA 請(qǐng)求以便在UART 、CPU 間傳輸數(shù)據(jù)。使用系統(tǒng)時(shí)鐘時(shí),Exynos4412 的 UART 波特率可以達(dá)到 4Mbps 。每個(gè)UART通道包含兩個(gè)FIFO用來接收和發(fā)送:
  • 通道 0有 256 字節(jié)的發(fā)送 FIFO 和 256 字節(jié)的接收FIFO
  • 通道 1、4有 64 字節(jié)的發(fā)送 FIFO 和 64 字節(jié)的接收FIFO
  • 通道 2、3有 16 字節(jié)的發(fā)送FIFO 和 16 字節(jié) 的接收 FIFO 。

UART include:

  • 波特率可以通過編程進(jìn)行 。
  • 紅外接收/發(fā)送
  • 每個(gè)通道支持停止位有 1位、 2位
  • 數(shù)據(jù)位有 5、6、7或 8位

每個(gè)UART還包括

  • 波特率發(fā)生器、發(fā)送器、接收器、控制邏輯組成。

2)Uart控制器

功能模塊

在這里插入圖片描述

每個(gè)UART包含一個(gè)波特率產(chǎn)生器,發(fā)送器,接收器和一個(gè)控制單元,如上圖所示:

  • 發(fā)送數(shù)據(jù) CPU 先將數(shù)據(jù)寫入發(fā)送FIFO 中,然后 UART 會(huì)自動(dòng)將FIFO 中的數(shù)據(jù)復(fù)制到“發(fā)送移位器” (Transmit Shifter )中,發(fā)送移位器將數(shù)據(jù)一位一位地發(fā)送到 TxDn 數(shù)據(jù)線上 (根據(jù)設(shè)定的格式,插入開始位 、校驗(yàn)和停止)。
  • 接收數(shù)據(jù) “移位器” (Receive Shifter )將 RxDn 數(shù)據(jù)線上的數(shù)據(jù)一位一位的接收進(jìn)來,然后復(fù)制到FIFO 中, CPU即可從中讀取數(shù)據(jù)。

UART是以異步方式實(shí)現(xiàn)通信的,其采樣速度由波特率決定,波特率產(chǎn)生器的工作頻率可以由PCLK(外圍設(shè)備頻率),F(xiàn)CLK/n(CPU工作頻率的分頻),UEXTCLK(外部輸入時(shí)鐘)三個(gè)時(shí)鐘作為輸入頻率,波特率設(shè)置寄存器是可編程的,用戶可以設(shè)置其波特率決定發(fā)送和接收的頻率。

發(fā)送器和接收器包含了64Byte的FIFO和數(shù)據(jù)移位器。UART通信是面向字節(jié)流的,待發(fā)送數(shù)據(jù)寫到FIFO之后,被拷貝到數(shù)據(jù)移位器(1字節(jié)大小)里,數(shù)據(jù)通過發(fā)送數(shù)據(jù)管腳TXDn發(fā)出。

同樣道理,接收數(shù)據(jù)通過RXDn管腳來接收數(shù)據(jù)(1字節(jié)大小)到接收移位器,然后將其拷貝到FIFO接收緩沖區(qū)里。

(1)數(shù)據(jù)發(fā)送 發(fā)送的數(shù)據(jù)幀可編程的,它的一個(gè)幀長(zhǎng)度是用戶指定的,它包括一個(gè)開始位,5~8個(gè)數(shù)據(jù)位,一個(gè)可選的奇偶校驗(yàn)位和1~2個(gè)停止位,數(shù)據(jù)幀格式可以通過設(shè)置ULCONn寄存器來設(shè)置。發(fā)送器也可以產(chǎn)生一個(gè)終止信號(hào),它是由一個(gè)全部為0的數(shù)據(jù)幀組成。在當(dāng)前發(fā)送數(shù)據(jù)被完全傳輸完以后,該模塊發(fā)送一個(gè)終止信號(hào)。在終止信號(hào)發(fā)送后,它可以繼續(xù)通過FIFO(FIFO)或發(fā)送保持寄存器(NON-FIFO)發(fā)送數(shù)據(jù)。

(2)數(shù)據(jù)接收 同樣接收端的數(shù)據(jù)也是可編程的,接收器可以偵測(cè)到溢出錯(cuò)誤奇偶校驗(yàn)錯(cuò)誤,幀錯(cuò)誤和終止條件,每個(gè)錯(cuò)誤都可以設(shè)置一個(gè)錯(cuò)誤標(biāo)志。• 溢出錯(cuò)誤 :在舊數(shù)據(jù)被讀取到之前,新數(shù)據(jù)覆蓋了舊數(shù)據(jù) • 奇偶校驗(yàn)錯(cuò)誤:接收器偵測(cè)到了接收數(shù)據(jù)校驗(yàn)結(jié)果失敗,接收數(shù)據(jù)無效 • 幀錯(cuò)誤 :接收到的數(shù)據(jù)沒有一個(gè)有效的停止位,無法判定數(shù)據(jù)幀結(jié)束 • 終止條件 :RxDn接收到保持邏輯0狀態(tài)持續(xù)長(zhǎng)于一個(gè)數(shù)據(jù)幀的傳輸時(shí)間

(3)自動(dòng)流控AFC(Auto Float Control) UART0和UART1支持有nRTS和nCTS的自動(dòng)流控。在AFC情況下,通信雙方nRTS和nCTS管腳分別連接對(duì)方的nCTS和nRTS管腳。通過軟件控制數(shù)據(jù)幀的發(fā)送和接收。在開啟AFC時(shí),發(fā)送端接收發(fā)送前要判斷nCTS信號(hào)狀態(tài),當(dāng)接收到nCTS激活信號(hào)時(shí),發(fā)送數(shù)據(jù)幀。該nCTS管腳連接對(duì)方nRTS管腳。接收端在準(zhǔn)備接收數(shù)據(jù)幀前,其接收器FIFO有大于32個(gè)字節(jié)的空閑空間,nRTS管腳會(huì)發(fā)送激活信號(hào),當(dāng)其接收FIFO小于32個(gè)字節(jié)的空閑空間,nRTS必須置非激活狀態(tài)。

在這里插入圖片描述

3)選擇時(shí)鐘源

Exynos4412 UART的時(shí)鐘源有八種選擇:XXTI 、XusbXTI 、SCLK_HDMI24M 、SCLK_USBPHY0 、 SCLK_HDMIPHY 、SCLKMPLL_USER_T 、SCLKEPLL 、SCLKVPLL ,由 CLK_SRC_PERIL0 寄存器控制。

選擇好時(shí)鐘源后,還可以通過 DIVUART0 ~4設(shè)置分頻系數(shù),由 CLK_DIV_PERIL0 寄存器控制。從分頻器得到的時(shí)鐘被稱為SCLK UART 。

SCLK UART 經(jīng)過上圖中的“ UCLK Generator”后,得到UCLK ,它的頻率就是UART 的波特率。“ Generator UCLK Generator ”通過這 2個(gè)寄存器來設(shè)置:UBRDIVn(UART BAUD RATE DIVISOR) 、UFRACVALn 。

4)UART配置寄存器

在這里插入圖片描述

ULCONn

在這里插入圖片描述
  • bite [6] 紅外模式 選擇串口0是否使用紅外模式:0 = 正常通信模式 1 = 紅外通信模式
  • bite [5:3] 校驗(yàn)?zāi)J?設(shè)置串口0在數(shù)據(jù)接收和發(fā)送時(shí)采用的校驗(yàn)方式:0xx = 無校驗(yàn) 100 = 奇校驗(yàn) 101 = 偶校驗(yàn) 110 = 強(qiáng)制校驗(yàn)/檢測(cè)是否為1 111 = 強(qiáng)制校驗(yàn)/檢測(cè)是否為0
  • [2] 停止位 設(shè)置串口0停止位數(shù):0 = 每個(gè)數(shù)據(jù)幀一個(gè)停止位 1 = 每個(gè)數(shù)據(jù)幀二個(gè)停止位
  • [1:0] 數(shù)據(jù)位 設(shè)置串口0數(shù)據(jù)位數(shù):00 = 5個(gè)數(shù)據(jù)位 01 = 6個(gè)數(shù)據(jù)位 10 = 7個(gè)數(shù)據(jù)位 11 = 8個(gè)數(shù)據(jù)位

該寄存器我們通用的配置是:

  1. ULCON2 = 0x3; //Normal mode, No parity,One stop bit,8 data bits 

UCONn

  • [15:12] FCLK分頻因子 當(dāng)UART0選擇FCLK作為時(shí)鐘源時(shí),設(shè)置其FCLK的分頻因子 UART0 工作時(shí)鐘頻率 = FCLK/ FCLK分頻因子 + 6
  • [11:10] UART時(shí)鐘源選擇 選擇UART0的工作時(shí)鐘PCLK,UEXTCLK,F(xiàn)CLK/n:00,10 = PCLK 01 = UEXTCLK 11 = FCLK/n 當(dāng)選擇FCLK/n作為UART0工作時(shí)鐘時(shí)還要做其它設(shè)置,具體請(qǐng)讀者自行查看硬件手冊(cè)
  • [9] 發(fā)送數(shù)據(jù)中斷產(chǎn)生類型 設(shè)置UART0中斷請(qǐng)求類型,在非FIFO傳輸模式下,一旦發(fā)送數(shù)據(jù)緩沖區(qū)為空,立即產(chǎn)生中斷信號(hào),在FIFO傳輸模式下達(dá)到發(fā)送數(shù)據(jù)觸發(fā)條件時(shí)立即產(chǎn)生中斷信號(hào):0 = 脈沖觸發(fā) 1 = 電平觸發(fā)
  • [8] 接收數(shù)據(jù)中斷產(chǎn)生類型 設(shè)置UART0中斷請(qǐng)求類型,在非FIFO傳輸模式下,一旦接收到數(shù)據(jù),立即產(chǎn)生中斷信號(hào),在FIFO傳輸模式下達(dá)到接收數(shù)據(jù)觸發(fā)條件時(shí)立即產(chǎn)生中斷信號(hào):0 = 脈沖觸發(fā) 1 = 電平觸發(fā)
  • [7] 接收數(shù)據(jù)超時(shí) 設(shè)置當(dāng)接收數(shù)據(jù)時(shí),如果數(shù)據(jù)超時(shí),是否產(chǎn)生接收中斷:0 = 不開啟超時(shí)中斷 1 = 開啟超時(shí)中斷 10 = 7個(gè)數(shù)據(jù)位 11 = 8個(gè)數(shù)據(jù)位
  • [6] 接收數(shù)據(jù)錯(cuò)誤中斷 設(shè)置當(dāng)接收數(shù)據(jù)時(shí),如果產(chǎn)生異常,如傳輸中止,幀錯(cuò)誤,校驗(yàn)錯(cuò)誤時(shí),是否產(chǎn)生接收狀態(tài)中斷信號(hào):0 = 不產(chǎn)生錯(cuò)誤狀態(tài)中斷 1 = 產(chǎn)生錯(cuò)誤狀態(tài)中斷
  • [5] 回送模式 設(shè)置該位時(shí)UART會(huì)進(jìn)入回送模式,該模式僅用于測(cè)試 0 = 正常模式 1 = 回送模式
  • [4] 發(fā)送終止信號(hào) 設(shè)置該位時(shí),UART會(huì)發(fā)送一個(gè)幀長(zhǎng)度的終止信號(hào),發(fā)送完畢后,該位自動(dòng)恢復(fù)為0 0 = 正常傳輸 1 = 發(fā)送終止信號(hào)
  • [3:2] 發(fā)送模式 設(shè)置采用哪個(gè)方式執(zhí)行數(shù)據(jù)寫入發(fā)送緩沖區(qū) 00 = 無效 01 = 中斷請(qǐng)求或查詢模式 10 = DMA0請(qǐng)求
  • [1:0] 接收模式 設(shè)置采用哪個(gè)方式執(zhí)行數(shù)據(jù)寫入接收緩沖區(qū) 00 = 無效 01 = 中斷請(qǐng)求或查詢模式 10 = DMA0請(qǐng)求

該寄存器通用配置為:

  1. UCON2 = 0x5;  //Interrupt request or polling mode 

一般裸機(jī)情況下,采用輪詢模式。

UTRSTATn

UTRSTAT n寄存器用來表明數(shù)據(jù)是否已經(jīng)發(fā)送完畢、是否已經(jīng)接收到數(shù)據(jù),格式如下圖所示,上面說的“緩沖區(qū)”,其實(shí)就是下圖中的 FIFO ,不使用 FIFO 功能時(shí)可以認(rèn)為其深度為 1。

當(dāng)我們讀取數(shù)據(jù)時(shí),就輪詢檢查bit[0]置1之后,然后再從URXHn寄存器讀取數(shù)據(jù);當(dāng)我們讀取數(shù)據(jù)時(shí),就輪詢檢查bit[1]置1之后,然后再向UTXHn寄存器寫入數(shù)據(jù)來發(fā)送數(shù)據(jù);

在這里插入圖片描述

在這里插入圖片描述

UTXHn寄存器(UART TRANSMIT BUFFER REGISTER)

CPU 將數(shù)據(jù)寫入這個(gè)寄存器, UART即會(huì)將它保存到緩沖區(qū)中,并自動(dòng)發(fā)送出去。

URXHn寄存器(UART RECEIVE BUFFER REGISTER)

當(dāng) UART 接收到數(shù)據(jù)時(shí),讀取這個(gè)寄存器,即可獲得數(shù)據(jù)。

UFRACVALn 計(jì)算波特率

在這里插入圖片描述

根據(jù)給定的波特率、所選擇時(shí)鐘源頻率,可以通過以下公式計(jì)算 UBRDIVn 寄存器 (n 為 0~4,對(duì)應(yīng) 5個(gè) UART 通道 )的值。

  1. UBRDIVn = (int)( UART clock / ( buad rate x 16) ) – 1 

上式計(jì)算出來的 UBRDIVn 寄存器值不一定是整數(shù), UBRDIVn 寄存器取其整數(shù)部分,小部分由 UFRACVALn 寄存器設(shè)置, UFRACVALn 寄存器的引入,使產(chǎn)生波特率更加精確。「【舉例】」當(dāng)UART clock為100MHz時(shí),要求波特率為115200 bps,則:

  1. 100000000/(115200 x 16) – 1 = 54.25 – 1 = 53.25 
  2.     UBRDIVn = 整數(shù)部分 = 53                
  3.     UFRACVALn/16 = 小數(shù)部分 = 0.25 
  4.     UFRACVALn = 4 

5)電路圖

外設(shè)電路圖:

在這里插入圖片描述

SP3232EEA 用來將TTL電平轉(zhuǎn)換成RS232電平。我們使用的是COM2。

外設(shè)與核心板連接電路圖

在這里插入圖片描述

可見UART的收發(fā)引腳連接到了GPA上,打開exynos4412芯片手冊(cè):

在這里插入圖片描述

我們只需要將GPA1 的低8位設(shè)置為0x22。

6.實(shí)例代碼

裸機(jī)代碼,主要實(shí)現(xiàn)uart_init()、putc()、getc()這三個(gè)函數(shù)。

uart_init()

該函數(shù)主要配置UART的,波特率115200,數(shù)據(jù)位:8,奇偶校驗(yàn)位:0,終止位:1,不設(shè)置流控。

如下圖:是運(yùn)行在windows下常用的串口工具配置信息,配置信息必須完全一致。

在這里插入圖片描述

putc()

該函數(shù)是向串口發(fā)送一個(gè)數(shù)據(jù)data,他的實(shí)現(xiàn)邏輯就是輪詢檢查寄存器UART2.UTRSTAT2 ,判斷其bite【1】是否置1,如果置1,則向UART2.UTXH2存入要發(fā)送的數(shù)據(jù)即可。

getc()

該函數(shù)是從串口接收一個(gè)數(shù)據(jù)data,他的實(shí)現(xiàn)邏輯就是輪詢檢查寄存器UART2.UTRSTAT2 ,判斷其bite【0】是否置1,如果置1,說明數(shù)據(jù)準(zhǔn)備好,則可以從寄存器UART2.URXH2取出數(shù)據(jù)。

代碼

  1. /* 
  2.  * UART2 
  3.  */ 
  4. typedef struct { 
  5.     unsigned int ULCON2; 
  6.     unsigned int UCON2; 
  7.     unsigned int UFCON2; 
  8.     unsigned int UMCON2; 
  9.     unsigned int UTRSTAT2; 
  10.     unsigned int UERSTAT2; 
  11.     unsigned int UFSTAT2; 
  12.     unsigned int UMSTAT2; 
  13.     unsigned int UTXH2; 
  14.     unsigned int URXH2; 
  15.     unsigned int UBRDIV2; 
  16.     unsigned int UFRACVAL2; 
  17.     unsigned int UINTP2; 
  18.     unsigned int UINTSP2; 
  19.     unsigned int UINTM2; 
  20. }uart2; 
  21. #define UART2 ( * (volatile uart2 *)0x13820000 ) 
  22. /* GPA1 */ 
  23. typedef struct { 
  24.     unsigned int CON; 
  25.     unsigned int DAT; 
  26.     unsigned int PUD; 
  27.     unsigned int DRV; 
  28.     unsigned int CONPDN; 
  29.     unsigned int PUDPDN; 
  30. }gpa1; 
  31. #define GPA1 (* (volatile gpa1 *)0x11400020) 
  32. void uart_init() 
  33. { /*UART2 initialize*/ 
  34.  GPA1.CON = (GPA1.CON & ~0xFF ) | (0x22); //GPA1_0:RX;GPA1_1:TX 
  35.  UART2.ULCON2 = 0x3; //Normal mode, No parity,One stop bit,8 data bits 
  36.  UART2.UCON2 = 0x5;  //Interrupt request or polling mode 
  37.  //Baud-rate : src_clock:100Mhz 
  38.  UART2.UBRDIV2 = 0x35; 
  39.  UART2.UFRACVAL2 = 0x4; 
  40. void putc(const char data) 
  41. { while(!(UART2.UTRSTAT2 & 0X2)); 
  42.  UART2.UTXH2 = data; 
  43.  if (data == '\n'
  44.    putc('\r'); 
  45. char getc(void) 
  46. char data; 
  47.  while(!(UART2.UTRSTAT2 & 0x1)); 
  48.  data = UART2.URXH2; 
  49.  if ((data == '\n')||(data == '\r')) 
  50.  { 
  51.    putc('\n'); 
  52.    putc('\r'); 
  53.  }else 
  54.    putc(data); 
  55.  return data; 

puts/gets

  1. void puts(const  char  *pstr) 
  2. { while(*pstr != '\0'
  3.   putc(*pstr++); 
  4. void gets(char *p) 
  5. char data; 
  6.  while((data = getc())!= '\r'
  7.  {  if(data == '\b'
  8.   {p--; 
  9.   } 
  10.   *p++ = data; 
  11.  } 
  12.  if(data == '\r'
  13.  *p++ = '\n'
  14.  *p = '\0'

7.如何裸機(jī)程序可以支持printf函數(shù)

首先看下文件的目錄結(jié)構(gòu):

代碼架構(gòu)

老規(guī)矩,關(guān)注,后臺(tái)回復(fù)【armprintf】,就可以得到代碼。

這里我們只貼出部分文件的代碼。

「cpu/start.s」改文件主要是實(shí)現(xiàn)異常向量表,實(shí)現(xiàn)各個(gè)模式的棧初始化

  1. .text 
  2. .global _start 
  3. _start: 
  4.   b  reset 
  5.   ldr  pc,_undefined_instruction 
  6.   ldr  pc,_software_interrupt 
  7.   ldr  pc,_prefetch_abort 
  8.   ldr  pc,_data_abort 
  9.   ldr  pc,_not_used 
  10.   ldr  pc,=irq_handler 
  11.   ldr  pc,_fiq 
  12.  
  13. _undefined_instruction: .word  _undefined_instruction 
  14. _software_interrupt: .word  _software_interrupt 
  15. _prefetch_abort:  .word  _prefetch_abort 
  16. _data_abort:   .word  _data_abort 
  17. _not_used:    .word  _not_used 
  18. _irq:     .word  irq_handler 
  19. _fiq:     .word  _fiq 
  20.  
  21.  
  22. reset: 
  23.  
  24.  ldr r0,=0x40008000 
  25.  mcr p15,0,r0,c12,c0,0  @ 協(xié)處理器指令設(shè)置異常向量表地址 
  26.  
  27.  
  28. init_stack: 
  29.   ldr  r0,stacktop         /*get stack top pointer*/ 
  30.  
  31.  /********svc mode stack********/ 
  32.   mov  sp,r0 
  33.   sub  r0,#128*4          /*512 byte  for irq mode of stack*/ 
  34.  /****irq mode stack**/ 
  35.   msr  cpsr,#0xd2 
  36.   mov  sp,r0 
  37.   sub  r0,#128*4          /*512 byte  for irq mode of stack*/ 
  38.  /***fiq mode stack***/ 
  39.   msr  cpsr,#0xd1 
  40.   mov  sp,r0 
  41.   sub  r0,#0 
  42.  /***abort mode stack***/ 
  43.   msr  cpsr,#0xd7 
  44.   mov  sp,r0 
  45.   sub  r0,#0 
  46.  /***undefine mode stack***/ 
  47.   msr  cpsr,#0xdb 
  48.   mov  sp,r0 
  49.   sub  r0,#0 
  50.    /*** sys mode and usr mode stack ***/ 
  51.   msr  cpsr,#0x10 
  52.   mov  sp,r0             /*1024 byte  for user mode of stack*/ 
  53.  
  54.   b  main @跳轉(zhuǎn)到c語言的main函數(shù) 
  55.  
  56.  .align 4 
  57.  
  58.  /****  swi_interrupt handler  ****/ 
  59.  
  60.  
  61.  /****  irq_handler  ****/ 
  62. irq_handler: 
  63.  
  64.  sub  lr,lr,#4 
  65.  stmfd sp!,{r0-r12,lr} 
  66.  .weak do_irq   @該函數(shù)可以沒有定義 
  67.  bl do_irq  @跳轉(zhuǎn)到中斷入口 
  68.  ldmfd sp!,{r0-r12,pc}^ 
  69.  
  70. stacktop:    .word   stack+4*512 @定義棧頂 
  71. .data 
  72.  
  73. stack:  .space  4*512  @分配一塊棧空間 

「lib/printf.c」

該文件主要實(shí)現(xiàn)打印函數(shù)printf一些格式控制,一些字符串轉(zhuǎn)換算數(shù)運(yùn)算需要借助頭文件ctype.h、stdarg.h中一些宏。其中vsprintf 具體的實(shí)現(xiàn)我們就不再詳解,有興趣讀者自行研究。

  1. …… 
  2. void printf (const char *fmt, ...) 
  3.  va_list args; 
  4.  unsigned int i; 
  5.  char printbuffer[100]; 
  6.  va_start (args, fmt); 
  7.  
  8.  /* For this to work, printbuffer must be larger than 
  9.   * anything we ever want to print. 
  10.   */ 
  11.  i = vsprintf (printbuffer, fmt, args);//對(duì)輸入的參數(shù)進(jìn)行格式整理 
  12.  va_end (args); 
  13.  puts (printbuffer); //調(diào)用上一章我們封裝的puts函數(shù)實(shí)現(xiàn)向串口打印書字符串 

「main.c」該文件可以直接調(diào)用printf()函數(shù)來打印信息了。

  1. void  delay_ms(unsigned int num) 
  2.     int i,j; 
  3.     for(i=num; i>0;i--) 
  4.  for(j=1000;j>0;j--) 
  5.   ; 
  6. /* 
  7.  *  裸機(jī)代碼,不同于LINUX 應(yīng)用層, 一定加循環(huán)控制 
  8.  */ 
  9.  
  10. int main (void) 
  11.  int i = 0; 
  12.  while (1) { 
  13.   printf("aaaaaaaaaaaaa\n"); 
  14.   delay_ms(500); 
  15.  } 
  16.    return 0; 

「Makefile」

  1. CROSS_COMPILE = arm-none-eabi- 
  2. NAME =gcd 
  3. CFLAGS=-mfloat-abi=softfp -mfpu=vfpv3 -mabi=apcs-gnu -fno-builtin  -fno-builtin-function -g -O0 -c  -I ./include -I ./lib                                                   
  4. LD = $(CROSS_COMPILE)ld 
  5. CC = $(CROSS_COMPILE)gcc 
  6. OBJCOPY = $(CROSS_COMPILE)objcopy 
  7. OBJDUMP = $(CROSS_COMPILE)objdump 
  8. OBJS=./cpu/start.o ./driver/uart.o  \ 
  9.         ./driver/_udivsi3.o ./driver/_divsi3.o ./driver/_umodsi3.o main.o ./lib/printf.o  
  10. #=============================================================================# 
  11. all:  $(OBJS) 
  12.  $(LD)  $(OBJS) -T map.lds -o $(NAME).elf 
  13.  $(OBJCOPY)  -O binary  $(NAME).elf $(NAME).bin  
  14.  $(OBJDUMP) -D $(NAME).elf > $(NAME).dis  
  15. %.o: %.S  
  16.  $(CC) $(CFLAGS) -c -o  $@ $< 
  17. %.o: %.s  
  18.  $(CC) $(CFLAGS) -c -o  $@ $< 
  19. %.o: %.c 
  20.  $(CC) $(CFLAGS) -c -o  $@ $< 
  21. clean: 
  22.  rm -rf $(OBJS) *.elf *.bin *.dis *.o 

 

 

責(zé)任編輯:姜華 來源: 一口Linux
相關(guān)推薦

2021-01-19 19:32:01

Cortex-A9 R嵌入式系統(tǒng)i2c 外設(shè)

2020-12-22 11:54:42

C語言Cortex-A9LED匯編

2021-01-26 06:15:42

Cortex-A9 R嵌入式系統(tǒng)啟動(dòng)代碼

2021-01-06 05:42:42

Cortex-A9 R嵌入式系統(tǒng) RTC

2021-01-16 11:40:28

ARM嵌入式開發(fā)ADC應(yīng)用

2021-01-08 12:06:59

WDT定時(shí)裝置

2022-08-05 13:38:08

C語言庫函數(shù)printf()

2021-02-05 12:04:45

LinuxUARTLinux系統(tǒng)

2024-11-27 08:14:43

2021-04-20 09:26:40

Cortex M架構(gòu)Cortex A架構(gòu)STM32系列

2022-09-11 15:02:22

機(jī)器學(xué)習(xí)算法感知器

2010-01-18 17:38:54

C++虛函數(shù)表

2020-09-02 07:19:41

printf 格式化輸出Unix

2022-02-28 08:17:24

重載函數(shù)JS前端

2021-08-23 06:59:38

Linux內(nèi)核代碼

2022-09-27 08:01:48

遞歸函數(shù)GScript

2022-04-02 07:52:47

DubboRPC調(diào)用動(dòng)態(tài)代理

2018-01-09 10:05:55

神經(jīng)網(wǎng)絡(luò)ClojureCortex

2018-07-19 15:13:15

深度學(xué)習(xí)圖像

2017-05-12 16:25:44

深度學(xué)習(xí)圖像補(bǔ)全tensorflow
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)