简易对讲机 - 嘉立创EDA开源硬件平台

编辑器版本 ×
标准版 Standard

1、简单易用,可快速上手

2、流畅支持300个器件或1000个焊盘以下的设计规模

3、支持简单的电路仿真

4、面向学生、老师、创客

专业版 professional

1、全新的交互和界面

2、流畅支持超过3w器件或10w焊盘的设计规模,支持面板和外壳设计

3、更严谨的设计约束,更规范的流程

4、面向企业、更专业的用户

专业版 简易对讲机

简介:基于air001的简易对讲机,可发送或监听。支持多频道选择,支持语音加密,不串频;对讲距离城市环境在1km以上,清晰具有分辨度。

开源协议: GPL 3.0

(未经作者授权,禁止转载)

已参加:星火计划2024

创建时间: 2024-02-20 14:58:30
更新时间: 2024-04-29 16:45:42
描述
# 项目说明 本项目采用air001主控芯片结合SR_FRS_2WUS无线对讲机模块,打造了一款简易对讲机。设备支持20个公共对讲机频道,支持亚音和扰频功能,提供更强的通信保密性。采用CW2015电池监测芯片,可实时监测电池电量,确保设备长时间稳定运行。同时,利用AT24C02芯片实现了参数设置的掉电存储功能,保障用户设置的参数在掉电情况下不会丢失,提升了用户体验和便利性。 # 开源协议 GPL3.0 # 项目相关功能 - 支持待机息屏功能,节省能量。 - 提供409.7500MHz~409.9875MHz共20个公共对讲机频道选择。 - 支持亚音技术,有效防止串频现象的发生。并且支持扰频功能,可对语音进行加密,提升通信安全性。 - 用户可灵活切换收发模式或监听模式,灵活应对不同场景需求。 - 在城市环境下,对讲机的通讯距离可达1公里以上,语音传输清晰且具备良好的分辨度。 - 内置电量监测功能,可实时监测电池电量。此外,还支持参数设置的掉电存储,提高了设备的可靠性和便利性。 # 项目属性 本项目为首次公开,为本人原创项目。项目未曾在别的比赛中获奖。 # 项目进度 - 2024.01.17 项目立项 - 2024.02.01 绘制验证板并进行原型验证 - 2024.02.20 原型验证完成,开始pcb绘制打板 - 2024.02.27 焊接调试 - 2024.03.10 硬件及软件调试完成 - 2024.03.12 绘制并打印3D外壳 - 2024.03.20 修改外壳及程序功能 - 2024.04.16 完成验收 # 电路设计原理 ## 系统框图 ![1.png](//image.lceda.cn/pullimage/2WaI2Hu6Yogb0GfBcP7kNtpXgf0VBlcu6SvShm2m.png) ## 电源电路 电源部分采用TP4056进行锂电池的充放电。需要注意的是,电路板未添加锂电池保护电路,因此建议选择带有保护电路的锂电池以确保安全使用。 ![2.png](//image.lceda.cn/pullimage/3YsUY8q6tgqwD38aqK6Q94JeiLI4GnCPADSR5AG7.png) 电池电量监测采用CW2015芯片,其外围电路较为简单。并且可以通过I2C通信直接读取电量百分比值以及剩余运行时间。 ![3.png](//image.lceda.cn/pullimage/XX9f0q51PMLLUpf4HTSFa1auUmu6XezQr1Y5RU3k.png) 主控电路和射频模块电路分别使用XC6201和SX1308进行供电。其中SX1308需要将EN引脚上拉从而启动电压转换。 ![4.png](//image.lceda.cn/pullimage/WZMcB91ZBtlkkiuQQ78zg0nr2dNyzFB001yv61In.png) ![5.png](//image.lceda.cn/pullimage/aLxcdw29bxAJoq9xM8qBCyuLOhw2zdhusi9NVoc2.png) ## air001最小系统电路 AIR001系列采用高性能的ARM Cortex-M0+ 32位内核,最高工作频率达到48MHz,并且支持低功耗模式。内置存储器包括32KB Flash和4KB SRAM。此外,还搭载了9个定时器、1个12位ADC,并配备了2个SPI接口、1个I2C接口以及2个USART接口。外围电路设计简单,无需外部晶振即可正常工作。这里仅需将boot引脚下拉,并接上复位电路即可完成air001最小系统电路的设计。 ![6.png](//image.lceda.cn/pullimage/nkiRl22Ad4CjTfXcml7lzVIiK03DYnwfhQs0kuYc.png) ## 独立按键 考虑到air001拥有较多的GPIO口,我们采用了独立按键进行输入。各个按键的功能包括选择、取消、上、下、左、右。 ![7.png](//image.lceda.cn/pullimage/Ti7bX6ed8JUn1KhnBuku5H0xZRyqAFOVTq6gq0Yf.png) ## eeprom存储 我们在对讲机的操作中需要设置频率、亚音、扰频、音量等级等参数。如果每次上电都需要重新设置,将会增加使用的复杂度。因此为了方便用户使用,我们采用AT24C02芯片对相关参数数据进行存储,实现了参数设置的掉电保存功能,从而提高了设备的便利性。该芯片使用I2C进行通信,与CW2015芯片共用I2C总线,减小GPIO的使用。 ![8.png](//image.lceda.cn/pullimage/15A31uu7am23FjderXGQif1AStGYdIGDfpvK2unr.png) ## 射频模块 射频模块采用SR_FRS_2WUS,它是一款性价比极高的无线语音对讲及数传模块。该模块内置高性能的射频收发芯片、微控制器以及射频功放。外部控制器可以通过标准的异步串行接口(UART)通信,实现设置模块的工作参数并控制整个模块的收发。此模块只需外接天线、MIC和语音功放,即可组装成一台完整的对讲机或数传电台。 ![9.png](//image.lceda.cn/pullimage/mBNP9ISpsC6oGzfOikMnSgk3nxdu469iBoCnAmFB.png) 在阻抗匹配部分采用了"嘉立创阻抗计算神器"进行走线线宽的简单计算,并预留了派型阻抗匹配电路,可用于更精确的阻抗匹配。如果不进行阻抗匹配,可在使用时通过接入0欧电阻将L2短路,即可正常使用。 ![10.png](//image.lceda.cn/pullimage/T7RMPdoaZS0AWOvyRQqEOiBZfiTpKMmJ02iDmoz9.png) ## mic输入 采用驻极体电容麦克风作为语音输入。 ![11.png](//image.lceda.cn/pullimage/1xmqyMBdGmlSvjnk4w4S0BFevtG1Fv9ziJ97dF0A.png) ## 音频输出 音频输出部分采用LM4871音频功率放大器,能够轻松驱动4欧8W的扬声器,特别适用于小体积、轻便的便携系统。LM4871的使能端连接射频模块的SQ端,当未接收到信号时,可将LM4871置于休眠模式,有效降低功耗并防止噪音输出。此外,LM4871内置过热自动关断保护机制,工作稳定,单位增益可调。通过配置外部电阻,可轻松调整放大器的电压增益,满足不同应用需求。 ![12.png](//image.lceda.cn/pullimage/mXPbfn1PHGrGekBcJGXeo3z0PIqmJNvyj4eWuqnk.png) # 软件部分说明 程序部分主要分为五大部分:OLED界面、按键控制、对讲模块功能设置、电量读取、参数存储。 ## OLED界面 IIC通信使用软件进行实现,实现较为简单。 ```c #ifndef __I2C_H #define __I2C_H #include "air001xx_hal.h" #define I2C_GPIO GPIOF #define I2C_SDA GPIO_PIN_0 #define I2C_SCL GPIO_PIN_1 #define I2C_GPIO_ENABLE() __HAL_RCC_GPIOF_CLK_ENABLE() #define I2C_CMD 0 //写命令 #define I2C_DATA 1 //写数据 void I2C_Init(void); void I2C_Start(void); void I2C_Stop(void); void I2C_WaitAck(void); void I2C_SendByte(uint8_t dat); uint8_t I2C_ReadByte(uint8_t ack); void OLED_WR_Byte(uint8_t dat,uint8_t mode); #endif ``` air001通过IIC与OLED进行通信,从而设置显示内容。 ```c void OLED_ShowChar(uint8_t x,uint8_t y,uint8_t chr,uint8_t size1,uint8_t mode) { uint8_t i,m,temp,size2,chr1; uint8_t x0=x,y0=y; if(size1==8)size2=6; else size2=(size1/8+((size1%8)?1:0))*(size1/2); //得到字体一个字符对应点阵集所占的字节数 chr1=chr-' '; //计算偏移后的值 for(i=0;i<size2;i++) { if(size1==8) {temp=asc2_0806[chr1][i];} //调用0806字体 else if(size1==12) {temp=asc2_1206[chr1][i];} //调用1206字体 else if(size1==16) {temp=asc2_1608[chr1][i];} //调用1608字体 else if(size1==24) {temp=asc2_2412[chr1][i];} //调用2412字体 else return; for(m=0;m<8;m++) { if(temp&0x01)OLED_DrawPoint(x,y,mode); else OLED_DrawPoint(x,y,!mode); temp>>=1; y++; } x++; if((size1!=8)&&((x-x0)==size1/2)) {x=x0;y0=y0+8;} y=y0; } } ``` ## 按键控制 按键部分采用六个独立按键,分别为确认、取消、上、下、左、右六个功能。在main函数的while循环中对按键进行扫描从而确定按下的按键并执行对应的程序。 ```c uint8_t Key_Scan(void) { if(HAL_GPIO_ReadPin(KEY_GPIOA,KEY_SEL_PIN)==0) { HAL_Delay(20); if(HAL_GPIO_ReadPin(KEY_GPIOA,KEY_SEL_PIN)==0) { while(HAL_GPIO_ReadPin(KEY_GPIOA,KEY_SEL_PIN)==0); return 1; } }else if(HAL_GPIO_ReadPin(KEY_GPIOA,KEY_RET_PIN)==0) { HAL_Delay(20); if(HAL_GPIO_ReadPin(KEY_GPIOA,KEY_RET_PIN)==0) { while(HAL_GPIO_ReadPin(KEY_GPIOA,KEY_RET_PIN)==0); return 2; } }else if(HAL_GPIO_ReadPin(KEY_GPIOB,KEY_UP_PIN)==0) { HAL_Delay(20); if(HAL_GPIO_ReadPin(KEY_GPIOB,KEY_UP_PIN)==0) { while(HAL_GPIO_ReadPin(KEY_GPIOB,KEY_UP_PIN)==0); return 3; } }else if(HAL_GPIO_ReadPin(KEY_GPIOA,KEY_DOWN_PIN)==0) { HAL_Delay(20); if(HAL_GPIO_ReadPin(KEY_GPIOA,KEY_DOWN_PIN)==0) { while(HAL_GPIO_ReadPin(KEY_GPIOA,KEY_DOWN_PIN)==0); return 4; } }else if(HAL_GPIO_ReadPin(KEY_GPIOA,KEY_LEFT_PIN)==0) { HAL_Delay(20); if(HAL_GPIO_ReadPin(KEY_GPIOA,KEY_LEFT_PIN)==0) { while(HAL_GPIO_ReadPin(KEY_GPIOA,KEY_LEFT_PIN)==0); return 5; } }else if(HAL_GPIO_ReadPin(KEY_GPIOA,KEY_RIGHT_PIN)==0) { HAL_Delay(20); if(HAL_GPIO_ReadPin(KEY_GPIOA,KEY_RIGHT_PIN)==0) { while(HAL_GPIO_ReadPin(KEY_GPIOA,KEY_RIGHT_PIN)==0); return 6; } } return 0; } ``` ## 对讲模块功能设置 对讲机功能设置使用UART与对讲机模块进行通信,并通过AT指令进行参数的设置。 ```c void Uart_TxData(uint8_t index, uint8_t level) { uint8_t *aTxBuffer; uint8_t tx_len=0; switch(index) { case 0://音量 AT_CMD2[10] = 0x31+level; aTxBuffer = AT_CMD2; tx_len=13; AT24CXX_WriteOneByte(ADDR_VOL, level); break; case 1://亚音 strncpy(AT_CMD1+30, subtone[level],2); strncpy(AT_CMD1+33, subtone[level],2); aTxBuffer = AT_CMD1; tx_len=41; AT24CXX_WriteOneByte(ADDR_SUB, level); break; case 2://射频开关 HAL_GPIO_WritePin(GPIOB, PD_PIN, level); AT24CXX_WriteOneByte(ADDR_SW, level); return; break; case 3://扰频 AT_CMD4[16] = 0x30+level; aTxBuffer = AT_CMD4; tx_len=21; AT24CXX_WriteOneByte(ADDR_SCR, level); break; case 4://免提灵敏度 AT_CMD3[10] = 0x30+level; aTxBuffer = AT_CMD3; tx_len=13; AT24CXX_WriteOneByte(ADDR_VOX, level); break; case 5://静噪级别 AT_CMD4[10] = 0x30+level; aTxBuffer = AT_CMD4; tx_len=21; AT24CXX_WriteOneByte(ADDR_SQU, level); break; case 6://麦克灵敏度 AT_CMD4[12] = 0x30+level; aTxBuffer = AT_CMD4; tx_len=21; AT24CXX_WriteOneByte(ADDR_MIC, level); break; } if (HAL_UART_Transmit_IT(&UartHandle, aTxBuffer, tx_len) != HAL_OK) { Error_Handler(); } } ``` ## 电量读取 CW2015通过IIC与主控芯片进行通信。在上电时首先设置电池信息,之后通过读取SOC寄存器中的数值即可获取当前电池的电量信息。 ```c uint8_t CW2015_ReadOneByte(uint8_t ReadAddr) { uint8_t temp=0; I2C_Start(); I2C_SendByte(0XC4); //发送器件地址0XA0,写数据 I2C_WaitAck(); I2C_SendByte(ReadAddr); //发送低地址 I2C_WaitAck(); I2C_Start(); I2C_SendByte(0XC5); //进入接收模式 I2C_WaitAck(); temp=I2C_ReadByte(0); I2C_Stop();//产生一个停止条件 return temp; } ``` ## 参数存储 对讲机的频道和其相关功能设置参数存储在AT24C02中,从而实现掉电存储功能。AT24C02通过IIC与主机进行通信。具体存储格式如下: | 地址 | 存储内容 | 表示范围| | --- | --- | --- | 0x00 |音量 |0-7 0x01 |亚音 |0-4 0x02 |射频开关 |0-1 0x03 |扰频 |0-7 0x04 |免提灵敏度 |0-8 0x05 |静噪级别 |0-9 0x06 |麦克灵敏度 |0-7 ## 整体核心代码 其中page_index为判断当前为主页还是菜单页。current_index和temp_list_level分别为当前菜单选中的功能和该功能参数的等级。 之后对OLED、UART、按键GPIO、CW2015进行初始化。最后进入循环,通过不断判断按键按下的状态从而实现功能的控制。 ```c int main(void) { uint8_t page_index=0;//page index uint8_t current_index=0;//list index uint8_t temp_list_level = 0; uint8_t key_index = 0;//key index uint8_t i=0, list_len = (sizeof(list)/sizeof(MENU_LIST)); /* 初始化所有外设,Flash接口,SysTick */ HAL_Init(); UART2_INIT(); Get_Init_Data(); Show_HomePage(list[0].current_level, list[2].current_level); CW2015_WriteOneByte(0x0a,0xff);//wake up cw2015 HAL_Delay(50); CW2015_WriteOneByte(0x0a,0x00);//wake up cw2015 HAL_Delay(50); uint8_t battary_data = 0; battary_data = CW2015_ReadOneByte(0x08); battary_data = battary_data & 0x02; HAL_Delay(50); if(battary_data == 0) { Update_Bat_Info(); } temp_list_level = list[0].current_level; while (1) { if(page_index == 0 && display_on) { OLED_ShowChar(8, 0, list[0].current_level + 0x30, 8, 1); battary_data = CW2015_ReadOneByte(0x04); HAL_Delay(50); OLED_ShowNum(127-24,0,battary_data,3,8,1); OLED_ShowChar(127-6,0,'%',8,1); OLED_Refresh(); } key_index=Key_Scan(); if(key_index == 1) { switch(page_index)//key_select { case 0://enter menu if(display_on){ page_index +=1; current_index=oled_showlist(list_len, current_index, (MENU_LIST *)list, 2); }else{ Show_HomePage(list[0].current_level, list[2].current_level); display_on = 1; } break; case 1://select setting list[current_index].current_level = temp_list_level; Uart_TxData(current_index, list[current_index].current_level); break; default: break; } }else if(key_index == 2)//key_return { switch(page_index) { case 0://none display_on = 0; OLED_Clear(); OLED_Refresh(); // current_index=oled_showlist(list_len, current_index, (MENU_LIST *)list, 1); break; case 1://return home page page_index -= 1; Show_HomePage(list[0].current_level, list[2].current_level); current_index=0; break; default: break; } }else if(key_index == 3)//key_up { if(page_index == 1)//current is menu page { current_index=oled_showlist(list_len, current_index, (MENU_LIST *)list, 0);//previous(up) temp_list_level = list[current_index].current_level; }else { Set_Level_Silent((MENU_LIST *)list, 0, 1); Uart_TxData(0, list[0].current_level); } }else if(key_index == 4)//key_down { if(page_index == 1) { current_index=oled_showlist(list_len, current_index, (MENU_LIST *)list, 1);//next(down) temp_list_level = list[current_index].current_level; }else { Set_Level_Silent((MENU_LIST *)list, 0, 0); Uart_TxData(0, list[0].current_level); } }else if(key_index == 5)//key_left { if(page_index == 1) { temp_list_level= Set_Level((MENU_LIST *)list, current_index, temp_list_level, 0); }else{ channel_index = Uart_SetFreq(channel_index, 0); } }else if(key_index == 6)//key_right { if(page_index == 1) { temp_list_level = Set_Level((MENU_LIST *)list, current_index, temp_list_level, 1); }else { channel_index = Uart_SetFreq(channel_index, 1); } } key_index = 0; } } ``` # 实物展示 ## 实物功能介绍 ![25.png](//image.lceda.cn/pullimage/oHPwMAqjJuJBeOZV1fMlG30cstVmV8Keb3XliPIJ.png) ## 实物外观展示 ![m_21.png](//image.lceda.cn/pullimage/DuM2YJFiGWEW03rWnsBT8y7EybvlyFqrLsaGbGbO.png) ![m_24.png](//image.lceda.cn/pullimage/pXEXvdFPMEiseEUPDpRqKxOCBtnS7kf2iFRohcsx.png) ![22.png](//image.lceda.cn/pullimage/NFF2YsGN1rNm6wmtpfOMP3nbCpenc0KaLiKLSVwW.png) ![23.png](//image.lceda.cn/pullimage/HOQ864b1A1qFknLM0fLm3v0eWRHYkrF7EiKIEGnm.png) # 设计注意事项 - 在电路设计中未添加锂电池保护电路,建议选购带有保护电路的锂电池以确保安全使用。 - 在进行烧录程序时,建议使用DAPLink调试器进行烧录(理论上也可通过串口进行烧录)。在使用DAPLink烧录时,请确保烧录器的3v3和GND与板子相连,以避免烧录失败的可能性。如果出现烧录失败情况,可以适当降低烧录器的时钟频率,并重新尝试。 - 在使用CW2015时,需要先写入电池信息,然后再读取SOC,以确保读取到的SOC值准确。具体内容可以参考:[CW2015电量计使用](https://blog.csdn.net/qq_30479517/article/details/136542186) - 注意SX1308芯片的EN引脚控制的是电压转换开关,而不是输出开关。当EN引脚接低电平时,该芯片仍然会输出电压。在第一版设计时可能未注意到这一问题,原理图和PCB对此已进行更正。 - 天线的匹配电路根据需要进行焊接。若无阻抗匹配条件,也可以使用0欧电阻直接将其短路,经验证也可实现较远距离的通信。 - 在未连接天线时,请勿按下PTT键,可能会造成未知后果。 - 软包锂电池接口的尺寸及线序为:1.25黑红 # 注意!!! **该项目仅供学习交流使用,测试使用时请遵守相关法律法规!** [中华人民共和国无线电管理条例](https://www.gov.cn/zhengce/content/2016-11/25/content_5137687.htm) [关于公众对讲机管理有关问题的通知](https://www.xsbn.gov.cn/xsbnzgxw/24468.news.detail.dhtml?news_id=516867) # 相关链接 - [演示视频](https://www.bilibili.com/video/BV1em411m76n/) - [程序代码](https://github.com/fengzhaoxin/simple-intercom.git)
设计图
原理图
1 /
PCB
1 /
未生成预览图,请在编辑器重新保存一次
工程视频/附件
序号 文件名称 下载次数
1

3D模型.zip

60
工程成员
侵权投诉
相关工程
换一批
加载中...
添加到专辑 ×

加载中...

温馨提示 ×

是否需要添加此工程到专辑?

温馨提示
动态内容涉嫌违规
内容:
  • 153 6159 2675

服务时间

周一至周五 9:00~18:00
  • 技术支持

support
  • 开源平台公众号

MP