Таймер 32F103

Pasha22
Offline
Зарегистрирован: 19.01.2018

Ребята помогите разобраться как этот код переделать чтобы работал на STM32F103.

 

 // Set up timer 1.
  // Prescaler = 1, phase correct PWM mode, TOP = ICR1A
 TCCR1A = (1 << COM1A1) | (1 << WGM11);
  TCCR1B = (1 << WGM12) | (1 << WGM13) | (1 << CS10);    // CTC mode, prescaler = 1
  TCCR1C = 0;
  OCR1AH = (TIMER1_TOP/2 >> 8);
  OCR1AL = (TIMER1_TOP/2 & 0xFF);
  ICR1H = (TIMER1_TOP >> 8);
  ICR1L = (TIMER1_TOP & 0xFF);
  TCNT1H = 0;
  TCNT1L = 0;
  TIFR1 = 0x07;      // clear any pending interrupt
  TIMSK1 = (1 << TOIE1);

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Ща сс-овец придёт и всё будет :)

А остальные тут как предпочитают вот такое решение :)

b707
Онлайн
Зарегистрирован: 26.05.2017

Pasha22 пишет:

Ребята помогите разобраться как этот код переделать чтобы работал на STM32F103.

чтобы это сделать, надо знать, для какого конкретного МК этот код. так как значения одних и тех же констант на разных контроллерах - разные.

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

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

ну не все, Женя!  Но и помочь тут не возможно.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

wdrakula пишет:

ну не все, Женя!  

Ну, не знаю, как Все, но Вы в той теме сказали примерно тоже, толь другими словами :))))

wdrakula пишет:

Прошу обратить внимание: изделие на STM32F103! Девица доверяет STM самое сокровенное! ;););)

Jeka_M
Jeka_M аватар
Offline
Зарегистрирован: 06.07.2014

Pasha22 пишет:

Ребята помогите разобраться как этот код переделать чтобы работал на STM32F103.

Конкретно этот - никак... Надо писать другой код под STM.

5N62V
Offline
Зарегистрирован: 25.02.2016

b707 пишет:

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

Стопудово! ТС, Ваш ход!

Pasha22
Offline
Зарегистрирован: 19.01.2018

Спасибо за ответы!

программа от Atmega2560.

 Таймер 1 используется для разделения системных часов примерно на 256 для создания квадратной волны 62,5 кГц.
 
nik182
Offline
Зарегистрирован: 04.05.2015

Важны буквы после 103. Важно в какой среде будет компилироваться программа. Важно какой таймер задействовать(1,2,3,4?). Важно аппаратно или программно выводить "волну" на ногу процессора. Нога любая или конкретная? Частота процессора(72 или 8 ?). 

В STM не обязательно делить "системные часы". Давай точно что тебе надо. Тогда помогу. Иначе не получится. 

Pasha22
Offline
Зарегистрирован: 19.01.2018
Плата - Blue PillSTM32F103C8. Arduino IDE, Generic stm32f103C.
 Я послушал Jeka_M и вот, что у меня получилось, 72 кГц.

 

Сейчас я хочу это поделить на 10, чтобы получить 7.2 кГц
 
HardwareTimer pwmtimer3(3);
void setup() {
  pinMode(PA7, PWM);   //выход 72 кГц, F1
  pwmtimer3.pause();
  pwmtimer3.setPrescaleFactor(10);      
  pwmtimer3.setOverflow(100-1);           
  pwmtimer3.setCompare(TIMER_CH2, 50);  
  pwmtimer3.resume();

  pinMode(PA3, PWM);  // выход 7.2 кГц, F2
  Divide F1 by 10 ???    //поделить F1 на 10
 
 
}

void loop() {
}

 

 

nik182
Offline
Зарегистрирован: 04.05.2015
  pwmtimer3.setPrescaleFactor(10);      
  pwmtimer3.setOverflow(100-1);           
  pwmtimer3.setCompare(TIMER_CH2, 50); 

