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
Previous article:STM32F10X PWM configuration routine detailed explanation, test correct
Next article:STM32+MS5611 detailed routine for measuring air pressure and temperature, test correct
- Popular Resources
- Popular amplifiers
- Learn ARM development(16)
- Learn ARM development(17)
- Learn ARM development(18)
- Embedded system debugging simulation tool
- A small question that has been bothering me recently has finally been solved~~
- Learn ARM development (1)
- Learn ARM development (2)
- Learn ARM development (4)
- Learn ARM development (6)
Professor at Beihang University, dedicated to promoting microcontrollers and embedded systems for over 20 years.
- LED chemical incompatibility test to see which chemicals LEDs can be used with
- Application of ARM9 hardware coprocessor on WinCE embedded motherboard
- What are the key points for selecting rotor flowmeter?
- LM317 high power charger circuit
- A brief analysis of Embest's application and development of embedded medical devices
- Single-phase RC protection circuit
- stm32 PVD programmable voltage monitor
- Introduction and measurement of edge trigger and level trigger of 51 single chip microcomputer
- Improved design of Linux system software shell protection technology
- What to do if the ABB robot protection device stops
- ASML predicts that its revenue in 2030 will exceed 457 billion yuan! Gross profit margin 56-60%
- Detailed explanation of intelligent car body perception system
- How to solve the problem that the servo drive is not enabled
- Why does the servo drive not power on?
- What point should I connect to when the servo is turned on?
- How to turn on the internal enable of Panasonic servo drive?
- What is the rigidity setting of Panasonic servo drive?
- How to change the inertia ratio of Panasonic servo drive
- What is the inertia ratio of the servo motor?
- Is it better for the motor to have a large or small moment of inertia?
- Let Arduino make your useless board playable Part 3 How to play ESP-C3, ESPS2
- Risking my life to tell the administrator: The title has too few words, and the problem description was cut off before it was finished.
- CC2640 debugging experience: adding serial port
- 【NXP Rapid IoT Review】+ GUI Usage
- N32WB452 asked: Does N32WB452 have a basically complete ported RT-Thread development kit?
- IoT Gateways – A Simple Guide to the Internet of Things
- [Anxinke UWB indoor positioning module NodeMCU-BU01] No.004-Distance measurement test, evaluation completed
- It's New Year's Eve soon. I wish you all a happy New Year.
- Using Ginkgo USB-ADC and heart rate sensor to implement a heart rate tester with Android APP source code
- 【DIY Creative LED】Add touch button and install it on LED lamp