0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線(xiàn)課程
  • 觀(guān)看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

如何根據(jù)UART傳輸協(xié)議將數(shù)據(jù)發(fā)送出去呢?

冬至子 ? 來(lái)源:兩猿社 ? 作者:IC猿 ? 2023-06-05 15:59 ? 次閱讀

00 簡(jiǎn)介

和接收部分相反,UART發(fā)送數(shù)據(jù)部分是CPU將需要發(fā)送的數(shù)據(jù)寫(xiě)到發(fā)送數(shù)據(jù)寄存器(TX_DATA),發(fā)送模塊進(jìn)行數(shù)據(jù)的發(fā)送。由于系統(tǒng)時(shí)鐘速率一般會(huì)比UART發(fā)送數(shù)據(jù)快,所以發(fā)送數(shù)據(jù)將緩存到發(fā)送數(shù)據(jù)FIFO(TX_FIFO)。當(dāng)TX_FIFO非空時(shí),發(fā)送數(shù)據(jù)模塊會(huì)根據(jù)UART傳輸協(xié)議將數(shù)據(jù)發(fā)送出去,直到TX_FIFO為空。

類(lèi)似的,發(fā)送模塊也涉及到ARM時(shí)鐘和26MHz功能時(shí)鐘。其中 發(fā)送FIFO讀寫(xiě)邏輯是ARM時(shí)鐘域,發(fā)送數(shù)據(jù)狀態(tài)機(jī)和同步邏輯等是功能時(shí)鐘域 。

01 模塊接口與描述

1.jpg

2.jpg

02 實(shí)現(xiàn)

UART_TX模塊主要由三部分組成: 配置信息同步 、TX_FIFO讀控制部分發(fā)送狀態(tài)機(jī)

配置信息是reg_if模塊由APB總線(xiàn)配置寄存器產(chǎn)生,功能時(shí)鐘域做兩級(jí)同步處理。(比如校驗(yàn)位使能、奇偶校驗(yàn)控制、停止位使能等)

發(fā)送數(shù)據(jù)FIFO控制部分將FIFO中的數(shù)據(jù)讀出,通過(guò)發(fā)送數(shù)據(jù)狀態(tài)機(jī)將數(shù)據(jù)發(fā)送。

發(fā)送狀態(tài)機(jī)是根據(jù)串口協(xié)議劃分,分為IDLE、IRQ、START_BIT、TX_DATA、CHECK_BIT、STOP和DELAY六種狀態(tài)。

配置信息同步

和接收模塊類(lèi)似,由于配置信息是由APB時(shí)鐘產(chǎn)生,到接收模塊的功能時(shí)鐘域需要做同步處理。配置信息是電平信號(hào),通常不會(huì)像數(shù)據(jù)一樣變化快,所以只需要兩級(jí)同步。

接收狀態(tài)機(jī)

使用典型的三段式狀態(tài)機(jī)設(shè)計(jì),狀態(tài)轉(zhuǎn)移圖如下:

圖片

uart發(fā)送狀態(tài)轉(zhuǎn)移圖

IDLE: 發(fā)送狀態(tài)機(jī)的IDLE狀態(tài)會(huì)產(chǎn)生tx_start的發(fā)送請(qǐng)求信號(hào),F(xiàn)IFO讀邏輯部分會(huì)判斷讀空信號(hào)tx_fifo_rempty和tx_start,如果TX_FIFO非空且發(fā)送請(qǐng)求有效,則產(chǎn)生發(fā)送響應(yīng)tx_ack,并發(fā)出FIFO讀使能。IDLE狀態(tài)機(jī)內(nèi)發(fā)現(xiàn)tx_ack有效,跳轉(zhuǎn)到IRQ狀態(tài)。IRQ: IRQ狀態(tài)目的是等待FIFO數(shù)據(jù)讀出。進(jìn)入IRQ后使能波特率時(shí)鐘,tx_start信號(hào)disable,跳轉(zhuǎn)到START_BIT。