Эти три строчки определяют частоту таймера 3. Первая делит частоту системы (72МГц) для тактирования таймера. Может быть от 1 до 2^16. Вторая строка количество тактов таймера. -1 что бы учесть ноль. Т.е. для 100 тактов надо написать число 99. Третья строка определяет на каком такте менять менять полярность. Для меандра и 100 тактов должно быть 100/2=50. 

Чтобы поделить частоту на 10 можно в первой строчке написать 100, или во второй-третей 1000-1 и 500. 

Pasha22
Offline
Зарегистрирован: 19.01.2018

Спасибо за объяснения.

В этом случае, чтобы иметь 72 i 7.2 кГц, мне нужно использовать два таймера. Можно ли использовать только один таймер, как я предполагал сделать в своем посте # 9. Я сделал то, что вы предлагаете,  но  когда я пытаюсь изменить частоту, например 70 и 7 кГц скважность импульсов не остается 50% и они не синхронные, смотрел на осциллографе. Вот код.
 
HardwareTimer pwmtimer3(3);
HardwareTimer pwmtimer2(2);
 
void setup() {
  pinMode(PA7, PWM);
  pwmtimer3.pause();
  pwmtimer3.setPrescaleFactor(10);     
  pwmtimer3.setOverflow(100-1);           
  pwmtimer3.setCompare(TIMER_CH2, 50); 
  pwmtimer3.refresh();
  pwmtimer3.resume();
 
  pinMode(PA3, PWM);
  pwmtimer2.pause();
  pwmtimer2.setPrescaleFactor(1);   
  pwmtimer2.setOverflow(10000-1);            
  pwmtimer2.setCompare(TIMER_CH4, 5000);
  pwmtimer2.refresh();
  pwmtimer2.resume();
}
 
void loop() {
}


каждый таймер может работать только на одной частоте

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

Таймеры не могут быть не синхронными. Они тактируются от одного генератора. Сделай одинаковый делитель для таймеров (setPrescaleFactor(10);) Сделай запуск почти одновременно (pwmtimer3.resume(); pwmtimer2.resume();)

void setup() {
  pinMode(PA7, PWM);
  pwmtimer3.pause();
  pwmtimer3.setPrescaleFactor(10);     
  pwmtimer3.setOverflow(100-1);           
  pwmtimer3.setCompare(TIMER_CH2, 50); 
  pwmtimer3.refresh();
 
 
  pinMode(PA3, PWM);
  pwmtimer2.pause();
  pwmtimer2.setPrescaleFactor(10);   
  pwmtimer2.setOverflow(1000-1);            
  pwmtimer2.setCompare(TIMER_CH4, 500);
  pwmtimer2.refresh();
  pwmtimer2.resume();
  pwmtimer3.resume();
}
Pasha22
Offline
Зарегистрирован: 19.01.2018

Убрал - void loop() - и работает ?

Но я бы хотел подать сигнал от вывода PA7 на вход таймера 2, он поделил бы его на 10, тогда легче изменять частоту.
 
nik182
Offline
Зарегистрирован: 04.05.2015

Конечно работает. Пустой loop() объявлен в недрах среды. Здесь перекрывается. Если не видно суслика, то он есть!

Можно подать на PA0 c выхода третьего таймера. Запрограмировать тактирование от внешнего источника и коэффициент деления 10.  Или запрограмировать в режиме slave. Тогда можно обойтись без внешних соединений. Проблема в том, что я не нашёл в библиотеке таймера команды выбора источника тактирования. Придется писать через регистры типа

TIMER2->regs.gen->CCER = 0b0001;

Я такие вещи через stdlib писал в виде для таймера 2 - ведущего и таймера 3 ведомого

  TIM_SelectMasterSlaveMode(TIM2, TIM_MasterSlaveMode_Enable);
  TIM_SelectOutputTrigger(TIM2, TIM_TRGOSource_Update);
  TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Gated);
  TIM_SelectInputTrigger(TIM3, TIM_TS_ITR1);
 
Надо расковырять эти определения и правильно заполнить названия регистров и констант. Что бы правильно написать надо знать какие точно таймеры и как соединять в цепочку.
Pasha22
Offline
Зарегистрирован: 19.01.2018

Большое спасибо за объяснения,  я останусь с № 12.

