|
做项目用stm8s太爽了,tim1高级定时器,使用一个通道作为pwm的DA转换,一个通道用作红外解码的输入捕获。很强大。
由于项目问题,只能发部分代码让大家参考下啊
//初始化定时器1
void init_time1(void)
{
//使用定时器1捕获通道1作为遥控解码
TIM1_CR1 = 0;
TIM1_CR2 = 0;
//预分频器
TIM1_PSCRH= 0;
TIM1_PSCRL= 0x07; //pwm 244HZ 周期4.096mS
//计数器
TIM1_CNTRH= 0;
TIM1_CNTRL= 0;
//TIM1预装载
TIM1_ARRH = 0x20;
TIM1_ARRL = 0x00;
//通道4配置为输出PWM模式0 使能预装载
TIM1_CCMR4 = BIT3|BIT4|BIT5|BIT6;
TIM1_CCR4H = 0x0; //比较寄存器0
TIM1_CCR4L = 0x0;
TIM1_CCER2 = BIT4; //允许输出
TIM1_BKR = BIT7; //主输出使能,无锁定保护
TIM1_EGR = BIT0; //产生更新事件初始化定时器1
TIM1_CR1 = BIT0; //启动定时器1选择边沿对齐模式 向上计数模式
}
//初始化红外接收
void init_irda(void)
{
irda_state = IRDA_STATE_IDLE; //红外接收空闲状态
irda_index = 0; //红外索引为0
//初始化输入捕获模块
//TIM1输入通道1用作红外输入解码
TIM1_CCER1 = 0; //关闭输入捕获
//采样频率fSAMPLING=fMASTER/32,N=8
//CC1通道被配置为输入,IC1映射在TI1FP1
TIM1_CCMR1 = BIT0|BIT4|BIT5|BIT6|BIT7;
//输入捕获通道1使能
//通道1下降沿捕获
TIM1_CCER1 = BIT0|BIT1;
//允许输入捕获1中断
//允许更新事件中断
TIM1_IER = BIT0|BIT1;
//输入捕获通道1使能
//通道1下降沿捕获
// TIM1_CCER1 = BIT0|BIT1;
}
//TIM1捕获比较中断
@far @interrupt void INTERRUPT_HANDLE_TIM1CAP(void)
{
static unsigned int irda_prerecdata; //前次红外捕获时间值
unsigned int irda_recdata,irda_time_temp; //本次红外捕获时间值
long irda_rectime; //红外接收时间
static unsigned char irda_indexmask; //接收掩码
static unsigned char irda_rectemp; //接收数据暂存
TIM1_SR1_CC1IF = 0; //清除捕获比较1中断标志
//对红外输出进行处理
TIM1_CCER1 = 0; //关闭输入捕获
//红外接收在空闲状态
if (IRDA_STATE_IDLE == irda_state)
{
//等待接收下降沿的起始位信号
//读取当前捕获值
irda_prerecdata = 0;
irda_prerecdata |= ((unsigned int)TIM1_CCR1H<<8);
irda_prerecdata |= TIM1_CCR1L;
//使能捕获通道1
//上升沿捕获
TIM1_CCER1 = BIT0;
irda_state = IRDA_STATE_START; //进入起始码接收状态
irda_tim1 = 0;
}
//红外起始码接收状态
else
{
//读取当前捕获值
irda_time_temp = 0;
irda_time_temp |= ((unsigned int)TIM1_CCR1H <<8);
irda_time_temp |= TIM1_CCR1L;
irda_recdata = irda_time_temp;
//判断间隔时间
if (irda_tim1)
{
//计算间隔时间
irda_rectime = 8192*irda_tim1 - irda_prerecdata;
irda_rectime += irda_recdata;
}
else
irda_rectime = irda_recdata-irda_prerecdata;
irda_prerecdata = irda_time_temp; //保存为前次测量值
irda_tim1 = 0; //扩展量程归0
//接收的上升沿,计算低电平脉宽
if (IRDA_STATE_START == irda_state)
{
//判断低电平是否在指定的范围 8mS<IR<10mS
if ((irda_rectime > 16000) && (irda_rectime < 20000))
{
//8mS<IR<10mS为有效地起始位
irda_state = IRDA_STATE_STARTEND; //进入下个状态准备测量高电平脉宽
}
else
irda_state = IRDA_STATE_IDLE; //脉宽不在允许范围内复位接收
}
//计算起始间隙位高电平位宽
else if (IRDA_STATE_STARTEND == irda_state)
{
//判断间隙脉宽是否有效
if (irda_rectime > 7000 && irda_rectime < 11000)
{
//3.5mS<IR<5.5mS为有效地间隙位
irda_state = IRDA_STATE_ADDR; //进入接收地址数据状态
irda_indexmask = 1; //移位掩码设置为最低位0x01
irda_rectemp = 0; //移位重组变量归零
irda_index = 0; //数据索引归0
}
else if (irda_rectime > 2800 && irda_rectime < 6400)
{
//1.4mS<IR<3.2mS为连按
irda_state = IRDA_STATE_IDLE;
irda_indexmask = 1; //移位掩码设置为最低位0x01
irda_rectemp = 0; //移位重组变量归零
irda_index = 0; //数据索引归0
task_mask.task_irda = 1; //按键连按,启动红外接收任务
}
else
//脉宽不在指定的范围,复位接收
irda_state = IRDA_STATE_IDLE;
}
//下降沿捕获,计算地址位脉宽周期
else if (IRDA_STATE_ADDR == irda_state)
{
//判断数据周期是否有效
if (irda_rectime > 3360 & irda_rectime < 6000)
{
//1.68mS<IR<3mS为有效数据1
irda_rectemp |= irda_indexmask; //重组接收数据
}
//IR<0.5mS 或 IR>3mS数据无效
else if (irda_rectime > 6000 || irda_rectime < 1000)
irda_state = IRDA_STATE_IDLE; //脉宽超过0/1的范围复位接收
//一个字节接收完成
if (irda_indexmask == 0x80)
{
if (irda_index < 4)
{
//4字节接收未完成
((unsigned char *)(&irda_rcv))[irda_index] = irda_rectemp;
if (++irda_index > 3) //四字节接收完成,复位接收历程
{
irda_state = IRDA_STATE_IDLE; //重新进入空闲状态
task_mask.task_irda; //启动红外接收任务
}
}
else
{
irda_state = IRDA_STATE_IDLE;
}
irda_indexmask = 1; //重新接收下个字节
irda_rectemp = 0;
}
else //未接受完整个字节,移位并继续接受
irda_indexmask <<= 1;
}
TIM1_CCER1 = BIT0|BIT1; //下降沿捕获
}
}
//TIM1更新溢出中断
@far @interrupt void INTERRUPT_HANDLE_TIM1UP(void)
{
TIM1_SR1_UIF = 0; //清除中断标志
//在接收中产生错误,复位接收状态
if (IRDA_STATE_IDLE != irda_state)
{
if (irda_tim1 > 50)
{
//在测量脉宽时200mS未检测到指定的边沿复位接收
irda_state = IRDA_STATE_IDLE; //为空闲状态等待接收下降沿的起始位
irda_tim1 = 0;
TIM1_CCER1 = BIT0|BIT1; //下降沿捕获
}
else
irda_tim1++;
}
}
先简单的做红外解码,另外以后在解码连按时加入一个时间窗口,超过这个时间窗口的就不能再认为是连按了。
做了下试验,效果不错啊 |
|
|