stm32F4 encoder measures speed and prints through serial port --- program source code

Publisher:美丽的1号Latest update time:2018-07-06 Source: eefocusKeywords:stm32F4 Reading articles on mobile phones Scan QR code
Read articles on your mobile phone anytime, anywhere

1. Use cubeMX software to initialize the ports and resources needed by the program.
In order to keep the program simple, only one serial port and one general timer are used here.
(1) Pin initialization


Note: There is no encoder mode in the pin configuration. I don't know why. The advanced registers are selected by the combined channels option.
Here, temporarily select Input Capture direct mode, and then modify it according to the specific code.
(2) Clock configuration



(3) Configuration of serial port resources




(4) Timer configuration



(5) Interrupt configuration
The serial port is not used to receive data, so the serial port interrupt does not need to be turned on. The timer interrupt needs to be turned on. When the timer overflows, it needs to be recorded to ensure the accuracy of the record.

(6) The final generated timer initialization code is as follows:


static void MX_TIM3_Init(void)

{

 

  TIM_ClockConfigTypeDef sClockSourceConfig;

  TIM_MasterConfigTypeDef sMasterConfig;

  TIM_IC_InitTypeDef sConfigIC;

 

  htim3.Instance = TIM3;

  htim3.Init.Prescaler = 0;

  htim3.Init.CounterMode = TIM_COUNTERMODE_UP;

  htim3.Init.Period = 65535;

  htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;

  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__);

  }

 

  if (HAL_TIM_IC_ConfigChannel(&htim3, &sConfigIC, TIM_CHANNEL_2) != HAL_OK)

  {

    _Error_Handler(__FILE__, __LINE__);

  }

 

}

Remove the code for Input Capture mode configuration and modify the code as follows:


void MX_TIM3_Init(void)

 

{    

 htimx_Encoder.Instance = TIM3; 

htim3.Init.Prescaler = 0; 

htim3.Init.CounterMode = TIM_COUNTERMODE_UP; 

htim3.Init.Period = 65535; 

htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;  

//HAL_TIM_Base_Init(&htimx_Encoder); 

sEncoderConfig.EncoderMode  = TIM_ENCODERMODE_TIx;  

sEncoderConfig.IC1Polarity  = TIM_ICPOLARITY_RISING;      

sEncoderConfig.IC1Selection       = TIM_ICSELECTION_DIRECTTI;   

sEncoderConfig.IC1Prescaler       = TIM_ICPSC_DIV1;    

sEncoderConfig.IC1Filter          = 0;     

sEncoderConfig.IC2Polarity        = TIM_ICPOLARITY_RISING;    

sEncoderConfig.IC2Selection       = TIM_ICSELECTION_DIRECTTI;     

sEncoderConfig.IC2Prescaler       = TIM_ICPSC_DIV1;    

sEncoderConfig.IC2Filter          = 0;   

__HAL_TIM_SET_COUNTER(&htimx_Encoder,0);     

HAL_TIM_Encoder_Init(&htimx_Encoder, &sEncoderConfig);      

__HAL_TIM_CLEAR_IT(&htimx_Encoder, TIM_IT_UPDATE); //Clear update interrupt flag   

__HAL_TIM_URS_ENABLE(&htimx_Encoder); //Only allow counter overflow to generate update interrupt   

__HAL_TIM_ENABLE_IT(&htimx_Encoder,TIM_IT_UPDATE); //Enable update interrupt     

HAL_NVIC_SetPriority(ENCODER_TIM_IRQn, 0, 0);    HAL_NVIC_EnableIRQ(ENCODER_TIM_IRQn); }

I won’t say much about the main function code, I’ll just paste it here. 


#include "main.h"

#include "stm32f4xx_hal.h"

#include "string.h"

#define SAMPLING_PERIOD 20 // Sampling period; unit: 20ms

 

TIM_HandleTypeDef htim3;

 

UART_HandleTypeDef huart1;

 

void SystemClock_Config(void);

static void MX_GPIO_Init(void);

static void MX_TIM3_Init(void);

static void MX_USART1_UART_Init(void);

static void MX_NVIC_Init(void);

 

void ENCODER_TIMx_Init(void);

/* USER CODE BEGIN PFP */

/* Private function prototypes -----------------------------------------------*/

/* Private type definition--------------------------------------------------------------*/

 

 

#define SAMPLING 0x01 // Sampling flag

#define TXD 0x02 // Send data flag   

#define MPR 5 //Single-turn distance of the lead screw; unit: mm/r       

