当前位置: 首页 > news >正文

rt-thread的定时器驱动(裸机版本)记录.

前言

  1. 本驱动运行stm32f407zgt6上已测试ok。
  2. 基于rtthread的定时器组件源码改编而来.
  3. 驱动记录

驱动代码

定时器组件

头文件

/*
* Copyright (c) 2006-2023, RT-Thread Development Team** SPDX-License-Identifier: Apache-2.0** Change Logs:* Date           Author       Notes*/
#ifndef HWTIMER_H
#define HWTIMER_H
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <assert.h>
#define HWTIMER_CNTMODE_UP      0x01 /* increment count mode */
#define HWTIMER_CNTMODE_DW      0x02 /* decreasing count mode *//* Timing Mode */
typedef enum
{HWTIMER_MODE_ONESHOT = 0x01,HWTIMER_MODE_PERIOD
} rt_hwtimer_mode_t;/* Timer Control Command */
typedef enum
{HWTIMER_CTRL_FREQ_SET = 0x01, /* set the count frequency */HWTIMER_CTRL_STOP = 0x02, /* stop timer */HWTIMER_CTRL_INFO_GET = 0x03, /* get a timer feature information */HWTIMER_CTRL_MODE_SET = 0x04 /* Setting the timing mode(oneshot/period) */
} rt_hwtimer_ctrl_t;/* Time Value */
typedef struct rt_hwtimerval
{int sec; /* second */int usec; /* microsecond */
} rt_hwtimerval_t;struct rt_hwtimer_device;struct rt_hwtimer_ops
{void (*init)(struct rt_hwtimer_device* timer, uint32_t state);int (*start)(struct rt_hwtimer_device* timer, uint32_t cnt, rt_hwtimer_mode_t mode);void (*stop)(struct rt_hwtimer_device* timer);uint32_t (*count_get)(struct rt_hwtimer_device* timer);int (*control)(struct rt_hwtimer_device* timer, uint32_t cmd, void* args);
};/* Timer Feature Information */
struct rt_hwtimer_info
{int maxfreq; /* the maximum count frequency timer support */int minfreq; /* the minimum count frequency timer support */uint32_t maxcnt; /* counter maximum value */uint32_t cntmode; /* count mode (inc/dec) */
};typedef struct rt_hwtimer_device
{const struct rt_hwtimer_ops* ops;const struct rt_hwtimer_info* info;int freq; /* counting frequency set by the user */int overflow; /* timer overflows */float period_sec;int cycles; /* how many times will generate a timeout event after overflow */int reload; /* reload cycles(using in period mode) */rt_hwtimer_mode_t mode; /* timing mode(oneshot/period) */int (*rx_indicate)(struct rt_hwtimer_device* dev);
} rt_hwtimer_t;int rt_hwtimer_init(rt_hwtimer_t* timer);
int rt_hwtimer_open(rt_hwtimer_t* timer);
int rt_hwtimer_close(rt_hwtimer_t* timer);
int rt_hwtimer_read(rt_hwtimer_t* timer, rt_hwtimerval_t* tv);
int rt_hwtimer_write(rt_hwtimer_t* timer, rt_hwtimerval_t* hwtimerval);
int rt_hwtimer_control(rt_hwtimer_t* timer, int cmd, void* args);
void rt_device_hwtimer_isr(rt_hwtimer_t* timer);#endif //HWTIMER_H

源文件

