Мульти Серво-тестер на STM32F103

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

ua6em, ну и ладно. Я думаю что вопрос связки таймеров можно закрыть, ибо предложенный мной вариант решает вопрос 32-битного захвата PWM сигнала.

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

ua6em пишет:
.еще читал что для именно для 103 процессора нельзя настроить таймер на запуск от фронта и остановку от спада сигнала, либо одно, либо другое


Врут. Причём нагло. Даже на примитивном стм8с это можно сделать. Гейт Модэ называется.

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

dimax пишет:

ua6em, ну и ладно. Я думаю что вопрос связки таймеров можно закрыть, ибо предложенный мной вариант решает вопрос 32-битного захвата PWM сигнала.


Да каждый сам себе режиссер. У древнего 103-го не так уж и много таймеров - кому-то прокатит, а кому-то и нет.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

ssss пишет:
dimax пишет:

ua6em, ну и ладно. Я думаю что вопрос связки таймеров можно закрыть, ибо предложенный мной вариант решает вопрос 32-битного захвата PWM сигнала.

Да каждый сам себе режиссер. У древнего 103-го не так уж и много таймеров - кому-то прокатит, а кому-то и нет.

Тут еще важно умение ими пользоваться )))
Да и вопрос азарта, не малую роль играет

Начало положено:


#include <Servo.h>
Servo myservo_ch1;  // Создаём объекты для контроля сервоприводов
Servo myservo_ch2;  
Servo myservo_ch3;  
Servo myservo_ch4;  
int potpin = PA0;             // Аналоговый пин для присоединения потенциометра (пин А0)
int val_ch2,val_ch3,val_ch4;  // переменные, хранящая значение считываемое с потенциометра
                              // и устанавливаемые взависимости от положения тумблеров

//Счетчик
uint16_t counter_pwm,tau_pwm;

void setup() {
  myservo_ch1.attach(PB6);  // Инициализируем объекты по управлению сервоприводами
  myservo_ch2.attach(PB7);
  myservo_ch3.attach(PB8);
  myservo_ch4.attach(PB9);
 
pinMode(PA6,INPUT_PULLDOWN); // вход измерения PWM счётчик 16 бит (TIM3)

//обнуление регистров
TIMER3_BASE->CR1=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->CCMR2=0; TIMER3_BASE->ARR=65535;
TIMER3_BASE->CR2=0; TIMER3_BASE->PSC= 0; 

//настройка счёта 16 бит
TIMER3_BASE->PSC=0x0011; //divider = 3
TIMER3_BASE->SMCR=(1<<6)|(1<<4)|(1<<2);// TS:101(TI1FP1) SMS:100(RESET MODE)
TIMER3_BASE->CCMR1=(1<<9)|(1<<0);// CC2 input,mapped on TI1, CC1 input,mapped on TI1
TIMER3_BASE->CCER=(1<<5)|(1<<4)|(1<<0);// cc2-capt.en/falling(4,5)   cc1-capt.en/rising(0)   
TIMER3_BASE->EGR=1; //перечитать регистры.
TIMER3_BASE->CR1=(1<<0);// старт захвата PWM

} // END SETUP

// Обработчик счетчика
void count_pwm(){
  counter_pwm = (TIMER3_BASE->CCR1)+1;
  tau_pwm = counter_pwm/24;
   }

// Обработчик сервоприводов
 void servo_go(){
  val_ch2 = analogRead(potpin);               // Считываем значение с потенциометра (0-4096)
  val_ch2 = map(val_ch2, 0, 4096, 544, 2400); // преобразовываем в диапазон стандарта 
  
  // здесь будет обработчик тумблеров
  val_ch3 = 1000;
  val_ch4 = 2000;
  //
  myservo_ch1.writeMicroseconds(tau_pwm);     // В канал 1 значение дублирует измеренное входное 
  myservo_ch2.writeMicroseconds(val_ch2);     // В канал 2 значение задаваемое потенциометром
  myservo_ch3.writeMicroseconds(val_ch3);     // Канал калибровки серв (1000 - 1500 - 2000 мксек)
  myservo_ch4.writeMicroseconds(val_ch4);     // Канал калибровки двигателей
  }  

void loop() {
count_pwm();
servo_go();

Serial.print(" PWM = ");
Serial.println(tau_pwm); 
delay(300);
}

 

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

dimax пишет:

ua6em, ну и ладно. Я думаю что вопрос связки таймеров можно закрыть, ибо предложенный мной вариант решает вопрос 32-битного захвата PWM сигнала.

Это да - вполне, в этом проекте даже излишне!
Вопрос, даже два?
1.как выделить из этого скетча только один таймер (первый)
2. как задать ему тактирование от 72 мегагерц с предделителем 3 (тактирование 24 мегагерца)
В этом случае я укладываюсь в диапазон разрешения счетчика требуемый мне - до 2400 мксек

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

ua6em,  а что их выделять -они друг с другом не связаны. Можно любой брать.  В настройках этих таймеров -единственное отличие - у одного прописан делитель /65536,  у другого  /1.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

dimax пишет:

ua6em, я кстати не случайно не написал строчки Serial.begin() он там включен по-умолчанию :)

Входы да, запаралелить физически.

Дима, попробовал из твоего скетча отсечь на данном этапе ненужное, оставить один 16 битный счетчик, прескалер поставил на 3, то-есть частота на входе счетчика должна быть 24 мегагерца.
Поясни, что не так?
Как я понимаю, счетчик отрицательным фронтом должен дёрнуть прерывание, оно вызвать нужную нам функцию, которая и сохранит значение счетчика в нашей переменной и одновременно подготовит счетчик к дальнейшему обсчету следующего входного импульса.
???

Скетч:
 

uint16_t counter_pwm,tau_pwm;

