Частотомер STM32 + индикатор на MAX7219 (Arduino) — rcl-radio.ru

Здравствуйте, подскажите пожалуйста. Собрал частотомер, прошил stm-ку. прошилась хорошо. Но при запуске выдает цифры 72.002.150 при подачи сигнала с генератора ни чего не меняется. Кто нибудь может с этим помочь, пожалуйста.

Какую?

stm32f103c8t6

А на схеме не такая :roll_eyes:

А какая на схеме, там просто STM32 и все.

Вооот! Какая схема, какая STM?

----- пусто

В таком виде код не прошивался, поменял TIMER1_BASE на TIM1. Тогда все загрузилось.

Не хотите читать правила форума, прочитайте хотя бы сообщение в окне в котором пишете!

Прошу прощения поторопился не принял во внимание.

“Бывает”(с) Можно поправить сообщение.
По поводу

Вы не знаете какой должен быть контроллер, вы не знаете какая должна быть версия IDE, вы не знаете какой должен быть аддон и его версию. Может ну его, этот частотомер, а?

Хорошо, не буду настаивать, разберусь сам, спасибо.

@Alexandr61 , логика состоит из двух логических блоков: блок ~селектора каналов МВ~ измерения частоты и блок индикации. Соответственно что? Надо понять в каком затык. Дальше видно будет. Попробуй на индикатор числа выводить.

Может на Ардуино лучше сделать для начала? С ней всё-таки попроще разобраться новичку.

Очень похоже как из генератора от @dimax выыдернули частотомер и прикрутили другой дисплей, скомпилировался под аддон используемый в генераторе…

Оно и есть, только проект этот не мог работать, скопипастили не думая

Скетч использует 14940 байт (22%) памяти устройства. Всего доступно 65536 байт.
Глобальные переменные используют 2184 байт (10%) динамической памяти, оставляя 18296 байт для локальных переменных. Максимум: 20480 байт.

Задам направление мысли, вот так до 1.2 мегагерца будет считать

#include <LedControl.h>                          //https://github.com/wayoda/LedControl/archive/master.zip
LedControl lc = LedControl(PB1, PB10, PB11, 1);  // DIN(PB1), CLK(PB10), CS(PB11)

volatile int mon_flag;
unsigned long freq;
byte fq[8], pd, x;

void setup() {
  // Serial1.begin(9600);
  lc.shutdown(0, false);
  lc.setIntensity(0, 8);  // яркость 0-15
  lc.clearDisplay(0);

  Serial.end();            // дефолтовый сериал не нужен                                               // вход частотомера
  nvic_irq_disable_all();  //отключить все прерывания
  systick_disable();
  // отключить системный таймер
  RCC_BASE->APB1ENR |= (1 << 2) | (1 << 1) | (1 << 0);                         //включить тактирование tim-2,3,4
  RCC_BASE->APB2ENR |= (1 << 3) | (1 << 11) | (1 << 2) | (1 << 0) | (1 << 4);  ////включить тактирование port-a-b-c,tim1
  AFIO_BASE->MAPR = (1 << 8) | (1 << 6);                                       //tim 1 && tim 2 Partial remap
}

void loop() {
  freq_meter();
  // Serial1.println(freq);
  fq[7] = freq / 10000000 % 10;
  fq[6] = freq / 1000000 % 10;
  fq[5] = freq / 100000 % 10;
  fq[4] = freq / 10000 % 10;
  fq[3] = freq / 1000 % 10;
  fq[2] = freq / 100 % 10;
  fq[1] = freq / 10 % 10;
  fq[0] = freq % 10 % 10;

  if (freq >= 10000000) { x = 8; }
  if (freq < 10000000) {
    lc.setRow(0, 7, 0);
    x = 7;
  }
  if (freq < 1000000) {
    lc.setRow(0, 6, 0);
    x = 6;
  }
  if (freq < 100000) {
    lc.setRow(0, 5, 0);
    x = 5;
  }
  if (freq < 10000) {
    lc.setRow(0, 4, 0);
    x = 4;
  }
  if (freq < 1000) {
    lc.setRow(0, 3, 0);
    x = 3;
  }
  if (freq < 100) {
    lc.setRow(0, 2, 0);
    x = 2;
  }
  if (freq < 10) {
    lc.setRow(0, 1, 0);
    x = 1;
  }

  for (int i = 0; i < x; i++) {
    if (i == 3) {
      pd = true;
    } else if (i == 6) {
      pd = true;
    } else if (i == 9) {
      pd = true;
    } else {
      pd = false;
    }
    lc.setDigit(0, i, fq[i], pd);
  }
}