/********************************************************************************* @file           : hwtimer.c* @author         : shchl* @brief          : None* @version        : 1.0* @attention      : None* @date           : 25-6-14******************************************************************************
*/
#include "main.h"
#include "hwtimer.h"
#ifndef DISABLE_INT
#define DISABLE_INT() __disable_irq()
#endif // DISABLE_INT
#ifndef ENABLE_INT
#define ENABLE_INT() __enable_irq()
#endif // ENABLE_INTstatic inline uint32_t timeout_calc(rt_hwtimer_t* timer, rt_hwtimerval_t* tv)
{float overflow;float timeout;uint32_t counter;int i, index = 0;float tv_sec;float devi_min = 1;float devi;/* changed to second */overflow = timer->info->maxcnt / (float)timer->freq;tv_sec = tv->sec + tv->usec / (float)1000000;if (tv_sec < (1 / (float)timer->freq)){/* little timeout */i = 0;timeout = 1 / (float)timer->freq;}else{for (i = 1; i > 0; i++){timeout = tv_sec / i;if (timeout <= overflow){counter = (uint32_t)(timeout * timer->freq);devi = tv_sec - (counter / (float)timer->freq) * i;/* Minimum calculation error */if (devi > devi_min){i = index;timeout = tv_sec / i;break;}if (devi == 0){break;}if (devi < devi_min){devi_min = devi;index = i;}}}}timer->cycles = i;timer->reload = i;timer->period_sec = timeout;counter = (uint32_t)(timeout * timer->freq);return counter;
}int rt_hwtimer_init(rt_hwtimer_t* timer)
{if (timer->ops->init == NULL) return -1;/* try to change to 1MHz */if ((1000000 <= timer->info->maxfreq) && (1000000 >= timer->info->minfreq)){timer->freq = 1000000;}else{timer->freq = timer->info->minfreq;}timer->mode = HWTIMER_MODE_ONESHOT;timer->cycles = 0;timer->overflow = 0;timer->ops->init(timer, 1);return 0;
}int rt_hwtimer_open(rt_hwtimer_t* timer)
{if (timer->ops->control == NULL) return -1;timer->ops->control(timer, HWTIMER_CTRL_FREQ_SET, &timer->freq);return 0;
}int rt_hwtimer_close(rt_hwtimer_t* timer)
{if (timer->ops->init == NULL) return -1;timer->ops->init(timer, 0);timer->rx_indicate = NULL;return 0;
}int rt_hwtimer_read(rt_hwtimer_t* timer, rt_hwtimerval_t* tv)
{if (timer->ops->count_get == NULL) return -1;DISABLE_INT();uint32_t cnt = timer->ops->count_get(timer);int32_t overflow = timer->overflow;ENABLE_INT();if (timer->info->cntmode == HWTIMER_CNTMODE_DW){cnt = (uint32_t)(timer->freq * timer->period_sec) - cnt;}if (timer->mode == HWTIMER_MODE_ONESHOT){overflow = 0;}float t = overflow * timer->period_sec + cnt / (float)timer->freq;tv->sec = (int32_t)t;tv->usec = (int32_t)((t - tv->sec) * 1000000);return 0;
}int rt_hwtimer_write(rt_hwtimer_t* timer, rt_hwtimerval_t* hwtimerval)
{uint32_t t;rt_hwtimer_mode_t opm = HWTIMER_MODE_PERIOD;if ((timer->ops->start == NULL) || (timer->ops->stop == NULL)) return -1;timer->ops->stop(timer);DISABLE_INT();timer->overflow = 0;ENABLE_INT();t = timeout_calc(timer, hwtimerval);if ((timer->cycles <= 1) && (timer->mode == HWTIMER_MODE_ONESHOT)){opm = HWTIMER_MODE_ONESHOT;}if (timer->ops->start(timer, t, opm) != 0) return -2;return 0;
}int rt_hwtimer_control(rt_hwtimer_t* timer, int cmd, void* args)
{int result = 0;switch (cmd){case HWTIMER_CTRL_STOP:{if (timer->ops->stop != NULL){timer->ops->stop(timer);}else{result = -1;}}break;case HWTIMER_CTRL_FREQ_SET:{int32_t* f;if (args == NULL){result = -2;break;}f = (int32_t*)args;if ((*f > timer->info->maxfreq) || (*f < timer->info->minfreq)){// LOG_W("frequency setting out of range! It will maintain at %d Hz", timer->freq);result = -3;break;}if (timer->ops->control != NULL){result = timer->ops->control(timer, cmd, args);if (result == 0){DISABLE_INT();timer->freq = *f;ENABLE_INT();}}else{result = -1;}}break;case HWTIMER_CTRL_INFO_GET:{if (args == NULL){result = -2;break;}*((struct rt_hwtimer_info*)args) = *timer->info;}break;case HWTIMER_CTRL_MODE_SET:{rt_hwtimer_mode_t* m;if (args == NULL){result = -2;break;}m = (rt_hwtimer_mode_t*)args;if ((*m != HWTIMER_MODE_ONESHOT) && (*m != HWTIMER_MODE_PERIOD)){result = -3;break;}DISABLE_INT();timer->mode = *m;ENABLE_INT();}break;default:{if (timer->ops->control != NULL){result = timer->ops->control(timer, cmd, args);}else{result = -1;}}break;}return result;
}void rt_device_hwtimer_isr(rt_hwtimer_t* timer)
{timer->overflow++;if (timer->cycles != 0){timer->cycles--;}if (timer->cycles == 0){timer->cycles = timer->reload;if (timer->mode == HWTIMER_MODE_ONESHOT){if (timer->ops->stop != NULL){timer->ops->stop(timer);}}if (timer->rx_indicate){timer->rx_indicate(timer);}}
}

定时器组件实现(STM32F407ZGT6)

头文件

/********************************************************************************* @file           : drv_hwtimer.h* @author         : shchl* @brief          : None* @version        : 1.0* @attention      : None* @date           : 25-6-14******************************************************************************
*/#ifndef DRV_HWTIMER_H
#define DRV_HWTIMER_H
#include "hwtimer.h"
#define TIM_DEV_INFO_CONFIG                     \
{                                           \.maxfreq = 1000000,                     \.minfreq = 3000,                        \.maxcnt  = 0xFFFF,                      \.cntmode = HWTIMER_CNTMODE_UP,          \
}enum
{TIM1_INDEX,TIM2_INDEX,TIM3_INDEX,TIM4_INDEX,TIM5_INDEX,TIM6_INDEX,TIM7_INDEX,TIM8_INDEX,TIM9_INDEX,TIM10_INDEX,TIM11_INDEX,TIM12_INDEX,TIM13_INDEX,TIM14_INDEX,TIM15_INDEX,TIM16_INDEX,TIM17_INDEX,
};void stm32_hwtimer_init(void);
rt_hwtimer_t* stm32_hwtimer_get(int index);
#endif //DRV_HWTIMER_H

源文件(根据具体芯片修改)

/********************************************************************************* @file           : drv_hwtimer.c* @author         : shchl* @brief          : None* @version        : 1.0* @attention      : None* @date           : 25-6-14******************************************************************************
*/
#include "main.h"
#include "tim.h"#include "drv_hwtimer.h"struct stm32_hwtimer
{rt_hwtimer_t time_device;TIM_HandleTypeDef* tim_handle;IRQn_Type tim_irqn;char* name;
};/* APBx timer clocks frequency doubler state related to APB1CLKDivider value */
static void pclkx_doubler_get(uint32_t* pclk1_doubler, uint32_t* pclk2_doubler)
{uint32_t flatency = 0;RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};HAL_RCC_GetClockConfig(&RCC_ClkInitStruct, &flatency);*pclk1_doubler = 1;*pclk2_doubler = 1;if (RCC_ClkInitStruct.APB1CLKDivider != RCC_HCLK_DIV1){*pclk1_doubler = 2;}if (RCC_ClkInitStruct.APB2CLKDivider != RCC_HCLK_DIV1){*pclk2_doubler = 2;}
}static void timer_init(struct rt_hwtimer_device* timer, uint32_t state)
{assert(timer);uint32_t pclk1_doubler, pclk2_doubler;TIM_HandleTypeDef* tim = NULL;struct stm32_hwtimer* tim_device = NULL;if (state){uint32_t prescaler_value = 0;tim_device = (struct stm32_hwtimer*)timer;tim = tim_device->tim_handle;pclkx_doubler_get(&pclk1_doubler, &pclk2_doubler);if (tim->Instance == TIM9 || tim->Instance == TIM10 || tim->Instance == TIM11){prescaler_value = (uint32_t)(HAL_RCC_GetPCLK2Freq() * pclk2_doubler / 10000) - 1;}else{prescaler_value = (uint32_t)(HAL_RCC_GetPCLK1Freq() * pclk1_doubler / 10000) - 1;}tim->Init.Period = 10000 - 1;tim->Init.Prescaler = prescaler_value;tim->Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;if (timer->info->cntmode == HWTIMER_CNTMODE_UP){tim->Init.CounterMode = TIM_COUNTERMODE_UP;}else{tim->Init.CounterMode = TIM_COUNTERMODE_DOWN;}tim->Init.RepetitionCounter = 0;// LOG_E("%s init failed", tim_device->name);if (HAL_TIM_Base_Init(tim) != HAL_OK) return;/* set the TIMx priority */HAL_NVIC_SetPriority(tim_device->tim_irqn, 0, 0);/* enable the TIMx global Interrupt */HAL_NVIC_EnableIRQ(tim_device->tim_irqn);/* clear update flag */__HAL_TIM_CLEAR_FLAG(tim, TIM_FLAG_UPDATE);/* enable update request source */__HAL_TIM_URS_ENABLE(tim);}
}static int timer_start(rt_hwtimer_t* timer, uint32_t t, rt_hwtimer_mode_t opmode)
{TIM_HandleTypeDef* tim = NULL;assert(timer != NULL);struct stm32_hwtimer* tim_device = (struct stm32_hwtimer*)timer;tim = tim_device->tim_handle;/* set tim cnt */__HAL_TIM_SET_COUNTER(tim, 0);/* set tim arr */__HAL_TIM_SET_AUTORELOAD(tim, t - 1);if (opmode == HWTIMER_MODE_ONESHOT){/* set timer to single mode */tim->Instance->CR1 |= TIM_OPMODE_SINGLE;}else{tim->Instance->CR1 &= (~TIM_OPMODE_SINGLE);}/* start timer */if (HAL_TIM_Base_Start_IT(tim) != HAL_OK) return -1;return 0;
}static void timer_stop(rt_hwtimer_t* timer)
{TIM_HandleTypeDef* tim = NULL;assert(timer != NULL);const struct stm32_hwtimer* tim_device = (struct stm32_hwtimer*)timer;tim = tim_device->tim_handle;/* stop timer */HAL_TIM_Base_Stop_IT(tim);/* set tim cnt */__HAL_TIM_SET_COUNTER(tim, 0);
}static uint32_t timer_counter_get(rt_hwtimer_t* timer)
{TIM_HandleTypeDef* tim = NULL;assert(timer != NULL);const struct stm32_hwtimer* tim_device = (struct stm32_hwtimer*)timer;tim = tim_device->tim_handle;return tim->Instance->CNT;
}static int timer_ctrl(rt_hwtimer_t* timer, uint32_t cmd, void* arg)
{uint32_t pclk1_doubler, pclk2_doubler;TIM_HandleTypeDef* tim = NULL;assert(timer != NULL);const struct stm32_hwtimer* tim_device = (struct stm32_hwtimer*)timer;tim = tim_device->tim_handle;switch (cmd){case HWTIMER_CTRL_FREQ_SET:{uint16_t val;/* set timer frequence */uint32_t freq = *((uint32_t*)arg);pclkx_doubler_get(&pclk1_doubler, &pclk2_doubler);if (tim->Instance == TIM9 || tim->Instance == TIM10 || tim->Instance == TIM11){val = HAL_RCC_GetPCLK2Freq() * pclk2_doubler / freq;}else{val = HAL_RCC_GetPCLK1Freq() * pclk1_doubler / freq;}__HAL_TIM_SET_PRESCALER(tim, val - 1);/* Update frequency value */tim->Instance->EGR |= TIM_EVENTSOURCE_UPDATE;}break;default:{return -2;}}return 0;
}static const struct rt_hwtimer_info _info = TIM_DEV_INFO_CONFIG;
static const struct rt_hwtimer_ops _ops =
{.init = timer_init,.start = timer_start,.stop = timer_stop,.count_get = timer_counter_get,.control = timer_ctrl,
};
struct stm32_hwtimer timer14_dev;void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef* htim)
{if (htim->Instance == TIM14){rt_device_hwtimer_isr(&timer14_dev.time_device);}
}
void TIM8_TRG_COM_TIM14_IRQHandler(void)
{/* enter interrupt */HAL_TIM_IRQHandler(timer14_dev.tim_handle);/* leave interrupt */
}
void stm32_hwtimer_init(void)
{timer14_dev.tim_handle = &htim14;timer14_dev.name = "timer14";timer14_dev.tim_irqn = TIM8_TRG_COM_TIM14_IRQn;timer14_dev.time_device.ops = &_ops;timer14_dev.time_device.info = &_info;
}rt_hwtimer_t* stm32_hwtimer_get(const int index)
{if (index == TIM14_INDEX) return &timer14_dev.time_device;return NULL;
}

测试

主程序

int receive_timeout_callback(rt_hwtimer_t* rt_hwtimer)
{printf("%d\r\n", HAL_GetTick());return 0;
}/* USER CODE END 0 *//*** @brief  The application entry point.* @retval int*/
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_DMA_Init();MX_USART1_UART_Init();MX_TIM14_Init();/* USER CODE BEGIN 2 */// 开启串口dma接收usart1_open_receive();stm32_hwtimer_init();rt_hwtimer_mode_t mode;uint32_t freq = 100000;rt_hwtimerval_t receive_time;rt_hwtimer_t* receive_time_dev = stm32_hwtimer_get(TIM14_INDEX);if (receive_time_dev == NULL){LOG_E("hwtimer sample run failed! can't find %s device!", RECEIVE_HWTIMER);return 1;}rt_hwtimer_init(receive_time_dev);rt_hwtimer_open(receive_time_dev);receive_time_dev->rx_indicate = receive_timeout_callback;rt_hwtimer_control(receive_time_dev, HWTIMER_CTRL_FREQ_SET, &freq);mode = HWTIMER_MODE_PERIOD;rt_hwtimer_control(receive_time_dev, HWTIMER_CTRL_MODE_SET, &mode);receive_time.sec = 5;receive_time.usec = 0;rt_hwtimer_write(receive_time_dev, &receive_time);/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){/* USER CODE END WHILE *//* USER CODE BEGIN 3 */HAL_Delay(1000);}/* USER CODE END 3 */
}

测试结果

在这里插入图片描述

http://www.xdnf.cn/news/1036909.html

相关文章:

  • Flutter JSON解析全攻略:使用json_serializable实现高效序列化
  • java设计模式[1]之设计模式概览
  • 免费电子印章生成工具,可在线设计印章
  • TLSF 内存分配器
  • 通达信跟老庄追涨停指标公式
  • 【大模型分布式训练】多卡解决单卡训练内存不足的问题
  • Python学习笔记面向对象编程
  • Python 中的 `lru_cache` 详解
  • 固件签名技术深度解析:HSM模块如何守护设备安全,CAS系统如何赋能产业升级
  • pytest的装饰器`pytest.mark.parametrize` 和 `@pytest.mark.smoke`区别
  • 中国电信天翼物联学习总结笔记:线上生成模型
  • 未来行业发展趋向
  • JavaScript 事件循环
  • 19 - SAFM模块
  • 27 - ASPP模块
  • 【redis——缓存雪崩(Cache Avalanche)】
  • 专注于PLC数据采集MES交互解决方案
  • 位运算详解之异或运算的奇妙操作
  • docker安装mysql数据库及简单使用
  • 鸿蒙NEXT-Data类型数据通过AppStore获取后找原本一样的数据(值一样)但是比较结果却为false
  • 关于cv::solvePnP算法的理解
  • Vue动态路由
  • 音频驱动数字人13款深度评测
  • leetcode_503 下一个更大元素
  • <11>-MySQL事务管理
  • 精益数据分析(103/126):免费移动应用的下载量、成本优化与案例解析
  • python队列练习 2022年信息素养大赛复赛/决赛真题 小学组/初中组 python编程挑战赛 真题详细解析
  • 使用 MoviePy 实现图像序列合成视频并添加背景音乐
  • 层压板选择、信号完整性和其他权衡
  • JasperReport生成PDF/A类型文档