查看: 1141|回复: 0
打印 上一主题 下一主题

stm8s高级定时器tim1红外解码外加pwm输出的用法

[复制链接]
跳转到指定楼层
沙发
发表于 2016-4-13 20:09:43 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
做项目用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++;
        }
}
先简单的做红外解码,另外以后在解码连按时加入一个时间窗口,超过这个时间窗口的就不能再认为是连按了。
做了下试验,效果不错啊

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 加入因仑

本版积分规则

快速回复 返回顶部 返回列表