做项目用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++; } } 先简单的做红外解码,另外以后在解码连按时加入一个时间窗口,超过这个时间窗口的就不能再认为是连按了。 做了下试验,效果不错啊 |
欢迎光临 中科因仑“3+1”工程特种兵精英论坛 (http://bbs.enlern.com/) | Powered by Discuz! X3.4 |