通用定时器基本原理
三种STM32定时器区别
定时器 种类 |
位数 |
计数器 模式 |
产生DMA请求 |
捕获比较 通道 |
互补 输出 |
特殊应用场景 |
高级定时器 (TIM1,TIM8) |
16 |
向上,向下,向上/下 |
可以 |
4 |
有 |
带可编程死区的互补输出 |
通用定时器(TIM2,TIM5) |
32 |
向上,向下,向上/下 |
可以 |
4 |
无 |
通用。定时计数,PWM输出,输入捕获,输出比较 |
通用定时器(TIM3,TIM4) |
16 |
向上,向下,向上/下 |
可以 |
4 |
无 |
通用。定时计数,PWM输出,输入捕获,输出比较 |
通用定时器(TIM9~TIM14) |
16 |
向上 |
没有 |
2 |
无 |
通用。定时计数,PWM输出,输入捕获,输出比较 |
基本定时器 (TIM6,TIM7) |
16 |
向上,向下,向上/下 |
可以 |
0 |
无 |
主要应用于驱动DAC |
通用定时器功能特点描述
STM32的通用 TIMx (TIM2、TIM3、TIM4 和 TIM5等)定时器功能特点包括:
16 /32 位向上、向下、向上/向下(中心对齐)计数模式,自动装载计数器(TIMx_CNT)。
16 位可编程(可以实时修改)预分频器(TIMx_PSC),计数器时钟频率的分频系数 为 1~65535 之间的任意数值。
4 个独立通道(TIMx_CH1~4),这些通道可以用来作为:
① 输入捕获
② 输出比较
③ PWM 生成(边缘或中间对齐模式)
④ 单脉冲模式输出
可使用外部信号(TIMx_ETR)控制定时器和定时器互连(可以用 1 个定时器控制另外一个定时器)的同步电路。
如下事件发生时产生中断/DMA(6个独立的IRQ/DMA请求生成器):
①更新:计数器向上溢出/向下溢出,计数器初始化(通过软件或者内部/外部触发)
②触发事件(计数器启动、停止、初始化或者由内部/外部触发计数)
③输入捕获
④输出比较
⑤支持针对定位的增量(正交)编码器和霍尔传感器电路
⑥触发输入作为外部时钟或者按周期的电流管理
STM32 的通用定时器可以被用于:测量输入信号的脉冲长度(输入捕获)或者产生输出波形(输出比较和 PWM)等。
使用定时器预分频器和 RCC 时钟控制器预分频器,脉冲长度和波形周期可以在几个微秒到几个毫秒间调整。STM32 的每个通用定时器都是完全独立的,没有互相共享的任何资源。
计数器模式
通用定时器可以向上计数、向下计数、向上向下双向计数模式。
①向上计数模式:计数器从0计数到自动加载值(TIMx_ARR),然后重新从0开始计数并且产生一个计数器溢出事件。
②向下计数模式:计数器从自动装入的值(TIMx_ARR)开始向下计数到0,然后从自动装入的值重新开始,并产生一个计数器向下溢出事件。
③中央对齐模式(向上/向下计数):计数器从0开始计数到自动装入的值-1,产生一个计数器溢出事件,然后向下计数到1并且产生一个计数器溢出事件;然后再从0开始重新计数。
通用定时器(TIM2,3,4,5)工作过程
![通用定时器工作过程]()
定时器中断原理与配置
时钟选择
计数器时钟可以由下列时钟源提供:
①内部时钟(CK_INT)
除非APB1的分频系数是1,否则通用定时器的时钟CK_INT等于APB1时钟的2倍。
![内部时钟选择]()
②外部时钟模式1:外部输入脚(TIx)
③外部时钟模式2:外部触发输入(ETR)(仅适用TIM2,3,4)
④内部触发输入(ITRx):使用一个定时器作为另一个定时器的预分频器,如可以配置一个定时器Timer1而作为另一个定时器Timer2的预分频器。
定时器中断实验相关寄存器
计数器当前值寄存器CNT
![计数器当前值寄存器CNT]()
预分频寄存器TIMx_PSC
![预分频寄存器TIMx_PSC]()
自动重装载寄存器(TIMx_ARR)
![自动重装载寄存器(TIMx_ARR)]()
控制寄存器1(TIMx_CR1)
![控制寄存器1(TIMx_CR1)]()
DMA中断使能寄存器(TIMx_DIER)
![DMA中断使能寄存器(TIMx_DIER)]()
定时器时基部分常用函数
①定时器时基参数初始化函数:
1 2 3 4 5 6 7 8 9 10
| HAL_StatusTypeDef HAL_TIM_Base_Init(TIM_HandleTypeDef *htim);
typedef struct { uint32_t Prescaler; uint32_t CounterMode; uint32_t Period; uint32_t ClockDivision; uint32_t RepetitionCounter; } TIM_Base_InitTypeDef;
|
②定时器时基参数初始化回调函数:
1 2 3 4
| void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim);
__HAL_RCC_TIM3_CLK_ENABLE();
|
③使能定时器:
1 2 3 4
| HAL_StatusTypeDef HAL_TIM_Base_Start(TIM_HandleTypeDef *htim)
HAL_StatusTypeDef HAL_TIM_Base_Start_IT(TIM_HandleTypeDef *htim)
|
④定时器中断通用处理函数:
1
| void HAL_TIM_IRQHandler(TIM_HandleTypeDef *htim);
|
该函数被中断服务函数调用。是定时器中断处理通用入口函数,
通过对中断类型进行分析判断,调用对应的回调函数。
⑤定时器中断处理回调函数:
1 2 3 4 5 6
| void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim); void HAL_TIM_OC_DelayElapsedCallback(TIM_HandleTypeDef *htim) void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim) void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim) void HAL_TIM_TriggerCallback(TIM_HandleTypeDef *htim) void HAL_TIM_ErrorCallback(TIM_HandleTypeDef *htim)
|
定时器中断实现步骤
① 使能定时器时钟。
1
| __HAL_RCC_TIM3_CLK_ENABLE();
|
② 初始化定时器,配置ARR,PSC。
③ 开启定时器/中断。
1 2 3
| HAL_TIM_Base_Start();
HAL_TIM_Base_Start_IT();
|
④ 设置中断优先级。
1 2
| HAL_NVIC_SetPriority(); HAL_NVIC_EnableIRQ();
|
⑤ 编写中断服务函数。
1 2 3 4 5
| TIMx_IRQHandler();
HAL_TIM_IRQHandler();
HAL_TIM_PeriodElapsedCallback();
|
程序源码
timer.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| #include "timer.h" #include "led.h"
TIM_HandleTypeDef TIM3_Handler;
void TIM3_Init(u16 arr,u16 psc) { TIM3_Handler.Instance=TIM3; TIM3_Handler.Init.Prescaler=psc; TIM3_Handler.Init.CounterMode=TIM_COUNTERMODE_UP; TIM3_Handler.Init.Period=arr; TIM3_Handler.Init.ClockDivision=TIM_CLOCKDIVISION_DIV1; HAL_TIM_Base_Init(&TIM3_Handler); HAL_TIM_Base_Start_IT(&TIM3_Handler); }
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim) { if(htim->Instance==TIM3) { __HAL_RCC_TIM3_CLK_ENABLE(); HAL_NVIC_SetPriority(TIM3_IRQn,1,3); HAL_NVIC_EnableIRQ(TIM3_IRQn); } }
void TIM3_IRQHandler(void) { HAL_TIM_IRQHandler(&TIM3_Handler); }
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { if(htim==(&TIM3_Handler)) { LED1=!LED1; } }
|
PWM输出原理与配置
STM32 PWM工作过程
PWM模式:脉冲宽度调制模式可以生成一个信号,该信号频率由TIMx_ARR寄存器决定,其占空比则由TIMx_CRRx寄存器决定。
![PWM工作过程1]()
![PWM工作过程2]()
CCR1:捕获比较(值)寄存器(x=1,2,3,4):设置比较值。
CCMR1: OC1M[2:0]位:
对于PWM方式下,用于设置PWM模式1【110】或者PWM模式2【111】
![PWM模式]()
CCER:CC1P位:输入/捕获1输出极性。0:高电平有效,1:低电平有效。
CCER:CC1E位:输入/捕获1输出使能。0:关闭,1:打开。
定时器PWM功能常用函数
①定时器PWM时基参数初始化函数:
1 2 3 4 5 6 7 8 9 10 11
| HAL_StatusTypeDef HAL_TIM_PWM_Init(TIM_HandleTypeDef *htim)
typedef struct { uint32_t Prescaler; uint32_t CounterMode; uint32_t Period; uint32_t ClockDivision; uint32_t RepetitionCounter; } TIM_Base_InitTypeDef;
|
②定时器PWM时基参数初始化回调函数:
1 2 3 4
| void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim);
__HAL_RCC_TIM3_CLK_ENABLE();
|
③PWM输出比较通道参数配置函数:
1 2 3 4 5 6 7 8 9 10 11 12
| HAL_StatusTypeDef HAL_TIM_PWM_ConfigChannel(TIM_HandleTypeDef *htim, TIM_OC_InitTypeDef* sConfig, uint32_t channel);
typedef struct { uint32_t OCMode; uint32_t Pulse; uint32_t OCPolarity; uint32_t OCNPolarity; uint32_t OCFastMode; uint32_t OCIdleState; uint32_t OCNIdleState; } TIM_OC_InitTypeDef;
|
④使能定时器和PWM输出比较通道:
1 2
| HAL_StatusTypeDef HAL_TIM_PWM_Start(TIM_HandleTypeDef *htim, uint32_t Channel); HAL_StatusTypeDef HAL_TIM_PWM_Start_IT(TIM_HandleTypeDef *htim, uint32_t Channel);
|
PWM输出配置步骤:
①使能定时器时钟和通道IO口时钟。
②配置IO口复用映射:
③初始化PWM时基参数:
④初始化PWM通道参数:
1
| HAL_TIM_PWM_ConfigChannel();
|
⑤使能定时器PWM
程序源码
timer.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| #include "timer.h" #include "led.h"
TIM_HandleTypeDef TIM3_Handler; TIM_OC_InitTypeDef TIM3_CH4Handler;
void TIM3_PWM_Init(u16 arr,u16 psc) { TIM3_Handler.Instance=TIM3; TIM3_Handler.Init.Prescaler=psc; TIM3_Handler.Init.CounterMode=TIM_COUNTERMODE_UP; TIM3_Handler.Init.Period=arr; TIM3_Handler.Init.ClockDivision=TIM_CLOCKDIVISION_DIV1; HAL_TIM_PWM_Init(&TIM3_Handler); TIM3_CH4Handler.OCMode=TIM_OCMODE_PWM1; TIM3_CH4Handler.Pulse=arr/2; TIM3_CH4Handler.OCPolarity=TIM_OCPOLARITY_LOW; HAL_TIM_PWM_ConfigChannel(&TIM3_Handler,&TIM3_CH4Handler,TIM_CHANNEL_4); HAL_TIM_PWM_Start(&TIM3_Handler,TIM_CHANNEL_4); }
void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim) { GPIO_InitTypeDef GPIO_Initure; __HAL_RCC_TIM3_CLK_ENABLE(); __HAL_RCC_GPIOB_CLK_ENABLE(); GPIO_Initure.Pin=GPIO_PIN_1; GPIO_Initure.Mode=GPIO_MODE_AF_PP; GPIO_Initure.Pull=GPIO_PULLUP; GPIO_Initure.Speed=GPIO_SPEED_HIGH; GPIO_Initure.Alternate= GPIO_AF2_TIM3; HAL_GPIO_Init(GPIOB,&GPIO_Initure); }
void TIM_SetTIM3Compare4(u32 compare) { TIM3->CCR4=compare; }
|
输入捕获原理与配置
STM32 输入捕获工作过程
![STM32 输入捕获工作过程]()
通过检测TIMx_CHx上的边沿信号,在边沿信号发生跳变(比如上升沿/下降沿)的时候,将当前定时器的值(TIMx_CNT)存放到对应的捕获/比较寄存器(TIMx_CCRx)里面,完成一次捕获。
步骤1:设置输入捕获滤波器
![设置输入捕获滤波器1]()
![设置输入捕获滤波器2]()
步骤2:设置输入捕获极性
![设置输入捕获极性1]()
![设置输入捕获极性2]()
步骤三:设置输入捕获映射通道
![设置输入捕获映射通道1]()
![设置输入捕获映射通道2]()
步骤四:设置输入捕获分频器
![设置输入捕获分频器(通道1为例)1]()
![设置输入捕获分频器(通道1为例)2]()
![设置输入捕获分频器(通道1为例)3]()
步骤五:捕获到有效信号可以开启中断
![捕获到有效信号可以开启中断]()
定时器输入捕获功能常用函数
①定时器输入捕获时基参数初始化函数:
1 2 3 4 5 6 7 8 9 10
| HAL_StatusTypeDef HAL_TIM_IC_Init(TIM_HandleTypeDef *htim)
typedef struct { uint32_t Prescaler; uint32_t CounterMode; uint32_t Period; uint32_t ClockDivision; uint32_t RepetitionCounter; } TIM_Base_InitTypeDef;
|
该函数和HAL_TIM_Base_Init/HAL_TIM_PWM_Init函数作用一样,
不同的是引导调用不同的回调函数。
②定时器输入捕获时基参数初始化回调函数:
1 2 3 4
| void HAL_TIM_IC_MspInit(TIM_HandleTypeDef *htim);
__HAL_RCC_TIM5_CLK_ENABLE();
|
③输入捕获通道参数配置函数:
1 2 3 4 5 6 7 8 9
| HAL_StatusTypeDef HAL_TIM_IC_ConfigChannel(TIM_HandleTypeDef *htim,TIM_IC_InitTypeDef* sConfig, uint32_t Channel);
typedef struct { uint32_t ICPolarity; uint32_t ICSelection; uint32_t ICPrescaler; uint32_t ICFilter; } TIM_IC_InitTypeDef;
|
④使能定时器并使能输入捕获通道:
1 2 3
| HAL_StatusTypeDef HAL_TIM_IC_Start (TIM_HandleTypeDef *htim, uint32_t Channel);
HAL_StatusTypeDef HAL_TIM_IC_Start_IT (TIM_HandleTypeDef *htim, uint32_t Channel);
|
⑤捕获中断回调函数:
1
| void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
|
⑥读取捕获值:
1
| uint32_t HAL_TIM_ReadCapturedValue(TIM_HandleTypeDef*htim,uint32_t Channel);
|
输入捕获的一般配置关键步骤
①使能定时器时钟和通道IO口时钟。
②配置IO口复用映射:
③初始化输入捕获时基参数:
④初始化输入捕获通道参数:
1
| HAL_TIM_IC_ConfigChannel();
|
⑤使能定时器(中断),设置优先级:
⑥编写中断服务回调函数:
1
| HAL_TIM_IC_CaptureCallback();
|
程序源码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182
| #include "timer.h" #include "led.h"
TIM_HandleTypeDef TIM3_Handler; TIM_OC_InitTypeDef TIM3_CH4Handler;
void TIM3_PWM_Init(u16 arr,u16 psc) { TIM3_Handler.Instance=TIM3; TIM3_Handler.Init.Prescaler=psc; TIM3_Handler.Init.CounterMode=TIM_COUNTERMODE_UP; TIM3_Handler.Init.Period=arr; TIM3_Handler.Init.ClockDivision=TIM_CLOCKDIVISION_DIV1; HAL_TIM_PWM_Init(&TIM3_Handler); TIM3_CH4Handler.OCMode=TIM_OCMODE_PWM1; TIM3_CH4Handler.Pulse=arr/2; TIM3_CH4Handler.OCPolarity=TIM_OCPOLARITY_LOW; HAL_TIM_PWM_ConfigChannel(&TIM3_Handler,&TIM3_CH4Handler,TIM_CHANNEL_4); HAL_TIM_PWM_Start(&TIM3_Handler,TIM_CHANNEL_4); }
void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim) { GPIO_InitTypeDef GPIO_Initure; __HAL_RCC_TIM3_CLK_ENABLE(); __HAL_RCC_GPIOB_CLK_ENABLE(); GPIO_Initure.Pin=GPIO_PIN_1; GPIO_Initure.Mode=GPIO_MODE_AF_PP; GPIO_Initure.Pull=GPIO_PULLUP; GPIO_Initure.Speed=GPIO_SPEED_HIGH; GPIO_Initure.Alternate= GPIO_AF2_TIM3; HAL_GPIO_Init(GPIOB,&GPIO_Initure); }
void TIM_SetTIM3Compare4(u32 compare) { TIM3->CCR4=compare; }
u32 TIM_GetTIM3Capture4(void) { return HAL_TIM_ReadCapturedValue(&TIM3_Handler,TIM_CHANNEL_4); }
TIM_HandleTypeDef TIM5_Handler;
void TIM5_CH1_Cap_Init(u32 arr,u16 psc) { TIM_IC_InitTypeDef TIM5_CH1Config; TIM5_Handler.Instance=TIM5; TIM5_Handler.Init.Prescaler=psc; TIM5_Handler.Init.CounterMode=TIM_COUNTERMODE_UP; TIM5_Handler.Init.Period=arr; TIM5_Handler.Init.ClockDivision=TIM_CLOCKDIVISION_DIV1; HAL_TIM_IC_Init(&TIM5_Handler); TIM5_CH1Config.ICPolarity=TIM_ICPOLARITY_RISING; TIM5_CH1Config.ICSelection=TIM_ICSELECTION_DIRECTTI; TIM5_CH1Config.ICPrescaler=TIM_ICPSC_DIV1; TIM5_CH1Config.ICFilter=0; HAL_TIM_IC_ConfigChannel(&TIM5_Handler,&TIM5_CH1Config,TIM_CHANNEL_1); HAL_TIM_IC_Start_IT(&TIM5_Handler,TIM_CHANNEL_1); __HAL_TIM_ENABLE_IT(&TIM5_Handler,TIM_IT_UPDATE); }
void HAL_TIM_IC_MspInit(TIM_HandleTypeDef *htim) { GPIO_InitTypeDef GPIO_Initure; __HAL_RCC_TIM5_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); GPIO_Initure.Pin=GPIO_PIN_0; GPIO_Initure.Mode=GPIO_MODE_AF_PP; GPIO_Initure.Pull=GPIO_PULLDOWN; GPIO_Initure.Speed=GPIO_SPEED_HIGH; GPIO_Initure.Alternate=GPIO_AF2_TIM5; HAL_GPIO_Init(GPIOA,&GPIO_Initure);
HAL_NVIC_SetPriority(TIM5_IRQn,2,0); HAL_NVIC_EnableIRQ(TIM5_IRQn); }
u8 TIM5CH1_CAPTURE_STA=0; u32 TIM5CH1_CAPTURE_VAL;
void TIM5_IRQHandler(void) { HAL_TIM_IRQHandler(&TIM5_Handler); }
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { if((TIM5CH1_CAPTURE_STA&0X80)==0) { if(TIM5CH1_CAPTURE_STA&0X40) { if((TIM5CH1_CAPTURE_STA&0X3F)==0X3F) { TIM5CH1_CAPTURE_STA|=0X80; TIM5CH1_CAPTURE_VAL=0XFFFFFFFF; }else TIM5CH1_CAPTURE_STA++; } } }
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim) { if((TIM5CH1_CAPTURE_STA&0X80)==0) { if(TIM5CH1_CAPTURE_STA&0X40) { TIM5CH1_CAPTURE_STA|=0X80; TIM5CH1_CAPTURE_VAL=HAL_TIM_ReadCapturedValue(&TIM5_Handler,TIM_CHANNEL_1); TIM_RESET_CAPTUREPOLARITY(&TIM5_Handler,TIM_CHANNEL_1); TIM_SET_CAPTUREPOLARITY(&TIM5_Handler,TIM_CHANNEL_1,TIM_ICPOLARITY_RISING); }else { TIM5CH1_CAPTURE_STA=0; TIM5CH1_CAPTURE_VAL=0; TIM5CH1_CAPTURE_STA|=0X40; __HAL_TIM_DISABLE(&TIM5_Handler); __HAL_TIM_SET_COUNTER(&TIM5_Handler,0); TIM_RESET_CAPTUREPOLARITY(&TIM5_Handler,TIM_CHANNEL_1); TIM_SET_CAPTUREPOLARITY(&TIM5_Handler,TIM_CHANNEL_1,TIM_ICPOLARITY_FALLING); __HAL_TIM_ENABLE(&TIM5_Handler); } } }
|
TIMER电容触摸按键原理与实验
电容触摸按键原理
结论:同样的条件下,电容值C跟时间值t成正比关系,电容越大,充电到达某个临界值的时间越长。
![电容触摸按键原理]()
R:外接电容充放电电阻。
Cs:TPAD和PCB间的杂散电容。
Cx:手指按下时,手指和TPAD之间的电容。
开关:电容放电开关,由STM32 IO口代替。
检测电容触摸按键过程
①TPAD引脚设置为推挽输出,输出0,实现电容放电到0。
②TPAD引脚设置为浮空输入(IO复位后的状态),电容开始充电。
③同时开启TPAD引脚的输入捕获开始捕获。
④等待充电完成(充电到底Vx,检测到上升沿)。
⑤计算充电时间。
没有按下的时候,充电时间为T1(default)。按下TPAD,电容变大,所以充电时间为T2。我们可以通过检测充放电时间,来判断是否按下。如果T2-T1大于某个值,就可以判断有按键按下。
几个重要的函数
①void TPAD_Reset(void)函数:复位TPAD
设置IO口为推挽输出输出0,电容放电。等待放电完成之后,设置为浮空
输入,从而开始充电。同时把计数器的CNT设置为0。
② TPAD_Get_Val()函数:获取一次捕获值(得到充电时间)
复位TPAD,等待捕获上升沿,捕获之后,得到定时器的值,计算充电时间。
③ TPAD_Get_MaxVal()函数:
多次调用TPAD_Get_Val函数获取充电时间。获取最大的值。
④ TPAD_Init()函数:初始化TPAD
在系统启动后,初始化输入捕获。先10次调用TPAD_Get_Val()函数获取
10次充电时间,然后获取中间N(N=8或者6)次的平均值,作为在没有电容触摸按键按下的时候的充电时间缺省值tpad_default_val。
⑤ TPAD_Scan()函数:扫描TPAD
调用TPAD_Get_MaxVal函数获取多次充电中最大的充电时间,跟
tpad_default_val比较,如果大于某个阈值,则认为有触摸动作。
⑥ void TIM2_CH2_Cap_Init(u16 arr,u16 psc//输入捕获通道初始化
可以使用任何一个定时器。M3使用定时器5,M4使用的定时器2。
程序思路![程序思路]()
程序源码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
| #include "tpad.h" #include "delay.h" #include "usart.h"
TIM_HandleTypeDef TIM2_Handler;
#define TPAD_ARR_MAX_VAL 0XFFFFFFFF vu16 tpad_default_val=0;
u8 TPAD_Init(u8 psc) { u16 buf[10]; u16 temp; u8 j,i; TIM2_CH1_Cap_Init(TPAD_ARR_MAX_VAL,psc-1); for(i=0;i<10;i++) { buf[i]=TPAD_Get_Val(); delay_ms(10); } for(i=0;i<9;i++) { for(j=i+1;j<10;j++) { if(buf[i]>buf[j]) { temp=buf[i]; buf[i]=buf[j]; buf[j]=temp; } } } temp=0; for(i=2;i<8;i++)temp+=buf[i]; tpad_default_val=temp/6; printf("tpad_default_val:%d\r\n",tpad_default_val); if(tpad_default_val>TPAD_ARR_MAX_VAL/2)return 1; return 0; }
void TPAD_Reset(void) { GPIO_InitTypeDef GPIO_Initure; GPIO_Initure.Pin=GPIO_PIN_5; GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP; GPIO_Initure.Pull=GPIO_PULLDOWN; GPIO_Initure.Speed=GPIO_SPEED_HIGH; HAL_GPIO_Init(GPIOA,&GPIO_Initure); HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_RESET); delay_ms(5); __HAL_TIM_CLEAR_FLAG(&TIM2_Handler,TIM_FLAG_CC1|TIM_FLAG_UPDATE); __HAL_TIM_SET_COUNTER(&TIM2_Handler,0); GPIO_Initure.Mode=GPIO_MODE_AF_PP; GPIO_Initure.Pull=GPIO_NOPULL; GPIO_Initure.Alternate=GPIO_AF1_TIM2; HAL_GPIO_Init(GPIOA,&GPIO_Initure); }
u16 TPAD_Get_Val(void) { TPAD_Reset(); while(__HAL_TIM_GET_FLAG(&TIM2_Handler,TIM_FLAG_CC1)==RESET) { if(__HAL_TIM_GET_COUNTER(&TIM2_Handler)>TPAD_ARR_MAX_VAL-500) return __HAL_TIM_GET_COUNTER(&TIM2_Handler); }; return HAL_TIM_ReadCapturedValue(&TIM2_Handler,TIM_CHANNEL_1); }
u16 TPAD_Get_MaxVal(u8 n) { u16 temp=0; u16 res=0; u8 lcntnum=n*2/3; u8 okcnt=0; while(n--) { temp=TPAD_Get_Val(); if(temp>(tpad_default_val*5/4))okcnt++; if(temp>res)res=temp; } if(okcnt>=lcntnum)return res; else return 0; }
u8 TPAD_Scan(u8 mode) { static u8 keyen=0; u8 res=0; u8 sample=3; u16 rval; if(mode) { sample=6; keyen=0; } rval=TPAD_Get_MaxVal(sample); if(rval>(tpad_default_val*4/3)&&rval<(10*tpad_default_val)) { if(keyen==0)res=1; printf("r:%d\r\n",rval); keyen=3; } if(keyen)keyen--; return res; }
void TIM2_CH1_Cap_Init(u32 arr,u16 psc) { TIM_IC_InitTypeDef TIM2_CH1Config; TIM2_Handler.Instance=TIM2; TIM2_Handler.Init.Prescaler=psc; TIM2_Handler.Init.CounterMode=TIM_COUNTERMODE_UP; TIM2_Handler.Init.Period=arr; TIM2_Handler.Init.ClockDivision=TIM_CLOCKDIVISION_DIV1; HAL_TIM_IC_Init(&TIM2_Handler); TIM2_CH1Config.ICPolarity=TIM_ICPOLARITY_RISING; TIM2_CH1Config.ICSelection=TIM_ICSELECTION_DIRECTTI; TIM2_CH1Config.ICPrescaler=TIM_ICPSC_DIV1; TIM2_CH1Config.ICFilter=0; HAL_TIM_IC_ConfigChannel(&TIM2_Handler,&TIM2_CH1Config,TIM_CHANNEL_1); HAL_TIM_IC_Start(&TIM2_Handler,TIM_CHANNEL_1); }
void HAL_TIM_IC_MspInit(TIM_HandleTypeDef *htim) { GPIO_InitTypeDef GPIO_Initure; __HAL_RCC_TIM2_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); GPIO_Initure.Pin=GPIO_PIN_5; GPIO_Initure.Mode=GPIO_MODE_AF_PP; GPIO_Initure.Pull=GPIO_NOPULL; GPIO_Initure.Speed=GPIO_SPEED_HIGH; GPIO_Initure.Alternate=GPIO_AF1_TIM2; HAL_GPIO_Init(GPIOA,&GPIO_Initure); }
|