А Вы могли бы перевести это на русский?
 
                      // ISR (TIMER1_OVF_vect)
 ++ticks;
  uint8_t ctr = TCNT0;
  int16_t val = (int16_t)(uint16_t)ADCH;   
  if (ctr != ((lastctr + 1) & 7))
  {
    ++misses;
  }
  lastctr = ctr;
  int16_t *p = &bins[ctr & 3];
  if (ctr < 4)
 

 

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

Прерывание по переполнению таймера 1.

Инкремент переменной ticks.

Считывание значение счётчика таймера 0.

Считывание значения регистров данных АЦП.

Если  значения счётчика таймера 0 не равны трём нижним битам предыдущего значения счетчика +1 то инкремент переменной misses.

Запомнить значение счетчика для следующего прерывания.

Получить адрес элемента массива bins под номером последних двух битов  счётчика таймера 0.

Если значение счётчика таймера 0 меньше 4 .......

Зачем это всё надо я смутно догадываюсь, но до конца не понимаю :-)

Pasha22
Offline
Зарегистрирован: 19.01.2018

Вот здесь я наткнулся на такой металлоискатель, я хочу переделать его на stm32 и увеличить частоту два раза, потому что stm 32  намного быстрее, сейчас он  работает  на 7.8 кГц, что является пределом возможностей Atmega2560.

Надеюсь что мне остолось переделать последний кусок этого кода -сообщение # 15
 
 
Pasha22
Offline
Зарегистрирован: 19.01.2018

Спасибо, что объяснили, не могли бы вы  написать то же самое для ARM stm32 - этот кусок AVR 

 

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

Для какого таймера и что там делает АЦП?

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

Из соображения таймер1 - системное время 4мкс, таймер 2 - рабочий, написано для stdlib embitz 1.11.

void TIM2_IRQHandler(void)
{
  if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)
  {
    TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
    
  ticks++;
  uint16_t ctr = TIM_GetCounter(TIM1);
  int16_t val = ADC_GetConversionValue(ADC1);   
  if (ctr != ((lastctr + 1) & 7))
  {
    ++misses;
  }
  lastctr = ctr;
  int32_t *p = &bins[ctr & 3];
  if (ctr < 4)
    
  }
 
}

 

Pasha22
Offline
Зарегистрирован: 19.01.2018

У меня есть предложение - изменить эту программу на заказ, что вы скажете?

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

К сожалению у меня нет времени вникать в проблемы металлоискателей. Возьмите готовую разработку http://fandy.ucoz.org/publ/metalloiskatel_quot_kvazar_quot_quot_quasar_quot/metalloiskatel_quot_quasar_arm_quot/2-1-0-5

лучше сделать очень трудно. Её делали люди разбирающиеся в вопросе.

Pasha22
Offline
Зарегистрирован: 19.01.2018

.

Pasha22
Offline
Зарегистрирован: 19.01.2018

Я в вопросе разбираюсь хорошо, "Quasar ARM" мне знакомый но там никаких изменений нельзя делать - hex файл, мне надо перевести этy АРМ программy на ARM, разбираться не надо там есть объяснения на английском, могу перевести если надо и добавить свои если что-то неясно. Я знаю, что должна делать программа.

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

Pasha22 пишет:

Я в вопросе разбираюсь хорошо, "Quasar ARM" мне знакомый но там никаких изменений нельзя делать - hex файл, мне надо перевести этy АРМ программy на ARM, разбираться не надо там есть объяснения на английском, могу перевести если надо и добавить свои если что-то неясно. Я знаю, что должна делать программа.

 

Для начала - протрезвей, Паша. Научись говорить внятно и с запятыми. 

Pasha22
Offline
Зарегистрирован: 19.01.2018

 Кот не вмешивайся пишу как хочу. Не нравится не читай.

 
ssss
Offline
Зарегистрирован: 01.07.2016

Pasha22 пишет:

Я в вопросе разбираюсь хорошо

Найдёшь медаль - повесь её себе на грудь!

Цитата:

Я знаю, что должна делать программа.

И что толку? Объяснить это другим ты все равно не можешь.

Pasha22
Offline
Зарегистрирован: 19.01.2018

Для nik182

