硬汉嵌入式论坛

 找回密码
 立即注册
查看: 255|回复: 9
收起左侧

[技术讨论] 中继器设计

[复制链接]

2

主题

6

回帖

12

积分

新手上路

积分
12
发表于 6 天前 | 显示全部楼层 |阅读模式
大佬们,我现在正在实现一个中继器(一个250khz以下的3.3v脉冲输入,输出ttl 5v脉冲)现在有两个问题
我现在考虑的是stm32定时器输入捕获+硬件触发+单脉冲输出,但是我已经实现了一个输入捕获+定时器一直跑的测脉冲周期的程序,如下

#include "stm32f10x.h" // 包含uint32_t等类型定义
#include "cezhoufa.h"
extern volatile uint32_t latest_period_ticks ;
extern  volatile uint8_t new_period_data_ready;
static volatile uint32_t last_absolute_time = 0;   // 上次的16位捕获值
static volatile uint32_t overflow_count = 0; // 自上次捕获后的溢出次数
extern  volatile uint8_t cnt;
void cezhoufa_init(void)
{
                GPIO_InitTypeDef GPIO_InitStructure;
    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
    TIM_ICInitTypeDef TIM_ICInitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;

    // 步骤 1: 使能 TIM3 和 GPIOA 的时钟
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

    // 步骤 2: 配置 GPIO (PA6) 为输入模式
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; // 使用上拉输入,在信号悬空时保持高电平,更稳定
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    // 步骤 3: 配置定时器时间基准单元 (自由滚动模式)
    TIM_InternalClockConfig(TIM3); // 明确使用内部时钟
   
    TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInitStructure.TIM_Period = 65535; // ARR, 16位最大值
    TIM_TimeBaseInitStructure.TIM_Prescaler = 0;  // PSC, 不分频,得到72MHz计数频率
    TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
    TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);

    // 步骤 4: 配置输入捕获通道1
    TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;
    TIM_ICInitStructure.TIM_ICFilter = 0x0;
    TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; // 捕获上升沿
    TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; // 不对捕获事件分频
    TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; // 将TI1引脚直接连接到捕获通道
    TIM_ICInit(TIM3, &TIM_ICInitStructure);

    // 步骤 5: 使能两种中断源
    // 使能“更新中断”(用于捕获溢出)
    TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);
    // 使能“通道1捕获中断”(用于捕获边沿)
    TIM_ITConfig(TIM3, TIM_IT_CC1, ENABLE);

    // 步骤 6: 配置TIM3中断的NVIC
    // Update 和 CC1 事件共享同一个中断向量 TIM3_IRQn
    NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; // 优先级可以根据系统需要调整
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    // 步骤 7: 清除可能存在的旧的中断标志位
    TIM_ClearFlag(TIM3, TIM_FLAG_Update | TIM_FLAG_CC1);

    // 步骤 8: 启动TIM3计数器
    TIM_Cmd(TIM3, ENABLE);
}
void TIM3_IRQHandler(void)
{
       
                if(TIM_GetITStatus(TIM3, TIM_IT_CC1) != RESET)
                {
                         cnt++;
                                // 1. 计算当前捕获事件的“绝对时间戳”
        //    我们使用的 overflow_count 是上一个时间片累加的值,与当前的捕获值 ccr1 在时间上是同步的。
        uint32_t current_absolute_time = (overflow_count * 65536UL) + TIM_GetCapture1(TIM3);
        
        // 2. 计算本周期的总时长 (ticks)
        //    通过32位无符号减法,自动处理时间戳回绕问题
        latest_period_ticks = current_absolute_time - last_absolute_time;
        
        // 3. 更新“上一次”的时间戳,为下一个周期测量做准备
        last_absolute_time = current_absolute_time;
        
        // 4. 置位标志,通知主循环有新的、完整的周期数据可以处理
        new_period_data_ready = 1;
        
        // 5. 清除【输入捕获】的中断标志位
        TIM_ClearITPendingBit(TIM3, TIM_IT_CC1);
                               
                }
                if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET)
    {
        TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
        overflow_count++;
    }
}
uint8_t is_snapshot_ready_cezhouqifa(void)
{
        return new_period_data_ready;
}
uint32_t get_cezhoufa_latestest_tick(void)
{
        new_period_data_ready =0;
        return latest_period_ticks;
}

问题1,能否在不改变原本测周期的程序的情况下,用该定时器空闲的通道实现输入捕获硬件触发输出一个脉冲?也就是只使用这一个定时器
问题2,常见的中继器是怎么实现?使用单片机之外的电路和芯片如何实现呢,有哪些方案?
回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
119429
QQ
发表于 6 天前 | 显示全部楼层
仅用单脉冲模式就够用

[C] 纯文本查看 复制代码
- The external signal is connected to TIM4_CH2 pin (PB.07),
    and a rising edge on this input is used to trigger the Timer.
  - The One Pulse signal is output on TIM4_CH1 (PB.06).

  The delay value is fixed to:
   - Delay =  CCR1/TIM4 counter clock
           = 16383 / 20000000 = 0,00081915[sec]
           
  The pulse value is fixed to :
   - Pulse value = (TIM_Period - TIM_Pulse)/TIM4 counter clock  
                 = (65535 - 16383) / 20000000 =0,0024576 [sec]

  The one pulse waveform can be displayed using an oscilloscope and it looks
  like this.
  LED3 is ON when there are an error.
  
                                ___
                               |   |
  CH2 _________________________|   |__________________________________________

                                             ___________________________
                                            |                           |
  CH1 ______________________________________|                           |_____
                               <---Delay----><------Pulse--------------->
回复

