0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

如何实现串口数据的接收呢?

冬至子 来源:两猿社 作者:IC猿 2023-06-05 15:24 次阅读

00 简介

UART接收数据部分是接收另一个串口设备发送的数据,缓存到接收FIFO中。FIFO快要写满时,产生中断通知CPU拿取数据,实现串口数据的接收。

模块涉及到两个时钟域,ARM时钟和26MHz功能时钟。其中 接收FIFO读写逻辑是ARM时钟域,接收数据状态机和同步逻辑等是功能时钟域

01 模块接口与描述

1.jpg

2.jpg

02 实现

UART_RX模块主要由三部分组成: 配置信息同步接收状态机接收数据FIFO控制

配置信息是reg_if模块由APB总线配置寄存器产生,功能时钟域做两级同步处理。

接收状态机是根据串口协议划分,分为IDLE、START、RX_DATA、CHECK_DATA、STOP和SEND六种状态。

接收数据FIFO控制部分将接收完成的数据写入到FIFO,在CPU读取RX_FIFO寄存器时将FIFO数据读出送到RX_FIFO寄存器。

  • 配置信息同步

由于配置信息是由ARM时钟产生,到接收模块的功能时钟域需要做同步处理。配置信息是电平信号,通常不会像数据一样变化快,所以只需要两级同步。

  • 接收状态产生

接收数据停止位状态指示st_error和接收数据校验位状态指示p_error是串口校验位和停止位检测状态指示。前者为1表示停止位错误;后者为1表示校验位错误。两个状态位都会传到reg_if模块,指示URAT当前状态,供CPU查询。当CPU发现停止位或者校验位错误时,会决定当前数据的处理方式(丢弃或者接受),清除状态位(即写1清0)。reg_if模块发现该状态位清除后,会回送一个ack到接收模块,即st_error_ack和p_error_ack。接收模块接收到ack后释放状态指示st_error和p_error,继续接收数据。

这个过程就是状态位的握手,本模块设计方式是握手期间,即发现校验位或者停止位错误后停止接收数据,直到CPU清除状态后才开始正常接收。读者可以根据自己的需要判断错误后是否继续接收数据。

  • 接收状态机

使用典型的三段式状态机设计,包含六种状态,IDLE、START、RX_DATA、CHECK_DATA、STOP和SEND。

图片

uart接收状态转移图

IDLE:状态机从IDLE状态开始,检测到uart_i的下降沿,进入START状态。

START:START状态起始位是否为低(避免毛刺触发状态机),起始位正常即进入RX_DATA开始接收数据。RX_DATA:接收满8bit后判断是否使能校验位,如使能,进入CHECK_DATA状态进行奇偶校验的判断;如不使能,直接进入停止状态STOP。

CHECK_DATA:CHECK_DATA状态判断奇偶校验是否正确,不正确则发出p_error信号,在状态寄存器指示校验错误,待CPU处理返回p_error_ack后回到IDLE状态。如果正确,判断是否使能停止位检查;使能停止位检查则跳转到STOP状态;不使能则跳转到SEND状态。

STOP:同样的,在STOP状态检测停止位是否是高电平。如果是,表示停止位正确,跳转到SEND状态;如果不是,则发出st_error信号,在状态寄存器指示停止位错误,待CPU处理返回st_error_ack后回到IDLE状态。

SEND:SEND状态主要是产生rx_start信号表示8bits数据接收正确,可以将数据写到接收FIFO。

前两段状态机,状态跳转:

// 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

第三段状态机,信号赋值:

// 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
  • 接收数据FIFO控制

接收状态机的SEND状态表示1Byte数据接收完成,此状态会产生一个rx_start信号。

FIFO写控制部分通过监控此信号产生写使能rx_fifo_winc(1个ARM时钟周期)和接收响应rx_ack,SEND状态发现rx_ack后释放rx_start,回到IDLE状态。由于FIFO写控制是在ARM时钟域进行,握手的时间很短,不会对接收下一Byte数据产生影响。

// 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寄存器时,产生读使能信号,FIFO将数据放到寄存器中。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 状态机
    +关注

    关注

    2

    文章

    492

    浏览量

    27529
  • FIFO存储
    +关注

    关注

    0

    文章

    103

    浏览量

    5968
  • UART接口
    +关注

    关注

    0

    文章

    124

    浏览量

    15288
  • 时钟域
    +关注

    关注

    0

    文章

    52

    浏览量

    9535
  • 状态寄存器
    +关注

    关注

    0

    文章

    39

    浏览量

    7083