void setup() {
pinMode(PA6,INPUT_PULLDOWN); // вход измерения PWM счётчик 16 бит (TIM3)

//обнуление регистров
TIMER3_BASE->CR1=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->CCMR2=0; TIMER3_BASE->ARR=65535;
TIMER3_BASE->CR2=0; TIMER3_BASE->PSC= 0; 

//настройка счёта 16 бит
TIMER3_BASE->PSC=0x0011; //divider = 3
TIMER3_BASE->SMCR=(1<<6)|(1<<4)|(1<<2);// TS:101(TI1FP1) SMS:100(RESET MODE)
TIMER3_BASE->CCMR1=(1<<9)|(1<<0);// CC2 input,mapped on TI1, CC1 input,mapped on TI1
TIMER3_BASE->CCER=(1<<5)|(1<<4)|(1<<0);// cc2-capt.en/falling(4,5)   cc1-capt.en/rising(0)   
TIMER3_BASE->EGR=1; //перечитать регистры.
TIMER3_BASE->CR1=(1<<0);// старт захвата PWM

} // END SETUP

void count_pwm(){
  counter_pwm = (TIMER3_BASE->CCR1)+1;
  tau_pwm = counter_pwm/24;
   }

void loop() {
count_pwm();
Serial.print(" PWM = ");
Serial.println(tau_pwm); 
delay(300);
}

 

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

ua6em, а где прерывание то? Его же прописать нужно.  Делитель на /3 -это 2. Там счёт с ноля.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

dimax пишет:

ua6em, а где прерывание то? Его же прописать нужно.  Делитель на /3 -это 2. Там счёт с ноля.


Это как?
По прерыванию

так исправил?

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

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

dimax пишет:

ua6em, по поводу того апноута AN2592: Провёл вчера большую работу, по проверке того алгоритма, что там описан. Там три модели обьединения таймеров, нас интересует "32-bit input capture timer resolution"  Сделал всё как там написано - не работает.
У меня очень веские основания полагать, что автор этого апноута либо никогда не запускал таймер в этом режиме  и выложил голые догадки,  либо же при написании алгоритма допустил ошибки (или не указал что-то важное что тоже приравниваю к ошибке). В доказательство этого не только тот факт, что у меня не получилось добиться работы, но и то, что нигде в инете нет рабочего примера именно этого алгоритма. Я поставил "на уши" гугля и яндекс - оба клянуться, что ничего не знают. Т.е.  выходит этим способом никто не объединял таймеры.    Ещё одним косвенным подтверждением того, что автор апноута отнёсся невнимательно к составлению алгоритма - некоторые настройки описаны довольно точно, например "selecting TI1FP1 as the input trigger by setting the TS bits in the SMCR register" -очень точное указание что делать. Некоторые размыто, но всё же понятно "the external signal is connected to channel 1 and the rising edge is configured as the active edge"  , - кто работал с таймерами тот догадается какие биты прописать для rising edge . А  какие то настройки и вовсе не указаны, например то, что тот же вход, указанный в предыдущей строке  нужно перевести в режим "capture input", об этом почему-то ни слова. В общем алгоритм нерабочий. Если кто-то из сведущих коллег возьмётся подтвердить, или опровергнуть на практическом примере -буду благодарен.

Подниму еще раз тему, интересно, есть здесь специалисты по STM32?
В настройках Cube Mx я не увидел, что таким образом можно триггера включить

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

Не все тригеры одинаково полезны. Для таймеров 1 и 8  есть таблица 82 в мануале:

Table 82. TIMx Internal trigger connection(1)
1. When a timer is not present in the product, the corresponding trigger ITRx is not available.
Slave TIM ITR0 (TS = 000) ITR1 (TS = 001) ITR2 (TS = 010) ITR3 (TS = 011)
TIM1 TIM5 TIM2 TIM3 TIM4
TIM8 TIM1 TIM2 TIM4 TIM5
 
Собственно для таймера 1 есть тригеры ITR1 ITR2  ITR3 от таймеров TIM2 TIM3 TIM4 их и надо выбирать как источники в настройках slave моды на третей закладке в свойстве конкретного таймера ( в данном случае TIM1).
 
для остальных таймеров таблица 86
 
Table 86. TIMx Internal trigger connection(1)
1. When a timer is not present in the product, the corresponding trigger ITRx is not available.
Slave TIM    ITR0  ITR1  ITR2  ITR3 
TIM2           TIM1 TIM8 TIM3 TIM4
TIM3           TIM1 TIM2 TIM5 TIM4
TIM4           TIM1 TIM2 TIM3 TIM8
TIM5           TIM2 TIM3 TIM4 TIM8
 
Если какогото таймера нет в соответствующем корпусе то и тригера отсутствуют.
Там же в мануале есть фигура 140 и вокруг неё описаны все возможные режимы каскадирования таймеров. 
В часности есть раздел Starting 2 timers synchronously in response to an external trigger это примерно то же,что делал Дима запуская два таймера с разной частотой клока. Здесь гарантируют синхронное срабатывание.

 

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Я правильно понимаю, в левой колоночке - мастер таймер, в правых -слэйв таймера?
То есть  для:

Мастер TIM1  Слэйв TIM2 для последнего входом будет триггер ITR1

Перечислил применительно к STM32F103С8

Наверно все таки не так?

 

 

 

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

Нет. По английски же написано - левая слейв таймер. Для него тригеры ITR0  ITR1  ITR2  ITR3 будут выдавать мастер таймеры под соответствующими тригерами. Например если слейв TIM3 то ITR0 будет выдавать мастер TIM1, ITR1- TIM2,  ITR3 - TIM4. 

А вот ITR2 для TIM3 никто выдавать не будет, т.к. TIM5 у 103с8 отсутствует.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

nik182 пишет:

Нет. По английски же написано - левая слейв таймер. Для него тригеры ITR0  ITR1  ITR2  ITR3 будут выдавать мастер таймеры под соответствующими тригерами. Например если слейв TIM3 то ITR0 будет выдавать мастер TIM1, ITR1- TIM2,  ITR3 - TIM4. 