void freq_meter() {  // http://arduino.ru/forum/proekty/generator-s-reguliruemoei-chastotoi-na-arduino#comment-296530
  /////////////////////счётчик импульсов
  pinMode(PA15, INPUT_PULLDOWN);  // вход частотометра
  uint32_t imp_long, imp_hi;      //переменные измерения длины такта
  __asm volatile("cpsid i");
  /// Timer2 счёт младших 16 бит
  TIMER2_BASE->CR1 = 0;  //стоп таймер
  TIMER2_BASE->CCER = 0;
  TIMER2_BASE->PSC = 0;
  TIMER2_BASE->CNT = 0;
  TIMER2_BASE->CCR1 = 0;
  TIMER2_BASE->CCR2 = 0;
  TIMER2_BASE->CCR3 = 0;
  TIMER2_BASE->CCR4 = 0;
  TIMER2_BASE->PSC = 0;
  TIMER2_BASE->SR = 0;
  TIMER2_BASE->CCMR2 = 0;
  TIMER2_BASE->CR2 = 1 << 5;                           //MMS:010 управление подчинённым в режиме "Update"
  // TIMER2_BASE->SMCR = (1 << 14);  // ECE & TS:000  режим 2 внешнего тактирования & разрешение работы от таймера1
  TIMER2_BASE->SMCR = (1 << 2) | (1 << 1) | (1 << 0);  // SMS = 111 (внешний тактовый сигнал)
  TIMER2_BASE->SMCR |= (4 << 4);                       // TS = 100 (Timer1 как источник)

  TIMER2_BASE->ARR = 65535;      //считать до максимума
  TIMER2_BASE->EGR = 1;          //перечитать регистры.
  TIMER2_BASE->CR1 |= (1 << 0);  //start timer2
                                 /// Timer3 счёт старших 16 бит
  TIMER3_BASE->CR1 = 1 << 0;     //стоп таймер
  TIMER3_BASE->CCER = 0;
  TIMER3_BASE->PSC = 0;
  TIMER3_BASE->CNT = 0;
  TIMER3_BASE->CCR1 = 0;
  TIMER3_BASE->CCR2 = 0;
  TIMER3_BASE->CCR3 = 0;
  TIMER3_BASE->CCR4 = 0;
  TIMER3_BASE->PSC = 0;
  TIMER3_BASE->SR = 0;
  TIMER3_BASE->CR2 = 0;
  TIMER3_BASE->CCMR1 = 0;
  TIMER3_BASE->SMCR = (1 << 2) | (1 << 1) | (1 << 0) | (1 << 4);  //SMS:111 && TS:001  такт брать от 2-го таймера
  TIMER3_BASE->ARR = 65535;                                       //считать до
  TIMER3_BASE->EGR = 1;                                           //перечитать регистры.
  TIMER3_BASE->CR1 |= (1 << 0);                                   //start timer3
                                                                  /// настройка времени разрешения на таймере1 для таймера2
  TIMER1_BASE->CR1 = (1 << 3) | (1 << 2);                         //один импульс, без прерываний
  TIMER1_BASE->CNT = 0;
  TIMER1_BASE->CR2 = (1 << 4);           //MMS:001 сигнал разрешения работы другим таймерам
  TIMER1_BASE->CCER = 0;                 // отключить выходы таймера на физ ноги
  TIMER1_BASE->PSC = F_CPU / 36000 - 1;  // 1999; // 72000000/2000= 36000кГц тактовая таймера
  TIMER1_BASE->ARR = 36000;              //считать до 36000 (1секунда)
  TIMER1_BASE->EGR = 1;                  //перечитать регистры.
  TIMER1_BASE->CR1 |= (1 << 0);
  __asm volatile("cpsie i");
  while (TIMER1_BASE->CR1 & 1) {
    asm volatile("nop");
    if (mon_flag) { return; }
  }
  freq = (TIMER3_BASE->CNT << 16 | TIMER2_BASE->CNT)/2;
}