Программа состоит из двух частей:
1. Из генератора двух сигналов - один для АЦП 62,5 кГц , втарой для Tx  катушки 7.8125кГц
В моем случае это может быть 72 кГц и 7,2 кГц.
2. Из измерителя фазы для изменения (ΔΦ), опорное напряжение  получается после нажатия кнопки энкодера.
 
Когда я отключу строчки #: 90 - 120 и 134 - 168, программа компилируется без ошибок для STM32F103.
Думаю что хватит переделать эти строки та программа будет работать. 
Номера строчек как  в оригинале.
 
Ссылка
 
ssss
Offline
Зарегистрирован: 01.07.2016

Pasha22 пишет:

В этом случае, чтобы иметь 72 i 7.2 кГц, мне нужно использовать два таймера.

И одного хватит.

Цитата:

когда я пытаюсь изменить частоту, например 70 и 7 кГц скважность импульсов не остается 50% и они не синхронные, смотрел на осциллографе.

Используй прелоад.

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

Посмотрел на схему и исходник. Сделать прямо не получится. Надо подбирать время работы АЦП. Оно как то завязано на измерение фазы отклика сигнала. 

То, что строки не компилируются - они железо зависимы. Почитайте в интернете статьи по програмированию stm32. Вам нужно про АЦП и таймеры. Меня тема металлоискателей не интересует. 

ssss
Offline
Зарегистрирован: 01.07.2016

Да, там нужно вникать в тонкости работы девайса, без этого - никак. На СТМ32, вполне может быть, АЦП и нахрен может быть не нужен. Может туда АЦП прилепили из-за ограниченности АВР по таймерам, хотя АЦП в АВР тоже тормознутый. А даже если и нужен, то АЦП в СТМ32 пошустрее АВРовского будет, но переложить код построчно всё равно не получится, увы.

Pasha22
Offline
Зарегистрирован: 19.01.2018


 
 
А можешь исправить мои  ошибки, я новичок в программировании.
К оригиналу я добавил # 1 и # 2 в начале и # 3 и # 4 в конце.
Вот ошибка;  error: 'firFilter' was not declared in this scope
 
    int outputVal = firFilter(inputVal);
 
                                      ^
 
exit status 1
'firFilter' was not declared in this scope.
 
и программа.

#include <stdio.h>
#include <stdint.h>
/*to be added
int inputVal = analogRead(PA6);
int outputVal = firFilter(inputVal);
analogWrite(PA7, outputVal);
*/

// #1
int inputPin = PA6; // set input pin for the signal
int inputValue = PA6; // potentiometer input variable
int ledPin = PA7; // set output pin for PA7

//#2
int inputVal = analogRead(PA6);
int outputVal = firFilter(inputVal);

//////////////////////////////////////////////////////////////
// Filter Code Definitions
//////////////////////////////////////////////////////////////

// maximum number of inputs that can be handled
// in one function call
#define MAX_INPUT_LEN 80
// maximum length of filter than can be handled
#define MAX_FLT_LEN 63
// buffer to hold all of the input samples
#define BUFFER_LEN (MAX_FLT_LEN - 1 + MAX_INPUT_LEN)

// array to hold input samples
double insamp[ BUFFER_LEN ];

// FIR init
void firFloatInit( void )
{
memset( insamp, 0, sizeof( insamp ) );
}

// the FIR filter function
void firFloat( double *coeffs, double *input, double *output,
int length, int filterLength )
{
double acc; // accumulator for MACs
double *coeffp; // pointer to coefficients
double *inputp; // pointer to input samples
int n;
int k;

// put the new samples at the high end of the buffer
memcpy( &insamp[filterLength - 1], input,
length * sizeof(double) );

// apply the filter to each input sample
for ( n = 0; n < length; n++ ) {
// calculate output n
coeffp = coeffs;
inputp = &insamp[filterLength - 1 + n];
acc = 0;
for ( k = 0; k < filterLength; k++ ) {
acc += (*coeffp++) * (*inputp--);
}
output[n] = acc;
}
// shift input samples back in time for next time
memmove( &insamp[0], &insamp[length],
(filterLength - 1) * sizeof(double) );

}