А вот ITR2 для TIM3 никто выдавать не будет, т.к. TIM5 у 103с8 отсутствует.


ааа, тогда всё логично, на выходе TIM1 - ITR0, TIM2-ITR1, TIM3-ITR2, TIM4-ITR3, слейв цеплять к выходу )))
Вся таблица уместилась в одну строку )))

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Попытался сконфигурировать как-то так :
main.c

/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  ** This notice applies to any and all portions of this file
  * that are not between comment pairs USER CODE BEGIN and
  * USER CODE END. Other portions of this file, whether 
  * inserted by the user or by software development tools
  * are owned by their respective copyright owners.
  *
  * COPYRIGHT(c) 2018 STMicroelectronics
  *
  * Redistribution and use in source and binary forms, with or without modification,
  * are permitted provided that the following conditions are met:
  *   1. Redistributions of source code must retain the above copyright notice,
  *      this list of conditions and the following disclaimer.
  *   2. Redistributions in binary form must reproduce the above copyright notice,
  *      this list of conditions and the following disclaimer in the documentation
  *      and/or other materials provided with the distribution.
  *   3. Neither the name of STMicroelectronics nor the names of its contributors
  *      may be used to endorse or promote products derived from this software
  *      without specific prior written permission.
  *
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  ******************************************************************************
  */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "stm32f1xx_hal.h"

/* USER CODE BEGIN Includes */

/* USER CODE END Includes */

/* Private variables ---------------------------------------------------------*/
I2C_HandleTypeDef hi2c1;

TIM_HandleTypeDef htim2;
TIM_HandleTypeDef htim3;

/* USER CODE BEGIN PV */
/* Private variables ---------------------------------------------------------*/

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_TIM3_Init(void);
static void MX_TIM2_Init(void);
static void MX_I2C1_Init(void);

/* USER CODE BEGIN PFP */
/* Private function prototypes -----------------------------------------------*/

/* USER CODE END PFP */

/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  *
  * @retval None
  */
