串口字节接收恢复
在串口综述中提到,串口数据总是以0开始,紧接着是8个比特的数据,最后以1结束。也就是说,起始比特的前一个比特恒定为1,即起始比特总是发生在前一个比特为1当前比特为0的情况。由此,定义一个比特计数器rSn,rSn≥9表征串口空闲或已完成上一次接收的状态。rSn < 9为正在逐个比特接收状态。
当rSn≥9且接收到的前一比特为1当前比特为0,rSn=0。若rSn < 9则每接收一个比特rSn加一计数。那么,当rSn=8时的采样时刻rx_smp刚好接收到停止比特,那么先前接收到的8个比特即为所需字节。另外,为了使系统上电时,UART处于空闲状态,特定义rSn初始态为rSn≥9的空闲态,在Quartus II中用power_up_level=high描述。这是为了去除系统上电后就发生的一次多余的串口接收事件。VHDL精确表述为:
attribute altera_attribute :string;
signal rSn :std_vector(3 downto 0);
attribute altera_attribute of rSn : signal is"power_up_level=high";
signal r_rg :std_vector(0 to 7);
signal b_rx :std_logic;
Process(clock) Begin
if rising_edge(clock)then
if rx_smp ='1' then
1. b_rx<= RXD_rg(RXD_rg'left);
2. ShiftRight(r_rg,b_rx);
3. RstIncDec(rSn,rSn>=9 and r_rg(r_rg'left) and not b_rx, rSn < 9);
4. LoadValue(q_rx,r_rg, b_rx and rSn=8);
5. rx_err<= not b_rx and rSn=8;
end if;
6. upd_rx <=rx_smp and b_rx and rSn=8;
end if;
End process;
行1的b_rx为当前接收到的比特值。
行2:右移b_rx使先接收到的放到低位。
行3:r_rg(r_rg'left)是相对于b_rx的前一比特值,rSn清零的三个条件是rSn≥9的空闲态,前一比特为1,当前比特为0。
行4:在rSn=8且当前比特b_rx为停止位,正确接收,把以为寄存器r_rg的值装载到输出q_rx中。
行5:在rSn=8时b_rx=0,没有正确接收到停止位,发生一次错误。
行6:upd_rx输出用来表征发生一次串口接收事件,用于更新串口接收。
q_rx和upd_rx交由上层处理,UART接收处理完毕。
串口发送
为简化上层设计,串口发送通常设置缓存功能。本帖为突出UART逻辑,只设置一个字节的缓存。发送对上层接口描述为:
d_tx :in std_vector(7 downto 0);
t_en :in std_logic;
TXD,t_busy : out std_logic;
端口d_tx时待发送的数据,t_en为一个时钟周期的高电平脉冲时启动发送,t_busy用来指示发送忙闲状态。t_busy在t_en后被置高,开始发送终止比特时置低。上层在闲忙指示为0的状态使能t_en保证正确发送,若在t_busy=0时使能t_en则有可能会被丢弃。TXD时发送到串口的信号。
发送使用的信号定义为:
signal cn_tFrq : std_vector(23downto 0);发送波特率计数器
signal t_data : std_vector(0to 7); 用作一个字节的缓存。
signal tx_rg :std_vector(0 to 8); 发送移位寄存器。
signal t_wait : std_logic;指示缓存等待发送。
signal tx_smp : std_logic; 依据波特率产生的发送比特使能脉冲。
signal tSn :std_vector(0 to 3);发送比特计数器。
Process(clock) Begin
if rising_edge(clock)then
1. RstIncDec(cn_tFrq, clk_en andcn_tFrq>=baud_tx, clk_en);
2. tx_smp <= clk_en and cn_tFrq=0;
3. LoadValue(t_data, d_tx, t_en);
4. SetReset(t_wait, t_en, t_smp andtSn>=9);
5. ShiftRight(tx_rg, '1', tx_smp);
6. LoadValue(tx_rg, t_data & '0', tx_smp and tx_wait and tSn>=9);
7. RstIncDec(tSn, tx_smp and tx_wait andtSn>=9, tx_smp and tSn<9);
8. t_busy <= t_en or t_wait ortSn<9;
end if;
End process;
9. TXD <=tx_rg(tx_rg'right);
行1和2:再解释就过于啰嗦了。
行3:t_en装载数据d_tx到缓存t_data。
行4:t_wait用来等待起始比特的开始时刻到来。
行5:右移tx_rg,被移入的是1,所以不用显式发送终止比特。
行6:装载起始比特和t_data到tx_rg。
行7:tSn>=9表征发送完毕或空闲。
行8:在发送终止比特之前t_busy始终被置高电平。
行9:万事大吉。
其他
为了避免系统在上电时,串口发送一个无用的字节,在定义tx_rg之后还要增加一句
attribute altera_attribute of tx_rg : signal is"power_up_level=high";另外在电路板上对TXD引脚应做弱上拉处理。由于串口是低速信号,RXD引脚会有跳弹现象,为使系统稳定应增加跳弹处理单元。
关于UART,您还有什么疑问吗?
|