//////////////////////////////////////////////////////////////
// Test program
//////////////////////////////////////////////////////////////

// bandpass filter centred around 1000 Hz
// sampling rate = 8000 Hz

#define FILTER_LEN 63
double coeffs[ FILTER_LEN ] =
{
-0.0448093, 0.0322875, 0.0181163, 0.0087615, 0.0056797,
0.0086685, 0.0148049, 0.0187190, 0.0151019, 0.0027594,
-0.0132676, -0.0232561, -0.0187804, 0.0006382, 0.0250536,
0.0387214, 0.0299817, 0.0002609, -0.0345546, -0.0525282,
-0.0395620, 0.0000246, 0.0440998, 0.0651867, 0.0479110,
0.0000135, -0.0508558, -0.0736313, -0.0529380, -0.0000709,
0.0540186, 0.0766746, 0.0540186, -0.0000709, -0.0529380,
-0.0736313, -0.0508558, 0.0000135, 0.0479110, 0.0651867,
0.0440998, 0.0000246, -0.0395620, -0.0525282, -0.0345546,
0.0002609, 0.0299817, 0.0387214, 0.0250536, 0.0006382,
-0.0187804, -0.0232561, -0.0132676, 0.0027594, 0.0151019,
0.0187190, 0.0148049, 0.0086685, 0.0056797, 0.0087615,
0.0181163, 0.0322875, -0.0448093
};

void intToFloat( int16_t *input, double *output, int length )
{
int i;

for ( i = 0; i < length; i++ ) {
output[i] = (double)input[i];
}
}

void floatToInt( double *input, int16_t *output, int length )
{
int i;

for ( i = 0; i < length; i++ ) {
if ( input[i] > 32767.0 ) {
input[i] = 32767.0;
} else if ( input[i] < -32768.0 ) {
input[i] = -32768.0;
}
// convert
output[i] = (int16_t)input[i];
}
}

// number of samples to read per loop
#define SAMPLES 80

int main( void )
{
int size;
int16_t input[SAMPLES];
int16_t output[SAMPLES];
double floatInput[SAMPLES];
double floatOutput[SAMPLES];
FILE *in_fid;
FILE *out_fid;

// open the input waveform file
in_fid = fopen( "input.pcm", "rb" );
if ( in_fid == 0 ) {
printf("couldn't open input.pcm");
return -1;
}

// open the output waveform file
out_fid = fopen( "outputFloat.pcm", "wb" );
if ( out_fid == 0 ) {
printf("couldn't open outputFloat.pcm");
return -1;
}

// initialize the filter
firFloatInit();

// process all of the samples
do {
// read samples from file
size = fread( input, sizeof(int16_t), SAMPLES, in_fid );
// convert to doubles
intToFloat( input, floatInput, size );
// perform the filtering
firFloat( coeffs, floatInput, floatOutput, size,
FILTER_LEN );
// convert to ints
floatToInt( floatOutput, output, size );
// write samples to file
fwrite( output, sizeof(int16_t), size, out_fid );
} while ( size != 0 );

fclose( in_fid );
fclose( out_fid );

return 0;
}

//#3
void loop() {
// read the value from input pin
inputValue = analogRead(inputPin);

// send the square wave signal to PA7
analogWrite(ledPin, inputValue / 4);

//#4
analogWrite(PA7, outputVal);

}

 

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

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

Pasha22
Offline
Зарегистрирован: 19.01.2018

Кот открой свою  новую тему - Вредный Кот, пригласи SSS

он будет вешать на твоем хвосте медали за каждой дурной ответ.
 
здесь ты бесполезный.
ssss
Offline
Зарегистрирован: 01.07.2016

Забей на это тухлое дело. Займись чем-то более приземленным. Тебе эту тему не поднять.

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

В среде ардуины фунция main определена в недрах. Если ты её перекрываешь, то теряешь init, setup и loop.  

brokly
brokly аватар
Онлайн
Зарегистрирован: 08.02.2014

Паша, не пей и не кури больше этого никогда ! Следующая остановка будет последней !

Pasha22
Offline
Зарегистрирован: 19.01.2018

Ну и напугал.