int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration----------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_TIM3_Init();
  MX_TIM2_Init();
  MX_I2C1_Init();
  /* USER CODE BEGIN 2 */

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {

  /* USER CODE END WHILE */

  /* USER CODE BEGIN 3 */

  }
  /* USER CODE END 3 */

}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{

  RCC_OscInitTypeDef RCC_OscInitStruct;
  RCC_ClkInitTypeDef RCC_ClkInitStruct;

    /**Initializes the CPU, AHB and APB busses clocks 
    */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

    /**Initializes the CPU, AHB and APB busses clocks 
    */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

    /**Configure the Systick interrupt time 
    */
  HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);

    /**Configure the Systick 
    */
  HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);

  /* SysTick_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
}

/* I2C1 init function */
static void MX_I2C1_Init(void)
{

  hi2c1.Instance = I2C1;
  hi2c1.Init.ClockSpeed = 100000;
  hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
  hi2c1.Init.OwnAddress1 = 0;
  hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
  hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
  hi2c1.Init.OwnAddress2 = 0;
  hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
  hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
  if (HAL_I2C_Init(&hi2c1) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

}

/* TIM2 init function */
static void MX_TIM2_Init(void)
{

  TIM_SlaveConfigTypeDef sSlaveConfig;
  TIM_MasterConfigTypeDef sMasterConfig;

  htim2.Instance = TIM2;
  htim2.Init.Prescaler = 0;
  htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim2.Init.Period = 0;
  htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  if (HAL_TIM_Base_Init(&htim2) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

  sSlaveConfig.SlaveMode = TIM_SLAVEMODE_TRIGGER;
  sSlaveConfig.InputTrigger = TIM_TS_ITR2;
  if (HAL_TIM_SlaveConfigSynchronization(&htim2, &sSlaveConfig) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

}

/* TIM3 init function */
static void MX_TIM3_Init(void)
{

  TIM_ClockConfigTypeDef sClockSourceConfig;
  TIM_MasterConfigTypeDef sMasterConfig;
  TIM_IC_InitTypeDef sConfigIC;

  htim3.Instance = TIM3;
  htim3.Init.Prescaler = 3;
  htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim3.Init.Period = 0;
  htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  if (HAL_TIM_Base_Init(&htim3) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim3, &sClockSourceConfig) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

  if (HAL_TIM_IC_Init(&htim3) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

  sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING;
  sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI;
  sConfigIC.ICPrescaler = TIM_ICPSC_DIV1;
  sConfigIC.ICFilter = 0;
  if (HAL_TIM_IC_ConfigChannel(&htim3, &sConfigIC, TIM_CHANNEL_1) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

}

/** Configure pins as 
        * Analog 
        * Input 
        * Output
        * EVENT_OUT
        * EXTI
*/
static void MX_GPIO_Init(void)
{

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOC_CLK_ENABLE();
  __HAL_RCC_GPIOD_CLK_ENABLE();
  __HAL_RCC_GPIOA_CLK_ENABLE();
  __HAL_RCC_GPIOB_CLK_ENABLE();

}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @param  file: The file name as string.
  * @param  line: The line in file as a number.
  * @retval None
  */
void _Error_Handler(char *file, int line)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  while(1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t* file, uint32_t line)
{ 
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

/**
  * @}
  */

/**
  * @}
  */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
/**
  ******************************************************************************
  * @file    stm32f1xx_it.c
  * @brief   Interrupt Service Routines.
  ******************************************************************************
  *
  * COPYRIGHT(c) 2018 STMicroelectronics
  *
  * Redistribution and use in source and binary forms, with or without modification,
  * are permitted provided that the following conditions are met:
  *   1. Redistributions of source code must retain the above copyright notice,
  *      this list of conditions and the following disclaimer.
  *   2. Redistributions in binary form must reproduce the above copyright notice,
  *      this list of conditions and the following disclaimer in the documentation
  *      and/or other materials provided with the distribution.
  *   3. Neither the name of STMicroelectronics nor the names of its contributors
  *      may be used to endorse or promote products derived from this software
  *      without specific prior written permission.
  *
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  ******************************************************************************
  */
/* Includes ------------------------------------------------------------------*/
#include "stm32f1xx_hal.h"
#include "stm32f1xx.h"
#include "stm32f1xx_it.h"

/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/* External variables --------------------------------------------------------*/
extern TIM_HandleTypeDef htim3;

/******************************************************************************/
/*            Cortex-M3 Processor Interruption and Exception Handlers         */ 
/******************************************************************************/

/**
* @brief This function handles Non maskable interrupt.
*/
void NMI_Handler(void)
{
  /* USER CODE BEGIN NonMaskableInt_IRQn 0 */

  /* USER CODE END NonMaskableInt_IRQn 0 */
  /* USER CODE BEGIN NonMaskableInt_IRQn 1 */

  /* USER CODE END NonMaskableInt_IRQn 1 */
}

/**
* @brief This function handles Hard fault interrupt.
*/
void HardFault_Handler(void)
{
  /* USER CODE BEGIN HardFault_IRQn 0 */

  /* USER CODE END HardFault_IRQn 0 */
  while (1)
  {
    /* USER CODE BEGIN W1_HardFault_IRQn 0 */
    /* USER CODE END W1_HardFault_IRQn 0 */
  }
  /* USER CODE BEGIN HardFault_IRQn 1 */

  /* USER CODE END HardFault_IRQn 1 */
}

/**
* @brief This function handles Memory management fault.
*/
void MemManage_Handler(void)
{
  /* USER CODE BEGIN MemoryManagement_IRQn 0 */

  /* USER CODE END MemoryManagement_IRQn 0 */
  while (1)
  {
    /* USER CODE BEGIN W1_MemoryManagement_IRQn 0 */
    /* USER CODE END W1_MemoryManagement_IRQn 0 */
  }
  /* USER CODE BEGIN MemoryManagement_IRQn 1 */

  /* USER CODE END MemoryManagement_IRQn 1 */
}

/**
* @brief This function handles Prefetch fault, memory access fault.
*/
void BusFault_Handler(void)
{
  /* USER CODE BEGIN BusFault_IRQn 0 */

  /* USER CODE END BusFault_IRQn 0 */
  while (1)
  {
    /* USER CODE BEGIN W1_BusFault_IRQn 0 */
    /* USER CODE END W1_BusFault_IRQn 0 */
  }
  /* USER CODE BEGIN BusFault_IRQn 1 */

  /* USER CODE END BusFault_IRQn 1 */
}

/**
* @brief This function handles Undefined instruction or illegal state.
*/
void UsageFault_Handler(void)
{
  /* USER CODE BEGIN UsageFault_IRQn 0 */

  /* USER CODE END UsageFault_IRQn 0 */
  while (1)
  {
    /* USER CODE BEGIN W1_UsageFault_IRQn 0 */
    /* USER CODE END W1_UsageFault_IRQn 0 */
  }
  /* USER CODE BEGIN UsageFault_IRQn 1 */

  /* USER CODE END UsageFault_IRQn 1 */
}

/**
* @brief This function handles System service call via SWI instruction.
*/
void SVC_Handler(void)
{
  /* USER CODE BEGIN SVCall_IRQn 0 */

  /* USER CODE END SVCall_IRQn 0 */
  /* USER CODE BEGIN SVCall_IRQn 1 */

  /* USER CODE END SVCall_IRQn 1 */
}

/**
* @brief This function handles Debug monitor.
*/
void DebugMon_Handler(void)
{
  /* USER CODE BEGIN DebugMonitor_IRQn 0 */

  /* USER CODE END DebugMonitor_IRQn 0 */
  /* USER CODE BEGIN DebugMonitor_IRQn 1 */

  /* USER CODE END DebugMonitor_IRQn 1 */
}

/**
* @brief This function handles Pendable request for system service.
*/
void PendSV_Handler(void)
{
  /* USER CODE BEGIN PendSV_IRQn 0 */

  /* USER CODE END PendSV_IRQn 0 */
  /* USER CODE BEGIN PendSV_IRQn 1 */

  /* USER CODE END PendSV_IRQn 1 */
}

/**
* @brief This function handles System tick timer.
*/
void SysTick_Handler(void)
{
  /* USER CODE BEGIN SysTick_IRQn 0 */

  /* USER CODE END SysTick_IRQn 0 */
  HAL_IncTick();
  HAL_SYSTICK_IRQHandler();
  /* USER CODE BEGIN SysTick_IRQn 1 */

  /* USER CODE END SysTick_IRQn 1 */
}

/******************************************************************************/
/* STM32F1xx Peripheral Interrupt Handlers                                    */
/* Add here the Interrupt Handlers for the used peripherals.                  */
/* For the available peripheral interrupt handler names,                      */
/* please refer to the startup file (startup_stm32f1xx.s).                    */
/******************************************************************************/

/**
* @brief This function handles TIM3 global interrupt.
*/
void TIM3_IRQHandler(void)
{
  /* USER CODE BEGIN TIM3_IRQn 0 */

  /* USER CODE END TIM3_IRQn 0 */
  HAL_TIM_IRQHandler(&htim3);
  /* USER CODE BEGIN TIM3_IRQn 1 */

  /* USER CODE END TIM3_IRQn 1 */
}

/* USER CODE BEGIN 1 */

/* USER CODE END 1 */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

 

/**
  ******************************************************************************
  * File Name          : stm32f1xx_hal_msp.c
  * Description        : This file provides code for the MSP Initialization 
  *                      and de-Initialization codes.
  ******************************************************************************
  ** This notice applies to any and all portions of this file
  * that are not between comment pairs USER CODE BEGIN and
  * USER CODE END. Other portions of this file, whether 
  * inserted by the user or by software development tools
  * are owned by their respective copyright owners.
  *
  * COPYRIGHT(c) 2018 STMicroelectronics
  *
  * Redistribution and use in source and binary forms, with or without modification,
  * are permitted provided that the following conditions are met:
  *   1. Redistributions of source code must retain the above copyright notice,
  *      this list of conditions and the following disclaimer.
  *   2. Redistributions in binary form must reproduce the above copyright notice,
  *      this list of conditions and the following disclaimer in the documentation
  *      and/or other materials provided with the distribution.
  *   3. Neither the name of STMicroelectronics nor the names of its contributors
  *      may be used to endorse or promote products derived from this software
  *      without specific prior written permission.
  *
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  ******************************************************************************
  */
/* Includes ------------------------------------------------------------------*/
#include "stm32f1xx_hal.h"
extern void _Error_Handler(char *, int);
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */
/**
  * Initializes the Global MSP.
  */
void HAL_MspInit(void)
{
  /* USER CODE BEGIN MspInit 0 */

  /* USER CODE END MspInit 0 */

  __HAL_RCC_AFIO_CLK_ENABLE();
  __HAL_RCC_PWR_CLK_ENABLE();

  HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);

  /* System interrupt init*/
  /* MemoryManagement_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(MemoryManagement_IRQn, 0, 0);
  /* BusFault_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(BusFault_IRQn, 0, 0);
  /* UsageFault_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(UsageFault_IRQn, 0, 0);
  /* SVCall_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(SVCall_IRQn, 0, 0);
  /* DebugMonitor_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DebugMonitor_IRQn, 0, 0);
  /* PendSV_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(PendSV_IRQn, 0, 0);
  /* SysTick_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);

    /**DISABLE: JTAG-DP Disabled and SW-DP Disabled 
    */
  __HAL_AFIO_REMAP_SWJ_DISABLE();

  /* USER CODE BEGIN MspInit 1 */

  /* USER CODE END MspInit 1 */
}

void HAL_I2C_MspInit(I2C_HandleTypeDef* hi2c)
{

  GPIO_InitTypeDef GPIO_InitStruct;
  if(hi2c->Instance==I2C1)
  {
  /* USER CODE BEGIN I2C1_MspInit 0 */

  /* USER CODE END I2C1_MspInit 0 */
  
    /**I2C1 GPIO Configuration    
    PB6     ------> I2C1_SCL
    PB7     ------> I2C1_SDA 
    */
    GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_7;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

    /* Peripheral clock enable */
    __HAL_RCC_I2C1_CLK_ENABLE();
  /* USER CODE BEGIN I2C1_MspInit 1 */

  /* USER CODE END I2C1_MspInit 1 */
  }

}

void HAL_I2C_MspDeInit(I2C_HandleTypeDef* hi2c)
{

  if(hi2c->Instance==I2C1)
  {
  /* USER CODE BEGIN I2C1_MspDeInit 0 */

  /* USER CODE END I2C1_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_I2C1_CLK_DISABLE();
  
    /**I2C1 GPIO Configuration    
    PB6     ------> I2C1_SCL
    PB7     ------> I2C1_SDA 
    */
    HAL_GPIO_DeInit(GPIOB, GPIO_PIN_6|GPIO_PIN_7);

  /* USER CODE BEGIN I2C1_MspDeInit 1 */

  /* USER CODE END I2C1_MspDeInit 1 */
  }

}

void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* htim_base)
{

  GPIO_InitTypeDef GPIO_InitStruct;
  if(htim_base->Instance==TIM2)
  {
  /* USER CODE BEGIN TIM2_MspInit 0 */

  /* USER CODE END TIM2_MspInit 0 */
    /* Peripheral clock enable */
    __HAL_RCC_TIM2_CLK_ENABLE();
  /* USER CODE BEGIN TIM2_MspInit 1 */

  /* USER CODE END TIM2_MspInit 1 */
  }
  else if(htim_base->Instance==TIM3)
  {
  /* USER CODE BEGIN TIM3_MspInit 0 */

  /* USER CODE END TIM3_MspInit 0 */
    /* Peripheral clock enable */
    __HAL_RCC_TIM3_CLK_ENABLE();
  
    /**TIM3 GPIO Configuration    
    PA6     ------> TIM3_CH1 
    */
    GPIO_InitStruct.Pin = GPIO_PIN_6;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_PULLDOWN;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    /* TIM3 interrupt Init */
    HAL_NVIC_SetPriority(TIM3_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(TIM3_IRQn);
  /* USER CODE BEGIN TIM3_MspInit 1 */

  /* USER CODE END TIM3_MspInit 1 */
  }

}

void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef* htim_base)
{

  if(htim_base->Instance==TIM2)
  {
  /* USER CODE BEGIN TIM2_MspDeInit 0 */

  /* USER CODE END TIM2_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_TIM2_CLK_DISABLE();
  /* USER CODE BEGIN TIM2_MspDeInit 1 */

  /* USER CODE END TIM2_MspDeInit 1 */
  }
  else if(htim_base->Instance==TIM3)
  {
  /* USER CODE BEGIN TIM3_MspDeInit 0 */

  /* USER CODE END TIM3_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_TIM3_CLK_DISABLE();
  
    /**TIM3 GPIO Configuration    
    PA6     ------> TIM3_CH1 
    */
    HAL_GPIO_DeInit(GPIOA, GPIO_PIN_6);

    /* TIM3 interrupt DeInit */
    HAL_NVIC_DisableIRQ(TIM3_IRQn);
  /* USER CODE BEGIN TIM3_MspDeInit 1 */

  /* USER CODE END TIM3_MspDeInit 1 */
  }

}

/* USER CODE BEGIN 1 */

/* USER CODE END 1 */

/**
  * @}
  */

/**
  * @}
  */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

 

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

А где одна из функций для собственно запуска?

Input Capture : HAL_TIM_IC_Start(), HAL_TIM_IC_Start_DMA(),HAL_TIM_IC_Start_IT()

Должно находиться между

105   /* USER CODE BEGIN 2 */
106  
107   /* USER CODE END 2 */

Без них ничего работать не будет и проверить не получится. Взято из UM1850. Стр 546 и вокруг много полезного.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Это видимо ручками надо прописывать, так как считаются уже пользовательские...
Кошмаррр!!! Придётся столько читать...Ардуино IDE отдыхает...
Видимо то и пинают, все кому не попадя, даже большие профессионалы - за невероятную лёгкость вхождения непрофессионалов )))

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

ua6em пишет:

Это видимо ручками надо прописывать, так как считаются уже пользовательские...
Кошмаррр!!! Придётся столько читать...Ардуино IDE отдыхает...
Видимо то и пинают, все кому не попадя, даже большие профессионалы - за невероятную лёгкость вхождения непрофессионалов )))

