完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
出差一周,刚回来又陪家人过端午,今天有空,继续上期的工作,首先完成多彩云灯的红外接收模块,因为我计划第一步实现红外遥控器控制多彩云灯,第二步实现手机端控制,不能一口吃成胖子 红外接收思路 了解一下红外信号的基本构成,看图 图片中就是一个常见红外遥控发出的信号,1和0的区别在于低电平持续的时间不同,一个正常的遥控指令包含起始码,2字节地址正、反码,2字节操作正、反码,停止位 实现接收的思路就是将一个红外接收头连接到IO口上,在GoKit上我将它连接在A0口,实际就是PA0,然后使用外部中断,一旦接收到上升沿就开始进入外部中断,然后统计两个上升沿之间的时间,通过判断时间的长短确定是起始码还是0或1,完成32个bit接收时判断正反码是否匹配,如果匹配,那么就接收到一个正确的遥控按键值。 使用微信宠物那个工程,官网可以下载。尽量不修改原来的代码,因为以后还要做手机端开,增加红外接收部分即可。 从以上思路,需要完成的工作包括一下内容: 1、硬件连接,这个就是把红外接收头焊接或其他方式连接到板上A0口,实现5V供电。 2、配置IO口,实现外部中断配置,我使用的外部中断0。 3、实现中断服务程序。 4、使用Systick作为红外接收的脉冲计时器。 修改延时代码 原来的工程代码还是做了一些修改,主要是延时部分,因为GoKit使用了SysTick作延时控制,实现方式不是我想要的。因为我也想使用SysTick来计时,因此我先修改原来的代码,来看一下原来的部分代码 void Delay_us(uint32_t nus) { uint32_t temp; SysTick->LOAD = nus*fac_us; SysTick->VAL=0x00; SysTick->CTRL = 0x01; do { temp = SysTick->CTRL; } while(temp & 0x01 && !(temp &(1<<16))); SysTick->CTRL = 0x00; SysTick->VAL = 0x00; } 这个是延时us的原代码,中文注释拷贝不出来。 SysTick是一个24位的递减计时器,到0的时候会产生异常,并重装载。 源代码将其时钟配置为1M,每减1表示1us,以上代码可以看出,调用这个函数,设置一个值,当减到0的时候表示完成延时,在原来的系统中没有问题,但是中断需要计时的情况就会产生冲突,这个函数的清除操作会破坏中断的计时。 为此,我作了一些修改,使得原来的代码调用这个函数的时候,时间大致不会有问题,又能与中断共用计时器。 来看一下代码: void Delay_Init(uint8_t SYSCLK) { SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); fac_us=SYSCLK/8; fac_ms =(u16)fac_us*1000; SysTick->LOAD = 0x00FFFFFF; SysTick->VAL=0x00; SysTick->CTRL = 0x01; } 初始化部分将重装载值设为最大的24位为1,一旦减到0就开始重头来过,默认初始化完成就启动SysTick,速率还是1M不变,每减1表示1us。 void Delay_us(uint32_t nus) { uint32_t temp; uint32_t delay_time; uint32_t time1; uint32_t time2; delay_time = nus*fac_us; time1 = SysTick->VAL; do { time2 = SysTick->VAL; if( time1 >= time2 ) { temp = time1 - time2; } else { temp = 0x00FFFFFF - time2 + time1; } } while( temp < delay_time ); } us的延时函数改了,调用函数的时候记录一个时刻,运行时不停读取另一个时刻,时间达到延时要求的时候就退出,全程不会修改SysTick的寄存器,如果这时候中断也使用这样的计时方式,那么相互不会影响。 void Delay_ms(uint16_t nms) { Delay_us(1000 * nms); } 延时1ms我就简单粗暴的直接调用上面的us函数,延时乘以1000就是ms了。 简单测试一下,这样改原来的系统运行没有问题。 接收实现代码 数据初始化部分,将红外接收的标志等数据清零。 void IR_RemoteInit(void) { IR_Remote.ID = IR_RemoteID IR_Remote.KeyVal = IR_DataNull; IR_Remote.RepetCnt = 0; IR_Remote.RxDoneFlag = FALSE; IR_Remote.RxStartFlag = FALSE; IR_Remote.HeadFlag = FALSE; IR_Remote.BitCnt = 0; IR_Remote.RxBit = 0; IR_Remote.LastTime = 0; IR_Remote.CurrentTime = 0; IR_Remote.PulseTime = 0; IR_Remote.RxTimeOut = 0; } 硬件初始化,将红外接收使用PA0口配置为外部中断,值得注意的是,红外接收头没有上拉,也就是传说中的开漏输出,所以一定要将信号的IO口配置为内部上拉,注意中断优先级不要与原来系统使用的冲突了。 void IR_Remote_GPIOInit(void) { GPIO_InitTypeDef GPIO_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; EXTI_InitTypeDef EXTI_InitStructure; IR_RemoteInit(); RCC_APB2PeriphClockCmd(GPIO_IR_Remote_CLK, ENABLE); NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); NVIC_InitStructure.NVIC_IRQChannel = IR_Remote_EXTI_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_InitStructure.GPIO_Pin = GPIO_IR_Remote_PIN; GPIO_Init(GPIO_IR_Remote_PORT, &GPIO_InitStructure); GPIO_EXTILineConfig(GPIO_IR_Remote_PortSource, GPIO_IR_Remote_PinSource); EXTI_InitStructure.EXTI_Line = IR_Remote_EXTI_Line; EXTI_InitStructure.EXTI_Mode = IR_Remote_EXTI_Mode; EXTI_InitStructure.EXTI_Trigger = IR_Remote_EXTI_Trigger; EXTI_InitStructure.EXTI_LineCmd = ENABLE; EXTI_Init(&EXTI_InitStructure); printf("IR remote Init OKrn"); } 中断服务程序,第一次进中断需要特别处理,首先接收起始码,时间关系与前面的图不一样,因为我这遥控器不知道是什么厂家的,没有资料,我通过调试确定了起始码,0和1大致的时间范围,然后识别出所有的按键,正反码都是正确匹配的。调试的时候可以加一些打印信息,正式的就不要再中断里面打印了,太费时间。 void IR_DecodeISR(void) { if(GPIO_ReadInputDataBit( GPIO_IR_Remote_PORT, GPIO_IR_Remote_PIN ) ) { if( IR_Remote.RxStartFlag == FALSE ) { IR_Remote.LastTime = SysTick->VAL; IR_Remote.CurrentTime = SysTick->VAL; IR_Remote.RxStartFlag = TRUE; IR_Remote.RxTimeOut = IR_TIME_OUT_VAL_MS; return; } IR_Remote.LastTime = IR_Remote.CurrentTime; IR_Remote.CurrentTime = SysTick->VAL; if(IR_Remote.CurrentTime <= IR_Remote.LastTime) { IR_Remote.PulseTime = IR_Remote.LastTime - IR_Remote.CurrentTime; } else { IR_Remote.PulseTime = 0x00FFFFFF - IR_Remote.CurrentTime + IR_Remote.LastTime; } if( IR_Remote.HeadFlag ) { if((IR_Remote.PulseTime > 0x4500) && (IR_Remote.PulseTime < 0x5200)) //time = 2.25ms, cnt = 17@128us; bit 1 code { IR_Remote.RxBit |= 0x01; IR_Remote.BitCnt++; } else if((IR_Remote.PulseTime > 0x2500) && (IR_Remote.PulseTime < 0x2A00)) //time = 1.125ms, cnt = 8@128us, bit 0 code { IR_Remote.RxBit &= 0xFFFFFFFE; IR_Remote.BitCnt++; } else //error pulse, reset { IR_RemoteInit(); } if(IR_Remote.PulseTime) { IR_Remote.PulseTime = 0; if( IR_Remote.BitCnt >= 32) { IR_Remote.UserCode = (IR_Remote.RxBit >> 16 ) & 0xFF; IR_Remote.UserCodeInv = (IR_Remote.RxBit >> 24 ) & 0xFF; IR_Remote.DataCode = (IR_Remote.RxBit >> 0 ) & 0xFF; IR_Remote.DataCodeInv = (IR_Remote.RxBit >> 8 ) & 0xFF; IR_Remote.RxDoneFlag = FALSE; if( ( IR_Remote.UserCode + IR_Remote.UserCodeInv == 0xFF ) &&( IR_Remote.UserCode == IR_Remote.ID ) ) { if( IR_Remote.DataCode + IR_Remote.DataCodeInv == 0xFF ) { IR_Remote.RxDoneFlag = TRUE; SEND_MSG(IR_REMOTE_RX_DONE_MSG); //printf("IR_Remote.DataCode = 0x%02xrn", IR_Remote.DataCode); //debug } } IR_Remote.HeadFlag = FALSE; IR_Remote.BitCnt = 0; } else { IR_Remote.RxBit <<= 1; } } } else { if(( IR_Remote.PulseTime > 0xB000) && (IR_Remote.PulseTime < 0xB500 )) //time = (9+4.5)ms, cnt = 105@128us header code { IR_Remote.HeadFlag = TRUE; IR_Remote.BitCnt = 0; IR_Remote.RxBit = 0; } else { IR_Remote.HeadFlag = FALSE; } IR_Remote.BitCnt = 0; //IR_Remote.RxBit = 0; IR_Remote.PulseTime = 0; } } else { //do nothing } } 补一下接收和接口图 |
|
相关推荐
2 个讨论
|
|
只有小组成员才能发言,加入小组>>
191个成员聚集在这个小组
加入小组【机智云转接板ML302-GC211试用体验】 第1章 机智云平台快速入门
8910 浏览 0 评论
3688 浏览 0 评论
【教程分享】Arduino uno R3接入机智云,快速实现物联网开发
7343 浏览 0 评论
4098 浏览 6 评论
1779 浏览 0 评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-25 22:13 , Processed in 0.651141 second(s), Total 57, Slave 42 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号