195 lines
7.0 KiB
C
195 lines
7.0 KiB
C
#include "ir.h"
|
||
|
||
timer_ic_parameter_struct timer_icinitpara;
|
||
|
||
// 遥控器接收状态
|
||
//[7]:收到了引导码标志
|
||
//[6]:得到了一个按键的所有信息
|
||
//[5]:保留
|
||
//[4]:标记上升沿是否已经被捕获
|
||
//[3:0]:溢出计时器
|
||
uint8_t RmtSta = 0;
|
||
uint16_t Dval; // 下降沿时计数器的值
|
||
uint32_t RmtRec = 0; // 红外接收到的数据
|
||
uint8_t RmtCnt = 0; // 按键按下的次数
|
||
|
||
/* 红外遥控初始化 */
|
||
void ir_init(void)
|
||
{
|
||
rcu_periph_clock_enable(RCU_AF);
|
||
|
||
/*configure PA6 (TIMER2 CH0) as alternate function*/
|
||
gpio_config(IR_IN_PERIPH, IR_IN_PIN, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, nullptr);
|
||
|
||
nvic_priority_group_set(NVIC_PRIGROUP_PRE1_SUB3);
|
||
nvic_irq_enable(TIMER2_IRQn, 1, 1);
|
||
|
||
/* TIMER2 configuration: PWM input mode ------------------------
|
||
the external signal is connected to TIMER2 CH0 pin(PA6)
|
||
the rising edge is used as active edge
|
||
the TIMER2 CH0CV is used to compute the frequency value
|
||
the TIMER2 CH1CV is used to compute the duty cycle value
|
||
------------------------------------------------------------ */
|
||
timer_parameter_struct timer_initpara;
|
||
|
||
rcu_periph_clock_enable(RCU_TIMER2);
|
||
|
||
timer_deinit(TIMER2);
|
||
|
||
/* TIMER2 configuration */
|
||
timer_initpara.prescaler = 107;
|
||
timer_initpara.alignedmode = TIMER_COUNTER_EDGE;
|
||
timer_initpara.counterdirection = TIMER_COUNTER_UP;
|
||
timer_initpara.period = 65535;
|
||
timer_initpara.clockdivision = TIMER_CKDIV_DIV1;
|
||
timer_initpara.repetitioncounter = 0;
|
||
timer_init(TIMER2, &timer_initpara);
|
||
|
||
/* TIMER2 configuration */
|
||
/* TIMER2 CH0 PWM input capture configuration */
|
||
timer_icinitpara.icpolarity = TIMER_IC_POLARITY_RISING;
|
||
timer_icinitpara.icselection = TIMER_IC_SELECTION_DIRECTTI;
|
||
timer_icinitpara.icprescaler = TIMER_IC_PSC_DIV1;
|
||
timer_icinitpara.icfilter = 0x00;
|
||
timer_input_pwm_capture_config(TIMER2, TIMER_CH_0, &timer_icinitpara);
|
||
|
||
/* auto-reload preload enable */
|
||
timer_auto_reload_shadow_enable(TIMER2);
|
||
/* clear channel 0 interrupt bit */
|
||
timer_interrupt_flag_clear(TIMER2, TIMER_INT_FLAG_CH0 | TIMER_INT_FLAG_UP);
|
||
/* channel 0 interrupt enable */
|
||
timer_interrupt_enable(TIMER2, TIMER_INT_CH0 | TIMER_INT_FLAG_UP);
|
||
|
||
/* TIMER2 counter enable */
|
||
timer_enable(TIMER2);
|
||
}
|
||
|
||
void ir_process(void)
|
||
{
|
||
uint8_t sta = 0;
|
||
uint8_t t1, t2;
|
||
if (RmtSta & (1 << 6)) // 得到一个按键的所有信息了
|
||
{
|
||
t1 = RmtRec >> 24; // 得到地址码
|
||
t2 = (RmtRec >> 16) & 0xff; // 得到地址反码
|
||
if (t1 == (uint8_t)~t2 && t1 == IR_ID) // 检验遥控识别码(ID)及地址
|
||
{
|
||
t1 = RmtRec >> 8; // 得到控制码
|
||
t2 = RmtRec; // 得到控制反码
|
||
if (t1 == (uint8_t)~t2)
|
||
{
|
||
sta = t1; // 键值正确
|
||
|
||
ir_key_triggered(sta);
|
||
|
||
RmtSta &= ~(1 << 6); // 清除接收到有效按键标识
|
||
RmtCnt = 0; // 清除按键次数计数器
|
||
}
|
||
}
|
||
|
||
if ((sta == 0) || ((RmtSta & 0X80) == 0)) // 按键数据错误/遥控已经没有按下了
|
||
{
|
||
RmtSta &= ~(1 << 6); // 清除接收到有效按键标识
|
||
RmtCnt = 0; // 清除按键次数计数器
|
||
}
|
||
}
|
||
}
|
||
|
||
__weak void ir_key_triggered(uint8_t key) {}
|
||
|
||
void TIMER2_IRQHandler(void)
|
||
{
|
||
if (SET == timer_interrupt_flag_get(TIMER2, TIMER_INT_FLAG_CH0))
|
||
{
|
||
/* 捕获到上升没沿,读取GPIO PIN状态当为1时是上升沿 */
|
||
if (gpio_input_bit_get(IR_IN_PERIPH, IR_IN_PIN))
|
||
{
|
||
/* 设置为下降沿捕获 */
|
||
timer_icinitpara.icpolarity = TIMER_IC_POLARITY_FALLING;
|
||
timer_icinitpara.icselection = TIMER_IC_SELECTION_DIRECTTI;
|
||
timer_icinitpara.icprescaler = TIMER_IC_PSC_DIV1;
|
||
timer_icinitpara.icfilter = 0;
|
||
timer_input_capture_config(TIMER2, TIMER_CH_0, &timer_icinitpara);
|
||
|
||
/* 清空定时器值 */
|
||
timer_counter_value_config(TIMER2, 0);
|
||
|
||
/* 标记上升沿已经被捕获 */
|
||
RmtSta |= 0X10;
|
||
}
|
||
else
|
||
{
|
||
Dval = timer_counter_read(TIMER2);
|
||
|
||
/* 设置为上升沿捕获 */
|
||
timer_icinitpara.icpolarity = TIMER_IC_POLARITY_RISING;
|
||
timer_icinitpara.icselection = TIMER_IC_SELECTION_DIRECTTI;
|
||
timer_icinitpara.icprescaler = TIMER_IC_PSC_DIV1;
|
||
timer_icinitpara.icfilter = 0;
|
||
timer_input_capture_config(TIMER2, TIMER_CH_0, &timer_icinitpara);
|
||
|
||
/* 完成一次高电平捕获 */
|
||
if (RmtSta & 0X10)
|
||
{
|
||
/* 接收到了引导码 */
|
||
if (RmtSta & 0X80)
|
||
{
|
||
/* 标准值为560us */
|
||
if (Dval > 300 && Dval < 800)
|
||
{
|
||
/* 左移一位, 接收到 0 */
|
||
RmtRec <<= 1;
|
||
RmtRec |= 0;
|
||
}
|
||
/* 标准值为1680us */
|
||
else if (Dval > 1400 && Dval < 1800)
|
||
{
|
||
/* 左移一位, 接收到 1 */
|
||
RmtRec <<= 1;
|
||
RmtRec |= 1;
|
||
}
|
||
else if (Dval > 2200 && Dval < 2600) // 得到按键键值增加的信息 2500为标准值2.5ms
|
||
{
|
||
RmtCnt++; // 按键次数增加1次
|
||
RmtSta &= 0XF0; // 清空计时器
|
||
}
|
||
}
|
||
else if (Dval > 4200 && Dval < 4700) // 4500为标准值4.5ms
|
||
{
|
||
RmtSta |= 1 << 7; // 标记成功接收到了引导码
|
||
RmtCnt = 0; // 清除按键次数计数器
|
||
}
|
||
}
|
||
|
||
RmtSta &= ~(1 << 4);
|
||
}
|
||
|
||
/* clear channel 0 interrupt bit */
|
||
timer_interrupt_flag_clear(TIMER2, TIMER_INT_FLAG_CH0);
|
||
}
|
||
|
||
if (SET == timer_interrupt_flag_get(TIMER2, TIMER_INT_FLAG_UP)) // 定时器超时,没有获捕获到任何信号
|
||
{
|
||
if (RmtSta & 0x80) // 上次有数据被接收到了
|
||
{
|
||
RmtSta &= ~0X10; // 取消上升沿已经被捕获标记
|
||
if ((RmtSta & 0X0F) == 0X00)
|
||
RmtSta |= 1 << 6; // 标记已经完成一次按键的键值信息采集
|
||
if ((RmtSta & 0X0F) < 14)
|
||
RmtSta++;
|
||
else
|
||
{
|
||
RmtSta &= ~(1 << 7); // 清空引导标识
|
||
RmtSta &= 0XF0; // 清空计数器
|
||
}
|
||
}
|
||
|
||
timer_icinitpara.icpolarity = TIMER_IC_POLARITY_RISING;
|
||
timer_icinitpara.icselection = TIMER_IC_SELECTION_DIRECTTI;
|
||
timer_icinitpara.icprescaler = TIMER_IC_PSC_DIV1;
|
||
timer_icinitpara.icfilter = 0;
|
||
|
||
timer_input_capture_config(TIMER2, TIMER_CH_0, &timer_icinitpara);
|
||
timer_interrupt_flag_clear(TIMER2, TIMER_INT_FLAG_UP);
|
||
}
|
||
} |