Да не .. в СТМ просто "хотели как лучше, а получилось как всегда" (с) Черномырдин.

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

Потребовалось добавить в работающий проект температуру и влажность с датчика DTH22. Вспомнил эту замечательную тему, копнул примеры на 103с8 и обнаружил инициализацию одного таймера для приема PWM на STL.

  /* TIM3 configuration: PWM Input mode ------------------------
     The external signal is connected to TIM3 CH2 pin (PA.01), 
     The Rising edge is used as active edge,
     The TIM3 CCR2 is used to compute the frequency value 
     The TIM3 CCR1 is used to compute the duty cycle value
  ------------------------------------------------------------ */

  TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;
  TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
  TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
  TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
  TIM_ICInitStructure.TIM_ICFilter = 0x0;

  TIM_PWMIConfig(TIM3, &TIM_ICInitStructure);

  /* Select the TIM3 Input Trigger: TI2FP2 */
  TIM_SelectInputTrigger(TIM3, TIM_TS_TI2FP2);

  /* Select the slave Mode: Reset Mode */
  TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset);

  /* Enable the Master/Slave Mode */
  TIM_SelectMasterSlaveMode(TIM3, TIM_MasterSlaveMode_Enable);

  /* TIM enable counter */
  TIM_Cmd(TIM3, ENABLE);

  /* Enable the CC2 Interrupt Request */
  TIM_ITConfig(TIM3, TIM_IT_CC2, ENABLE);