Это вот этот код вы считаете образцом для подражания?

я тебе давал ссылку, если ты не понял ни кода ни как надо оформлять, то программирование не твоё!
У тебя же хорошо получается путешествовать, я бы даже сказал ОТЛИЧНО!
Правда в путешествиях тебе нравится сама дорога, может есть смысл стать блогером?

А код, да это я его так кромсаю, не @dimax конечно, он в таймерах ГУРУ, но пытаюсь, по мере своих возможностей:

Код для частотомера до 90 мегагерц, если это вообще еще кому-то актуально:

// http://rcl-radio.ru/?p=76772&cpage=1#comment-6740
// на основе кода
// https://arduino.ru/forum/proekty/generator-s-reguliruemoei-chastotoi-na-arduino#comment-296530

#include <LedControl.h>

// Инициализация дисплея
LedControl lc = LedControl(PB1, PB10, PB11, 1);

// Переменные для частотомера
volatile int mode = 9; // Режим частотомера
volatile uint32_t freq = 0; // Измеренная частота
volatile boolean infreqpsc = true; // Включен делитель 8 для высоких частот
volatile float t_hi, t_low; // Длительности импульсов
volatile int duty = 0; // Скрыжность

// Прототипы функций
void freq_meter();
void mon_out();
void myint();

void setup() {
  // Инициализация дисплея
  lc.shutdown(0, false);
  lc.setIntensity(0, 8);
  lc.clearDisplay(0);
  
  // Настройка аппаратного обеспечения
  RCC_BASE->APB1ENR |= (1<<0)|(1<<1)|(1<<2); // TIM2, TIM3, TIM4
  RCC_BASE->APB2ENR |= (1<<3)|(1<<11)|(1<<2)|(1<<0)|(1<<4); // PORTA,B,C, TIM1
  AFIO_BASE->MAPR |= (1<<25)|(1<<8)|(1<<6); // JTAG Disabled
  
  // Настройка входа частотомера
  pinMode(PA15, INPUT_PULLDOWN); // Вход частотомера
  
  // Инициализация системного таймера
  systick_init(SYSTICK_RELOAD_VAL);
  
  // Вывод начальной информации
  mon_out();
}

void loop() {
  freq_meter(); // Измерение частоты
  mon_out();    // Вывод результатов
  delay(100);   // Задержка между измерениями
}


