STM32 F103C8T6

Andrey_Ak
Andrey_Ak аватар
Offline
Зарегистрирован: 13.05.2020

Подскажите пожалуйста, никак не могу разобраться..  Вот код установки частоты:

#include <Wire.h> 

  int del=1;
  int f_g=2;
  int imp=1;

void setup() {      
              pinMode(LED_BUILTIN, OUTPUT); 	  // Включение светодиода
              pinMode(PB0, PWM); 	          // Выход генератора

              Timer3.pause();			  // Останавливаем таймер перед настройкой
              Timer3.setPrescaleFactor(del);      // Устанавливаем делитель  
              Timer3.setOverflow(f_g-1); 	  // Устанавливаем переполнение, период
              Timer3.setCompare(TIMER_CH3, imp);  // Устанавливаем длину импульса 
              Timer3.refresh();			  // Обнулить таймер 
              Timer3.resume();			  // Запускаем таймер
              }


void loop() {

            } 

По идее, он должен работать на контроллере с частотой 128MHz, и должен выдавать частоту 64MHz но контроллер при выборе данной частоты просто зависает после прошивки и перезагрузки.

Запускаю код на частоте 72MHz, работает, но выход частоты составляет всего 3735 kHz.

Информацию по коду изучал в этой статье:  https://istarik.ru/blog/arduino/105.html

nik182
Offline
Зарегистрирован: 04.05.2015

Странное число. 72 / 2 / 2 = 18 МГц должно быть. Если бы del = 0 , то 72 / 2 = 36 МГц. 3.735МГц * 4 = 14.94 МГц тактирование таймера. Не понятная величина. Я б вывел такт ядра/2 на  РА8 RRC-MCO что бы знать такт ядра, должно быть 36МГЦ, но как это сделать в командах этого аддона не знаю, не разбирался, а так выставть ногу на выход и выставить бит SET_BIT(RCC->APB2ENR, RCC_APB2ENR_IOPAEN);     

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

Andrey_Ak, в скетче ошибок нет. Наиболее вероятно, что мк поддельный. На помойку его..

Andrey_Ak
Andrey_Ak аватар
Offline
Зарегистрирован: 13.05.2020

dimax пишет:

Andrey_Ak, в скетче ошибок нет. Наиболее вероятно, что мк поддельный. На помойку его..

Спасибо, будем ждать когда другие, вроде оригинальные приедут..
Возможно из-за этого и не работает на 128МГц

Или может быть проблема в библиотеке Wire.h - может для STM32 нужна другая версия?

А Вы не могли-бы, дать такой-же простой код, только для генерации частоты и скважности,
но по вашему варианту кода отсюда:
http://arduino.ru/forum/proekty/generator-s-reguliruemoei-chastotoi-na-arduino#comment-395540
 

nik182 пишет:

 Я б вывел такт ядра/2 на  РА8 RRC-MCO что бы знать такт ядра, должно быть 36МГЦ, но как это сделать в командах этого аддона не знаю, не разбирался, а так выставть ногу на выход и выставить бит SET_BIT(RCC->APB2ENR, RCC_APB2ENR_IOPAEN);     

- Может сможете подсказать какой-то другой код, чтоб только проверить на
какой частоте работает контроллер?

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

Andrey_Ak , там есть простой код, #27

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

Andrey_Ak пишет:

- Может сможете подсказать какой-то другой код, чтоб только проверить на
какой частоте работает контроллер?

 

pinMode(PA8, PWM);
    RCC_BASE->CFGR &= ~(0xf << 24);
    RCC_BASE->CFGR |= 1 << 26 ; //вывод системной частоты на А8

PS: Свыше 50МГц амплитуда сильно падает...

muravei
Offline
Зарегистрирован: 01.06.2020

"Такой личный неприязнь испытывал к " этой Ардуине , но купился на простоту. Хотя простота, иногда , хуже...

Хотел сделать загрузку по юсб, но долгие "танцы с бубном" ни к чему не привели. :( Драйверы на Вин10 не ставятся.

Подумал, а нафига они? Нашелся https://github.com/Serasidis/STM32_HID_Bootloader .

Залил. Залился. Заливает. Но проблема, блинк не блинкает. :( 

Как я думаю , загрузка не по тому адресу: нужно 0x8001000, а грузит в 0x8000800.

Может кто-нибудь уже ходил по этим граблям, и что-то посоветует.

 

b707
Offline
Зарегистрирован: 26.05.2017

muravei пишет:

Хотел сделать загрузку по юсб, но долгие "танцы с бубном" ни к чему не привели. :( Драйверы на Вин10 не ставятся.

 

какие драйверы то? сначала загрузчик в плату надо залить через UART -переходник.

Либо, самое простое - прошивать через программатор, Ст-линк например

muravei
Offline
Зарегистрирован: 01.06.2020

b707 пишет:

какие драйверы то? сначала загрузчик в плату надо залить через UART -переходник.

А как вы думаете я заливал хид-загрузчик?

И я не спрашиваю, про самое простое, я спрашиваю про юсб.

b707
Offline
Зарегистрирован: 26.05.2017

muravei пишет:

И я не спрашиваю, про самое простое, я спрашиваю про юсб.

так и я вам говорю про ЮСБ-загрузчик...

ну как знаете.

muravei
Offline
Зарегистрирован: 01.06.2020
b707 пишет:
 
так и я вам говорю про ЮСБ-загрузчик...
 
 

b707 пишет:

Либо, самое простое - прошивать через программатор, Ст-линк например

И где тут про юсб?

 

b707
Offline
Зарегистрирован: 26.05.2017

muravei пишет:

Как я думаю , загрузка не по тому адресу: нужно 0x8001000, а грузит в 0x8000800.

это не имеет значения

muravei
Offline
Зарегистрирован: 01.06.2020

b707 пишет:

muravei пишет:

Как я думаю , загрузка не по тому адресу: нужно 0x8001000, а грузит в 0x8000800.

это не имеет значения

С чего вы так решили?

Думаю, он запускает с 1000,  а стартовый 800.

b707
Offline
Зарегистрирован: 26.05.2017

muravei пишет:

С чего вы так решили?

Думаю, он запускает с 1000,  а стартовый 800.

"Он" - это кто? У вас и "загружает" и "запускает" одна и та же программа - тот HID-бутлоадер. что вы залили в плату. Так что он по какому адресу прошивку положил, по тому и запускает.

А что этот адрес меньше, чем у другого бута - так это совершенно нормально, размеры бутов разные вот и все

muravei
Offline
Зарегистрирован: 01.06.2020

b707 пишет:

 Так что он по какому адресу прошивку положил, по тому и запускает.

Это вы так считаете.

А по ссылке , автор утверждает, что " user FLASH begins and the interrupt vector resides (0x8001000)."

b707
Offline
Зарегистрирован: 26.05.2017

muravei пишет:

Это вы так считаете.

А по ссылке , автор утверждает, что " user FLASH begins and the interrupt vector resides (0x8001000)."

ну то есть автор намеренно грузит код по неправильному адресу? :)   зачем вы такой бутлоадер взяли?

Уважаемый, а может поменьше пафоса? Если вы так уверены в своих знаниях, странно что вы пришли на форум задавать элементарные вопросы.

muravei
Offline
Зарегистрирован: 01.06.2020

b707 пишет:

ну то есть автор намеренно грузит код по неправильному адресу? :)   зачем вы такой бутлоадер взяли?

Уважаемый, а может поменьше пафоса? Если вы так уверены в своих знаниях, странно что вы пришли на форум задавать элементарные вопросы.

Думаю, это вы считаете, что вопрос элементарный, а он таковым не является. И это проблема Ардуино иде.

Бутлодер такой взял, потому что ему не нужна установка драйверов. 

Надеюсь, что здесь есть люди , способные не только, как вы,  давать советы "космической глупости". :)

 

 

 