Получаем значения в прерывании.

void TIM3_IRQHandler(void)
{
  /* Clear TIM3 Capture compare interrupt pending bit */
  TIM_ClearITPendingBit(TIM3, TIM_IT_CC2);

  /* Get the Input Capture value */
  IC2Value = TIM_GetCapture2(TIM3);

  if (IC2Value != 0)
  {
    /* Duty cycle computation */
    DutyCycle = (TIM_GetCapture1(TIM3) * 100) / IC2Value;

    /* Frequency computation */
    Frequency = SystemCoreClock / IC2Value;
  }
  else
  {
    DutyCycle = 0;
    Frequency = 0;
  }
}

В куб всё это переводится очень просто - названия очень созвучны с позициями куба. Заработало сразу. DHT данные выдает в формате близком к PWM. Получились тики 53мкс 72мкс и 128мкс. Таймер тактировал 1 МГц. 

В результате имеем чтение датчика через прерывания. Соверщенно не мешает основной программе. Можно ещё DMA прикрутить, но и так отлично получилось. Это я к вопросу о небходимости 32 разрядного датчика для измерения PWM сигнала. 16 битного таймера хватит для 20мс периода сервомашинки. Длительность сигнала управления можно получить с точностью до 0.5мкс. Куда уж точнее?  

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

nik182 пишет:

Потребовалось добавить в работающий проект температуру и влажность с датчика DTH22. Вспомнил эту замечательную тему, копнул примеры на 103с8 и обнаружил инициализацию одного таймера для приема PWM на STL.

  /* TIM3 configuration: PWM Input mode ------------------------
     The external signal is connected to TIM3 CH2 pin (PA.01), 
     The Rising edge is used as active edge,
     The TIM3 CCR2 is used to compute the frequency value 
     The TIM3 CCR1 is used to compute the duty cycle value
  ------------------------------------------------------------ */

  TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;
  TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
  TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
  TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
  TIM_ICInitStructure.TIM_ICFilter = 0x0;

  TIM_PWMIConfig(TIM3, &TIM_ICInitStructure);

  /* Select the TIM3 Input Trigger: TI2FP2 */
  TIM_SelectInputTrigger(TIM3, TIM_TS_TI2FP2);

  /* Select the slave Mode: Reset Mode */
  TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset);

  /* Enable the Master/Slave Mode */
  TIM_SelectMasterSlaveMode(TIM3, TIM_MasterSlaveMode_Enable);

  /* TIM enable counter */
  TIM_Cmd(TIM3, ENABLE);

  /* Enable the CC2 Interrupt Request */
  TIM_ITConfig(TIM3, TIM_IT_CC2, ENABLE);

Получаем значения в прерывании.

void TIM3_IRQHandler(void)
{
  /* Clear TIM3 Capture compare interrupt pending bit */
  TIM_ClearITPendingBit(TIM3, TIM_IT_CC2);

  /* Get the Input Capture value */
  IC2Value = TIM_GetCapture2(TIM3);

  if (IC2Value != 0)
  {
    /* Duty cycle computation */
    DutyCycle = (TIM_GetCapture1(TIM3) * 100) / IC2Value;

    /* Frequency computation */
    Frequency = SystemCoreClock / IC2Value;
  }
  else
  {
    DutyCycle = 0;
    Frequency = 0;
  }
}