使用道具 举报

2

主题

6

回帖

12

积分

新手上路

积分
12
 楼主| 发表于 6 天前 | 显示全部楼层
eric2013 发表于 2025-11-15 09:25
仅用单脉冲模式就够用

[mw_shl_code=c,true]- The external signal is connected to TIM4_CH2 pin (PB.0 ...

这样是没错,但是单脉冲模式需要输出通道的定时器停下来,但是我现在用这个定时器一直运行来测量输入信号周期,要是设置成单脉冲模式就出问题了吧
回复

使用道具 举报

2

主题

6

回帖

12

积分

新手上路

积分
12
 楼主| 发表于 6 天前 | 显示全部楼层
单脉冲模式(OPM)是前述众多模式的一个特例。这种模式允许计数器响应一个激励,并在一个
程序可控的延时之后,产生一个脉宽可程序控制的脉冲。
可以通过从模式控制器启动计数器,在输出比较模式或者PWM模式下产生波形。设置
TIMx_CR1寄存器中的OPM位将选择单脉冲模式,这样可以让计数器自动地在产生下一个更新
事件UEV时停止。
仅当比较值与计数器的初始值不同时,才能产生一个脉冲。启动之前(当定时器正在等待触发),
必须如下配置:向上计数方式:CNT < CCRx ≤ ARR (特别地,0 < CCRx),
向下计数方式:CNT > CCRx。 例如,你需要在从TI2输入脚上检测到一个上升沿开始,延迟tDELAY之后,在OC1上产生一个长
度为tPULSE的正脉冲。
假定TI2FP2作为触发1:
● 置TIMx_CCMR1寄存器中的CC2S=’01’,把TI2FP2映像到TI2。
● 置TIMx_CCER寄存器中的CC2P=’0’,使TI2FP2能够检测上升沿。
● 置TIMx_SMCR寄存器中的TS=’110’,TI2FP2作为从模式控制器的触发(TRGI)。
● 置TIMx_SMCR寄存器中的SMS=’110’(触发模式),TI2FP2被用来启动计数器。
OPM波形由写入比较寄存器的数值决定(要考虑时钟频率和计数器预分频器)
● tDELAY由写入TIMx_CCR1寄存器中的值定义。
● tPULSE由自动装载值和比较值之间的差值定义(TIMx_ARR - TIMx_CCR1)。
● 假定当发生比较匹配时要产生从’0’到’1’的波形,当计数器到达预装载值时要产生一个从’1’
到’0’的波形;首先要置TIMx_CCMR1寄存器的OC1M=’111’,进入PWM模式2;根据需要有
选择地使能预装载寄存器:置TIMx_CCMR1中的OC1PE=’1’和TIMx_CR1寄存器中的
ARPE;然后在TIMx_CCR1寄存器中填写比较值,在TIMx_ARR寄存器中填写自动装载
值,修改UG位来产生一个更新事件,然后等待在TI2上的一个外部触发事件。本例中,
CC1P=’0’。
在这个例子中,TIMx_CR1寄存器中的DIR和CMS位应该置低。
因为只需一个脉冲,所以必须设置TIMx_CR1寄存器中的OPM=’1’,在下一个更新事件(当计数
器从自动装载值翻转到0)时停止计数。
如上,单脉冲模式需要停止计数器,这样除非用另外一个计数器否则肯定会影响我原本的功能的
回复

使用道具 举报

2

主题

6

回帖

12

积分

新手上路

积分
12
 楼主| 发表于 6 天前 | 显示全部楼层
或者是否可以采用上升沿触发dma搬运一个高电平到gpio,然后下降沿触发dma搬运一个低电平到gpio,这样实现一个信号中继,不使用定时器输出信号呢
回复

使用道具 举报

7

主题

146

回帖

167

积分

初级会员

积分
167
发表于 6 天前 | 显示全部楼层
你这个中继器我不能理解。

我理解的中继器比如远程数据传输或者电平转换或者对波形进行整形的,

大部分应该是纯硬件实现的,比如电平转换芯片,继电器,三极管和MOS管这些,当然还有一些其他的隔离放大的硬件电路,

如果用MCU去实现输入逻辑电路和输出逻辑电路直通,那MCU还有什么意义?

你这个如果只是3.3V变5V的脉冲,最简单直接一个电平转换芯片/缓冲器芯片比如74HC245这类的就行了。
回复

使用道具 举报

4

主题

146

回帖

158

积分

初级会员

积分
158
发表于 6 天前 | 显示全部楼层
电平转换直接用TI的电平转换器,或者高速隔离器就行,辅组测量功能就行。
回复

使用道具 举报

4

主题

146

回帖

158

积分

初级会员

积分
158
发表于 6 天前 | 显示全部楼层
eric2013 发表于 2025-11-15 09:25
仅用单脉冲模式就够用

[mw_shl_code=c,true]- The external signal is connected to TIM4_CH2 pin (PB.0 ...

这是用AI搞出来的么?
回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
119429
QQ
发表于 6 天前 | 显示全部楼层
turnip 发表于 2025-11-15 12:30
这是用AI搞出来的么?

不是,是STM32Cube软件包里面的一个例子。
回复

使用道具 举报

2

主题

6

回帖

12

积分

新手上路

积分
12
 楼主| 发表于 6 天前 | 显示全部楼层
死不低头 发表于 2025-11-15 12:28
你这个中继器我不能理解。

我理解的中继器比如远程数据传输或者电平转换或者对波形进行整形的,

确实,感觉用mcu有点脱裤子放屁了,还是老实用硬件吧
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2025-11-21 22:25 , Processed in 0.045362 second(s), 25 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表