b707
Offline
Зарегистрирован: 26.05.2017

muravei пишет:

Думаю, это вы считаете, что вопрос элементарный, а он таковым не является. И это проблема Ардуино иде.

ну, во-первых, это не проблема Ардуино ИДЕ.   ИДЕ не имеет ни малейшего отношения ни к драйверам ( их пишет производитель чипов - компания ST) , ни к вашему загрузчику.

Ну а далее - уже то, что у вас драйвера не встали (или вы не сумели)  - довольно подозрительно. Вообще у большинства пользователей нет проблем с драйверами на Вин10. Зато есть случаи, когда фирменные драйвера не подходят - и чаще всего это говорит. что чипы поддельные или не вполне рабочие. Особенно много клонов СТМ32 появилось на Али в последние полгода.

Кстати. было бы неплохо, если б вы выложили ссылку на лот, где покупали платы и на их фото в хорошем качестве с двух сторон

Andrey_Ak
Andrey_Ak аватар
Offline
Зарегистрирован: 13.05.2020

У меня явно фейковый контроллер:
http://arduino.ru/forum/programmirovanie/stm32-f103c8t6?page=15#comment-...

И даже перемычка была не распаяна к ноге чипа, что нельзя
было переключить в BOOT0 режим..  Замкнув ногу, контроллер
перевел в режим загрузки, и залил прошивку через UART..

После загрузки прошивки, подключил контроллер через его USB,
сначала устройство нашлось, но без номера порта, потом выдергивания,
и / или перезагрузка решили вопрос, устройство все-таки опозналось
как COM порт, и после этого Arduino IDE смог снюхаться с платой..

Но если честно, мне не нравиться работа Arduino IDE через
встроенный USB порт платы, как-то криво работает..
Поэтому удалил этот загрузчик и работаю с платой через ST-Link..

muravei
Offline
Зарегистрирован: 01.06.2020

b707 пишет:

   ИДЕ не имеет ни малейшего отношения ни к драйверам ( их пишет производитель чипов - компания ST) , ни к вашему загрузчику.

К драйверам да( ST, думаю тоже), а к загрузчику очень даже. Она должна же знать адрес загрузки. чтобы компилировать под него.

В boards.txt я нашел строчку:

"genericSTM32F103C.menu.upload_method.HIDUploadMethod.build.vect=VECT_TAB_ADDR=0x8001000"

Так что грузить должен правильно.

 

 

Kost286
Offline
Зарегистрирован: 20.09.2016

Нужно знать, с какого адреса он будет грузить вашу программу. В конфигурации программы, своей, указать такой же адрес. Не знаю как там у вас в ардуине это делается.

Например, в бутлоадере указано, что он начнёт грузить с 0x08001000, значит ваша программа при линковке должна иметь стартовый адрес 0x08001000.

vganin
Offline
Зарегистрирован: 03.07.2019

Привет всем. Вот уже месяц как как юзаюSTM32F103. может кому поможет. Как программист я не очень и задачи у меня утилитарные(включить-выкл, математические вычисления, дисплей,генераторы меандра звуковых частот,( из за этого и пересел на STM, что бы была возможность точно воспроизводить аккорды, у ардуино не хватает точности воспроизведения особенно низких частот. Конечно это мой косяк как программиста. поэтому решаю свои проблемы так как понимаю) но пост не об этом!!!

По работе много работаю с FBD. открыл FB Prog, все то же самое. Выбираю контроллер NANO, делаю свои примитивные алгоритмы или блоками , или лестницей. послев настройках ставлю "открывать IDE при компиляции" и копирую готовый скетч в свой IDE. А там элементарно допиливаю нумерацию и адресацию пинов, составляю несколько скечей вместе,если нужно. Я конечно только в начале пути, но пока все что попробовал заработало на STM сразу. Язык русский, библиотеки шин IIC  и SPI работают(у меня по крайней мере).

Пожалуй все, рад если кому поможет.

muravei
Offline
Зарегистрирован: 01.06.2020

Kost286 пишет:

 Не знаю как там у вас в ардуине это делается.

Вот и я не знаю. :)