收藏 人收藏

    评论

    相关推荐

    stm32串口是如何实现接收不定长度数据

    1.不定长度数据为什么会存在串口接收不定长度数据?首先,在通信双方进行数据传输的时候,由于不同
    发表于 08-11 08:18

    如何去实现STM32串口发送数据接收数据

    串口发送数据最直接的方式是什么?如何去实现STM32串口发送数据接收
    发表于 12-07 06:03

    如何去实现STM32的USART串口接收数据处理

    如何去实现STM32的USART串口接收数据处理?其代码程序该如何去实现
    发表于 12-09 07:30

    如何实现串口USART2的发送和接收功能

    如何实现串口USART2的发送和接收功能?如何实现USART2中断接收任意长度和任意格式的
    发表于 01-20 06:16

    net2.0实现串口GPS数据接收设计应用

    net2.0实现串口GPS数据接收设计应用
    发表于 02-08 16:42 25次下载

    python串口接收数据

    本文主要介绍了python串口接收数据。其中涉及了Python使用线程来接收串口数据,以及pyt
    发表于 01-15 09:52 4.6w次阅读
    python<b class='flag-5'>串口</b><b class='flag-5'>接收</b><b class='flag-5'>数据</b>

    labview串口接收数据_labview串口被动接收数据

    字节的数据。最后,用一个状态机来实现相邻两个字符串的判断。如果串口在相邻两个字符串之间接收时间大于50ms,则判断为两个独立的字符串;如果小于50ms,则自动拼接前后两个字符串。
    发表于 01-15 15:49 6.7w次阅读
    labview<b class='flag-5'>串口</b><b class='flag-5'>接收</b><b class='flag-5'>数据</b>_labview<b class='flag-5'>串口</b>被动<b class='flag-5'>接收</b><b class='flag-5'>数据</b>

    MCU-串口接收实现

    MCU-串口接收实现例程仓库:https://gitee.com/ll0_0ll/MCU-UART1.串口接收中断+空闲中断空闲中断是接受
    发表于 10-25 10:36 12次下载
    MCU-<b class='flag-5'>串口</b><b class='flag-5'>接收</b><b class='flag-5'>实现</b>

    stm32 串口接收不定长度数据及黏包处理 + 串口DMA接收

    1.不定长度数据 为什么会存在串口接收不定长度数据?首先,在通信双方进行数据传输的时候,由于不
    发表于 12-23 19:09 27次下载
    stm32 <b class='flag-5'>串口</b><b class='flag-5'>接收</b>不定长度<b class='flag-5'>数据</b>及黏包处理 + <b class='flag-5'>串口</b>DMA<b class='flag-5'>接收</b>

    STM32—无需中断来实现使用DMA接收串口数据

    如何来优化?比如四轴飞行器,当在不停地获取姿态控制方向时,又要去接收串口数据.答:使用DMA,无需CPU中断便能实现接收
    发表于 12-24 19:01 8次下载
    STM32—无需中断来<b class='flag-5'>实现</b>使用DMA<b class='flag-5'>接收</b><b class='flag-5'>串口</b><b class='flag-5'>数据</b>

    STM32之串口DMA接收不定长数据

    目录STM32之串口DMA接收不定长数据引言DMA简介什么是DMA在STM32的DMA资源DMA接收数据判断
    发表于 12-24 19:03 30次下载
    STM32之<b class='flag-5'>串口</b>DMA<b class='flag-5'>接收</b>不定长<b class='flag-5'>数据</b>

    stm32 发送完数据串口继续发送_STM32之串口DMA接收不定长数据

    引言在使用stm32或者其他单片机的时候,会经常使用到串口通讯,那么如何有效地接收数据?假如这段数据是不定长的有如何高效
    发表于 12-24 19:17 8次下载
    stm32 发送完<b class='flag-5'>数据</b>后 <b class='flag-5'>串口</b>继续发送_STM32之<b class='flag-5'>串口</b>DMA<b class='flag-5'>接收</b>不定长<b class='flag-5'>数据</b>

    如何有效地使用串口通讯接收数据

    在使用stm32或者其他单片机的时候,会经常使用到串口通讯,那么如何有效地接收数据?假如这段数据是不定长的有如何高效
    的头像 发表于 02-14 09:50 2731次阅读
    如何有效地使用<b class='flag-5'>串口</b>通讯<b class='flag-5'>接收</b><b class='flag-5'>数据</b>

    串口接收数据的两种方式是什么

    上方是发送数据的例子,那么串口接收又该如何配置,又要在串口发送的例子上做哪些更改? 这里我们可以通过查询或者中断的方式来进行
    的头像 发表于 11-10 16:20 2314次阅读
    <b class='flag-5'>串口</b><b class='flag-5'>接收</b><b class='flag-5'>数据</b>的两种方式是什么

    基于RA2L1实现串口DTC数据接收

    基于RA2L1实现串口DTC数据接收
    的头像 发表于 10-10 09:34 541次阅读
    基于RA2L1<b class='flag-5'>实现</b><b class='flag-5'>串口</b>DTC<b class='flag-5'>数据</b><b class='flag-5'>接收</b>