START_BIT: 發(fā)送起始位。拉低utxd_o后跳轉(zhuǎn)到發(fā)送數(shù)據(jù)狀態(tài)TX_DATA。

TX_DATA: 發(fā)送從TX_FIFO讀出的8bit數(shù)據(jù),發(fā)送完8bit數(shù)據(jù)后判斷校驗(yàn)位是否使能(check_syn2),使能則進(jìn)入CHECK_BIT,不使能則進(jìn)入STOP狀態(tài)。

CHECK_BIT: 8bit數(shù)據(jù)按位異或(偶校驗(yàn))或同或(奇校驗(yàn)),計(jì)算出校驗(yàn)位發(fā)送,判斷是否使能停止位(stop_bit_syn2),如使能停止位則進(jìn)入STOP狀態(tài),不使能則進(jìn)入DELAY狀態(tài)。

這里提一下 奇偶校驗(yàn) 。

所謂奇校驗(yàn),就是判斷發(fā)送的數(shù)據(jù)位中1的個(gè)數(shù)是否是奇數(shù),如果數(shù)據(jù)位中1的個(gè)數(shù)是偶數(shù),那就給校驗(yàn)位賦值1;如果數(shù)據(jù)位中1的個(gè)數(shù)是奇數(shù),那就給校驗(yàn)位賦值0。目的是確保發(fā)送的數(shù)據(jù)中1的個(gè)數(shù)是奇數(shù)。

偶校驗(yàn)則相反,判斷發(fā)送的數(shù)據(jù)位中1的個(gè)數(shù)是否是偶數(shù),如果數(shù)據(jù)位中1的個(gè)數(shù)是偶數(shù),那就給校驗(yàn)位賦值0;如果數(shù)據(jù)位中1的個(gè)數(shù)是奇數(shù),那就給校驗(yàn)位賦值1。目的是確保發(fā)送的數(shù)據(jù)中1的個(gè)數(shù)是偶數(shù)。

實(shí)現(xiàn)時(shí),奇偶校驗(yàn)可以用同或和異或操作計(jì)算,相同的8bit數(shù)奇偶校驗(yàn)的值一定是相反的。

STOP: STOP狀態(tài)拉高utxd_o,然后進(jìn)入DELAY狀態(tài)。

DELAY: DELAY狀態(tài)控制相鄰兩次發(fā)送之間的間隔,間隔時(shí)間以波特率時(shí)鐘為單位,受CPU控制(配置字two_tx_delay),默認(rèn)delay兩個(gè)波特率時(shí)鐘周期。延時(shí)后回到IDLE狀態(tài)進(jìn)行等待或下一Byte數(shù)據(jù)傳輸。

前兩段狀態(tài)機(jī),狀態(tài)跳轉(zhuǎn):

// state to nextstate with clk in this block.
always@(posedge clk26m ornegedge rst26m_) begin
    if(!rst26m_) begin
        state <= IDLE;
    end
    elsebegin
        state <= nextstate;
    end
end

