• 发文章

  • 发资料

  • 发帖

  • 提问

  • 发视频

创作活动
0
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
返回

电子发烧友 电子发烧友

  • 全文搜索
    • 全文搜索
    • 标题搜索
  • 全部时间
    • 全部时间
    • 1小时内
    • 1天内
    • 1周内
    • 1个月内
  • 默认排序
    • 默认排序
    • 按时间排序
  • 全部板块
    • 全部板块
大家还在搜
  • Room规则导致网络丢失的情况,有什么好办法解决?

    求助大佬们… 新打回来的板子,好几个地方不导电,检查了DRC和DFM都OK,Gerber也仔细看了,板厂也说按文件测没问题... 没办法,只能看看原始设计文件有没有问题… 结果发现孔隔离了,电源孔地孔都没连上! 但我记得我设计的时候没这样的,也没有改文件,不知道怎么回事… PS:之前STM32引脚间距报错,我有设了个Room区域规则想调小间距,但后面又觉得没必要,就没用那个规则,有没有可能是因为Room区域没删干净,所以… 请问有啥好办法可以解决类似问题吗?

    2025-07-04 11:00

  • 【中科昊芯Core_DSC280025C开发板试用体验】+2.RAM工程与FLASH工程对比

    前言 大家好,非常感谢电子发烧友与中科昊芯提供的DSC280025C开发板,这是一款DSP的开发板,基于RISC-V指令架构。 在开发DSP的芯片的时候,要分代码运行在RAM模式和FlASH模式。代码运行在RAM下,主要用于开发调试模式,优点是下载速度快,运行的也快,缺点是断电程序就丢失了。 若代码在FLASH下开发,下载稍微要耗时一点,当然断电代码也不会丢失,同样仿真器也是正常硬件仿真,但是断点只支持2个。程序运行稍慢一些,但是可以通用修饰语句,让某些函数加载到RAM里面,已达到运行提速的目的。 所以,通常开发DSP的时候,大家是先在RAM模式下开发运行,调试仿真,代码OK没有问题的时候,在把工程切换为FLASH,并下载。 RAM与FLASH工程对比 DSP的这种RAM和FLASH开发方式,在代码上有什么区别?这是我比较关心的问题。所以,不如直接建立两个工程,然后进行代码对比,找出差异。 其实写代码和做项目,我反而不着急,我主要想弄清楚底层运行逻辑,所以愿意花费一些时间在这上面,这与每个人的性格和习惯不一样,分别建立RAM和FLASH工程如下。 两个工程我都编译了,都是0 errors, 0 warnings。也没有写什么业务逻辑,全是编译器自己生成的工程和代码。 这里需要多说一句: 编译器自己就已经把这个芯片的外设库文件添加到工程里面了,用户只需要添加自己的代码就行。 通过与原厂咨询,IDE自动生成的外设库文件是最新版本的。建议用户直接使用,反而他们提供的参考例程代码里面的库文件是早期的版本。 所以,大家大胆的用起来吧,就用最新版本。 下面我开始对比两个工程之间的差异。 其实我以为是的是两个工程在源代码之间对比,肯定有一点差异的,也是或多或少的问题,但是万万没有想到,居然是一点都没有,仅仅是工程文件有一定的差异。 最主要的差异还是在.cproject文件中。倘若,我将Flash工程配置,改为RAM,连这点差异就消失了。 所以,通过这件事情,我觉的这款DSP的开发方式真的很简单,很方便。 学习方式推荐 其实,首次使用这颗芯片,最主要的还是IDE不太熟悉。开发工具使用不太顺手导致,所以,建议还是多看一下IDE的使用手册。 另外控制器迁移指南也需要读一下。 之前我就忽略了这个文档,当时我想的是,我是从零开始学习,所以不存在什么迁移、移植之类的。但是,经过和厂家技术支持的提点,我再重新看了下这个文档,有收获!所以这个文档很重要。 一些其他的知识 关于main函数运行之前,程序运行的机制. 在main函数之前,通过浏览代码,其执行了一个_init()的函数。 这里里面应该是将代码进行拷贝(在FLASH模式下) 关于主函数中的 Device_init() 函数的内容。 这个函数主要是对FLASH初始化,系统时钟初始化,外设开启等,这些都是厂家编写好了的,我们直接使用即可。 那么问题来了,我们代码中,系统主频时是多少?用的是外部晶振来源?我也看了下我们的DSCF280025CPMS开发板,上面贴了一个20MHZ的无源晶振,所以是它? 非也! 从上述代码可以看出, 工程中的系统时钟确实是160MHZ,但是时钟来源确是内部振荡器,主频10MHZ,经过16倍频,达到外部系统的160MHZ。 所以,外部晶振是没有用上,也就是仅仅贴在板上。如果我们需要把外部晶振启用,所以还需要调整工程。 ! 将原来的USE_PLL_SRC_INTOSC 注释掉,启用USE_PLL_SRC_XTAL 这样就可以正常启用外部晶振。 从程序中也能看到定义的外部晶振的主频时20MHZ,和实物也是能对应上的。 关于外设初始化 从代码中也是能看到,厂家的代码是将这款DSP的所有外设资源全部都开启了的。但是,我们在实际工程项目使用的时候,可以把我们没有用到的外设给关闭,比如I2S,LIN等等. 这样的好处是有利于减少主控芯片的功耗与发热。 从厂家提供的手册中也能窥探一二,减少电流如下,所以这事还是值得做。

    2025-07-04 10:37

  • 需要CS1237和CS1238的资料

    你好,请帮忙提供一下CS1237和CS1238的资料,包括程序例子,PCB及电路设计说明和demo。所有资料吧,程序、电路、芯片等相关的所有资料。之前设计的电路EMC性能不理想。邮箱:linhuikui@qq.com 谢谢

    2025-07-04 10:25

  • 【沁恒CH585开发板免费试用体验】3、无线寻光之旅-HTML通过BLE点灯

    JS早已进化出可以控制笔记本电脑蓝牙设备的能力,所以编写一个HTML就可以完成BLE点灯工作。 一、从机程序 示例中有一个BLE从机程序 CH585EVT\\\\EVT\\\\EXAM\\\\BLE\\\\Peripheral 在此基础上添加点灯部分 初始化PA0: GPIOA_ModeCfg(GPIO_Pin_0, GPIO_ModeOut_PP_5mA); 在peripheral.C中,第一个特征值SIMPLEPROFILE_CHAR1写入事件发生时,增加判断,如果输入为0x20则点亮PA0,否则熄灭PA0 static void simpleProfileChangeCB(uint8_t paramID, uint8_t *pValue, uint16_t len) { switch(paramID) { case SIMPLEPROFILE_CHAR1: { uint8_t newValue[SIMPLEPROFILE_CHAR1_LEN]; tmos_memcpy(newValue, pValue, len); PRINT(\"profile ChangeCB CHAR1.. \\\\n\"); if(newValue[0]==0x20) { GPIOA_ResetBits(GPIO_Pin_0); }else { GPIOA_SetBits(GPIO_Pin_0); } break; } 二、HTML控制端 <!DOCTYPE html> <html lang=\"zh-CN\"> <head> <meta charset=\"UTF-8\"> <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"> <title>智能灯控制面板</title> <style> body { font-family: \'Arial\', sans-serif; background-color: #f5f5f5; display: flex; justify-content: center; align-items: center; height: 100vh; margin: 0; } .control-panel { background: white; border-radius: 20px; box-shadow: 0 10px 30px rgba(0,0,0,0.1); padding: 30px; width: 300px; text-align: center; } h1 { color: #333; margin-bottom: 30px; } .btn { background: #4285f4; color: white; border: none; border-radius: 50px; padding: 15px 30px; margin: 10px; font-size: 18px; cursor: pointer; width: 80%; transition: all 0.3s; box-shadow: 0 4px 6px rgba(0,0,0,0.1); } .btn:hover { transform: translateY(-2px); box-shadow: 0 6px 10px rgba(0,0,0,0.15); } .btn:active { transform: translateY(0); } .btn.on { background: #34a853; } .btn.off { background: #ea4335; } .connection-status { margin: 20px 0; font-weight: bold; } .connected { color: #34a853; } .disconnected { color: #ea4335; } .advanced-toggle { color: #4285f4; text-decoration: underline; cursor: pointer; margin-top: 20px; display: inline-block; } .advanced-settings { display: none; margin-top: 20px; text-align: left; } </style> </head> <body> <div class=\"control-panel\"> <h1>智能灯控制</h1> <div class=\"connection-status disconnected\" id=\"connection-status\">设备未连接</div> <button class=\"btn connect\" id=\"connect-btn\">连接设备</button> <div id=\"control-buttons\" style=\"display:none;\"> <button class=\"btn on\" id=\"on-btn\">开灯</button> <button class=\"btn off\" id=\"off-btn\">关灯</button> <button class=\"btn\" id=\"disconnect-btn\">断开连接</button> </div> <div class=\"advanced-toggle\" id=\"advanced-toggle\">显示高级设置</div> <div class=\"advanced-settings\" id=\"advanced-settings\"> <h3>高级设置</h3> <div> <label>服务UUID: <input type=\"text\" id=\"service-uuid\" value=\"0000ffe0-0000-1000-8000-00805f9b34fb\"></label> </div> <div> <label>特征值UUID: <input type=\"text\" id=\"characteristic-uuid\" value=\"0000ffe1-0000-1000-8000-00805f9b34fb\"></label> </div> <div> <label>开灯指令: <input type=\"text\" id=\"on-command\" value=\"20\"></label> </div> <div> <label>关灯指令: <input type=\"text\" id=\"off-command\" value=\"10\"></label> </div> </div> </div> <script> // 设备配置 (可以在后台预设) const defaultConfig = { serviceUUID: \'0000ffe0-0000-1000-8000-00805f9b34fb\', characteristicUUID: \'0000ffe1-0000-1000-8000-00805f9b34fb\', onCommand: \'20\', offCommand: \'10\' }; // DOM元素 const connectBtn = document.getElementById(\'connect-btn\'); const onBtn = document.getElementById(\'on-btn\'); const offBtn = document.getElementById(\'off-btn\'); const disconnectBtn = document.getElementById(\'disconnect-btn\'); const connectionStatus = document.getElementById(\'connection-status\'); const controlButtons = document.getElementById(\'control-buttons\'); const advancedToggle = document.getElementById(\'advanced-toggle\'); const advancedSettings = document.getElementById(\'advanced-settings\'); // 设备变量 let device = null; let characteristic = null; let isConnected = false; // 初始化UI document.getElementById(\'service-uuid\').value = defaultConfig.serviceUUID; document.getElementById(\'characteristic-uuid\').value = defaultConfig.characteristicUUID; document.getElementById(\'on-command\').value = defaultConfig.onCommand; document.getElementById(\'off-command\').value = defaultConfig.offCommand; // 连接设备 connectBtn.addEventListener(\'click\', async () => { try { connectionStatus.textContent = \"正在连接...\"; device = await navigator.bluetooth.requestDevice({ acceptAllDevices: true, //optionalServices: [\'generic_access\'] // 默认包含的服务 optionalServices: [\'0000ffe0-0000-1000-8000-00805f9b34fb\'] //filters: [ //{ namePrefix: \'simple\' } //], }); const server = await device.gatt.connect(); const service = await server.getPrimaryService(defaultConfig.serviceUUID); characteristic = await service.getCharacteristic(defaultConfig.characteristicUUID); device.addEventListener(\'gattserverdisconnected\', onDisconnected); isConnected = true; connectionStatus.textContent = \"设备已连接\"; connectionStatus.className = \"connection-status connected\"; connectBtn.style.display = \"none\"; controlButtons.style.display = \"block\"; } catch (error) { console.error(\"连接失败:\", error); connectionStatus.textContent = \"连接失败\"; connectionStatus.className = \"connection-status disconnected\"; } }); // 断开连接 disconnectBtn.addEventListener(\'click\', () => { if (device && isConnected) { device.gatt.disconnect(); } }); // 断开连接处理 function onDisconnected() { isConnected = false; device = null; characteristic = null; connectionStatus.textContent = \"设备未连接\"; connectionStatus.className = \"connection-status disconnected\"; connectBtn.style.display = \"block\"; controlButtons.style.display = \"none\"; } // 开灯 onBtn.addEventListener(\'click\', async () => { if (!isConnected) return; try { const command = document.getElementById(\'on-command\').value.trim(); const data = hexStringToArrayBuffer(command); await characteristic.writeValue(data); console.log(\"开灯指令发送成功\"); } catch (error) { console.error(\"发送开灯指令失败:\", error); } }); // 关灯 offBtn.addEventListener(\'click\', async () => { if (!isConnected) return; try { const command = document.getElementById(\'off-command\').value.trim(); const data = hexStringToArrayBuffer(command); await characteristic.writeValue(data); console.log(\"关灯指令发送成功\"); } catch (error) { console.error(\"发送关灯指令失败:\", error); } }); // 切换高级设置 advancedToggle.addEventListener(\'click\', () => { if (advancedSettings.style.display === \'none\') { advancedSettings.style.display = \'block\'; advancedToggle.textContent = \'隐藏高级设置\'; } else { advancedSettings.style.display = \'none\'; advancedToggle.textContent = \'显示高级设置\'; } }); // 辅助函数: 十六进制字符串转ArrayBuffer function hexStringToArrayBuffer(hexString) { hexString = hexString.replace(/\\\\s/g, \'\'); if (hexString.length % 2 !== 0) { throw new Error(\'十六进制字符串长度必须为偶数\'); } const bytes = new Uint8Array(hexString.length / 2); for (let i = 0; i < hexString.length; i += 2) { bytes[i/2] = parseInt(hexString.substr(i, 2), 16); } return bytes.buffer; } </script> </body> </html> 执行HTML 为了体现卓然不同的气质,起了一个非常中二的名称\"智能灯控制\"

    2025-07-04 10:05

  • 【BPI-CanMV-K230D-Zero开发板体验】无线网络摄像头(RTSP 推流 1080P 60fps)

    香蕉派 K230D 支持 MIPI-CSI 摄像头、支持视频编码,支持无线网络,可以将摄像头采集到的数据进行 H264 编码后再进行 RTSP 推流,这样就能在局域网下的任意地方打开摄像头查看图像。 这里 Camera 出 1080P 60fps,视频流和编码占用 K230D 性能很高,再加上无线传输,推流过程有一定延迟和发热。 实验准备 1、香蕉派 K230D 开发板 2、无线路由器 3、VLC 视频播放器 实验需要使用支持播放 RTSP 流的播放器,Windows 系统可选择的有 1、VLC 播放器 优点:兼容性好、功能强大 缺点:配置繁多且复杂,如果不会配置的话显示效果会比较差 2、YAHBOOM Rtsp Player(已内置在配套小工具程序中) 优点:无需配置,一键使用,低延迟 缺点:体积较大 这里使用 VLC 播放器 配置网络 输入以下代码,连接无线网络(ssid 和 password 需要换成自己的网络和密码): import network wlan = network.WLAN(network.STA_IF) wlan.connect(\"ssid\",\"password\") print(wlan.status()) while wlan.ifconfig()[0] == \'0.0.0.0\': os.exitpoint() print(wlan.ifconfig()) 配置完成后,启动即可联网,获取到 IP 即可访问网络,如下: 配置 RTSP Server RTSP 已经封装成一个类,可以直接调用,配置的网络端口为 8554,代码如下: from media.vencoder import * from media.sensor import * from media.media import * import time, os import _thread import multimedia as mm from time import * class RtspServer: def __init__(self,session_name=\"test\",port=8554,video_type = mm.multi_media_type.media_h264,enable_audio=False): self.session_name = session_name # session name self.video_type = video_type# 视频类型264/265 self.enable_audio = enable_audio # 是否启用音频 self.port = port#rtsp 端口号 self.rtspserver = mm.rtsp_server() # 实例化rtsp server self.venc_chn = VENC_CHN_ID_0 #venc通道 self.start_stream = False #是否启动推流线程 self.runthread_over = False #推流线程是否结束 def start(self): # 初始化推流 self._init_stream() self.rtspserver.rtspserver_init(self.port) # 创建session self.rtspserver.rtspserver_createsession(self.session_name,self.video_type,self.enable_audio) # 启动rtsp server self.rtspserver.rtspserver_start() self._start_stream() # 启动推流线程 self.start_stream = True _thread.start_new_thread(self._do_rtsp_stream,()) def stop(self): if (self.start_stream == False): return # 等待推流线程退出 self.start_stream = False while not self.runthread_over: sleep(0.1) self.runthread_over = False # 停止推流 self._stop_stream() self.rtspserver.rtspserver_stop() #self.rtspserver.rtspserver_destroysession(self.session_name) self.rtspserver.rtspserver_deinit() def get_rtsp_url(self): return self.rtspserver.rtspserver_getrtspurl(self.session_name) def _init_stream(self): width = 1280 height = 720 width = ALIGN_UP(width, 16) # 初始化sensor self.sensor = Sensor() self.sensor.reset() self.sensor.set_framesize(width = width, height = height, alignment=12) self.sensor.set_pixformat(Sensor.YUV420SP) # 实例化video encoder self.encoder = Encoder() self.encoder.SetOutBufs(self.venc_chn, 8, width, height) # 绑定camera和venc self.link = MediaManager.link(self.sensor.bind_info()[\'src\'], (VIDEO_ENCODE_MOD_ID, VENC_DEV_ID, self.venc_chn)) # init media manager MediaManager.init() # 创建编码器 chnAttr = ChnAttrStr(self.encoder.PAYLOAD_TYPE_H264, self.encoder.H264_PROFILE_MAIN, width, height) self.encoder.Create(self.venc_chn, chnAttr) def _start_stream(self): # 开始编码 self.encoder.Start(self.venc_chn) # 启动camera self.sensor.run() def _stop_stream(self): # 停止camera self.sensor.stop() # 接绑定camera和venc del self.link # 停止编码 self.encoder.Stop(self.venc_chn) self.encoder.Destroy(self.venc_chn) # 清理buffer MediaManager.deinit() def _do_rtsp_stream(self): try: streamData = StreamData() while self.start_stream: os.exitpoint() # 获取一帧码流 self.encoder.GetStream(self.venc_chn, streamData) # 推流 for pack_idx in range(0, streamData.pack_cnt): stream_data = bytes(uctypes.bytearray_at(streamData.data[pack_idx], streamData.data_size[pack_idx])) self.rtspserver.rtspserver_sendvideodata(self.session_name,stream_data, streamData.data_size[pack_idx],1000) #print(\"stream size: \", streamData.data_size[pack_idx], \"stream type: \", streamData.stream_type[pack_idx]) # 释放一帧码流 self.encoder.ReleaseStream(self.venc_chn, streamData) except BaseException as e: print(f\"Exception {e}\") finally: self.runthread_over = True # 停止rtsp server self.stop() self.runthread_over = True 主程序 调用网络连接代码连接网络,再调用 RTSP Server,即可打开推流服务器,主程序如下: if __name__ == \"__main__\": wlan = network.WLAN(network.STA_IF) wlan.connect(\"ssid\",\"password\") print(wlan.status()) while wlan.ifconfig()[0] == \'0.0.0.0\': os.exitpoint() print(wlan.ifconfig()) os.exitpoint(os.EXITPOINT_ENABLE) # 创建rtsp server对象 rtspserver = RtspServer() # 启动rtsp server rtspserver.start() # 打印rtsp url print(\"rtsp server start:\",rtspserver.get_rtsp_url()) # 推流60s sleep(60) # 停止rtsp server rtspserver.stop() print(\"done\") RTSP 协议简介 RTSP是一种用于控制流媒体服务器的网络应用层协议,由RFC 2326定义。它建立并控制一个或多个时间同步的连续媒体流。 主要特点 实时性强 支持点播和直播 支持流媒体控制(播放、暂停、快进等) 工作在应用层,默认使用554端口 常见应用场景 视频监控系统 安防摄像头 工业监控 交通监控 流媒体直播 视频会议 在线教育 远程医疗 **RTSP vs 其他流媒体协议** 协议 延迟 可靠性 交互性 应用场景 RTSP 低 中 高 视频监控、点播 HLS 高 高 低 直播、点播 RTMP 低 中 中 直播推流 WebRTC 极低 中 高 实时通讯 RTSP工作流程 RTSP传输模式

    2025-07-04 09:34

  • 【沁恒CH585开发板免费试用体验】2、基于BLE UART的双向数据传输-BLE控制PC机动作

    CH585开发板关于BLE的例程非常丰富,其中的CH585EVT\\\\EVT\\\\EXAM\\\\BLE\\\\BLE_UART是一个蓝牙串口透传例程 关于这个例程的说明如下: 特性: 1, 使用两个128bit uuid, 2, 两个uuid 分别是write without respone,和 notify 方式,分别对应串口收和发,可以在工程文件ble_uart_service/ble_uart_service.c中修改 3, 可以兼容 N* 家的 ble uart 的工程, 4, 支持MTU在20-247 中任意设置,自适适应当前的mtu 5, 默认在CH592上调试,串口使用的UART3,TXD3@PA5,RXD3@PA4,其他的串口需要修改代码 6, ble 名称为\"chCH592le_uart\" 7, 默认开启串口notify 成功回写,不需要需要可以去掉代码,在ble service 的回掉函数,BLE_UART_EVT_BLE_DATA_RECIEVED 事件中 屏蔽即可 8, 默认开启串口调试,使用串口1,PA9_TXD 115200. 本文将描述利用BLE UART配合手机BLE工具控制PC机执行动作 一、例程分析 在开始之前先分析一下例程 1、uart初始化 UART3(TX:PA5;RX:PA4),需要用一个串口工具将UART3和PC机USB连接 void app_uart_init() { //tx fifo and tx fifo //The buffer length should be a power of 2 app_drv_fifo_init(&app_uart_tx_fifo, app_uart_tx_buffer, APP_UART_TX_BUFFER_LENGTH); app_drv_fifo_init(&app_uart_rx_fifo, app_uart_rx_buffer, APP_UART_RX_BUFFER_LENGTH); //uart tx io GPIOA_SetBits(bTXD3); GPIOA_ModeCfg(bTXD3, GPIO_ModeOut_PP_5mA); //uart rx io GPIOA_SetBits(bRXD3); GPIOA_ModeCfg(bRXD3, GPIO_ModeIN_PU); //uart3 init UART3_DefInit(); //enable interupt UART3_INTCfg(ENABLE, RB_IER_RECV_RDY | RB_IER_LINE_STAT); PFIC_EnableIRQ(UART3_IRQn); } 2、BLE接收数据处理 实现了BLE串口桥接:手机APP通过BLE发送数据→MCU通过UART接收并处理。 数据回环:例如:手机发送\"ABC\",设备回传\"ABC\"。 case BLE_UART_EVT_BLE_DATA_RECIEVED: PRINT(\"BLE RX DATA len:%d\\\\r\\\\n\", p_evt->data.length); //for notify back test //to ble uint16_t to_write_length = p_evt->data.length; app_drv_fifo_write(&app_uart_rx_fifo, (uint8_t *)p_evt->data.p_data, &to_write_length); tmos_start_task(Peripheral_TaskID, UART_TO_BLE_SEND_EVT, 2); //end of nofify back test //ble to uart app_uart_tx_data((uint8_t *)p_evt->data.p_data, p_evt->data.length); break; 3、UART消息转BLE 通过ble_uart_notify函数,将UART接收到的消息通过BLE发生给订阅者 case SEND_TO_BLE_TO_SEND: //notify is not enabled if(!ble_uart_notify_is_ready(peripheralConnList.connHandle)) { if(peripheralConnList.connHandle == GAP_CONNHANDLE_INIT) { //connection lost, flush rx fifo here app_drv_fifo_flush(&app_uart_rx_fifo); } break; } read_length = ATT_GetMTU(peripheralConnList.connHandle) - 3; if(app_drv_fifo_length(&app_uart_rx_fifo) >= read_length) { PRINT(\"FIFO_LEN:%d\\\\r\\\\n\", app_drv_fifo_length(&app_uart_rx_fifo)); result = app_drv_fifo_read(&app_uart_rx_fifo, to_test_buffer, &read_length); uart_to_ble_send_evt_cnt = 0; } else { if(uart_to_ble_send_evt_cnt > 10) { result = app_drv_fifo_read(&app_uart_rx_fifo, to_test_buffer, &read_length); uart_to_ble_send_evt_cnt = 0; } else { tmos_start_task(Peripheral_TaskID, UART_TO_BLE_SEND_EVT, 4); uart_to_ble_send_evt_cnt++; PRINT(\"NO TIME OUT\\\\r\\\\n\"); } } if(APP_DRV_FIFO_RESULT_SUCCESS == result) { noti.len = read_length; noti.pValue = GATT_bm_alloc(peripheralConnList.connHandle, ATT_HANDLE_VALUE_NOTI, noti.len, NULL, 0); if(noti.pValue != NULL) { tmos_memcpy(noti.pValue, to_test_buffer, noti.len); result = ble_uart_notify(peripheralConnList.connHandle, &noti, 0); if(result != SUCCESS) { PRINT(\"R1:%02x\\\\r\\\\n\", result); send_to_ble_state = SEND_TO_BLE_SEND_FAILED; GATT_bm_free((gattMsg_t *)&noti, ATT_HANDLE_VALUE_NOTI); tmos_start_task(Peripheral_TaskID, UART_TO_BLE_SEND_EVT, 2); } else { send_to_ble_state = SEND_TO_BLE_TO_SEND; //app_fifo_write(&app_uart_tx_fifo,to_test_buffer,&read_length); //app_drv_fifo_write(&app_uart_tx_fifo,to_test_buffer,&read_length); read_length = 0; tmos_start_task(Peripheral_TaskID, UART_TO_BLE_SEND_EVT, 2); } } else { send_to_ble_state = SEND_TO_BLE_ALLOC_FAILED; tmos_start_task(Peripheral_TaskID, UART_TO_BLE_SEND_EVT, 2); } } else { //send_to_ble_state = SEND_TO_BLE_FIFO_EMPTY; } break; 二、手机蓝牙助手使用 使用大夏龙雀的蓝牙助手做为控制端 点击“智能小车” 点击“设置UUID\"设置 Service、Notify和Write UUID Notify是PC机-->UART--->BLE(CH585)-->手机 Write是手机->BLE(CH585)->UART-->PC机 点击搜索BLE,其中“ch592_ble_uart”是开发板BLE广播名 点击“ch592_ble_uart”进行连接,可以看到下面控制面板 点击面板上的上下左右,可以在PC机上接收到abcd 也就是说PC机上接收到手机上传来的数据,并且abcd对应上下左右的控制。 三、PYTHON写一个受控脚本 为了直观感受控制信号,用PYTHON写个脚本 import serial import pygame import sys # 初始化pygame pygame.init() screen = pygame.display.set_mode((800, 600)) pygame.display.set_caption(\"串口控制方块\") # 方块属性 block_x, block_y = 400, 300 block_size = 50 block_color = (0, 128, 255) # 串口设置 ser = serial.Serial(\'COM35\', 115200, timeout=1)# 根据实际情况修改端口 def move_block(direction): global block_x, block_y move_amount = 10 if direction == \'c\': block_x -= move_amount elif direction == \'d\': block_x += move_amount elif direction == \'a\': block_y -= move_amount elif direction == \'b\': block_y += move_amount # 主循环 running = True while running: for event in pygame.event.get(): if event.type == pygame.QUIT: running = False # 读取串口数据 if ser.in_waiting > 0: command = ser.readline().decode(\'utf-8\').strip() print(\"Received:\", command) move_block(command) # 绘制 screen.fill((255, 255, 255)) pygame.draw.rect(screen, block_color, (block_x, block_y, block_size, block_size)) pygame.display.flip() pygame.time.delay(30) ser.close() pygame.quit() sys.exit()

    2025-07-04 09:28

  • NVMe高速传输之摆脱XDMA设计之七:系统初始化

    直接采用PCIe实现NVMe功能,它的系统初始化流程主要分为链路训练、PCIe 初始化和 NVMe 初始化, 分别实现 PCIe链路连接、 PCIe 设备枚举配置和 NVMe 设备配置功能。 其中链路训练由 PCIE 集成块实现, 初始化模块根据链路训练完成信号和初始化启动信号来执行 PCIe 初始化和NVMe 初始化。 图1 系统初始化流程`` 系统初始化的主要流程如图 1 所示, 在系统供电后, 首先进入复位状态, 一旦退出复位状态, 由 PCIE 集成块执行链路训练, PCIE 集成块提供了 LinkUp 信号用于指示链路训练是否成功。 链路训练消耗时间为毫秒级别, 为了确保系统的稳定, 在系统复位退出后 1 秒时如果 LinkUp 信号仍为低电平, 则断言为链路训练失败, 初始化流程终止。 如果 LinkUp 为高电平, 此时用户可通过系统控制模块启动 PCIe 初始化,进入 PCIe 初始化状态。 PCIe 初始化状态机在执行完初始化流程后, 会报告初始化执行状态, 如果在初始化过程中出错, 进入初始化终止状态并将错误信息反馈到初始化状态寄存器。 当 PCIe 初始化正常完成后, 可以进入 NVMe 初始化状态, NVMe 初始化也由用户通过系统控制模块启动。 当 NVMe 初始化正常完成后, 系统的初始化完成, NoP 逻辑加速引擎进入正常工作模式。 想进一步了解相关视频,请搜索B站用户:专注与守望链接:https://space.bilibili.com/585132944/dynamic?spm_id_from=333.1365.list.card_title.click

    2025-07-04 09:14

  • 深度拆解SiLM8246GAHB-DG 小封装高抗扰的双通道隔离栅极驱动器新锐

    近期关注到SiLM824x系列 SiLM8246GAHB-DG 隔离栅极驱动器,其融合了小尺寸封装、高驱动能力与强抗干扰特性,在新能源与工业电源领域展现出独特潜力。今天想结合参数与设计逻辑,和大家聊聊这款器件的技术突破点及其对高可靠性系统的意义。 一、核心定位:为高频、高密、高可靠场景而生的驱动方案SiLM8246GAHB-DG 是一款 高侧/低侧兼容 的隔离双通道门极驱动器,专为驱动 MOSFET/IGBT 及第三代半导体(SiC/GaN)设计。其核心价值在于解决三大矛盾: 功率密度 vs 驱动能力:在仅 5x5mm LGA 封装 下实现 4A 源极/6A 灌电流峰值,支持高达 33V 驱动电压,为紧凑型电源模块提供强推力; 速度 vs 稳定性: 45ns 超低传播延迟 提升开关频率潜力,而 150kV/μs 共模瞬态抗扰度(CMTI) 抵御功率环路噪声,避免误触发; 灵活性 vs 安全性:支持 3V-18V 宽逻辑输入范围,同时通过 DIS 引脚全局关断 和 故障强制输出低电平 机制实现故障安全。 二、突破性特性解析:如何重构设计边界?1. 可编程死区时间(DT)——动态优化效率与安全 传统驱动器死区时间固定,易造成开关损耗或直通风险; SiLM8246GAHB-DG 通过 外部电阻调节 DT 时间,允许根据功率器件特性(如 GaN 的超快开关)动态平衡效率与安全性,尤其适合多工况应用(如光伏逆变器、变频伺服)。 2. 专为第三代半导体优化的电气性能 宽 UVLO 阈值选项:兼容低阈值 GaN 器件驱动需求,避免驱动不足导致的导通损耗; 5V 反向极性容忍:防止逻辑侧接线错误损毁芯片,提升系统鲁棒性。 3. 小封装的“大隔离”能力 在 LGA5x5-13 封装 下实现 2.5kVRMS 隔离耐压(UL 1577 认证),突破小尺寸与高隔离不可兼得的传统限制; 待认证的 VDE 0884-17 与 CQC(GB4943.1-2022) 进一步满足工业与新能源设备的安全合规需求。 三、严苛环境下的生存力:从参数到场景 温度适应性: -40°C 至 +125°C 工作范围 系统级防护: 双通道独立 UVLO 监测 VDDA/VDDB,防止欠压驱动导致的器件应力; 故障安全逻辑(异常时强制输出低电平)避免功率级“盲区”风险。 四、典型应用场景 新能源电力转换 光伏逆变器/储能变流器 电动汽车充电模块 工业电源与伺服系统 通信电源/服务器电源 变频器与伺服驱动

    2025-07-04 08:45

  • 【沁恒CH585开发板免费试用体验】CH585开发环境搭建(二)

    3 基于VS Code开发 3.1 GCC编译工具安装 1.编译工具简介 编译代码需要编译器,Linux系统的编译器是GCC,而Windows的C/C++编译器是Microsoft Visual C++,那么要想在Windows也能GCC等一系列编译工具,就需要安装MinGW。 MinGW,是Minimalist GNU for Windows的缩写。它是一个可自由使用和自由发布的Windows特定头文件和使用GNU工具集导入库的集合,允许你在GNU/Linux和Windows平台生成本地的Windows程序而不需要第三方C运行时(C Runtime)库。 MinGW 是用于进行 Windows 应用开发的 GNU 工具链(开发环境),它的编译产物一般是原生 Windows 应用,虽然它本身不一定非要运行在 Windows 系统下(是的 MinGW 工具链也存在于 Linux、BSD 甚至 Cygwin 下)。说的通俗点,MinGW就是你在Windows下使用GNU工具链的一个编译工具。 MinGW编译的程序只能在X86上运行,不能运行在嵌入式的硬件平台,因为嵌入式平台大都是ARM体系结构,因此这就需要一个在Windows环境下能使用GNU编译ARM体系结构的编译工具,这也就是交叉编译工具。 所谓交叉编译工具就是在一种平台上编译出能运行在体系结构不同的另一种平台上的程序,比如在PC平台(X86 CPU)上编译出能运行在以ARM为内核的CPU平台上的程序,编译得到的程序在X86 CPU平台上是不能运行的,必须放到ARM CPU平台上才能运行。 做过嵌入式开发的朋友都知道,在嵌入式开发过程中有宿主机和目标机的角色之分:宿主机是执行编译、链接嵌入式软件的计算机;目标机是运行嵌入式软件的硬件平台。 嵌入式开发流程大致就是在宿主机完成目标的开发工具,使用功能交叉编译工具生成固件,将固件烧写到目标机,在开发初期,还需要在线调试等工作,这就需要诸如J-link等调试工具。 CH585属于RISC-V体系结构,在Windows环境下开发也需要借助交叉编译工具。 这里可以直接使用MounRiver Stuido的工具链。 2.编译工具安装 把MounRiver Stuido目录下RISC-V Embedded GCC12的bin文件夹添加到环境变量: 然后在命令窗口中输入下面的命令验证安装是否成功: # riscv-none-elf-gcc -v 如果有信息输出,那就是装好了。 3.2 make工具安装 如果需要编译代码,则需要使用Makefile 来编译工程,那么就需要一个工具来识别Makefile文件,也就是make工具,在Linux中已经自带make了,在Windows就需要安装make工具。 在安装make工具之前,先来看看什么是makefile?Makefile 可以简单的认为是一个工程文件的编译规则,描述了整个工程的编译和链接等规则。其中包含了那些文件需要编译,那些文件不需要编译,那些文件需要先编译,那些文件需要后编译,那些文件需要重建等等。编译整个工程需要涉及到的,在 Makefile 中都可以进行描述。换句话说,Makefile 可以使得我们的项目工程的编译变得自动化,不需要每次都手动输入一堆源文件和参数。 本文的make工具是依赖Git工具的,我相信很多朋友都用过Git,但是很少使用Git的make等功能。 Git的bash实际上也就是一个mingw,是可以支持部分Linux指令的,但是只有少部分。在编译代码的时候经常会使用make命令反而在bash下默认是不支持的。 Make工具下载地址:https://sourceforge.net/projects/ezwinports/files/ 下载make-4.1-2-without-guile-w32-bin.zip 文件。 把该文件进行解压,把解压出来的文件全部拷贝的git的安装目录下: C:\\\\Program Files\\\\Git\\\\mingw64 把文件夹进行合并,如果跳出来需要替换的文件要选择不替换。 这样在git bash窗口下就可以执行make了。 没有安装Git先安装Git工具。 Git下载地址:https://git-scm.com/download/win 3.3 Visual Studio Code安装与配置 1. Visual Studio Code安装 根据使用的操作系统,直接从 Visual Studio Code 官网下载安装最新版。 下载地址:https://code.visualstudio.com/Download 安装很简单,这里就不在赘述了。 2.插件安装 打开 VS Code,点击 “Extensions” 图标,搜索 C/C++ 插件(由 Microsoft 提供),点击安装。 安装中文插件。 重启应用,Visual Studio Code就是中文界面了。 3.4 编译 使用make编译下前文新建的工程,编译通过显示如下: $ make -j12 all 也可以编译成功。 根据自己喜好吧,但是后面的方法需要安装Git和make工具。 3.5 下载固件 编译没有错误就可以进行下载了。 下载固件之前先安装下载工具。 WCHISPTool :http://www.wch.cn/downloads/WCHISPTool_Setup_exe.html 然后打开WCHISPTool,选择相应设备和固件。 默认下载 boot 脚:PB22; USB 下载通道:USB 全速口(FS); USB 下载方式 第 1 步:打开“WCHISPTool.exe”工具软件,选择芯片型号:CH585(具体匹配当前如果烧写的芯片型 号),下载方式:USB 下载。 第 2 步:将 MCU 的 PB22 引脚接到 GND 上(此过程 MCU 不要上电)。 第 3 步:通过 USB 线连接下载板到电脑,下载板供电。 第 4 步:电脑端的烧录工具软件检测到“USB 设备”(如果没有请重复上述 1-3 步骤),点击“下载”控件,执行烧录。 第 5 步:“下载记录”中查看烧录结果。提示完成后,将直接运行用户程序,也可重新上电或硬件复位来运行下载板中刚烧录的用户程序。如果提示失败,请重复上述步骤 4-5。

    2025-07-03 23:12

  • 【沁恒CH585开发板免费试用体验】CH585开发环境搭建(一)

    CH585是基于RISC-V开源指令集设计,因此开发环境和其他的RISC-V的开发环境类似。 RISC-V系列的MCU开发环境有很多,可以使用VS Code开发,也可以使用IDE,比如Embedded studio、Eclipse(Nuclei Studio、MounRiver Stuido、GNU MCU Eclipse)等,IAR也支持RISC-V。 本文笔者就介绍使用IDE和VS Code两种方式来开发CH32V208。 1 CH585概述 CH585系列是集成BLE无线通讯和高速USB及NFC的RISC-V MCU/SoC。片上集成了2Mbps低功耗蓝牙BLE通讯模块、USB全速控制器及收发器、USB高速控制器及收发器(480Mbps)、NFC近场通信无线接口、段式LCD驱动模块、LED点阵屏接口、2个SPI、4个串口、14路ADC、触摸按键检测模块等丰富的外设资源。资源非常丰富,如下图是CH585的系统框图。 Figure 1‑1 CH585的系统框图 2 基于MounRiver Stuido开发 MounRiver Stuido下载:http://www.mounriver.com/ MounRiver Stuido是一款针对嵌入式项目(RISC-V/ARM)的集成开发环境,提供了包括编辑器、C编译器、宏汇编、链接器、库管理、仿真调试器和下载器等在内的完整开发资源,工具链方面增加了对WCH RISC-V系列单片机中断硬件自动保存上下文功能的支持。 2.1 MounRiver Stuido安装 MounRiver Stuido 有多个系统版本,根据自己的系统下载对应的版本即可。 值得注意的是,安装MounRiver Stuido之前,电脑中要有Java运行时环境(JRE)。 因为MounRiver Stuido是Java写的,不然怎么能跨平台,这也是为什么在安装前需要检查Java环境。如果你安装过JDK,那么跳过此步骤即可。 JDK下载地址:https://www.oracle.com/java/technologies/downloads/ 下载后点击JavaSetupxxx.exe即可安装。 打开命令提示符,输入java会有如下显示,则安装成功。 注意:打开命令提示符方法 win+R 输入cmd 即可。 还可以查看Jre版本: Java -version 接下来就可以安装MounRiver Stuido,安装很简单,这里就不在赘述了。然后打开MounRiver Stuido。 2.2 工程导入 这是既然是快速入门,自然是导入已有的工程,可以到CH官网下载相应的CH585EVT.ZIP。 下载地址:https://www.wch.cn/downloads/CH585EVT_ZIP.html 下载CH585开发板例程。 解压CH585EVT.ZIP,里面有以下文件: EXAM是CH585的软件开发驱动及相应示例。 PUB提供了CH585评估板说明书、评估板原理图。 接下来就可以直接工程了,有两种导入方式: 第一种:在相应的工程路径下直接双击.wvproj 后缀名的工程文件; 第二种:在 MounRiver IDE 中点击 File,点击 Load Project,选择相应路径下.project 文件,点击Confirm 应用即可。 笔者这里选择ADC的实例。 导入工程后如下: 2.3 编译 接下来就可以编译工程了。 编译选项 1 为增量编译,对选中工程中修改过的部分进行编译; 编译选项 2 为 ReBuild,对选中工程进行全局编译; 编译选项 3 为 All Build,对所有的工程进行全局编译。 这里选择编译选项3。 出现以上信息表示编译成功了。 2.4 下载固件 编译没有错误就可以进行下载了。 下载固件之前先安装下载工具。 WCHISPTool :http://www.wch.cn/downloads/WCHISPTool_Setup_exe.html 然后打开WCHISPTool,选择相应设备和固件。 默认下载 boot 脚:PB22; USB 下载通道:USB 全速口(FS); 2.4.1 USB 下载方式 第 1 步:打开“WCHISPTool.exe”工具软件,选择芯片型号:CH585(具体匹配当前如果烧写的芯片型 号),下载方式:USB 下载。 第 2 步:将 MCU 的 PB22 引脚接到 GND 上(此过程 MCU 不要上电)。 第 3 步:通过 USB 线连接下载板到电脑,下载板供电。 第 4 步:电脑端的烧录工具软件检测到“USB 设备”(如果没有请重复上述 1-3 步骤),点击“下载”控件,执行烧录。 第 5 步:“下载记录”中查看烧录结果。提示完成后,将直接运行用户程序,也可重新上电或硬件复位来运行下载板中刚烧录的用户程序。如果提示失败,请重复上述步骤 4-5。 2.5 新建模板工程 点击‘File->New-> MounRiver Project’,选择相应的型号即可创建工程。 新建工程后如下: 然后就和前面工程一样了。

    2025-07-03 23:02