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

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

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

如何實(shí)現(xiàn)串口數(shù)據(jù)的接收呢?

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

00 簡(jiǎn)介

UART接收數(shù)據(jù)部分是接收另一個(gè)串口設(shè)備發(fā)送的數(shù)據(jù),緩存到接收FIFO中。FIFO快要寫滿時(shí),產(chǎn)生中斷通知CPU拿取數(shù)據(jù),實(shí)現(xiàn)串口數(shù)據(jù)的接收。

模塊涉及到兩個(gè)時(shí)鐘域,ARM時(shí)鐘和26MHz功能時(shí)鐘。其中 接收FIFO讀寫邏輯是ARM時(shí)鐘域,接收數(shù)據(jù)狀態(tài)機(jī)和同步邏輯等是功能時(shí)鐘域 。

01 模塊接口與描述

1.jpg

2.jpg

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

UART_RX模塊主要由三部分組成: 配置信息同步接收狀態(tài)機(jī)接收數(shù)據(jù)FIFO控制 。

配置信息是reg_if模塊由APB總線配置寄存器產(chǎn)生,功能時(shí)鐘域做兩級(jí)同步處理。

接收狀態(tài)機(jī)是根據(jù)串口協(xié)議劃分,分為IDLE、START、RX_DATA、CHECK_DATA、STOP和SEND六種狀態(tài)。

接收數(shù)據(jù)FIFO控制部分將接收完成的數(shù)據(jù)寫入到FIFO,在CPU讀取RX_FIFO寄存器時(shí)將FIFO數(shù)據(jù)讀出送到RX_FIFO寄存器。

  • 配置信息同步

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

  • 接收狀態(tài)產(chǎn)生

接收數(shù)據(jù)停止位狀態(tài)指示st_error和接收數(shù)據(jù)校驗(yàn)位狀態(tài)指示p_error是串口校驗(yàn)位和停止位檢測(cè)狀態(tài)指示。前者為1表示停止位錯(cuò)誤;后者為1表示校驗(yàn)位錯(cuò)誤。兩個(gè)狀態(tài)位都會(huì)傳到reg_if模塊,指示URAT當(dāng)前狀態(tài),供CPU查詢。當(dāng)CPU發(fā)現(xiàn)停止位或者校驗(yàn)位錯(cuò)誤時(shí),會(huì)決定當(dāng)前數(shù)據(jù)的處理方式(丟棄或者接受),清除狀態(tài)位(即寫1清0)。reg_if模塊發(fā)現(xiàn)該狀態(tài)位清除后,會(huì)回送一個(gè)ack到接收模塊,即st_error_ack和p_error_ack。接收模塊接收到ack后釋放狀態(tài)指示st_error和p_error,繼續(xù)接收數(shù)據(jù)。

這個(gè)過(guò)程就是狀態(tài)位的握手,本模塊設(shè)計(jì)方式是握手期間,即發(fā)現(xiàn)校驗(yàn)位或者停止位錯(cuò)誤后停止接收數(shù)據(jù),直到CPU清除狀態(tài)后才開(kāi)始正常接收。讀者可以根據(jù)自己的需要判斷錯(cuò)誤后是否繼續(xù)接收數(shù)據(jù)。

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

使用典型的三段式狀態(tài)機(jī)設(shè)計(jì),包含六種狀態(tài),IDLE、START、RX_DATA、CHECK_DATA、STOP和SEND。

圖片

uart接收狀態(tài)轉(zhuǎn)移圖

IDLE:狀態(tài)機(jī)從IDLE狀態(tài)開(kāi)始,檢測(cè)到uart_i的下降沿,進(jìn)入START狀態(tài)。

START:START狀態(tài)起始位是否為低(避免毛刺觸發(fā)狀態(tài)機(jī)),起始位正常即進(jìn)入RX_DATA開(kāi)始接收數(shù)據(jù)。RX_DATA:接收滿8bit后判斷是否使能校驗(yàn)位,如使能,進(jìn)入CHECK_DATA狀態(tài)進(jìn)行奇偶校驗(yàn)的判斷;如不使能,直接進(jìn)入停止?fàn)顟B(tài)STOP。

CHECK_DATA:CHECK_DATA狀態(tài)判斷奇偶校驗(yàn)是否正確,不正確則發(fā)出p_error信號(hào),在狀態(tài)寄存器指示校驗(yàn)錯(cuò)誤,待CPU處理返回p_error_ack后回到IDLE狀態(tài)。如果正確,判斷是否使能停止位檢查;使能停止位檢查則跳轉(zhuǎn)到STOP狀態(tài);不使能則跳轉(zhuǎn)到SEND狀態(tài)。