// nextstate transform
always@(*) begin
    case(state)
    IDLE: begin
        if(tx_ack_delay2) begin
            nextstate = IRQ;
        end
        elsebegin
            nextstate = IDLE;
        end
    end
    IRQ: begin
        if(tx_bpsclk) begin
            nextstate = START_BIT;
        end
        elsebegin
            nextstate = IRQ;
        end
    end
    START_BIT: begin
        if(tx_bpsclk) begin
            nextstate = TX_DATA;
        end
        elsebegin
            nextstate = START_BIT;
        end
    end
    TX_DATA: begin
        // send 8 bit data
        if(data_cnt < 4'd8) begin
            nextstate = TX_DATA;
        end
        elsebegin
            if(tx_bpsclk) begin
                if(check_syn2) begin
                    nextstate = CHECK_BIT;
                end
                elsebegin
                    nextstate = STOP;
                end
            end
            elsebegin
                nextstate = TX_DATA;
            end
        end
    end
    CHECK_BIT: begin
        if(tx_bpsclk) begin
            if(stop_bit_syn2) begin
                nextstate = STOP;
            end
            elsebegin
                nextstate = DELAY;
            end
        end
        elsebegin
            nextstate = CHECK_BIT;
        end
    end
    STOP: begin
        if(tx_bpsclk) begin
            nextstate = DELAY;
        end
        elsebegin
            nextstate = STOP;
        end
    end
    DELAY: begin
        if(baud_cnt < two_tx_delay_syn2) begin
            nextstate = DELAY;
        end
        elsebegin
            nextstate = IDLE;
        end
    end
    default: begin
        nextstate = IDLE;
    end
    endcase
end

第三段狀態(tài)機(jī),信號(hào)賦值:

// output signal
always@(posedge clk26m ornegedge rst26m_) begin
    if(!rst26m_) begin
        tx_bpsen <= 1'b0;
        tx_start <= 1'b0;
        utxd_o   <= 1'b1;
        data_cnt <= 4'd0;
        baud_cnt <= 4'd0;
    end
    elsebegin
        case(nextstate)
        IDLE: begin
            tx_start   <= 1'b1;
            baud_cnt   <= 4'd0;
            data_cnt   <= 4'd0;
        end
        IRQ: begin
            tx_bpsen   <= 1'b1;
            tx_start   <= 1'b0;
        end
        START_BIT: begin
            if(tx_bpsclk) begin
                utxd_o <= 1'b0;
            end
        end
        TX_DATA: begin
            if(tx_bpsclk) begin
                utxd_o   <= data_tx[data_cnt];
                data_cnt <= data_cnt + 1'b1;
            end
        end
        CHECK_BIT: begin
            if(tx_bpsclk) begin
                // odd check
                if(parity_syn2) begin
                    utxd_o <= ^data_tx;
                end
                // even check
                elsebegin
                    utxd_o <= ^~data_tx;
                end
            end
        end
        STOP: begin
            if(tx_bpsclk) begin
                utxd_o <= 1'b1;
            end
        end
        DELAY: begin
            if(tx_bpsclk) begin
                baud_cnt <= baud_cnt + 1'b1;
                utxd_o   <= 1'b1;    // the delay between twice send data is 1
            end
        end
        endcase
    end
end

接收數(shù)據(jù)FIFO控制

TX_FIFO使用同步FIFO設(shè)計(jì),工作在APB時(shí)鐘域。

TX_FIFO的讀邏輯使用一段式狀態(tài)機(jī)產(chǎn)生。首先判斷FIFO是否為空,發(fā)送狀態(tài)機(jī)的發(fā)送請(qǐng)求tx_start是否有效。兩個(gè)信號(hào)都有效時(shí)將產(chǎn)生讀FIFO使能和發(fā)送數(shù)據(jù)響應(yīng),通知發(fā)送狀態(tài)機(jī)可以開(kāi)始發(fā)送數(shù)據(jù)。

注意讀FIFO使能僅有效一個(gè)APB時(shí)鐘周期,待tx_start不使能時(shí)disable發(fā)送數(shù)據(jù)響應(yīng)。等待一個(gè)狀態(tài)后狀態(tài)機(jī)回到初始態(tài)(等待一個(gè)狀態(tài)是為了確保發(fā)送狀態(tài)機(jī)已經(jīng)進(jìn)行跳轉(zhuǎn),避免tx_ack和FIFO讀使能一直有效)。

// this state machine to receive data from RX FIFO
always@(posedge clk ornegedge rst_) begin
    if(!rst_) begin
        tx_ack       <= 1'b0;
        tx_fifo_rinc <= 1'b0;
        rdata_state  <= 2'b0;
    end
    elsebegin
        case(rdata_state)
        2'b00: begin
            if(!tx_fifo_rempty && tx_start_delay2) begin
                tx_ack       <= 1'b1;
                tx_fifo_rinc <= 1'b1;
                rdata_state  <= 2'b01;
            end
        end
        2'b01: begin
            tx_fifo_rinc <= 1'b0;
            if(!tx_start_delay2) begin
                tx_ack      <= 1'b0;
                rdata_state <= 2'b10;
            end
        end
        2'b10: begin
            rdata_state <= 2'b0;
        end
        endcase
    end
end

TX_FIFO寫(xiě)邏輯放在reg_if模塊,APB寫(xiě)TX_DATA寄存器時(shí),產(chǎn)生寫(xiě)使能信號(hào),將寄存器數(shù)據(jù)放到TX_FIFO中。

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀(guān)點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • ARM
    ARM
    +關(guān)注

    關(guān)注

    134

    文章

    9006

    瀏覽量

    366037
  • 寄存器
    +關(guān)注

    關(guān)注

    31

    文章

    5270

    瀏覽量

    119646
  • 有限狀態(tài)機(jī)

    關(guān)注

    0

    文章

    52

    瀏覽量

    10307
  • FIFO存儲(chǔ)
    +關(guān)注

    關(guān)注

    0

    文章

    103

    瀏覽量

    5953
  • UART接口
    +關(guān)注

    關(guān)注

    0

    文章

    124

    瀏覽量

    15232
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    如何算得的數(shù)據(jù)(10進(jìn)制)轉(zhuǎn)換為16進(jìn)制通過(guò)串口發(fā)送出?

    我用公式節(jié)點(diǎn)算得一組數(shù)據(jù),好比是1212,1313,1414等,這些數(shù)據(jù)轉(zhuǎn)為16進(jìn)制就是04BC,0521,0586,如何十進(jìn)制的數(shù)據(jù)轉(zhuǎn)換為十六進(jìn)制然后通過(guò)串口
    發(fā)表于 01-30 14:05

    程序是ADC采集的數(shù)據(jù)和串口接收的數(shù)據(jù)通過(guò)ble藍(lán)牙發(fā)送出去,請(qǐng)問(wèn)為什么打開(kāi)uart后找不到搜索藍(lán)牙?如何解決?

    我寫(xiě)的程序是ADC采集的數(shù)據(jù)和串口接收的數(shù)據(jù)通過(guò)ble藍(lán)牙發(fā)送出去,不知道為什么,打開(kāi)uart后,手機(jī)無(wú)法搜索藍(lán)牙,通過(guò)調(diào)試發(fā)現(xiàn)卡在0x0
    發(fā)表于 06-29 16:27

    請(qǐng)問(wèn)用光敏實(shí)驗(yàn)采集的數(shù)據(jù),怎么樣通過(guò)WIFI發(fā)送出去?

    比如用光敏實(shí)驗(yàn)采集的數(shù)據(jù),怎么樣通過(guò)WIFI發(fā)送出去?怎么樣通過(guò)WIFI用電腦控制開(kāi)發(fā)板上面的LED燈,這類(lèi)的問(wèn)題,謝謝解答。
    發(fā)表于 06-03 21:35

    lwip中數(shù)據(jù)不能發(fā)送出去

    我現(xiàn)在在stm32上用lwip和上位機(jī)通訊,正常情況下數(shù)據(jù)每次能發(fā)送出去,并且lwip中tcp_output函數(shù)里 pcb->unacked == NULL的,但是當(dāng)出現(xiàn)異常情況時(shí),數(shù)據(jù)發(fā)送
    發(fā)表于 07-04 04:35

    請(qǐng)問(wèn)特征值發(fā)送出去用什么函數(shù)?

    請(qǐng)問(wèn)下,我想把特征值 里面的值發(fā)送出去需要用什么函數(shù)呢?還是說(shuō)我只要用SimpleProfile_SetParameter()這個(gè)函數(shù)設(shè)置好要發(fā)的特征值就可以了,讓主機(jī)自己去讀呢?小白請(qǐng)教大家。謝謝。
    發(fā)表于 03-05 10:30

    CC2541的串口沒(méi)法發(fā)送出去

    你好,在使用CC2541時(shí)目前遇到一個(gè)很困惑的問(wèn)題,我的程序希望通過(guò)串口發(fā)送,同樣的程序在開(kāi)發(fā)板上運(yùn)行能夠正常的收發(fā),程序下載到我們自己的目標(biāo)板上,就沒(méi)法發(fā)送出去了,跟蹤到
    發(fā)表于 03-18 08:32

    請(qǐng)問(wèn)用NRF2401溫度數(shù)據(jù)發(fā)送出去怎么在電路板上把天線(xiàn)做出來(lái)?

    用NRF2401溫度數(shù)據(jù)發(fā)送出去,怎么在電路板上就把天線(xiàn)做出來(lái),求原理圖和PCB布線(xiàn)!謝謝各位大神!
    發(fā)表于 04-13 04:35

    NRF24L01如何才能將所有數(shù)據(jù)發(fā)送出去呢

    利用NRF24L01通信發(fā)送數(shù)據(jù),資料說(shuō)的是可以發(fā)送最長(zhǎng)32個(gè)字節(jié)但是我只能發(fā)送16個(gè)字節(jié),只能發(fā)送一半,后面的全部都為了0了,請(qǐng)問(wèn)這是為什
    發(fā)表于 06-10 09:25

    DSP處理結(jié)果如何通過(guò)SCI發(fā)送出去

    在工程實(shí)際應(yīng)用中需要將DSP處理結(jié)果通過(guò)SCI發(fā)送出去,但是所要傳輸數(shù)據(jù)是浮點(diǎn)float型,無(wú)法通過(guò)SCI發(fā)送,該如何處理?謝謝~
    發(fā)表于 07-23 06:27

    為什么文章無(wú)法提交 發(fā)送出去

    為什么文章無(wú)法提交 發(fā)送出去
    發(fā)表于 07-22 14:23

    如何一個(gè)浮點(diǎn)型的數(shù)通過(guò)串口發(fā)送出去?

    如何一個(gè)浮點(diǎn)型的數(shù)通過(guò)串口發(fā)送出去?
    發(fā)表于 11-22 06:16

    如何printf()函數(shù)的數(shù)據(jù)用STM32的串口發(fā)送出去呢

    如何去使用C語(yǔ)言中的printf()函數(shù)呢?如何printf()函數(shù)的數(shù)據(jù)用STM32的串口發(fā)送出去呢?
    發(fā)表于 12-01 07:58

    智能家居設(shè)備可能會(huì)將數(shù)據(jù)通過(guò)網(wǎng)絡(luò)發(fā)送出去 數(shù)據(jù)安全受到威脅

    你可能覺(jué)得你的智能家居設(shè)備只會(huì)與你進(jìn)行溝通,然而事實(shí)并非如此,你的設(shè)備可能會(huì)將數(shù)據(jù)通過(guò)網(wǎng)絡(luò)發(fā)送出去,以便與服務(wù)器進(jìn)行通信,甚至可能會(huì)發(fā)送到你不希望擁有這些數(shù)據(jù)的人手中?,F(xiàn)在,普林斯頓的
    發(fā)表于 04-19 08:48 ?628次閱讀

    Linux如何操作數(shù)據(jù)發(fā)送出去

    ? Linux 服務(wù)器收到網(wǎng)絡(luò)數(shù)據(jù)包,需要經(jīng)過(guò)哪些處理,一步步數(shù)據(jù)傳給應(yīng)用進(jìn)程的呢?應(yīng)用進(jìn)程發(fā)送數(shù)據(jù)包時(shí),Linux 又是如何操作
    的頭像 發(fā)表于 06-17 16:00 ?954次閱讀
    Linux如何操作<b class='flag-5'>將</b><b class='flag-5'>數(shù)據(jù)</b>包<b class='flag-5'>發(fā)送出去</b>

    stm32 HAL庫(kù)spi接收的同時(shí)為什么有數(shù)據(jù)發(fā)送出去

    stm32 HAL庫(kù)spi接收的同時(shí)為什么有數(shù)據(jù)發(fā)送出去? 在STM32 HAL庫(kù)中,SPI接口的數(shù)據(jù)收發(fā)是通過(guò)DMA傳輸完成的。因此,通過(guò)SPI接收
    的頭像 發(fā)表于 10-26 17:42 ?1503次閱讀