// Вывод результатов на дисплей
void mon_out() {
  static uint32_t last_freq = 0;
  
  // Обновляем дисплей только при изменении значений
  if (freq != last_freq) {
    // Очищаем дисплей
    lc.clearDisplay(0);
    
    // Выводим только цифры частоты
    if (freq >= 1000000) {
      // Мегагерцы: формат "XX.XXXXXX" (6 цифр после точки)
      uint32_t mhz_int = freq / 1000000; // целая часть
      uint32_t mhz_frac = freq % 1000000; // дробная часть (0-999999)
      
      // Выводим целую часть (максимум 2 цифры)
      if (mhz_int >= 10) {
        lc.setDigit(0, 7, mhz_int / 10, false);
        lc.setDigit(0, 6, mhz_int % 10, true); // точка после второй цифры
      } else {
        lc.setDigit(0, 7, 0, false);
        lc.setDigit(0, 6, mhz_int, true); // точка после первой цифры
      }
      
      // Выводим 6 цифр дробной части
      lc.setDigit(0, 5, (mhz_frac / 100000) % 10, false);
      lc.setDigit(0, 4, (mhz_frac / 10000) % 10, false);
      lc.setDigit(0, 3, (mhz_frac / 1000) % 10, false);
      lc.setDigit(0, 2, (mhz_frac / 100) % 10, false);
      lc.setDigit(0, 1, (mhz_frac / 10) % 10, false);
      lc.setDigit(0, 0, mhz_frac % 10, false);
      
    } else if (freq >= 1000) {
      // Килогерцы: формат "XXXXX.X" (1 цифра после точки)
      uint32_t khz_int = freq / 1000; // целая часть
      uint32_t khz_frac = (freq % 1000) / 100; // одна цифра после точки
      
      // Выводим целую часть (максимум 5 цифр)
      if (khz_int >= 10000) {
        lc.setDigit(0, 7, khz_int / 10000, false);
        lc.setDigit(0, 6, (khz_int / 1000) % 10, false);
        lc.setDigit(0, 5, (khz_int / 100) % 10, false);
        lc.setDigit(0, 4, (khz_int / 10) % 10, false);
        lc.setDigit(0, 3, khz_int % 10, true); // точка после 5 цифр
      } else if (khz_int >= 1000) {
        lc.setDigit(0, 7, 0, false);
        lc.setDigit(0, 6, khz_int / 1000, false);
        lc.setDigit(0, 5, (khz_int / 100) % 10, false);
        lc.setDigit(0, 4, (khz_int / 10) % 10, false);
        lc.setDigit(0, 3, khz_int % 10, true); // точка после 4 цифр
      } else if (khz_int >= 100) {
        lc.setDigit(0, 7, 0, false);
        lc.setDigit(0, 6, 0, false);
        lc.setDigit(0, 5, khz_int / 100, false);
        lc.setDigit(0, 4, (khz_int / 10) % 10, false);
        lc.setDigit(0, 3, khz_int % 10, true); // точка после 3 цифр
      } else if (khz_int >= 10) {
        lc.setDigit(0, 7, 0, false);
        lc.setDigit(0, 6, 0, false);
        lc.setDigit(0, 5, 0, false);
        lc.setDigit(0, 4, khz_int / 10, false);
        lc.setDigit(0, 3, khz_int % 10, true); // точка после 2 цифр
      } else {
        lc.setDigit(0, 7, 0, false);
        lc.setDigit(0, 6, 0, false);
        lc.setDigit(0, 5, 0, false);
        lc.setDigit(0, 4, 0, false);
        lc.setDigit(0, 3, khz_int, true); // точка после 1 цифры
      }
      
      // Выводим дробную часть
      lc.setDigit(0, 2, khz_frac, false);
      lc.setDigit(0, 1, ' ', false);
      lc.setDigit(0, 0, ' ', false);
      
    } else {
      // Герцы: формат "XXXXXX" (без точки)
      if (freq >= 100000) {
        lc.setDigit(0, 7, freq / 100000, false);
        lc.setDigit(0, 6, (freq / 10000) % 10, false);
        lc.setDigit(0, 5, (freq / 1000) % 10, false);
        lc.setDigit(0, 4, (freq / 100) % 10, false);
        lc.setDigit(0, 3, (freq / 10) % 10, false);
        lc.setDigit(0, 2, freq % 10, false);
        lc.setDigit(0, 1, ' ', false);
        lc.setDigit(0, 0, ' ', false);
      } else if (freq >= 10000) {
        lc.setDigit(0, 7, 0, false);
        lc.setDigit(0, 6, freq / 10000, false);
        lc.setDigit(0, 5, (freq / 1000) % 10, false);
        lc.setDigit(0, 4, (freq / 100) % 10, false);
        lc.setDigit(0, 3, (freq / 10) % 10, false);
        lc.setDigit(0, 2, freq % 10, false);
        lc.setDigit(0, 1, ' ', false);
        lc.setDigit(0, 0, ' ', false);
      } else if (freq >= 1000) {
        lc.setDigit(0, 7, 0, false);
        lc.setDigit(0, 6, 0, false);
        lc.setDigit(0, 5, freq / 1000, false);
        lc.setDigit(0, 4, (freq / 100) % 10, false);
        lc.setDigit(0, 3, (freq / 10) % 10, false);
        lc.setDigit(0, 2, freq % 10, false);
        lc.setDigit(0, 1, ' ', false);
        lc.setDigit(0, 0, ' ', false);
      } else if (freq >= 100) {
        lc.setDigit(0, 7, 0, false);
        lc.setDigit(0, 6, 0, false);
        lc.setDigit(0, 5, 0, false);
        lc.setDigit(0, 4, freq / 100, false);
        lc.setDigit(0, 3, (freq / 10) % 10, false);
        lc.setDigit(0, 2, freq % 10, false);
        lc.setDigit(0, 1, ' ', false);
        lc.setDigit(0, 0, ' ', false);
      } else if (freq >= 10) {
        lc.setDigit(0, 7, 0, false);
        lc.setDigit(0, 6, 0, false);
        lc.setDigit(0, 5, 0, false);
        lc.setDigit(0, 4, 0, false);
        lc.setDigit(0, 3, freq / 10, false);
        lc.setDigit(0, 2, freq % 10, false);
        lc.setDigit(0, 1, ' ', false);
        lc.setDigit(0, 0, ' ', false);
      } else {
        lc.setDigit(0, 7, 0, false);
        lc.setDigit(0, 6, 0, false);
        lc.setDigit(0, 5, 0, false);
        lc.setDigit(0, 4, 0, false);
        lc.setDigit(0, 3, 0, false);
        lc.setDigit(0, 2, freq, false);
        lc.setDigit(0, 1, ' ', false);
        lc.setDigit(0, 0, ' ', false);
      }
    }
    
    // Сохраняем текущие значения для сравнения
    last_freq = freq;
  }
}