STOP:同樣的,在STOP狀態(tài)檢測(cè)停止位是否是高電平。如果是,表示停止位正確,跳轉(zhuǎn)到SEND狀態(tài);如果不是,則發(fā)出st_error信號(hào),在狀態(tài)寄存器指示停止位錯(cuò)誤,待CPU處理返回st_error_ack后回到IDLE狀態(tài)。

SEND:SEND狀態(tài)主要是產(chǎn)生rx_start信號(hào)表示8bits數(shù)據(jù)接收正確,可以將數(shù)據(jù)寫到接收FIFO。

前兩段狀態(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(neg_urxd_i) begin
            nextstate = START;
        end
        elsebegin
            nextstate = IDLE;
        end
    end
    START: begin
        if(start_right) begin// start bit is right,then reserve data
            nextstate = RX_DATA;
        end
        elsebegin
            nextstate = IDLE;
        end
    end
    RX_DATA: begin
        if(data_cnt < 4'd8) begin// reserve 8 datas
            nextstate = RX_DATA;
        end
        elsebegin
            if(rx_bpsclk) begin
                if(check_syn2) begin
                    nextstate = CHECK_DATA;
                end
                elsebegin
                    nextstate = STOP;
                end
            end
            elsebegin
                nextstate = RX_DATA;
            end
        end
    end
    CHECK_DATA: begin
        if(p_error_ack_delay2) begin
            nextstate = IDLE;
        end
        elsebegin
            if(rx_bpsclk) begin
		            // p_error:1:parity bit error,0:parity bit error
		            if(p_error) begin
		                nextstate = CHECK_DATA;
		            end
		            elsebegin
		                // st_check:1:check stop bit,0:don't check stop bit
		                if(st_check_syn2) begin
		                    nextstate = STOP;
		                end
		                elsebegin
		                    nextstate = SEND;
		                end
		            end
		        end
		        elsebegin
		            nextstate = CHECK_DATA;
		        end
        end
    end
    STOP: begin
        if(st_error_ack_delay2) begin
            nextstate = IDLE;
        end
        elsebegin
            if(rx_bpsclk) begin
		            // st_error:1:stop bit error,0:stop bit error
		            if(st_error) begin
		                nextstate = STOP;
		            end
		            elsebegin
		                nextstate = SEND;
		            end
		        end
		        elsebegin
		            nextstate = STOP;
		        end
        end
    end
    SEND: begin
        if(rx_ack_delay2) begin
            nextstate = IDLE;
        end
        elsebegin
            nextstate = SEND;
        end
    end
    default: begin
        nextstate = IDLE;
    end
    endcase
end

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

// output signal state
always@(posedge clk26m ornegedge rst26m_) begin
    if(!rst26m_) begin
        rx_bpsen <= 1'b0;
        data_rx  <= 8'd0;
        data_cnt <= 4'd0;
        p_error  <= 1'b0;
        st_error <= 1'b0;
        rx_start <= 1'b0;
        start_right <= 1'b0;
    end
    elsebegin
        case(nextstate)
        IDLE: begin
            rx_bpsen    <= 1'b0;
            data_cnt    <= 4'd0;
            st_error    <= 1'b0;
            p_error     <= 1'b0;
            rx_start    <= 1'b0;
            start_right <= 1'b0;
        end
        START: begin
            rx_bpsen    <= 1'b1;
            if(rx_bpsclk) begin
                if(urxd_i == 1'b0) begin
                    start_right <= 1'b1;
                end
                elsebegin
                    start_right <= 1'b0;
                end
            end
        end
        RX_DATA: begin
            if(rx_bpsclk) begin
                data_rx[data_cnt] <= urxd_i;
                data_cnt <= data_cnt + 1'b1;
            end
        end
        CHECK_DATA: begin
            if(rx_bpsclk) begin
                // odd check
                if(parity_syn2) begin
                    if(^data_rx == urxd_i) begin// odd check is wrong
                        p_error  <= 1'b1;
                        rx_bpsen <= 1'b0;
                    end
                end
                // even check
                elsebegin
                    if(^data_rx == !urxd_i) begin// even check is wrong
                        p_error  <= 1'b1;
                        rx_bpsen <= 1'b0;
                    end
                end
            end
        end
        STOP: begin
            if(rx_bpsclk) begin
                if(urxd_i == 1'b0) begin// stop bit is wrong
                    st_error <= 1'b1;
                    rx_bpsen <= 1'b0;
                end
            end
        end
        SEND: begin
            rx_start <= 1'b1;
        end
        endcase
    end
end
  • 接收數(shù)據(jù)FIFO控制

接收狀態(tài)機(jī)的SEND狀態(tài)表示1Byte數(shù)據(jù)接收完成,此狀態(tài)會(huì)產(chǎn)生一個(gè)rx_start信號(hào)。

FIFO寫控制部分通過(guò)監(jiān)控此信號(hào)產(chǎn)生寫使能rx_fifo_winc(1個(gè)ARM時(shí)鐘周期)和接收響應(yīng)rx_ack,SEND狀態(tài)發(fā)現(xiàn)rx_ack后釋放rx_start,回到IDLE狀態(tài)。由于FIFO寫控制是在ARM時(shí)鐘域進(jìn)行,握手的時(shí)間很短,不會(huì)對(duì)接收下一Byte數(shù)據(jù)產(chǎn)生影響。

// this state machine to send data to RX FIFO
always@(posedge clk ornegedge rst_) begin
    if(!rst_) begin
        rx_ack       <= 1'b0;
        rx_fifo_winc <= 1'b0;
        wdata_state  <= 2'b0;
    end
    elsebegin
        case(wdata_state)
        2'b00: begin
            if(!rx_fifo_wfull && rx_start_delay2) begin
                rx_ack       <= 1'b1;
                rx_fifo_winc <= 1'b1;
                wdata_state  <= 2'b01;
            end
        end
        2'b01: begin
            rx_fifo_winc    <= 1'b0;
            if(!rx_start_delay2) begin
                rx_ack      <= 1'b0;
                wdata_state <= 2'b10;
            end
        end
        2'b10: begin
            wdata_state <= 2'b0;
        end
        endcase
    end
end

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

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

    關(guān)注

    2

    文章

    491

    瀏覽量

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

    關(guān)注

    0

    文章

    103

    瀏覽量

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

    關(guān)注

    0

    文章

    124

    瀏覽量

    15256
  • 時(shí)鐘域
    +關(guān)注

    關(guān)注

    0

    文章

    51

    瀏覽量

    9524
  • 狀態(tài)寄存器
    +關(guān)注

    關(guān)注

    0

    文章

    38

    瀏覽量

    7062
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    stm32串口是如何實(shí)現(xiàn)接收不定長(zhǎng)度數(shù)據(jù)

    1.不定長(zhǎng)度數(shù)據(jù)為什么會(huì)存在串口接收不定長(zhǎng)度數(shù)據(jù)?首先,在通信雙方進(jìn)行數(shù)據(jù)傳輸?shù)臅r(shí)候,由于不同
    發(fā)表于 08-11 08:18

    如何去實(shí)現(xiàn)STM32串口發(fā)送數(shù)據(jù)接收數(shù)據(jù)

    串口發(fā)送數(shù)據(jù)最直接的方式是什么?如何去實(shí)現(xiàn)STM32串口發(fā)送數(shù)據(jù)接收
    發(fā)表于 12-07 06:03

    如何去實(shí)現(xiàn)STM32的USART串口接收數(shù)據(jù)處理

    如何去實(shí)現(xiàn)STM32的USART串口接收數(shù)據(jù)處理?其代碼程序該如何去實(shí)現(xiàn)
    發(fā)表于 12-09 07:30

    如何實(shí)現(xiàn)串口USART2的發(fā)送和接收功能

    如何實(shí)現(xiàn)串口USART2的發(fā)送和接收功能?如何實(shí)現(xiàn)USART2中斷接收任意長(zhǎng)度和任意格式的
    發(fā)表于 01-20 06:16

    net2.0實(shí)現(xiàn)串口GPS數(shù)據(jù)接收設(shè)計(jì)應(yīng)用

    net2.0實(shí)現(xiàn)串口GPS數(shù)據(jù)接收設(shè)計(jì)應(yīng)用
    發(fā)表于 02-08 16:42 ?25次下載

    python串口接收數(shù)據(jù)

    本文主要介紹了python串口接收數(shù)據(jù)。其中涉及了Python使用線程來(lái)接收串口數(shù)據(jù),以及pyt
    發(fā)表于 01-15 09:52 ?4.6w次閱讀
    python<b class='flag-5'>串口</b><b class='flag-5'>接收</b><b class='flag-5'>數(shù)據(jù)</b>

    labview串口接收數(shù)據(jù)_labview串口被動(dòng)接收數(shù)據(jù)

    字節(jié)的數(shù)據(jù)。最后,用一個(gè)狀態(tài)機(jī)來(lái)實(shí)現(xiàn)相鄰兩個(gè)字符串的判斷。如果串口在相鄰兩個(gè)字符串之間接收時(shí)間大于50ms,則判斷為兩個(gè)獨(dú)立的字符串;如果小于50ms,則自動(dòng)拼接前后兩個(gè)字符串。
    發(fā)表于 01-15 15:49 ?6.6w次閱讀
    labview<b class='flag-5'>串口</b><b class='flag-5'>接收</b><b class='flag-5'>數(shù)據(jù)</b>_labview<b class='flag-5'>串口</b>被動(dòng)<b class='flag-5'>接收</b><b class='flag-5'>數(shù)據(jù)</b>

    MCU-串口接收實(shí)現(xiàn)

    MCU-串口接收實(shí)現(xiàn)例程倉(cāng)庫(kù):https://gitee.com/ll0_0ll/MCU-UART1.串口接收中斷+空閑中斷空閑中斷是接受
    發(fā)表于 10-25 10:36 ?12次下載
    MCU-<b class='flag-5'>串口</b><b class='flag-5'>接收</b><b class='flag-5'>實(shí)現(xiàn)</b>

    stm32 串口接收不定長(zhǎng)度數(shù)據(jù)及黏包處理 + 串口DMA接收

    1.不定長(zhǎng)度數(shù)據(jù) 為什么會(huì)存在串口接收不定長(zhǎng)度數(shù)據(jù)?首先,在通信雙方進(jìn)行數(shù)據(jù)傳輸?shù)臅r(shí)候,由于不
    發(fā)表于 12-23 19:09 ?27次下載
    stm32 <b class='flag-5'>串口</b><b class='flag-5'>接收</b>不定長(zhǎng)度<b class='flag-5'>數(shù)據(jù)</b>及黏包處理 + <b class='flag-5'>串口</b>DMA<b class='flag-5'>接收</b>

    STM32—無(wú)需中斷來(lái)實(shí)現(xiàn)使用DMA接收串口數(shù)據(jù)

    如何來(lái)優(yōu)化?比如四軸飛行器,當(dāng)在不停地獲取姿態(tài)控制方向時(shí),又要去接收串口數(shù)據(jù).答:使用DMA,無(wú)需CPU中斷便能實(shí)現(xiàn)接收
    發(fā)表于 12-24 19:01 ?8次下載
    STM32—無(wú)需中斷來(lái)<b class='flag-5'>實(shí)現(xiàn)</b>使用DMA<b class='flag-5'>接收</b><b class='flag-5'>串口</b><b class='flag-5'>數(shù)據(jù)</b>

    STM32之串口DMA接收不定長(zhǎng)數(shù)據(jù)

    目錄STM32之串口DMA接收不定長(zhǎng)數(shù)據(jù)引言DMA簡(jiǎn)介什么是DMA在STM32的DMA資源DMA接收數(shù)據(jù)判斷
    發(fā)表于 12-24 19:03 ?30次下載
    STM32之<b class='flag-5'>串口</b>DMA<b class='flag-5'>接收</b>不定長(zhǎng)<b class='flag-5'>數(shù)據(jù)</b>

    stm32 發(fā)送完數(shù)據(jù)串口繼續(xù)發(fā)送_STM32之串口DMA接收不定長(zhǎng)數(shù)據(jù)

    引言在使用stm32或者其他單片機(jī)的時(shí)候,會(huì)經(jīng)常使用到串口通訊,那么如何有效地接收數(shù)據(jù)?假如這段數(shù)據(jù)是不定長(zhǎng)的有如何高效
    發(fā)表于 12-24 19:17 ?8次下載
    stm32 發(fā)送完<b class='flag-5'>數(shù)據(jù)</b>后 <b class='flag-5'>串口</b>繼續(xù)發(fā)送_STM32之<b class='flag-5'>串口</b>DMA<b class='flag-5'>接收</b>不定長(zhǎng)<b class='flag-5'>數(shù)據(jù)</b>

    如何有效地使用串口通訊接收數(shù)據(jù)

    在使用stm32或者其他單片機(jī)的時(shí)候,會(huì)經(jīng)常使用到串口通訊,那么如何有效地接收數(shù)據(jù)?假如這段數(shù)據(jù)是不定長(zhǎng)的有如何高效
    的頭像 發(fā)表于 02-14 09:50 ?2605次閱讀
    如何有效地使用<b class='flag-5'>串口</b>通訊<b class='flag-5'>接收</b><b class='flag-5'>數(shù)據(jù)</b>

    串口接收數(shù)據(jù)的兩種方式是什么

    上方是發(fā)送數(shù)據(jù)的例子,那么串口接收又該如何配置,又要在串口發(fā)送的例子上做哪些更改? 這里我們可以通過(guò)查詢或者中斷的方式來(lái)進(jìn)行
    的頭像 發(fā)表于 11-10 16:20 ?2187次閱讀
    <b class='flag-5'>串口</b><b class='flag-5'>接收</b><b class='flag-5'>數(shù)據(jù)</b>的兩種方式是什么

    基于RA2L1實(shí)現(xiàn)串口DTC數(shù)據(jù)接收

    基于RA2L1實(shí)現(xiàn)串口DTC數(shù)據(jù)接收
    的頭像 發(fā)表于 10-10 09:34 ?458次閱讀
    基于RA2L1<b class='flag-5'>實(shí)現(xiàn)</b><b class='flag-5'>串口</b>DTC<b class='flag-5'>數(shù)據(jù)</b><b class='flag-5'>接收</b>