#define PSPM ((600*4)/MPR) //The number of pulses output per unit distance, calculated based on the actual wheel or connecting rod

 

/* USER CODE END PFP */

#define abs(x)                    ((x)<0?(-x):(x))

 

__IO uint16_t time_count=0; // Time count, increases by one every 1ms (related to the tick timer frequency)

__IO int32_t CaptureNumber=0; // Input capture number

__IO int32_t Last_CaptureNumber=0; // Last captured value

 

__IO static int16_t Speed ​​= 50; // Converted to the speed of the screw, the unit is: 0.1mm/s so the actual speed is 5mm/s

__IO uint16_t SUM_Pulse = 0;      

__IO int16_t MSF = 0; // Motor feedback speed

__IO float MMPS = 0;                // mm Per Seconed (mm/s)

__IO uint8_t Time_Flag = 0; // Mark time

 

uint8_t aTxBuffer[60];        

int16_t OverflowCount=0; // encoder count overflow counter

TIM_HandleTypeDef    htimx_Encoder;

 

/* Timer Encoder Configuration Structure declaration */

TIM_Encoder_InitTypeDef sEncoderConfig;

int main(void)

{

  HAL_Init();

 

  SystemClock_Config();

 

  MX_GPIO_Init();

  //MX_TIM3_Init();

   ENCODER_TIMx_Init();

   HAL_TIM_Encoder_Start(&htimx_Encoder, TIM_CHANNEL_ALL);

  MX_USART1_UART_Init();

 

 

  /* Initialize interrupts */

  MX_NVIC_Init();

 

 

int a=0;

  while (1)

  {

if(Time_Flag & SAMPLING){

MSF = CaptureNumber  - Last_CaptureNumber;

Last_CaptureNumber = CaptureNumber;

MSF = abs(MSF);

MMPS = (float)(MSF*500/PSPM);

CaptureNumber = 65535*OverflowCount+__HAL_TIM_GET_COUNTER(&htimx_Encoder);

     // Calculate the number of pulses between units.

     Time_Flag &= ~SAMPLING; 

   }

     if(Time_Flag & TXD)

    {

  

sprintf(aTxBuffer,"The current encoder value is: %d The current speed is: %.2f mm/s\n",CaptureNumber,MMPS);

    

      HAL_UART_Transmit(&huart1,aTxBuffer,strlen((const char*)aTxBuffer),1000);

  

      Time_Flag &= ~TXD;

    }

  }

}

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)

{

 

   if(__HAL_TIM_IS_TIM_COUNTING_DOWN(&htimx_Encoder)){

    OverflowCount--; //Count down overflow

}

  else

{

    OverflowCount++; //Count up overflow

}

 __HAL_TIM_CLEAR_IT(&htimx_Encoder, TIM_IT_UPDATE);//很重要

}

int fputc(int ch, FILE *f)

{

  HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xffff);

  return ch;

}

 

/**

  * Function: Redirect C library functions getchar, scanf to DEBUG_USARTx

  * Input parameters: None

  * Return value: None

  * Description: None

  */

int fgetc(FILE * f)

{

  uint8_t ch = 0;

  while(HAL_UART_Receive(&huart1,&ch, 1, 0xffff)!=HAL_OK);

  return ch;

}

void HAL_SYSTICK_Callback(void)

{

  // Automatically increase by one every 1ms

  time_count++;         

  if(time_count%(20) == 0) // Read the encoder value every 20ms

  {

    Time_Flag |= SAMPLING;

  }

  else if(time_count>=1000) //send data once every 1s

  {

    Time_Flag |= TXD;

    time_count=0;

  }

}

 

/** System Clock Configuration

*/

void SystemClock_Config(void)

{

  RCC_OscInitTypeDef RCC_OscInitStruct;

  RCC_ClkInitTypeDef RCC_ClkInitStruct;

 /**Configure the main internal regulator output voltage 

    */

  __HAL_RCC_PWR_CLK_ENABLE();

  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);

 

  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;

  RCC_OscInitStruct.HSEState = RCC_HSE_ON;

  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;

  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;

  RCC_OscInitStruct.PLL.PLLM = 8;

  RCC_OscInitStruct.PLL.PLLN = 336;

  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;

  RCC_OscInitStruct.PLL.PLLQ = 4;

  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_DIV4;

  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;

 

 

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != 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);

}

 

/**

  * Function: Initialize the general timer and configure the channel PWM output

  * Input parameters: None

  * Return value: None

  * Description: None

  */

void ENCODER_TIMx_Init(void)

