首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >在STM32F103 (Bluepill)上通过串行发送时钟信号时的抖动问题

在STM32F103 (Bluepill)上通过串行发送时钟信号时的抖动问题
EN

Stack Overflow用户
提问于 2021-10-03 12:39:10
回答 2查看 78关注 0票数 0

我想在stm32f1 bluepill板上用串口产生一个Midi时钟信号。该信号基本上只需要以128Hz128 hz的最大频率向31250 bps串行接口发送一个字节(0xF8)。我使用其中一个STM32f1s计时器创建了一个最小示例。问题是,我的midi设备上接收到的信号似乎不是很稳定。它在319到321 bpm之间跳跃,而对于128 60的信号,它应该显示320bpm的稳定时钟(转换公式: freq = bpm * 24 / 60)。你知道为什么会有这么多的抖动吗?是串行实现造成了抖动,还是硬件问题?或者是引入抖动的hal抽象层?

这是我在124赫兹测量的时钟信号之间的时间差:

Y轴是以秒为单位的时间差,x轴是读数。8000 us应该是信号之间的正确时间间隔。但每隔一段时间,似乎就会有一个时差只有500左右的信号发出。是什么导致了这种情况?也许是计数器溢出?

在将预分频器降低到12 the后,我得到了这个模式:

下面是生成时钟信号的代码

代码语言:javascript
运行
复制
#![no_std]
#![no_main]

use cortex_m_rt::entry;
use stm32f1xx_hal::{
  pac, 
  pac::{interrupt, Interrupt, TIM4},
  prelude::*,
  gpio,
  afio,
  serial::{Serial, Config},
  timer::{Event, Timer, CountDownTimer},
};

use core::mem::MaybeUninit;

use stm32f1xx_hal::pac::{USART2};

pub use embedded_hal::digital::v2::{OutputPin, InputPin};

pub type Usart2Serial = Serial<
    USART2, (gpio::gpioa::PA2<gpio::Alternate<gpio::PushPull>>, 
    gpio::gpioa::PA3<gpio::Input<gpio::Floating>>)>;

// When a panic occurs, stop the microcontroller
#[allow(unused_imports)]
use panic_halt;

static mut G_TIM2: MaybeUninit<CountDownTimer<TIM4>> = MaybeUninit::uninit();
static mut G_SERIAL: MaybeUninit<Usart2Serial> = MaybeUninit::uninit();

#[entry]
fn main() -> ! {

  let dp = pac::Peripherals::take().unwrap();

    let rcc = dp.RCC.constrain();
    let mut flash = dp.FLASH.constrain();
    let clocks = rcc.cfgr
      .use_hse(8.mhz()) // set clock frequency to external 8mhz oscillator
      .sysclk(72.mhz()) // set sysclock 
      .pclk1(36.mhz()) // clock for apb1 prescaler -> TIM1
      .pclk2(36.mhz()) // clock for apb2 prescaler -> TIM2,3,4
      .adcclk(12.mhz()) // clock for analog digital converters
      .freeze(&mut flash.acr);

    let mut apb1 = rcc.apb1;
    let mut apb2 = rcc.apb2;
    let mut gpioa = dp.GPIOA.split(&mut apb2);
    let mut afio = dp.AFIO.constrain(&mut apb2);

    // init serial
    let mut serial = init_usart2(dp.USART2, gpioa.pa2, gpioa.pa3, &mut gpioa.crl, &mut afio, &clocks, &mut apb1);

    unsafe { G_SERIAL.write(serial) };

    // init timer
    let bpm = 320;
    let frequency_in_hertz : u32 = (bpm as u32) * 24 / 60;
    let mut timer = Timer::tim4(dp.TIM4, &clocks, &mut apb1).start_count_down((frequency_in_hertz).hz());
    timer.listen(Event::Update);

    // write to global static var
    unsafe { G_TIM2.write(timer); }

    cortex_m::peripheral::NVIC::unpend(Interrupt::TIM4);
    unsafe {
      cortex_m::peripheral::NVIC::unmask(Interrupt::TIM4);
    }

  loop {
    // do nothing
  }
}

fn init_usart2(
  usart2: USART2, 
  pa2: gpio::gpioa::PA2<gpio::Input<gpio::Floating>>,
  pa3: gpio::gpioa::PA3<gpio::Input<gpio::Floating>>,
  crl: &mut gpio::gpioa::CRL,
  afio: &mut afio::Parts, 
  clocks: &stm32f1xx_hal::rcc::Clocks, 
  apb1: &mut stm32f1xx_hal::rcc::APB1
) -> Usart2Serial {
  let tx = pa2.into_alternate_push_pull(crl);
  let rx = pa3;

  return Serial::usart2(
    usart2,
    (tx, rx),
    &mut afio.mapr,
    Config::default().baudrate(31250.bps()),
    *clocks,
    apb1,
  );
}

#[interrupt]
fn TIM4() {
  let serial = unsafe { &mut *G_SERIAL.as_mut_ptr() };
  serial.write(0xF8).ok();

  let tim2 = unsafe { &mut *G_TIM2.as_mut_ptr() };
  tim2.clear_update_interrupt_flag();
}
EN

回答 2

Stack Overflow用户

发布于 2021-10-03 21:13:07

好了,我自己找到了解决方案。它似乎和计时器计数器有关。我猜它溢出并在错误的时间间隔触发计时器。

将以下行添加到定时器中断函数可复位计数器并消除抖动:

代码语言:javascript
运行
复制
#[interrupt]
fn TIM4() {
  ...
  tim2.reset();
}
票数 0
EN

Stack Overflow用户

发布于 2021-10-04 19:50:18

您需要确认中断的优先级,以确保没有其他优先级更高的中断会延迟UART输出。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69424911

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档