一、使用cubeMX软件对程序需要使用的端口和资源进行初始化。
为了保持程序的简洁性,这里仅使用一个串口和一路通用定时器。
(1)引脚的初始化
注:在引脚配置这里,是没有编码器模式的,不知道为什么。高级寄存器是由combined channels选项的。
这里先暂时选择为Input Capture direct mode,后面在针对具体的代码进行修改即可。
(2)时钟的配置
(3)串口资源的配置
(4)定时器的配置
(5)中断的配置
这里不适用串口来接收数据,所以串口的中断也不用打开。这里需要打开定时器的中断,在定时器发生上下计数溢出时,需要对进行记录,保证记录的准确性。
(6)最后生成的定时器初始化代码如下:
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__);
}
}
去掉Input Capture模式配置的代码,对代码修改如下:
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); //清除更新中断标志位
__HAL_TIM_URS_ENABLE(&htimx_Encoder); //仅允许计数器溢出才产生更新中断
__HAL_TIM_ENABLE_IT(&htimx_Encoder,TIM_IT_UPDATE); //使能更新中断
HAL_NVIC_SetPriority(ENCODER_TIM_IRQn, 0, 0); HAL_NVIC_EnableIRQ(ENCODER_TIM_IRQn); }
主函数代码不多说,直接贴上了。
#include "main.h"
#include "stm32f4xx_hal.h"
#include "string.h"
#define SAMPLING_PERIOD 20 // 采样周期;单位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 -----------------------------------------------*/
/* 私有类型定义 --------------------------------------------------------------*/
#define SAMPLING 0x01 // 采样标记
#define TXD 0x02 // 发送数据标记
#define MPR 5 //丝杠单圈距离;单位:mm/r
#define PSPM ((600*4)/MPR) //单位距离输出的脉冲数,根据实际的轮子或连杆计算
/* USER CODE END PFP */
#define abs(x) ((x)<0?(-x):(x))
__IO uint16_t time_count=0; // 时间计数,每1ms增加一(与滴答定时器频率有关)
__IO int32_t CaptureNumber=0; // 输入捕获数
__IO int32_t Last_CaptureNumber=0; // 上一次捕获值
__IO static int16_t Speed = 50; // 换算为丝杠上行进的速度,单位为:0.1mm/s所以实际速度是5mm/s
__IO uint16_t SUM_Pulse = 0;
__IO int16_t MSF = 0; // 电机反馈速度
__IO float MMPS = 0; // mm Per Seconed (mm/s)
__IO uint8_t Time_Flag = 0; // 标记时间
uint8_t aTxBuffer[60];
int16_t OverflowCount=0; // 编码器计数溢出 计数器
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);
//计算单位之间内脉冲个数。
Time_Flag &= ~SAMPLING;
}
if(Time_Flag & TXD)
{
sprintf(aTxBuffer,"编码器当前值为: %d 当前速度为: %.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--; //向下计数溢出
}
else
{
OverflowCount++; //向上计数溢出
}
__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;
}
/**
* 函数功能: 重定向c库函数getchar,scanf到DEBUG_USARTx
* 输入参数: 无
* 返 回 值: 无
* 说 明:无
*/
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)
{
// 每1ms自动增一
time_count++;
if(time_count%(20) == 0)// 20ms读取一次编码器数值
{
Time_Flag |= SAMPLING;
}
else if(time_count>=1000) //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);
}
/**
* 函数功能: 通用定时器初始化并配置通道PWM输出
* 输入参数: 无
* 返 回 值: 无
* 说 明: 无
*/
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); //清除更新中断标志位
__HAL_TIM_URS_ENABLE(&htimx_Encoder); //仅允许计数器溢出才产生更新中断
__HAL_TIM_ENABLE_IT(&htimx_Encoder,TIM_IT_UPDATE); //使能更新中断
HAL_NVIC_SetPriority(TIM3_IRQn, 0, 0); //这里只是设置一个总的中断。其他的中断还需要另外设置。
HAL_NVIC_EnableIRQ(TIM3_IRQn); //不像外部按键中断,外部中断比较简单只有一个。
}
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
上一篇:STM32F10X PWM配置例程详解,测试无误
下一篇:STM32+MS5611测气压温度例程详解,测试无误
推荐阅读最新更新时间:2024-03-16 16:07
设计资源 培训 开发板 精华推荐
- 非常见问题解答第223期:如何在没有软启动方程的情况下测量和确定软启动时序?
- 兆易创新GD25/55全系列车规级SPI NOR Flash荣获ISO 26262 ASIL D功能安全认证证书
- 新型IsoVu™ 隔离电流探头:为电流测量带来全新维度
- 英飞凌推出简化电机控制开发的ModusToolbox™电机套件
- 意法半导体IO-Link执行器电路板为工业监控和设备厂商带来一站式参考设计
- Melexis采用无磁芯技术缩小电流感测装置尺寸
- 千丘智能侍淳博:用数字疗法,点亮“孤独症”儿童的光
- 数药智能冯尚:ADHD数字疗法正为儿童“多动症”提供更有效便捷服务
- Vicor高性能电源模块助力低空航空电子设备和 EVTOL的发展
- 创实技术electronica 2024首秀:加速国内分销商海外拓展之路