Короче, блинк-за блинкал. Надеюсь, загрузилось куда надо.

И дело было в Ардуине... , ну почти. :) Требовалось это :

https://github.com/stm32duino/Arduino_Core_STM32 , а было Arduino_STM32. После чего появился HIDbootloader 2.2(был 2.0)

Так что кому хочется загружаться без драйверов, можно пробовать.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

vganin пишет:

( из за этого и пересел на STM, что бы была возможность точно воспроизводить аккорды, у ардуино не хватает точности воспроизведения особенно низких частот.

Это как?

Элементарная арифметика показывает, что чем ниже частота, тем точнее ее можно воспроизвести.

Юрий48
Offline
Зарегистрирован: 19.06.2018

Извините, тест.

Andrey_Ak
Andrey_Ak аватар
Offline
Зарегистрирован: 13.05.2020

Помогите пожалуйста разобраться с ШИМ на разных частотах,
никак не могу понять как сделать..  

Вот скетч генератора:

 


#include <Wire.h> 

  int del=1;
  int f_g=1;
  int imp=50;

void setup() {      
              pinMode(PB0, PWM); 	          // Выход генератора

              Timer3.pause();			  // Останавливаем таймер перед настройкой
              Timer3.setPrescaleFactor(del);      // Устанавливаем делитель  
              Timer3.setOverflow(f_g); 		  // Устанавливаем переполнение, период
              Timer3.setCompare(TIMER_CH3, imp);  // Устанавливаем длину импульса 
              Timer3.refresh();			  // Обнулить таймер 
              Timer3.resume();			  // Запускаем таймер
              }

Частота задается делителем, переменной "del",
при del=1, частота 36 МГц,
при del=65535, частота 549 Гц

 

 

nik182
Offline
Зарегистрирован: 04.05.2015

Всё как должно быть. Если нужен ШИМ, то переполнение должно быть больше импульса. Собственно частота при ШИМ это частота тактирования делённая на глубину ШИМ. Если нужен, скажем, ШИМ на 1000 точек, то выходная частота будет 36кГц.

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

Andrey_Ak, изучать принципы работы таймеров посредством ардуиновских функций -дело заведомо гиблое. Функция делителя -делить тактовую  таймера. На частоту он влияет конечно, но непосредственно управляет частотой регистр переполнения ARR, в данном случае  функция setOverflow,  значение там всегда должно быть >= регистра сравнения. Например для 50-% заполнения там должно быть число 100, если в сравнение записано 50.

Andrey_Ak
Andrey_Ak аватар
Offline
Зарегистрирован: 13.05.2020

Пытаюсь использовать другой код вывода частоты,
не могу решить задачу плавной регулировки + - частоты.

//Выход таймера PA8 (T1C1)

#define GPIOA_CRH      (*(volatile unsigned int*)0x40010804)
#define RCC_APB2ENR    (*(volatile unsigned int*)0x40021018)
#define TIM1_CR1       (*(volatile unsigned int*)0x40012c00)
#define TIM1_CCMR1     (*(volatile unsigned int*)0x40012c18)
#define TIM1_CCER      (*(volatile unsigned int*)0x40012c20)
#define TIM1_PSC       (*(volatile unsigned int*)0x40012c28)
#define TIM1_ARR       (*(volatile unsigned int*)0x40012c2c)
#define TIM1_CCR1      (*(volatile unsigned int*)0x40012c34)


#define CLK PB1
#define DT PB10
#define SW PB11

#define CLK1 PB9
#define DT1 PB8
#define SW1 PB5

#include "GyverEncoder.h"
Encoder enc1(CLK, DT, SW, TYPE2);   // TYPE2 - "HW-040"  
Encoder enc2(CLK1, DT1, SW1, TYPE2);   // TYPE2 - "HW-040"  

  int x = 1;
  int y = 1;
  int z = 1;

  int f=1000000;    // Частота по умолчанию
  int d=50;         // Скважность по умолчанию


void setup(){

pinMode(LED_BUILTIN, OUTPUT); // Включение светодиода

Serial1.begin(115200); 
  
GPIOA_CRH |= (1<<1)|(1<<0)|(1<<3);
GPIOA_CRH &= ~(1<<2); 
RCC_APB2ENR|= 1<<11;                // включить тактирование tim1
TIM1_CCER|=1<<0;                    // cc1e enable 
TIM1_CCMR1=(1<<6)|(1<<5)|(1<<3);    // PWM mode 1
TIM1_PSC=0;//prescaler   
TIM1_CCR1=  0;                      // скважность по умолчанию в тактах
TIM1_ARR= 1;                        // частота по умолчанию в тактах
TIM1_CR1=1;

CallFunction2(); 

}

void loop() {

              enc1.tick();   // Инициализация энкодера
              enc2.tick();   // Инициализация энкодера

              if(enc1.isLeft()||enc1.isFastL()){               // Уменьшение
                                                Serial1.print("LEFT enc1-- ");
                                                f=f-x;
                                                if(f<1){ f=1; }
                                                if(f>72E6){ f=72E6; }

                                                Serial1.print(" f: "); Serial1.print(f);
                                                CallFunction2(); 
                                                 
                                               }
                                    
              if(enc1.isRight()||enc1.isFastR()){              // Увеличение 
                                                Serial1.print("RIGHT enc1-- ");
                                                f=f+x;
                                                if(f<1){ f=1; }
                                                if(f>72E6){ f=72E6; }                                                

                                                Serial1.print(" f: "); Serial1.print(f);
                                                CallFunction2();   

                                                }
                                            

              if(enc2.isLeft()||enc2.isFastL()){
                                                Serial1.print("LEFT enc2-- ");

                                                d=d+1;
                                                if(d<1){ d=1; }
                                                if(d>100){ d=99; }
                                                 
                                                CallFunction2();                                               
                                                 
                                               }
                                    
              if(enc2.isRight()||enc2.isFastR()){
                                                Serial1.print("RIGHT enc2-- ");
                                                
                                                d=d-1;
                                                if(d<1){ d=1; }
                                                if(d>100){ d=99; }
                                                
                                                CallFunction2(); 
                                                 
                                                }                                                


}

void CallFunction2() {  // Функция запуска генератора -------------------------

int divider=1;
 int freq = 72E6/ f;
  int duty = d;
   while ( (freq/divider) > 65535) {divider++;} 
    TIM1_PSC=divider-1;
     TIM1_ARR=(freq/divider)-1;
      if (!duty){ TIM1_CCR1= freq/divider/2;}
      else { TIM1_CCR1=(freq/divider)*duty/100; }
     freq= 72E6/((TIM1_ARR+1)*divider);
    Serial1.print(" freq: "); Serial1.print(freq); Serial1.print("Hz");
    float duty2=  (float) TIM1_CCR1 / ((TIM1_ARR+1) / 100.0) ;
    Serial1.print("  Duty=" ); Serial1.println(duty2,0);    

return; }  // Конец функции запуска генератора ------------------------------- 

Код установки частоты принимает значение f и под
него подстраивает частоту..

Увеличиваю значение f энкодером:
 
RIGHT enc1--  f: 999991 freq: 1000000Hz  Duty=50
RIGHT enc1--  f: 999992 freq: 1000000Hz  Duty=50
RIGHT enc1--  f: 999993 freq: 1000000Hz  Duty=50
RIGHT enc1--  f: 999994 freq: 1000000Hz  Duty=50
RIGHT enc1--  f: 999995 freq: 1000000Hz  Duty=50
RIGHT enc1--  f: 999996 freq: 1000000Hz  Duty=50
RIGHT enc1--  f: 999997 freq: 1000000Hz  Duty=50
RIGHT enc1--  f: 999998 freq: 1000000Hz  Duty=50
RIGHT enc1--  f: 999999 freq: 1000000Hz  Duty=50
RIGHT enc1--  f: 1000000 freq: 1000000Hz  Duty=50
RIGHT enc1--  f: 1000001 freq: 1014084Hz  Duty=49
RIGHT enc1--  f: 1000002 freq: 1014084Hz  Duty=49
RIGHT enc1--  f: 1000003 freq: 1014084Hz  Duty=49
RIGHT enc1--  f: 1000004 freq: 1014084Hz  Duty=49

И для следующего шага частоты от 1.000МГц до 1.014
нужно много крутить энкодер..

И назад тоже:

LEFT enc1--  f: 1000004 freq: 1014084Hz  Duty=49
LEFT enc1--  f: 1000003 freq: 1014084Hz  Duty=49
LEFT enc1--  f: 1000002 freq: 1014084Hz  Duty=49
LEFT enc1--  f: 1000001 freq: 1014084Hz  Duty=49
LEFT enc1--  f: 1000000 freq: 1000000Hz  Duty=50
LEFT enc1--  f: 999999 freq: 1000000Hz  Duty=50

Не получается сообразить как реализовать нормально..
Что-то типа проверки..  Блин, даже объяснить сложно...

Нужно придумать какое-то хитрое условие, например после установки частоты,
чтоб f сама увеличивалась/уменьшалась пока не измениться частота freq..

Типа цикл, увеличивать f пока freq не измениться..
Ну никак не могу сообразить... :(

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013
 
Andrey_Ak, ну например в моём генераторе это реализовано таким образом, что свыше ~8 кГц энкодер подстраивает уже не частоту, а регистр ARR, таким образом "холостого хода"  у энкодера нет. 
b707
Offline
Зарегистрирован: 26.05.2017

Andrey_Ak пишет:

не могу решить задачу плавной регулировки + - частоты.

Андрей, еще в самом начале, когда вы только спрашивали как сделать генератор на СТМ - я вам писал. что настраивать частоту в районе 1 МГц с точностью в герц и даже в килогерц невозможно. Так чему ж вы удивляетесь? 1 МГц и 1.014 МГц - это разница между прескалером 72 и 71, меньше быть не может

Andrey_Ak
Andrey_Ak аватар
Offline
Зарегистрирован: 13.05.2020

b707 пишет:

Андрей, еще в самом начале, когда вы только спрашивали как сделать генератор на СТМ - я вам писал. что настраивать частоту в районе 1 МГц с точностью в герц и даже в килогерц невозможно. Так чему ж вы удивляетесь? 1 МГц и 1.014 МГц - это разница между прескалером 72 и 73, меньше быть не может

Я это понимаю, проблема сделать один щелчек энкодера - частота 1.000, еще один щелчек - частота 1.014 и т.д.. А у меня десять-сто-тысяча щелчков надо сделать...

b707
Offline
Зарегистрирован: 26.05.2017

Andrey_Ak пишет:

Пытаюсь использовать другой код вывода частоты,

И еще. Первое, что вам надо было сделать, прежде чем браться за код - это понять, что означают каждый из регистров таймера. Судя по коду в #826 для вас это темный лес. вы их подбираете методом тыка.

А вы, вместо того чтоб разобрать, в общем, элементарнывй код - зачем-то бросились искать другой, в котором так же нихрена не понимаете. Поймите, не поняв принципов работы таймеров в СТМ - вы не напишете генератор.

Andrey_Ak
Andrey_Ak аватар
Offline
Зарегистрирован: 13.05.2020

Да, не понимаю...  Ну никак, сложно все..  Поэтому беру готовый кусок и пытаюсь разобраться как его приспособить..  Прошлую версию генератора на Mega328 под себя написал как хотел..  Хоть и остался непонятным кусок кода с установкой таймера.. 

Andrey_Ak
Andrey_Ak аватар
Offline
Зарегистрирован: 13.05.2020

А что касается кода в #826, так он самый понятный, и переменные вроде понятны, какая что делает, не понимаю как увязать все три переменные, когда они друг на друга влияют... 

b707
Offline
Зарегистрирован: 26.05.2017

Andrey_Ak пишет:

А что касается кода в #826, так он самый понятный, и переменные вроде понятны, какая что делает, не понимаю как увязать все три переменные, когда они друг на друга влияют... 

простите, но это называется "нихрена не понимаю" :)

очень распространенная ситуация в практике начинающих переводчиков - каждое слово в предложении перевел, а смысла фразы так и не понял. Тут путь один - прокачиваться дальше. у большинства слов не одно и не два значения в словарике, а десятки...

вот и у вас так же - похоже вам только кажется. что вы поняли каждую переменную

nik182
Offline
Зарегистрирован: 04.05.2015

С таймером всё очень просто. Есть два делителя тактовой частоты таймера. Предделитель, который делит входную тактовую 72МГц и собственно счётчик таймера. Т.Е. частота делится 2 раза в подряд. Соответственно устанавливая в два регистра (Ваши del - предделитель и f_g - максимальный счётчик) любые числа можно исходную частоту поделить на нужную величину. Для понимания возможностей можно например в экселе рассчитать конечную частоту для всех целых чисел, поделив 72000000  на все числа от 1 до 2^32. Третий Ваш регистр - imp это регистр сравнения. В момент, когда imp= счётчику в выбранном Вами режиме происходит переброс выходной ноги. Обратно нога сбрасывается, когда счетчик достигает f_g. Поэтому, что бы получить меандр на выходе imp должен быть равен половине f_g. Есть режим, где нога перебрасывается только в момент когда imp= счётчику, на выходе всегда получается меандр, но частота его в 2 раза ниже, т.к. для полного цикла счетчик должен пробежать 2 раза. В этом режиме imp можно присвоить 1 и про него забыть.

Вообще режимов работы таймера множество. Все они базируются на трёх китах - предделитель, счётчик, регистры сравнения. Остальное обвязка для соединения этих регистров и входных - выходных ног в желаемую конфигурацию. Возможен почти любой каприз. 

Вот энкодером не понял. У меня энкодеры висят на двух входных ногах таймера, находящегося в режиме чтения энкодера. На каждый клик энкодера прилетает прерывание таймера, в котором выдается направление клика. Соответственно выставляю флаг клика и в loop делаю один шаг по частоте. Всё работает без задержек.  

     

Andrey_Ak
Andrey_Ak аватар
Offline
Зарегистрирован: 13.05.2020

Подскажите пожалуйста, никак не могу разобраться, вот код:

if (Serial1.available()) { 
int divider=1;
 int freq = 72E6/ Serial1.parseInt();
  int duty = Serial1.parseInt();
   while ( (freq/divider) > 65535) {divider++;} 
    TIM1_PSC=divider-1;
     TIM1_ARR=(freq/divider)-1;
      if (!duty){ TIM1_CCR1= freq/divider/2;}
      else { TIM1_CCR1=(freq/divider)*duty/100; }
     freq= 72E6/((TIM1_ARR+1)*divider);
    Serial1.print(freq); Serial1.print("Hz");
    float duty2=  (float) TIM1_CCR1 / ((TIM1_ARR+1) / 100.0) ;
   Serial1.print("  Duty=" ); Serial1.println(duty2,0);

"Терминал принимает два числа через пробел. Частоту и дьюти в процентах.
Если дьюти не задать, то он по умолчанию 50%"

Взят отсюда:
http://arduino.ru/forum/proekty/generator-s-reguliruemoei-chastotoi-na-a...
Cообщение #27

---

Вводим в терминале значения частоты:
9000 --> 9000Hz  Duty=50
9001 --> 9001Hz  Duty=50
9002 --> 9002Hz  Duty=50
9003 --> 9003Hz  Duty=50
9004 --> 9004Hz  Duty=50
9005 --> 9005Hz  Duty=50
9006 --> 9006Hz  Duty=50
9007 --> 9007Hz  Duty=50
9008 --> 9009Hz  Duty=50  

- Вот тут понятно, частоту 9008 генератор не может дать,
и дает следующую возможною, а именно 9009, хорошо, пусть так..

А теперь обратная ситуация, мы идем на уменьшение:
9010 --> 9010Hz  Duty=50  
9009 --> 9009Hz  Duty=50  
9008 --> 9009Hz  Duty=50  
9008 --> 9009Hz  Duty=50  

- И происходит затык, после значения 9009 мне нужно уменьшить
частоту генератора на возможную, но при вводе 9008 он дает
возможную следующую частоту, но в большую сторону, а мне
нужно в меньшую.  

Как подправить этот код, чтоб он давал возможные частоты,
но на уменьшение???

Так-бы я представленный код выше использовал для увеличения
частот, а подправленный код использовал для уменьшения частот..

Andrey_Ak
Andrey_Ak аватар
Offline
Зарегистрирован: 13.05.2020

Вообщем решил проблему, возможно конечно не грамотно, но работает как надо:

//Выход таймера PA8 (T1C1)


//---------------------------------------------------------- 
#define GPIOA_CRH      (*(volatile unsigned int*)0x40010804) 
#define RCC_APB2ENR    (*(volatile unsigned int*)0x40021018)
#define TIM1_CR1       (*(volatile unsigned int*)0x40012c00)
#define TIM1_CCMR1     (*(volatile unsigned int*)0x40012c18)
#define TIM1_CCER      (*(volatile unsigned int*)0x40012c20)
#define TIM1_PSC       (*(volatile unsigned int*)0x40012c28)
#define TIM1_ARR       (*(volatile unsigned int*)0x40012c2c)
#define TIM1_CCR1      (*(volatile unsigned int*)0x40012c34)
//----------------------------------------------------------


#define CLK PB1
#define DT PB10
#define SW PB11

#define CLK1 PB9
#define DT1 PB8
#define SW1 PB5

#include <LiquidCrystal_I2C.h>                 // Подключаем библиотеку для работы с LCD дисплеем по шине I2C
          LiquidCrystal_I2C lcd(0x27, 16, 2);  // для шины I2C с другой кодировкой надо заменить адрес 0х27 на ваш

#include "GyverEncoder.h"
Encoder enc1(CLK, DT, SW, TYPE2);   // TYPE2 - "HW-040"  
Encoder enc2(CLK1, DT1, SW1, TYPE2);   // TYPE2 - "HW-040"  
      
  int y = 1;
  int z = 1;
  int p = 0;

  int push = 0;
  int mn = 1;          // Шаг устанавливаемой частоты

  int f=100000;        // Устанавливаемая частота по умолчанию 
  int d=50;            // Скважность по умолчанию

void setup(){

pinMode(LED_BUILTIN, OUTPUT); // Включение светодиода

        lcd.init(); //инициализация экрана
        lcd.backlight(); //включение подсветки экрана
        lcd.setCursor(0, 0);
        lcd.print("GENERATOR v.8.17"); //заставка
        lcd.setCursor(0, 1);
        lcd.print("www.tis.kz"); //заставка
        delay(3000);
        lcd.clear();

Serial1.begin(115200); 
Serial1.println("-------------- START ----------------");


//-----------------------------------------------------
GPIOA_CRH |= (1<<1)|(1<<0)|(1<<3);
GPIOA_CRH &= ~(1<<2); 
RCC_APB2ENR|= 1<<11; //включить тактирование tim1
TIM1_CCER|=1<<0;//cc1e enable 
TIM1_CCMR1=(1<<6)|(1<<5)|(1<<3);//PWM mode 1
TIM1_PSC=0;//prescaler   
TIM1_CCR1=  0;// скважность по умолчанию в тактах
TIM1_ARR= 1; //  частота по умолчанию в тактах
TIM1_CR1=1;
//-----------------------------------------------------  


CallFunction2(); 
CallFunction1(); 

Serial1.print(" Freq: "); Serial1.print(f); Serial1.print("Hz"); Serial1.print("  Duty: " ); Serial1.println(d);

}

void loop() {

              enc1.tick();   // Инициализация энкодера
              enc2.tick();   // Инициализация энкодера

if (enc1.isPress()) {                             // нажатие на кнопку (+ дебаунс)                  
                     if (push<=7) { push+=1; }
                     if (push==8) { push=0;  }
                                  
                     if (push==0) { lcd.setCursor(10, 1); lcd.print ("    +1"); mn=1; }  
                     if (push==1) { lcd.setCursor(10, 1); lcd.print ("   +10"); mn=10; }  
                     if (push==2) { lcd.setCursor(10, 1); lcd.print ("  +100"); mn=100; }  
                     if (push==3) { lcd.setCursor(10, 1); lcd.print (" +1000"); mn=1000; } 
                     if (push==4) { lcd.setCursor(10, 1); lcd.print ("+10000"); mn=10000; }
                     if (push==5) { lcd.setCursor(10, 1); lcd.print (" +1000"); mn=1000; }                         
                     if (push==6) { lcd.setCursor(10, 1); lcd.print ("  +100"); mn=100; } 
                     if (push==7) { lcd.setCursor(10, 1); lcd.print ("   +10"); mn=10; }
                     if (push==8) { lcd.setCursor(10, 1); lcd.print ("    +1"); mn=1; }                
                     }              

// ------------------------------------------------------------------------------------------------------------------------                                               
                                    
if(enc1.isRight()||enc1.isFastR()){                              // Увеличение частоты
                                   
                                   if(f>4000000) { f=4000000; } // Если устанавливаемая частота больше 4 МНц то установить ее 4 МНц
                                   
                                   Serial1.print(" freq_do:"); Serial1.print(f); 
                                   
                                   if( (f+mn)>4000000 ) { f=4000000; }  else { f=f+mn;  }
                                                                                                          
                                   CallFunction2();                                      
                                   Serial1.print(" freq_posle:"); Serial1.println(f);
                                   CallFunction1();
                                                                                                         
                                    }
// ------------------------------------------------------------------------------------------------------------------------

if(enc1.isLeft()||enc1.isFastL()){                               // Уменьшение частоты

  
                                   if(f<1){ f=1; }               // Если устанавливаемая частота меньше 1 Гц то установить ее 1 Гц
                                  
                                   Serial1.print(" freq_do:"); Serial1.print(f); 

                                   if( (f-mn)<1 ) { f=1; }  else { f=f-mn;  }
                                                   
                                   CallFunction3();                                      
                                   Serial1.print(" freq_posle:"); Serial1.println(f);
                                   CallFunction1();                                

                                  }         
// ------------------------------------------------------------------------------------------------------------------------

// Запуск последовательного перебора всех возможных частот в сторону увеличения

  if (p==0) {
             if (enc1.isHolded()) { Serial1.print("Holded "); p=1; Serial1.println(p); delay(100); mn=1; push=0;  } 
            }
  if (p==1) {

             if(f>4000000) { f=4000000; } // Если устанавливаемая частота больше 4 МНц то установить ее 4 МНц
             if( (f+mn)>4000000 ) { f=4000000; }  else { f=f+mn;  }                        

             CallFunction2();
             CallFunction1();

             float fprn=f;
                      if (fprn>1000000) {
                                       Serial1.print(fprn/1000000,3); // Если больше 1.000.000 то делить на 1.000.000
                                       Serial1.println(" MHz ");                        
                                      }                                        
                                      else {
                                            if (fprn>1000) { 
                                                         Serial1.print(fprn/1000,3);  // Если больше 1.000 то делить на 1.000
                                                         Serial1.println(" kHz ");
                                                         }
                                                          else {
                                                                Serial1.print(fprn,2);
                                                                Serial1.println(" Hz ");
                                                                }
                                             }
             
                                           
             if (enc1.isHolded()) { Serial1.print("Holded "); p=0; Serial1.println(p); delay(100); push=0; mn=1; CallFunction1(); }
             
             if (f>=4000000) { f=4000000; p=0; Serial1.println(p); delay(100); push=0; mn=1; CallFunction1(); }

             }   
             
// Окончание запуска последовательного перебора всех возможных частот 

// ------------------------------------------------------------------------------------------------------------------------ 

              if(enc2.isLeft()||enc2.isFastL()){                              // Увеличение скважности 

                                                d=d-1;
                                                if(d<2){ d=2; }
                                                if(d>98){ d=98; }

                                                 
                                                CallFunction2();                                               
                                                Serial1.print("  Duty=" ); Serial1.println(d); 
                                                CallFunction1();
                                               }
                                    
              if(enc2.isRight()||enc2.isFastR()){                              // Уменьшение скважности
                                                
                                                d=d+1;
                                                if(d<2){ d=2; }
                                                if(d>98){ d=98; }

                                                
                                                CallFunction2(); 
                                                Serial1.print("  Duty=" ); Serial1.println(d); 
                                                CallFunction1();
                                                } 

             if (enc2.isPress()) { d=50; CallFunction2(); CallFunction1(); }     // Установка скважности 50%

}

void CallFunction1() {  // Вывод информации на дисплей -------------------------------------------
  
                      lcd.clear();   

                      float fprn=f;    

           //         Serial1.print(" float fprn:" ); Serial1.println(fprn); 

                      if (fprn>1000000) {
                                       lcd.setCursor(0, 0);
                                       lcd.print("F: ");
                                       lcd.print(fprn/1000000,3); // Если больше 1.000.000 то делить на 1.000.000
                                       lcd.print(" MHz ");                        
                                      }                                        
                                      else {
                                            if (fprn>1000) { 
                                                         lcd.setCursor(0, 0);
                                                         lcd.print("F: ");
                                                         lcd.print(fprn/1000,3);  // Если больше 1.000 то делить на 1.000
                                                         lcd.print(" kHz ");
                                                         }
                                                          else {
                                                                lcd.setCursor(0, 0);
                                                                lcd.print("F: ");
                                                                lcd.print(fprn,2);
                                                                lcd.print(" Hz ");
                                                                }
                                             }
                                    
                       lcd.setCursor(0, 1);
                       lcd.print("D: ");
                       lcd.print(d);
                       lcd.print(" % ");                                            
                                           
                       if (push==0 | push==8) { lcd.setCursor(10, 1); lcd.print ("    +1"); }  
                       if (push==1 | push==7) { lcd.setCursor(10, 1); lcd.print ("   +10"); }  
                       if (push==2 | push==6) { lcd.setCursor(10, 1); lcd.print ("  +100"); }  
                       if (push==3 | push==5) { lcd.setCursor(10, 1); lcd.print (" +1000"); }  
                       if (push==4) { lcd.setCursor(10, 1);           lcd.print ("+10000"); }  
                                             
return; }  // Конец функции информации на дисплей ------------------------------------------------


void CallFunction2() {  // Функция запуска генератора --------------------------------------------

int divider=1;
 int freq = 72E6/ f;   // f - переменная частоты
  int duty = d;        // в - переменная скважности
   while ( (freq/divider) > 65535) {divider++;} 
    TIM1_PSC=divider-1;
     TIM1_ARR=(freq/divider)-1;
      if (!duty){ TIM1_CCR1= freq/divider/2;}
      else { TIM1_CCR1=(freq/divider)*duty/100; }
     freq= 72E6/((TIM1_ARR+1)*divider);
//  Serial1.print(" -=== FreqGen:" ); Serial1.print(freq); Serial1.print("Hz");
    float duty2=  (float) TIM1_CCR1 / ((TIM1_ARR+1) / 100.0) ;
//  Serial1.print("  DutyGen:"); Serial1.print(duty2,0); Serial1.print("% ===- ");

f=freq; 


return; }  // Конец функции запуска генератора --------------------------------------------------- 

void CallFunction3() {  // Функция запуска генератора --------------------------------------------

int divider=1;
 int freq = 72E6/ f;   // f - переменная частоты
  int duty = d;        // в - переменная скважности
   while ( (freq/divider) > 65535) {divider++;} 
    TIM1_PSC=divider-1;
     TIM1_ARR=(freq/divider)-1;
      if (!duty){ TIM1_CCR1= freq/divider/2;}
      else { TIM1_CCR1=(freq/divider)*duty/100; }
     freq= 72E6/((TIM1_ARR+1)*divider);
//  Serial1.print(" -=== FreqGen:" ); Serial1.print(freq); Serial1.print("Hz");
    float duty2=  (float) TIM1_CCR1 / ((TIM1_ARR+1) / 100.0) ;
//  Serial1.print("  DutyGen:"); Serial1.print(duty2,0); Serial1.print("% ===- ");

//  Serial1.println("  ");  Serial1.print(" f="); Serial1.print(f); Serial1.print(" freq="); Serial1.println(freq); 
 


   if (f<freq) { //  Serial1.println(" -->>>- CICLE -->>>--  ");    // Если частота не уменьшилась запускаем цикл уменьшения     
                     y=f; 
                     if (f>1000000) {z=1000; } else {z=1; }         // Уменьшение частоты на 1 или на 1000 (если > 1МНz)
                     while (true)  {  
                                     //   Serial1.print(" y=f f="); Serial1.print(f); Serial1.print(" y="); Serial1.print(y);
                                          if( (y-z)<1 ) { y=1; }  else { y=y-z; }
                                     //   Serial1.print(" y-1="); Serial1.print(y);
                                     //   Serial1.print(" freq_do:"); Serial1.print(freq);

                                                                int divider=1;
                                                                int freq = 72E6/ y;   // f - переменная частоты
                                                                int duty = d;        // в - переменная скважности
                                                                while ( (freq/divider) > 65535) {divider++;} 
                                                                TIM1_PSC=divider-1;
                                                                TIM1_ARR=(freq/divider)-1;
                                                                if (!duty){ TIM1_CCR1= freq/divider/2;}
                                                                else { TIM1_CCR1=(freq/divider)*duty/100; }
                                                                freq= 72E6/((TIM1_ARR+1)*divider);
                                      //                        Serial1.print(" -=== FreqGen:" ); Serial1.print(freq); Serial1.print("Hz");
                                                                float duty2=  (float) TIM1_CCR1 / ((TIM1_ARR+1) / 100.0) ;
                                      //                        Serial1.print("  DutyGen:"); Serial1.print(duty2,0); Serial1.print("% ===- ");
                                          
                                          if (freq<f) { // Serial1.print(" CICLE freq<f - OK, Break, freq="); Serial1.println(freq); 
                                                           f=freq;  break; } 
                                     //   Serial1.print(" freq_posle:"); Serial1.println(freq);
                                      }
                                                                                       
                                               
                    } 

                    else { f=freq; }


return; }  // Конец функции запуска генератора ---------------------------------------------------  

 

Список всех возможных частот начиная от 100кГц:

http://tis.kz/temp/arduino/2st.gen.II.txt

Максимальную частоту ограничил 4MHz, больше там уже только подобие сигнала...

И список частот от 100кГц в сравнении с генератором на ATMEGA328A:

http://tis.kz/temp/arduino/freq_16_72.xls

 

b707
Offline
Зарегистрирован: 26.05.2017

Андрей, сначала меня смутила вот эта фраза

Andrey_Ak пишет:

Максимальную частоту ограничил 4MHz, больше там уже только подобие сигнала...

цифровой генератор он тем и характерен, что без проблем должен выдавать любую частоту вплоть до максимальной

Но когда я увмдел вот это в коде

void CallFunction3() {  // Функция запуска генератора --------------------------------------------

int divider=1;
 int freq = 72E6/ f;   // f - переменная частоты
  int duty = d;        // в - переменная скважности
   while ( (freq/divider) > 65535) {divider++;} 
    TIM1_PSC=divider-1;
     TIM1_ARR=(freq/divider)-1;
      if (!duty){ TIM1_CCR1= freq/divider/2;}
      else { TIM1_CCR1=(freq/divider)*duty/100; }
     freq= 72E6/((TIM1_ARR+1)*divider);

 

я удивляться перестал

Выражение в скобкаж while() никогда не превысит 65536. поэтому вся эта конструкция бесполезна в принципе

 

Andrey_Ak
Andrey_Ak аватар
Offline
Зарегистрирован: 13.05.2020

Ну этот кусок кода вывода частоты был готовый..   Я его мало понимаю... 

 

b707
Offline
Зарегистрирован: 26.05.2017

Andrey_Ak пишет:

Ну этот кусок кода вывода частоты был готовый..   Я его мало понимаю... 

я вам наверно уже раза три сказал. что сначала надо разобраться, как это работает, а потом генераторы писать. Там математика на уровне школьной программы, академиком для этого быть не надо.

Что касается строчки с while() - у вас переменные freq и divider обьявлены как int, значит и результат может быть только int ... еще и знаковый...

Хотя нет, это же STM32 - там int 4 байта.   Возражение снимается

Densl
Offline
Зарегистрирован: 28.11.2018

Да, если видете в коде слово int, надо быть очень внимательным. Желательно от них вообще оказаться, заменять на short или long для того, если кто-то решит перенести код на другую платформу, чтобы не было проблем потом.

b707
Offline
Зарегистрирован: 26.05.2017

Коллеги, подскажите, в аддоне Кларка обновление регистра ARR функцией Timer.setOverflow(x) идет через Прелоад или непосредственно в регистр? что по исходнику понять не могу

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Densl пишет:
Да, если видете в коде слово int, надо быть очень внимательным. Желательно от них вообще оказаться, заменять на short или long для того, если кто-то решит перенести код на другую платформу, чтобы не было проблем потом.

есть прекрасные, самоговорящие за себя имена типов, int8_t, uint32_t, даже int64_t есть, и как вишенка на торте AVR GCC - __int24.  Используй их, люк, и волосы будут мяхкими и шелковистыми.

gena321
Offline
Зарегистрирован: 19.01.2019

простой генератор с регулировкой частоты

HardwareTimer pwmtimer3(3);


#include <LiquidCrystal.h>
LiquidCrystal lcd(PA0, PA1, PA2, PA3, PA4, PA5);
int i;
void setup() {
   pinMode(PB12, INPUT_PULLDOWN);
  pinMode(PB14, INPUT_PULLDOWN);
  lcd.begin(16, 2);


  pinMode(PB0, PWM);
  pwmtimer3.pause();
  pwmtimer3.setPrescaleFactor(10);   
 //  pwmtimer3.setPrescaleFactor(100);     
  pwmtimer3.refresh();
  pwmtimer3.resume();
}


void loop() {
       
  pwmtimer3.setOverflow(1+2*i);           
  pwmtimer3.setCompare(TIMER_CH3, i);  
 
  if (digitalRead(PB12) == HIGH)
  {
    if (i < 6000)
      // if (i < 25)
    {
      i++;
     
      delay(50);
    }
  }
  if (digitalRead(PB14) == HIGH)
  {
    if (i > 0)
    {
      i--;
     
      delay(50);
    }
  }
  lcd.setCursor(0, 1);
  lcd.print(i);
}

 

b707
Offline
Зарегистрирован: 26.05.2017

хреновенький такой генератор, Геня. Зачем дергать таймер и дисплей на каждом проходе loop() -обращайтесь к ним только в случае изменения периода

krepton85
Offline
Зарегистрирован: 02.02.2016

Подскажите, а куда в этой плате подключать источник опорного напряжения для АЦП?

nik182
Offline
Зарегистрирован: 04.05.2015

На блюпиле Aref не выведены на пины.

krepton85
Offline
Зарегистрирован: 02.02.2016

Скорей всего как я понял это 9 пин микроконтроллера, он по умолчанию припаян к +3,3 вольта.