完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
` 本帖最后由 zhangxh 于 2017-3-8 15:50 编辑 这是自己设计制作的PCB板 航模遥控器 供大家一起学习交流 遥控器我采用的是STM32作为主控芯片,综合考虑这款芯片的性价比最高。无线发射与接收模块采用经济适用的24L01+模块,这款模块成本低,威廉希尔官方网站 成熟、稳定性好空中传输速率选择在250K,以提高传输距离。采用跳频通讯方式能够很好地避开通讯中的信道冲突。理论上可以65535个遥控器仪器同时使用,相互不会产生干扰。 采用硬件SPI通讯,使用W25X40 FLASH芯片作为存储单元。使用低成本的12864液晶作为显示单元。使用TL431基准芯片为ADC采样提供基准电压信号,是遥控器的ADC采集稳定可靠。左手油门和右手油门可以软件设定,但是需要硬件支持。 ShockBurst模式下nRF24L01可以与成本较低的低速MCU相连高速信号处理是由芯片内部的射频协议处理的nRF24L01提供SPI接口数据率取决于单片机本身接口速度ShockBurst模式通过允许与单片机低速通信而无线部分高速通信减小了通信的平均消耗电流在ShockBurstTM接收模式下当接收到有效的地址和数据时IRQ通知MCU随后MCU可将接收到的数据从RX FIFO寄存器中读出 在ShockBurstTM发送模式下nRF24L01自动生成前导码及CRC校验。数据发送完毕后IRQ通知MCU减少了MCU的查询时间也就意味着减少了MCU 的工作量同时减少了软件的开发时间nRF24L01内部有三个不同的RX FIFO寄存器6个通道共享此寄存器和三个不同的TX FIFO寄存器在掉电模式下待机模式下和数据传输的过程中MCU可以随时访问FIFO寄存器这就允许SPI接口可以以低速进行数据传送并且可以应用于MCU硬件上没有SPI接口的情况下 遥控器支持模拟器,可以直接连接解密狗,输出标准的PPM信号。使用这个遥控器可以再电脑上模拟飞行。 下面接收遥控器和接收机之间的通许协议。通讯协议分为4种类型,分别是遥控器发出的PCM帧和广播帧。接收机发出的对码帧和数据帧。 遥控数据格式由32个字节数据组成。 遥控和接收机对码原理: 遥控器部分工作原理:遥控器上电后,首先检查上次对码的接收机信息,并发送上一次对码成功信息的地址,1秒后没有收到上次对码成功的接收机信息,遥控器会同时发送广播信息以接收其它接收机的配对信息。当遥控器接收到接收机的配对信息并确认后,停止发送广播信息。只发送接收机的信息。1秒以后仍然没有接收到信息,遥控器会扫频发送广播信息。 接收机部分工作原理:接收机上电后,首先检查上一次对码的遥控器信息,并等待接收遥控器信息。短接对码接口后,接收机会将广播地址打开,扫频接收广播信息。直到对码成功。 遥控器软件选择FreeRTOS ,现将部分代码分享出来 int main(void) { __set_PRIMASK(1);//关全局中断 W25_dat.Sector=0xffff;//设置W25x40内存数据不可用 BSP_Config();//硬件及软件配置 AppResourcesInit();//任务资源初始化 #if TASK_DEBUG xTaskCreate(Simulation_Task,"Simulation_Task1",512,NULL,1,NULL); //仿真调试监视任务 xTaskCreate(UartDebug_Task,"UartDebug_Task",512,NULL,3,NULL); //串口仿真调试监视任务 UartRxQueue = xQueueCreate(10, sizeof(P_DAT) );//创建串口接收队列 #endif xTaskCreate(Dog_Task,"Dog_200mS",256,NULL,5,NULL); //看门狗监视任务 xTaskCreate(AppInit_Task,"AppInit",512,NULL,9,&AppInitHandleTaskStart); //应用初始化任务 vTaskStartScheduler();//开始调度任务 while(1) {} } void AppInit_Task( void *pvParameters ) //应用初始化任务 { #if TASK_DEBUG u8 buf[20]; #endif portTickType xLastWakeTime; const TickType_t xTicksToWait = 50 / portTICK_PERIOD_MS; /* 延迟50ms */ xLastWakeTime=xTaskGetTickCount();//获取当前心跳值 #if TASK_DEBUG DPrintfGetTheKey(); //获取打印资源 DPrintf(" 初始化任务已经启动 "); DPrintfGiveUpKey();//释放打印资源 #endif for( ;; ) { vTaskDelayUntil(&xLastWakeTime,xTicksToWait); Spi2GetTheKey();//获取Spi2的钥匙 /**********************FLASH芯片初始化************************/ W25_dat.ChipID=W25_DeviceID();//读取芯片的8位型号ID 唤醒芯片 W25_dat.Jedec_Id=W25_JEDEC_ID();//读取芯片的制造商ID和16位型号ID if(W25_ReadSector(0)==0)W25_ReadSector(0);//读指定扇区的数据到内存 如果失败在读取一次 if((W25_dat.page[0][0]!=0x18)||(W25_dat.page[0][1]!=0x18))//判断FLASH是否需要初始化 {//以下更新内存 W25_dat.page[0][0]=0x18;W25_dat.page[0][1]=0x18; ee_wrfun();//初始化写EE数据 for(;W25_WeadeSector()==0;);//将内存的数据写入FLASH } else//读取已经初始化的数据 { ee_rdfun();//初始化读EE数据 } Spi2GiveUpKey();//归还Spi2的钥匙 /***************打印输出初始化数据*****************/ #if TASK_DEBUG DPrintfGetTheKey(); //获取打印资源 DPrintf(" FLASH初始化完成 "); U8_Uchar(&W25_dat.ChipID,buf,3);buf[3]=' ';buf[4]=' ';buf[5]=0; DPrintf(" FLASH ID编号:");DPrintf((const signed char *)buf); DPrintf(" 初始化任务删除自身任务 "); DPrintfGiveUpKey();//释放打印资源 #endif LcmInit();//液晶初始化? lcd_rst_flag=1;//液晶完成初始化 AppTaskCreate();//创建任务 vTaskDelete(AppInitHandleTaskStart);//应用初始化任务执行一次后删除任务 } } void Dog_Task( void *pvParameters ) //看门狗监视任务 { EventBits_t uxBits; portTickType xLastWakeTime; const TickType_t xTicksToWait = 200 / portTICK_PERIOD_MS; /* 延迟200ms */ xLastWakeTime=xTaskGetTickCount();//获取当前心跳值 /* 开始执行启动任务主函数前使能独立看门狗。 设置LSI是128分频,下面函数参数范围0-0xFFF,分别代表最小值3.2ms和最大值13107.2ms 下面设置的是1s,如果1s内没有喂狗,系统复位。 */ bsp_InitIwdg(0x138); #if TASK_DEBUG DPrintfGetTheKey(); //获取打印资源 DPrintf(" 监视任务已经启动 "); DPrintfGiveUpKey();//释放打印资源 #endif for( ;; ) { vTaskDelayUntil(&xLastWakeTime,xTicksToWait); /* 等待所有任务发来事件标志 */ uxBits = xEventGroupWaitBits(DogEventGroup, /* 事件标志组句柄 */ TASK_BIT_0_1, /* 等碩ASK_BIT_0_1被设置 */ pdTRUE, /* 退出前TASK_BIT_0_1被清除,这里是TASK_BIT_0_1都被设置才表示“退出”*/ pdTRUE, /* 设置为pdTRUE表示等待TASK_BIT_0_1都被设置*/ xTicksToWait); /* 等待延迟时间 */ if((uxBits & TASK_BIT_0_1) == TASK_BIT_0_1) { IWDG_Feed();//喂狗 #if TASK_DEBUG //DPrintfGetTheKey(); //获取打印资源 //DPrintf("喂狗成功 "); //DPrintfGiveUpKey();//释放打印资源 #endif } else { #if TASK_DEBUG //DPrintfGetTheKey(); //获取打印资源 //DPrintf("等待喂狗指令 "); // DPrintfGiveUpKey();//释放打印资源 #endif } } } void UartDebug_Task( void *pvParameters )//串口仿真调试任务 { u8 buf[512]; P_DAT p_dat; u16 len; for(;;) { xQueueReceive(UartRxQueue,&p_dat,portMAX_DELAY); if(p_dat.id==1) { len=UsartTaskRead(&p_dat,buf,USART1_MAX_LEN);//解析读取数据 Uart1GetTheKey();//获取串口1的钥匙 Usart1Tx(buf,len); //发送数据 Uart1GiveUpKey();//归还串口1的钥匙 } } } void Simulation_Task( void *pvParameters )//仿真调试监视任务 { portTickType xLastWakeTime; uint8_t pcWriteBuffer[512]; const TickType_t xTicksToWait = 5000 / portTICK_PERIOD_MS; /* 延迟5000ms */ xLastWakeTime=xTaskGetTickCount();//获取当前心跳值 DPrintfGetTheKey(); //获取打印资源 DPrintf(" 仿真任务已经启动 "); DPrintfGiveUpKey();//释放打印资源 for(;;) { vTaskDelayUntil(&xLastWakeTime,xTicksToWait);//延迟10s DPrintfGetTheKey(); //获取打印资源 DPrintf("================================================= "); DPrintf(" 任务名称 任务状态 优先级 剩余栈 任务序号 "); vTaskList( (char *)&pcWriteBuffer ); DPrintf((const signed char *)pcWriteBuffer); DPrintf("================================================= "); DPrintf(" 任务名称 运行计数 使用效率 "); vTaskGetRunTimeStats( (char *)&pcWriteBuffer ); DPrintf((const signed char *)pcWriteBuffer); DPrintfGiveUpKey();//释放打印资源 } } void AppTaskCreate(void)//创建任务 { RF2401xQueue = xQueueCreate(10, sizeof(RF_DAT) );//创建RF接收队列 xTaskCreate(Task0,"Task0",512,NULL,3,NULL); xTaskCreate(ADC_Task,"ADC_Task",256,NULL,8,NULL); xTaskCreate(URT_DEBUG_Task,"URT_DEBUG_Task",512,NULL,5,NULL); xTaskCreate(NRF2401_Task,"NRF2401_Task",512,NULL,9,NULL); xTaskCreate(NRF2401TX_Task,"NRF2401TX_Task",512,NULL,9,NULL);//最高优先级 xTaskCreate(Task_lcd,"Task_lcd",512,NULL,3,NULL); xTaskCreate(Tim5mS_Task,"Tim10mS",512,NULL,8,NULL); //5毫秒定时器任务 } void Tim5mS_Task( void *pvParameters ) //5毫秒定时器任务 { u8 i,rf_da; RF_DAT rf_dat; portTickType xLastWakeTime; const TickType_t xTicksToWait = 5/ portTICK_PERIOD_MS; /* 延迟5ms */ xLastWakeTime=xTaskGetTickCount();//获取当前心跳值 for( ;; ) { vTaskDelayUntil(&xLastWakeTime,xTicksToWait);//延迟5ms rf_da++; if(rf_da>=2){rf_da=0;rf_dat.id=1; rf_dat.p=NULL;xQueueSend(RF2401xQueue,&rf_dat,pdPASS);} if(bz_con){bz_con--;GPIO_SetBits(GPIOA,GPIO_Pin_12);}//蜂鸣器控制 else{GPIO_ResetBits(GPIOA,GPIO_Pin_12);} key_bmbuf[key_bmcnt]=GPIO_ReadInputData(GPIOB); key_bmcnt++;if(key_bmcnt>=20){key_bmcnt=0;if(key_bmflag==0){key_bmflag=1;for(i=0;i<50;i++){key_bmbuff=key_bmbuf;}}} UsartRxQuery();//串口接收查询函数 /* 发送事件标志,表示任务正常运行 */ xEventGroupSetBits(DogEventGroup, TASK_BIT_1); } } 产品设计过程及成本分析 首先设计的是遥控器和接收机,当时考虑遥控器是不是要采购一个外壳,但是在淘宝搜索了好久也没有找到什么合适的 后来找到广东航模配件店购买了2套外壳 一套黑色12元 一套白色13元。 接下来选择高频模块,最后选择了24L01模块 接收机部分才有低成本的 200米 模块4.5元 遥控器采用 32元的100豪瓦的模块收发距离2500米的哪一种 ,两种模块结合使用经过测试 空旷传输800米没有问题 指示500米以上方向性比较强。 在接下来就是选择液晶显示 最后考虑成本选择了一款10元左右的12864液晶模块,以上图形大家看到的液晶就是此液晶和背光。当然以上都是不包含运费的价格。 以后就是设计原理图和PCB 遥控器的PCB做了有两款 一款是有外壳的 一款是没有外壳的 接收机开始设计了一款但是体积比较大 后来又设计了一款 小体积的 以减轻重量 2*3CM的尺寸 产品设计过程及成本分析 首先设计的是遥控器和接收机,当时考虑遥控器是不是要采购一个外壳,但是在淘宝搜索了好久也没有找到什么合适的 后来找到广东航模配件店购买了2套外壳 一套黑色12元 一套白色13元。 接下来选择高频模块,最后选择了24L01模块 接收机部分才有低成本的 200米 模块4.5元 遥控器采用 32元的100豪瓦的模块收发距离2500米的哪一种 ,两种模块结合使用经过测试 空旷传输800米没有问题 指示500米以上方向性比较强。 在接下来就是选择液晶显示 最后考虑成本选择了一款10元左右的12864液晶模块,以上图形大家看到的液晶就是此液晶和背光。当然以上都是不包含运费的价格。 以后就是设计原理图和PCB 遥控器的PCB做了有两款 一款是有外壳的 一款是没有外壳的 接收机开始设计了一款但是体积比较大 后来又设计了一款 小体积的 以减轻重量 2*3CM的尺寸 这款遥控器采用STM32 芯片 12864液晶 串口下载程序已经做到板子上 只需要一根串口线就可以下载 采用18650电池用电 电池壳固定尺寸已经画到线路板上 可以连接使用手机充电器充电,充电电路也已经集成到线路板上 ,可以使用充电宝供电 。充电口采用和手机一样的接口 方便实用。 震撼的外观、集成多种功能 、方便程序调试 。是DIY遥控器的不二选择 447026.rar 447028.rar 447027.rar ` |
|
相关推荐
21 个讨论
|
|
厉害了我的哥
|
|
|
|
|
|
只有小组成员才能发言,加入小组>>
5599 浏览 0 评论
11848 浏览 9 评论
4928 浏览 1 评论
14164 浏览 0 评论
14442 浏览 0 评论
哪位大哥有库卡KUKA.EtherNetIP MS(2.X版本)软件包?
4546浏览 0评论
如果设计一款桌面款的机器玩具,最吸引人的外观与功能要有哪些?
3823浏览 0评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2025-1-7 07:29 , Processed in 1.016612 second(s), Total 92, Slave 81 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号