В куб всё это переводится очень просто - названия очень созвучны с позициями куба. Заработало сразу. DHT данные выдает в формате близком к PWM. Получились тики 53мкс 72мкс и 128мкс. Таймер тактировал 1 МГц. 

В результате имеем чтение датчика через прерывания. Соверщенно не мешает основной программе. Можно ещё DMA прикрутить, но и так отлично получилось. Это я к вопросу о небходимости 32 разрядного датчика для измерения PWM сигнала. 16 битного таймера хватит для 20мс периода сервомашинки. Длительность сигнала управления можно получить с точностью до 0.5мкс. Куда уж точнее?  

Если тактировать 16 битный таймер частотой 24 мегагерца, то для диапазона 544-2400 мксек разрядности хватает.

Вопрос? Как эти воспользоваться в реализации ARDUINO IDE

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Проба 3

/*
 * V1.03 - 12.11.2018 Объединены сктчи DIMAX и мой по выводу значений на сервы, компилируется, работоспособность
 * и адекватность не проверялись. Измеряемый сигнал подавать на два пина PA0 и PA6
 * (по калибровке передатчика показания соответствуют)
 */

#include <Servo.h>
Servo myservo_ch1;  // Создаём объекты для контроля сервоприводов
Servo myservo_ch2;  
Servo myservo_ch3;  
Servo myservo_ch4;  

unsigned int potpin = PA2;                     // Аналоговый пин для присоединения потенциометра (пин А2)
unsigned int val_ch1,val_ch2,val_ch3,val_ch4;  // переменные, хранящая значение считываемое с потенциометра
                                               // и устанавливаемые взависимости от положения тумблеров
//Счетчик
uint32_t imp_long, imp_hi;

void setup() {
  myservo_ch1.attach(PB6);  // Инициализируем объекты по управлению сервоприводами
  myservo_ch2.attach(PB7);
  myservo_ch3.attach(PB8);
  myservo_ch4.attach(PB9);

pinMode(PA6,INPUT_PULLDOWN); // вход измерения PWM счёт младших 16 бит
pinMode(PA0,INPUT_PULLDOWN); // вход измерения PWM счёт старших 16 бит 

//обнуление регистров
TIMER3_BASE->CR1=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->CCMR2=0; TIMER3_BASE->ARR=65535;
TIMER3_BASE->CR2=0; TIMER3_BASE->PSC= 0; 
TIMER2_BASE->CR1=0;//стоп таймер 
TIMER2_BASE->CCER=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->SMCR=0; TIMER2_BASE->ARR=65535;

//настройка счёта младших 16 бит
TIMER3_BASE->SMCR=(1<<6)|(1<<4)|(1<<2);// TS:101(TI1FP1) SMS:100(RESET MODE)
TIMER3_BASE->CCMR1=(1<<9)|(1<<0);// CC2 input,mapped on TI1, CC1 input,mapped on TI1
TIMER3_BASE->CCER=(1<<5)|(1<<4)|(1<<0);// cc2-capt.en/falling(4,5)   cc1-capt.en/rising(0)   
TIMER3_BASE->EGR=1; //перечитать регистры.
TIMER3_BASE->CR1=(1<<0);// старт захвата PWM
//настройка счёта старших 16 бит
TIMER2_BASE->PSC=0xffff; //divider =65536
TIMER2_BASE->SMCR=(1<<6)|(1<<4)|(1<<2);//TS:101(TI1FP1) SMS:100(RESET MODE)
TIMER2_BASE->CCMR1=(1<<9)|(1<<0);// CC2 input,mapped on TI1, CC1 input,mapped on TI1
TIMER2_BASE->CCER=(1<<5)|(1<<4)|(1<<0);// cc2-capt.en/falling(4,5)   cc1-capt.en/rising(0)   
TIMER2_BASE->EGR=1; //перечитать регистры.
TIMER2_BASE->CR1=(1<<0);// старт захвата PWM

} // END SETUP *********************


// Обработчик счетчика **************
void count_pwm(){
      imp_long = (TIMER3_BASE->CCR1 |  TIMER2_BASE->CCR1 << 16) +1  ;
      imp_hi = (TIMER3_BASE->CCR2 |  TIMER2_BASE->CCR2 << 16) +1 ;
      Serial.print(" long="); Serial.print( imp_long ); Serial.print(" hi=");Serial.print( imp_hi );
      Serial.print(" freq="); Serial.print( (float)F_CPU/imp_long);
      Serial.println("  ");
      //delay(300);
}
   

// Обработчик сервоприводов **********
 void servo_go(){
  val_ch2 = analogRead(potpin);               // Считываем значение с потенциометра (0-4096)
  val_ch2 = map(val_ch2, 0, 4096, 544, 2400); // преобразовываем в диапазон стандарта 
  
  // здесь будет обработчик тумблеров
   val_ch1 = imp_hi/72;
//  val_ch2 = 1000;
  val_ch3 = 1500;
  val_ch4 = 2000;
  //
  myservo_ch1.writeMicroseconds(val_ch1);     // В канал 1 значение дублирует измеренное входное 
  myservo_ch2.writeMicroseconds(val_ch2);     // В канал 2 значение задаваемое потенциометром
  myservo_ch3.writeMicroseconds(val_ch3);     // Канал калибровки серв (1000 - 1500 - 2000 мксек)
  myservo_ch4.writeMicroseconds(val_ch4);     // Канал калибровки двигателей
  }  


void loop() {
count_pwm();
servo_go();

Serial.print(F(" PWM = "));
//Serial.println(tau_pwm); 
Serial.println(val_ch1); 
Serial.println(val_ch2);
Serial.println(val_ch3); 
Serial.println(val_ch4); 
delay(300);
}

 

a5021
Offline
Зарегистрирован: 07.07.2013