// Измерение частоты
void freq_meter() {
  pinMode(PA15, INPUT_PULLDOWN); // Вход частотомера
  
  __asm volatile("cpsid i");
  
  // Сброс и настройка таймеров
  RCC_BASE->APB2RSTR |= 1<<11; // reset timer 1
  RCC_BASE->APB2RSTR &= ~(1<<11);
  RCC_BASE->APB1RSTR |= (1<<0)|(1<<1); // сброс таймера2,3
  RCC_BASE->APB1RSTR &= ~((1<<0)|(1<<1));
  
  // Timer2 - младшие 16 бит с делителем 8 для высоких частот
  TIMER2_BASE->CR2 = 1<<5; // MMS:010
  TIMER2_BASE->SMCR = (1<<14)|(5<<0)|(infreqpsc<<13)|(infreqpsc<<12);
  TIMER2_BASE->ARR = 65535;
  TIMER2_BASE->EGR = 1;
  TIMER2_BASE->CR1 |= (1<<0);
  
  // Timer3 - старшие 16 бит
  TIMER3_BASE->SMCR = (1<<2)|(1<<1)|(1<<0)|(1<<4);
  TIMER3_BASE->ARR = 65535;
  TIMER3_BASE->EGR = 1;
  TIMER3_BASE->CR1 |= (1<<0);
  
  // Timer1 - время измерения (1 секунда)
  TIMER1_BASE->CR1 = 0;
  TIMER1_BASE->CNT = 0;
  TIMER1_BASE->CCER = 0;
  
  uint16_t psc = 1;
  uint32_t tim_arr = F_CPU; // 1 секунда измерения
  while ((tim_arr/psc) > 65536) psc++;
  
  TIMER1_BASE->PSC = psc-1;
  TIMER1_BASE->ARR = (tim_arr/psc)-1;
  TIMER1_BASE->EGR = 1;
  TIMER1_BASE->CR1 = (1<<3)|(1<<2);
  TIMER1_BASE->CR2 = (1<<4);
  TIMER1_BASE->CR1 |= (1<<0);
  
  __asm volatile("cpsie i");
  
  // Ждем завершения измерения
  while (TIMER1_BASE->CR1 & 1) {
    asm volatile("nop");
  }
  
  // Читаем результат
  uint32_t count_low = TIMER2_BASE->CNT;
  uint32_t count_high = TIMER3_BASE->CNT;
  freq = (count_high << 16) | count_low;
  
  // Учитываем делитель
  if (infreqpsc) {
    freq *= 8;
  }
  
  // Для высоких частот (> 1 МГц) отключаем дополнительную обработку
  if (freq > 1000000) {
    // Для высоких частот просто используем прямое измерение
    t_hi = 0;
    t_low = 0;
    duty = 0;
  } else {
    // Для низких частот выполняем дополнительный анализ
    measure_low_freq_details();
  }
}