{    

  htimx_Encoder.Instance = TIM3;

  htimx_Encoder.Init.Prescaler = 0;

  htimx_Encoder.Init.CounterMode = TIM_COUNTERMODE_UP;

  htimx_Encoder.Init.Period = 0xFFFF;

  htimx_Encoder.Init.ClockDivision=TIM_CLOCKDIVISION_DIV1;

  HAL_TIM_Base_Init(&htimx_Encoder);

  

  sEncoderConfig.EncoderMode        = TIM_ENCODERMODE_TI12;  

  

  sEncoderConfig.IC1Polarity        = TIM_ICPOLARITY_RISING;   

  sEncoderConfig.IC1Selection       = TIM_ICSELECTION_DIRECTTI;  

  sEncoderConfig.IC1Prescaler       = TIM_ICPSC_DIV1; 

  sEncoderConfig.IC1Filter          = 0;

  

  sEncoderConfig.IC2Polarity        = TIM_ICPOLARITY_RISING;   

  sEncoderConfig.IC2Selection       = TIM_ICSELECTION_DIRECTTI;  

  sEncoderConfig.IC2Prescaler       = TIM_ICPSC_DIV1; 

  sEncoderConfig.IC2Filter          = 0;

 

 

  

  HAL_TIM_Encoder_Init(&htimx_Encoder, &sEncoderConfig);

 

 

  //

  __HAL_TIM_CLEAR_IT(&htimx_Encoder, TIM_IT_UPDATE); //Clear update interrupt flag

  __HAL_TIM_URS_ENABLE(&htimx_Encoder); //Only allow counter overflow to generate update interrupt

  __HAL_TIM_ENABLE_IT(&htimx_Encoder,TIM_IT_UPDATE); //Enable update interrupt

  

  HAL_NVIC_SetPriority(TIM3_IRQn, 0, 0); //This is just a general interrupt. Other interrupts need to be set separately.

  HAL_NVIC_EnableIRQ(TIM3_IRQn); //Unlike external key interrupt, external interrupt is relatively simple and there is only one.

}

 

static void MX_NVIC_Init(void)

{

  /* TIM3_IRQn interrupt configuration */

  HAL_NVIC_SetPriority(TIM3_IRQn, 0, 0);

  HAL_NVIC_EnableIRQ(TIM3_IRQn);

}

 

 

/* 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 = 0;

  htim3.Init.CounterMode = TIM_COUNTERMODE_UP;

  htim3.Init.Period = 65535;

  htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;

  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__);

  }

 

 

  if (HAL_TIM_IC_ConfigChannel(&htim3, &sConfigIC, TIM_CHANNEL_2) != HAL_OK)

  {

    _Error_Handler(__FILE__, __LINE__);

  }

 

}

/* USART1 init function */

static void MX_USART1_UART_Init(void)

{

 

 

  huart1.Instance = USART1;

  huart1.Init.BaudRate = 115200;

  huart1.Init.WordLength = UART_WORDLENGTH_8B;

  huart1.Init.StopBits = UART_STOPBITS_1;

  huart1.Init.Parity = UART_PARITY_NONE;

  huart1.Init.Mode = UART_MODE_TX_RX;

  huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;

  huart1.Init.OverSampling = UART_OVERSAMPLING_16;

  if (HAL_UART_Init(&huart1) != HAL_OK)

  {

    _Error_Handler(__FILE__, __LINE__);

  }

}

 

static void MX_GPIO_Init(void)

{

 

 

  /* GPIO Ports Clock Enable */

  __HAL_RCC_GPIOH_CLK_ENABLE();

  __HAL_RCC_GPIOC_CLK_ENABLE();

  __HAL_RCC_GPIOB_CLK_ENABLE();

}

 

/**

  * @brief  This function is executed in case of error occurrence.

  * @param  None

  * @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,

    ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */

  /* USER CODE END 6 */

 

}

#endif


Keywords:stm32F4 Reference address:stm32F4 encoder measures speed and prints through serial port --- program source code

Previous article:STM32F10X PWM configuration routine detailed explanation, test correct
Next article:STM32+MS5611 detailed routine for measuring air pressure and temperature, test correct

Latest Microcontroller Articles
Change More Related Popular Components

EEWorld
subscription
account

EEWorld
service
account

Automotive
development
circle

About Us Customer Service Contact Information Datasheet Sitemap LatestNews


Room 1530, 15th Floor, Building B, No.18 Zhongguancun Street, Haidian District, Beijing, Postal Code: 100190 China Telephone: 008610 8235 0740

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号