Сброс таймеру можно делать конечно и занулением регистров, но есть способ попроще: у STM32F103 существуют два регистра, взведение того или иного бита в которых приводит к аппаратному сбросу соответствующего периферийного блока. Речь о RCC_BASE->APB1RSTR и RCC_BASE->APB2RSTR, если описывать их в стиле вышеприведенного кода. Аппаратный резет обоих таймеров мог бы выглядеть, например, так:

RCC_BASE->APB1RSTR |= (0x1U << (0U));   /* 0x00000001 = put Timer 2 into the reset state */ 
RCC_BASE->APB1RSTR |= (0x1U << (1U));   /* 0x00000002 = put Timer 3 into the reset state */
RCC_BASE->APB1RSTR &= ~(0x1U << (0U));  /* release Timer 2 */ 
RCC_BASE->APB1RSTR &= ~(0x1U << (1U));  /* release Timer 3 */

 Могу где-то ошибиться в названиях, но сам смысл, надеюсь, понятен. Назначения битов в регистрах RCC_APBnRSTR, можно уточнить в референсе.

 
ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

a5021 пишет:

Сброс таймеру можно делать конечно и занулением регистров, но есть способ попроще: у STM32F103 существуют два регистра, взведение того или иного бита в которых приводит к аппаратному сбросу соответствующего периферийного блока. Речь о RCC_BASE->APB1RSTR и RCC_BASE->APB2RSTR, если описывать их в стиле вышеприведенного кода. Аппаратный резет обоих таймеров мог бы выглядеть, например, так:

RCC_BASE->APB1RSTR |= (0x1U << (0U));   /* 0x00000001 = put Timer 2 into the reset state */ 
RCC_BASE->APB1RSTR |= (0x1U << (1U));   /* 0x00000002 = put Timer 3 into the reset state */
RCC_BASE->APB1RSTR &= ~(0x1U << (0U));  /* release Timer 2 */ 
RCC_BASE->APB1RSTR &= ~(0x1U << (1U));  /* release Timer 3 */

 Могу где-то ошибиться в названиях, но сам смысл, надеюсь, понятен. Назначения битов в регистрах RCC_APBnRSTR, можно уточнить в референсе.

Залил и Ваш вариант, работает )))

А для использования Таймера 1 с энкодером, сброс также надо делать?

a5021
Offline
Зарегистрирован: 07.07.2013

Я не в курсе используется/инициализируется ли он у них в стартапе, но если выяснить не удается и/или подозрения на сей счет возникают, то сбросить будет не лишним. По тому, как у них написаны библиотеки, одной лишней операцией больше, одной меньше, погоды не делает. :)

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

В stm32duino по умолчанию инициализируются все таймеры.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

andriano пишет:

В stm32duino по умолчанию инициализируются все таймеры.

Это реализовано в загрузчике IDE?

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

Думаю, это реализовано в 20 кбайтах пустого скетча.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

andriano пишет:

Думаю, это реализовано в 20 кбайтах пустого скетча.

Логично!

a5021
Offline
Зарегистрирован: 07.07.2013

Специально качнул эту mapple, а сходу не могу найти, где и как оно инициализируется, хотя согласен, что пустой скетч получается подозрительно толстым.

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

c:\Users\Toshiba\Documents\Arduino\hardware\Arduino_STM32-master\STM32F1\variants\generic_stm32f103c\wirish\boards.cpp

Инициализируется всё.

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

Ну, как бы не совсем все. DMA, напимер, не инициализируется. И еще кое-какая экзотика.

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

DMA даже в кубе не выделена в отдельную периферию. Это как бы намекает. 

a5021
Offline
Зарегистрирован: 07.07.2013

nik182 пишет:
Инициализируется всё.

Не похоже на всё. Кроме DMA, о которой уже сказали, не вижу SPI, I2C, CAN, CRC, как минимум.

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

Не подскажете что из того что не инициализируется используется в wiring? Для wiring проинициализировано всё и даже больше чем для дефолтной ардуины. Остальное инициализируется в дополнительных библиотеках при их подключении. 

a5021
Offline
Зарегистрирован: 07.07.2013

nik182 пишет:
Не подскажете что из того что не инициализируется используется в wiring?

Словом "всё", без уточнений, принято называть самое полное множество. Сложилось так.

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

andriano пишет:

Думаю, это реализовано в 20 кбайтах пустого скетча.

это на какой плате? у меня на "голубой таблетке" пустой скетч менее 11 Кб (11048)

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

Наверное, какая-то разница все же есть:

режим компилляции: smallest

Скетч использует 13764 байт (21%) памяти устройства. Всего доступно 65536 байт.
Глобальные переменные используют 3088 байт (15%) динамической памяти, оставляя 17392 байт для локальных переменных. Максимум: 20480 байт.
 
режим компилляции: fast
Скетч использует 15308 байт (23%) памяти устройства. Всего доступно 65536 байт.
Глобальные переменные используют 3096 байт (15%) динамической памяти, оставляя 17384 байт для локальных переменных. Максимум: 20480 байт.
 

режим компилляции: fastest

Скетч использует 15068 байт (22%) памяти устройства. Всего доступно 65536 байт.
Глобальные переменные используют 3096 байт (15%) динамической памяти, оставляя 17384 байт для локальных переменных. Максимум: 20480 байт.
 
режим компилляции: debug
Скетч использует 15580 байт (23%) памяти устройства. Всего доступно 65536 байт.
Глобальные переменные используют 3096 байт (15%) динамической памяти, оставляя 17384 байт для локальных переменных. Максимум: 20480 байт.
 
Это все для STM32F103C8, 64 k flash, 72 MHz, stm32duino bootloader
 

 

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Проверил у себя на пустом скетче - Скетч использует 13732 байт (10%) памяти устройства. Всего доступно 131072 байт.
Глобальные переменные используют 3088 байт (15%) динамической памяти, оставляя 17392 байт для локальных переменных. Максимум: 20480 байт.