// Дополнительные измерения для низких частот
void measure_low_freq_details() {
  uint32_t divider = 1;
  while ((F_CPU/divider/((freq>0)?freq:1)) > 65000) divider++;
  
  __asm volatile("cpsid i");
  RCC_BASE->APB1RSTR |= 1<<0;
  RCC_BASE->APB1RSTR &= ~(1<<0);
  
  TIMER2_BASE->CR1 = 0;
  TIMER2_BASE->PSC = divider-1;
  TIMER2_BASE->SMCR = (1<<4)|(1<<6)|(1<<2);
  TIMER2_BASE->CCMR1 = (1<<0)|(1<<9);
  TIMER2_BASE->CCER = (1<<5)|(1<<0)|(1<<4);
  TIMER2_BASE->EGR = 1;
  
  TIMER1_BASE->CR1 = (1<<3);
  TIMER1_BASE->CNT = 0;
  TIMER1_BASE->CR2 = 0;
  TIMER1_BASE->CCER = 0;
  TIMER1_BASE->PSC = F_CPU/15625-1;
  TIMER1_BASE->ARR = 31250;
  TIMER1_BASE->EGR = 1;
  timer_attach_interrupt(TIMER1, TIMER_UPDATE_INTERRUPT, myint);
  TIMER1_BASE->CR1 |= (1<<0);
  
  __asm volatile("cpsie i");
  
  TIMER2_BASE->CR1 |= (1<<0);
  
  // Ждем завершения измерений или таймаута
  uint32_t timeout = millis() + 2000;
  while ((TIMER2_BASE->SR & 0x65F) != 0x65F && millis() < timeout) {
    asm volatile("nop");
  }
  
  TIMER2_BASE->CR1 = 0;
  timer_detach_interrupt(TIMER1, TIMER_UPDATE_INTERRUPT);
  
  if ((TIMER2_BASE->SR & 0x65F) == 0x65F) {
    uint32_t imp_long = (uint32_t)((TIMER2_BASE->CCR1)*divider);
    uint32_t imp_hi = (uint32_t)((TIMER2_BASE->CCR2)*divider);
    
    duty = (float)imp_hi / (imp_long / 100.0);
    if (duty > 100 || duty < 0) duty = 0;
    
    t_low = (double)(imp_long-imp_hi) / (F_CPU/1E6);
    t_hi = (double)imp_hi / (F_CPU/1E6);
  }
}

// Прерывание тайм-аута
void myint() {
  t_low = 0;
  t_hi = 0;
  duty = 0;
  timer_detach_interrupt(TIMER1, TIMER_UPDATE_INTERRUPT);
}

ЗЫ если @dimax увидит он мне конечно напихает, ну так за дело жеж

Вот я об этом и спросил - это строчки с 88 по 117 ты считаешь образцом? Или со 127 по 180-ю?
Советую изучить массивы и циклы, а не копировать заново блок для каждой разрядности числа. Даже средние программисты так не пишут, я уж не говорю про тех, чей код стоит изучать начинающим.

Ну и идея запустить таймер на секунду и ждать его окончания в блокирующем цикле - просто-таки верх искусства программирования :slight_smile: Снимаю шляпу

1 лайк