ua6em, ну и ладно. Я думаю что вопрос связки таймеров можно закрыть, ибо предложенный мной вариант решает вопрос 32-битного захвата PWM сигнала.
Это да - вполне, в этом проекте даже излишне!
Вопрос, даже два?
1.как выделить из этого скетча только один таймер (первый)
2. как задать ему тактирование от 72 мегагерц с предделителем 3 (тактирование 24 мегагерца)
В этом случае я укладываюсь в диапазон разрешения счетчика требуемый мне - до 2400 мксек
ua6em, а что их выделять -они друг с другом не связаны. Можно любой брать. В настройках этих таймеров -единственное отличие - у одного прописан делитель /65536, у другого /1.
ua6em, я кстати не случайно не написал строчки Serial.begin() он там включен по-умолчанию :)
Входы да, запаралелить физически.
Дима, попробовал из твоего скетча отсечь на данном этапе ненужное, оставить один 16 битный счетчик, прескалер поставил на 3, то-есть частота на входе счетчика должна быть 24 мегагерца.
Поясни, что не так?
Как я понимаю, счетчик отрицательным фронтом должен дёрнуть прерывание, оно вызвать нужную нам функцию, которая и сохранит значение счетчика в нашей переменной и одновременно подготовит счетчик к дальнейшему обсчету следующего входного импульса.
???
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 я не увидел, что таким образом можно триггера включить
Собственно для таймера 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 это примерно то же,что делал Дима запуская два таймера с разной частотой клока. Здесь гарантируют синхронное срабатывание.
Нет. По английски же написано - левая слейв таймер. Для него тригеры ITR0 ITR1 ITR2 ITR3 будут выдавать мастер таймеры под соответствующими тригерами. Например если слейв TIM3 то ITR0 будет выдавать мастер TIM1, ITR1- TIM2, ITR3 - TIM4.
А вот ITR2 для TIM3 никто выдавать не будет, т.к. TIM5 у 103с8 отсутствует.
Нет. По английски же написано - левая слейв таймер. Для него тригеры ITR0 ITR1 ITR2 ITR3 будут выдавать мастер таймеры под соответствующими тригерами. Например если слейв TIM3 то ITR0 будет выдавать мастер TIM1, ITR1- TIM2, ITR3 - TIM4.
А вот ITR2 для TIM3 никто выдавать не будет, т.к. TIM5 у 103с8 отсутствует.
ааа, тогда всё логично, на выходе TIM1 - ITR0, TIM2-ITR1, TIM3-ITR2, TIM4-ITR3, слейв цеплять к выходу )))
Вся таблица уместилась в одну строку )))
/**
******************************************************************************
* @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****/
Это видимо ручками надо прописывать, так как считаются уже пользовательские...
Кошмаррр!!! Придётся столько читать...Ардуино IDE отдыхает...
Видимо то и пинают, все кому не попадя, даже большие профессионалы - за невероятную лёгкость вхождения непрофессионалов )))
Это видимо ручками надо прописывать, так как считаются уже пользовательские...
Кошмаррр!!! Придётся столько читать...Ардуино IDE отдыхает...
Видимо то и пинают, все кому не попадя, даже большие профессионалы - за невероятную лёгкость вхождения непрофессионалов )))
Да не .. в СТМ просто "хотели как лучше, а получилось как всегда" (с) Черномырдин.
Потребовалось добавить в работающий проект температуру и влажность с датчика 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мкс. Куда уж точнее?
Потребовалось добавить в работающий проект температуру и влажность с датчика 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
Сброс таймеру можно делать конечно и занулением регистров, но есть способ попроще: у 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, можно уточнить в референсе.
Сброс таймеру можно делать конечно и занулением регистров, но есть способ попроще: у 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 с энкодером, сброс также надо делать?
Я не в курсе используется/инициализируется ли он у них в стартапе, но если выяснить не удается и/или подозрения на сей счет возникают, то сбросить будет не лишним. По тому, как у них написаны библиотеки, одной лишней операцией больше, одной меньше, погоды не делает. :)
Не подскажете что из того что не инициализируется используется в wiring? Для wiring проинициализировано всё и даже больше чем для дефолтной ардуины. Остальное инициализируется в дополнительных библиотеках при их подключении.
Проверил у себя на пустом скетче - Скетч использует 13732 байт (10%) памяти устройства. Всего доступно 131072 байт.
Глобальные переменные используют 3088 байт (15%) динамической памяти, оставляя 17392 байт для локальных переменных. Максимум: 20480 байт.
ua6em, ну и ладно. Я думаю что вопрос связки таймеров можно закрыть, ибо предложенный мной вариант решает вопрос 32-битного захвата PWM сигнала.
Врут. Причём нагло. Даже на примитивном стм8с это можно сделать. Гейт Модэ называется.
ua6em, ну и ладно. Я думаю что вопрос связки таймеров можно закрыть, ибо предложенный мной вариант решает вопрос 32-битного захвата PWM сигнала.
Да каждый сам себе режиссер. У древнего 103-го не так уж и много таймеров - кому-то прокатит, а кому-то и нет.
ua6em, ну и ладно. Я думаю что вопрос связки таймеров можно закрыть, ибо предложенный мной вариант решает вопрос 32-битного захвата PWM сигнала.
Тут еще важно умение ими пользоваться )))
Да и вопрос азарта, не малую роль играет
Начало положено:
ua6em, ну и ладно. Я думаю что вопрос связки таймеров можно закрыть, ибо предложенный мной вариант решает вопрос 32-битного захвата PWM сигнала.
Это да - вполне, в этом проекте даже излишне!
Вопрос, даже два?
1.как выделить из этого скетча только один таймер (первый)
2. как задать ему тактирование от 72 мегагерц с предделителем 3 (тактирование 24 мегагерца)
В этом случае я укладываюсь в диапазон разрешения счетчика требуемый мне - до 2400 мксек
ua6em, а что их выделять -они друг с другом не связаны. Можно любой брать. В настройках этих таймеров -единственное отличие - у одного прописан делитель /65536, у другого /1.
ua6em, я кстати не случайно не написал строчки Serial.begin() он там включен по-умолчанию :)
Входы да, запаралелить физически.
Дима, попробовал из твоего скетча отсечь на данном этапе ненужное, оставить один 16 битный счетчик, прескалер поставил на 3, то-есть частота на входе счетчика должна быть 24 мегагерца.
Поясни, что не так?
Как я понимаю, счетчик отрицательным фронтом должен дёрнуть прерывание, оно вызвать нужную нам функцию, которая и сохранит значение счетчика в нашей переменной и одновременно подготовит счетчик к дальнейшему обсчету следующего входного импульса.
???
Скетч:
ua6em, а где прерывание то? Его же прописать нужно. Делитель на /3 -это 2. Там счёт с ноля.
ua6em, а где прерывание то? Его же прописать нужно. Делитель на /3 -это 2. Там счёт с ноля.
Это как?
По прерыванию
так исправил?
вспомнился Козьма Прутков, если на клетке с буйволом увидишь надпись тигр не верь глазам своим
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 я не увидел, что таким образом можно триггера включить
Не все тригеры одинаково полезны. Для таймеров 1 и 8 есть таблица 82 в мануале:
Я правильно понимаю, в левой колоночке - мастер таймер, в правых -слэйв таймера?
То есть для:
Мастер TIM1 Слэйв TIM2 для последнего входом будет триггер ITR1
Перечислил применительно к STM32F103С8
Наверно все таки не так?
Нет. По английски же написано - левая слейв таймер. Для него тригеры ITR0 ITR1 ITR2 ITR3 будут выдавать мастер таймеры под соответствующими тригерами. Например если слейв TIM3 то ITR0 будет выдавать мастер TIM1, ITR1- TIM2, ITR3 - TIM4.
А вот ITR2 для TIM3 никто выдавать не будет, т.к. TIM5 у 103с8 отсутствует.
Нет. По английски же написано - левая слейв таймер. Для него тригеры ITR0 ITR1 ITR2 ITR3 будут выдавать мастер таймеры под соответствующими тригерами. Например если слейв TIM3 то ITR0 будет выдавать мастер TIM1, ITR1- TIM2, ITR3 - TIM4.
А вот ITR2 для TIM3 никто выдавать не будет, т.к. TIM5 у 103с8 отсутствует.
ааа, тогда всё логично, на выходе TIM1 - ITR0, TIM2-ITR1, TIM3-ITR2, TIM4-ITR3, слейв цеплять к выходу )))
Вся таблица уместилась в одну строку )))
Попытался сконфигурировать как-то так :
main.c
А где одна из функций для собственно запуска?
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 и вокруг много полезного.
Это видимо ручками надо прописывать, так как считаются уже пользовательские...
Кошмаррр!!! Придётся столько читать...Ардуино IDE отдыхает...
Видимо то и пинают, все кому не попадя, даже большие профессионалы - за невероятную лёгкость вхождения непрофессионалов )))
Это видимо ручками надо прописывать, так как считаются уже пользовательские...
Кошмаррр!!! Придётся столько читать...Ардуино IDE отдыхает...
Видимо то и пинают, все кому не попадя, даже большие профессионалы - за невероятную лёгкость вхождения непрофессионалов )))
Потребовалось добавить в работающий проект температуру и влажность с датчика DTH22. Вспомнил эту замечательную тему, копнул примеры на 103с8 и обнаружил инициализацию одного таймера для приема PWM на STL.
Получаем значения в прерывании.
В куб всё это переводится очень просто - названия очень созвучны с позициями куба. Заработало сразу. DHT данные выдает в формате близком к PWM. Получились тики 53мкс 72мкс и 128мкс. Таймер тактировал 1 МГц.
В результате имеем чтение датчика через прерывания. Соверщенно не мешает основной программе. Можно ещё DMA прикрутить, но и так отлично получилось. Это я к вопросу о небходимости 32 разрядного датчика для измерения PWM сигнала. 16 битного таймера хватит для 20мс периода сервомашинки. Длительность сигнала управления можно получить с точностью до 0.5мкс. Куда уж точнее?
Потребовалось добавить в работающий проект температуру и влажность с датчика DTH22. Вспомнил эту замечательную тему, копнул примеры на 103с8 и обнаружил инициализацию одного таймера для приема PWM на STL.
Получаем значения в прерывании.
В куб всё это переводится очень просто - названия очень созвучны с позициями куба. Заработало сразу. DHT данные выдает в формате близком к PWM. Получились тики 53мкс 72мкс и 128мкс. Таймер тактировал 1 МГц.
В результате имеем чтение датчика через прерывания. Соверщенно не мешает основной программе. Можно ещё DMA прикрутить, но и так отлично получилось. Это я к вопросу о небходимости 32 разрядного датчика для измерения PWM сигнала. 16 битного таймера хватит для 20мс периода сервомашинки. Длительность сигнала управления можно получить с точностью до 0.5мкс. Куда уж точнее?
Если тактировать 16 битный таймер частотой 24 мегагерца, то для диапазона 544-2400 мксек разрядности хватает.
Вопрос? Как эти воспользоваться в реализации ARDUINO IDE
Проба 3
Сброс таймеру можно делать конечно и занулением регистров, но есть способ попроще: у STM32F103 существуют два регистра, взведение того или иного бита в которых приводит к аппаратному сбросу соответствующего периферийного блока. Речь о RCC_BASE->APB1RSTR и RCC_BASE->APB2RSTR, если описывать их в стиле вышеприведенного кода. Аппаратный резет обоих таймеров мог бы выглядеть, например, так:
Могу где-то ошибиться в названиях, но сам смысл, надеюсь, понятен. Назначения битов в регистрах RCC_APBnRSTR, можно уточнить в референсе.
Сброс таймеру можно делать конечно и занулением регистров, но есть способ попроще: у STM32F103 существуют два регистра, взведение того или иного бита в которых приводит к аппаратному сбросу соответствующего периферийного блока. Речь о RCC_BASE->APB1RSTR и RCC_BASE->APB2RSTR, если описывать их в стиле вышеприведенного кода. Аппаратный резет обоих таймеров мог бы выглядеть, например, так:
Могу где-то ошибиться в названиях, но сам смысл, надеюсь, понятен. Назначения битов в регистрах RCC_APBnRSTR, можно уточнить в референсе.
Залил и Ваш вариант, работает )))
А для использования Таймера 1 с энкодером, сброс также надо делать?
Я не в курсе используется/инициализируется ли он у них в стартапе, но если выяснить не удается и/или подозрения на сей счет возникают, то сбросить будет не лишним. По тому, как у них написаны библиотеки, одной лишней операцией больше, одной меньше, погоды не делает. :)
В stm32duino по умолчанию инициализируются все таймеры.
В stm32duino по умолчанию инициализируются все таймеры.
Это реализовано в загрузчике IDE?
Думаю, это реализовано в 20 кбайтах пустого скетча.
Думаю, это реализовано в 20 кбайтах пустого скетча.
Логично!
Специально качнул эту mapple, а сходу не могу найти, где и как оно инициализируется, хотя согласен, что пустой скетч получается подозрительно толстым.
c:\Users\Toshiba\Documents\Arduino\hardware\Arduino_STM32-master\STM32F1\variants\generic_stm32f103c\wirish\boards.cpp
Инициализируется всё.
Ну, как бы не совсем все. DMA, напимер, не инициализируется. И еще кое-какая экзотика.
DMA даже в кубе не выделена в отдельную периферию. Это как бы намекает.
Не похоже на всё. Кроме DMA, о которой уже сказали, не вижу SPI, I2C, CAN, CRC, как минимум.
Не подскажете что из того что не инициализируется используется в wiring? Для wiring проинициализировано всё и даже больше чем для дефолтной ардуины. Остальное инициализируется в дополнительных библиотеках при их подключении.
Словом "всё", без уточнений, принято называть самое полное множество. Сложилось так.
Думаю, это реализовано в 20 кбайтах пустого скетча.
это на какой плате? у меня на "голубой таблетке" пустой скетч менее 11 Кб (11048)
Наверное, какая-то разница все же есть:
режим компилляции: smallest
режим компилляции: fastest
Проверил у себя на пустом скетче - Скетч использует 13732 байт (10%) памяти устройства. Всего доступно 131072 байт.
Глобальные переменные используют 3088 байт (15%) динамической памяти, оставляя 17392 байт для локальных переменных. Максимум: 20480 байт.