BetaFlight模块设计之三十六:SoftSerial
BetaFlight模块设计之三十六:SoftSerial
- 1. 源由
- 2. API接口
- 2.1 openSoftSerial
- 2.2 onSerialRxPinChange
- 2.3 onSerialTimerOverflow
- 2.4 processTxState
- 2.5 processRxState
- 3. 辅助函数
- 3.1 applyChangedBits
- 3.2 extractAndStoreRxByte
- 3.3 prepareForNextRxByte
- 4. 总结
1. 源由
鉴于Betaflight关于STM32F405 SBUS协议兼容硬件电气特性问题,从程序代码上看,软串口应该能够采用定时器、中断的方式进行电平协议的解析。
但是从实测Betaflight4.4.2固件的角度看,又无法使用,怀疑可能存在以下问题:
- 配置问题
- 代码移植BUG(unified_target ==> config)
- 代码不支持
所以尝试整理下SoftSerial代码结构,通过对整体代码的了解,能否找出其中的一些深层次原因。
2. API接口
从对外接口的角度看,主要有以下API:
- 打开软件串口
openSoftSerial - 底层串行信号电平变更处理
onSerialRxPinChange - 底层串行信号超市处理
onSerialTimerOverflow - 后端Tx状态处理
processTxState - 后端Rx状态处理
processRxState
serialPort_t *openSoftSerial(softSerialPortIndex_e portIndex, serialReceiveCallbackPtr rxCallback, void *rxCallbackData, uint32_t baud, portMode_e mode, portOptions_e options)
void onSerialRxPinChange(timerCCHandlerRec_t *cbRec, captureCompare_t capture)
void onSerialTimerOverflow(timerOvrHandlerRec_t *cbRec, captureCompare_t capture)
void processTxState(softSerial_t *softSerial)
void processRxState(softSerial_t *softSerial)
2.1 openSoftSerial
根据资源进行配置:
- 【Hardware】GPIO:Tx/Rx/SERIAL_INVERTED
- 【Hardware】TIMER
- 【Hardware】Interrupt:ICPOLARITY_RISING/ICPOLARITY_FALLING
- 【Software】Buffer
- 【Software】Callback:onSerialRxPinChange(edgeCb)/onSerialTimerOverflow(overCb)/rxCallback
openSoftSerial││ // get serial port description├──> softSerial_t *softSerial = &(softSerialPorts[portIndex]);││ // get serial port rx/tx ioTag├──> ioTag_t tagRx = softSerialPinConfig()->ioTagRx[portIndex];├──> ioTag_t tagTx = softSerialPinConfig()->ioTagTx[portIndex];││ // one wire(Sbus etc.) or two wire softserial(UART etc.)├──> const timerHardware_t *timerTx = timerAllocate(tagTx, OWNER_SOFTSERIAL_TX, RESOURCE_INDEX(portIndex));├──> const timerHardware_t *timerRx = (tagTx == tagRx) ? timerTx : timerAllocate(tagRx, OWNER_SOFTSERIAL_RX, RESOURCE_INDEX(portIndex));││ // get serial port rx/tx IO_t├──> IO_t rxIO = IOGetByTag(tagRx);├──> IO_t txIO = IOGetByTag(tagTx);││ // timer & io set├──> <options & SERIAL_BIDIR> // bi-direction configuration│ ├──> <!timerTx || (timerTx->output & TIMER_OUTPUT_N_CHANNEL)>│ │ │ // If RX and TX pins are both assigned, we CAN use either with a timer.│ │ │ // However, for consistency with hardware UARTs, we only use TX pin,│ │ │ // and this pin must have a timer, and it should not be N-Channel.│ │ └──> return NULL;│ ├──> softSerial->timerHardware = timerTx;│ ├──> softSerial->txIO = txIO;│ ├──> softSerial->rxIO = txIO;│ └──> IOInit(txIO, OWNER_SOFTSERIAL_TX, RESOURCE_INDEX(portIndex));├──> < else > // unidirection configuration│ ├──> <mode & MODE_RX>│ │ ├──> <!timerRx || (timerRx->output & TIMER_OUTPUT_N_CHANNEL)>│ │ │ │ // Need a pin & a timer on RX. Channel should not be N-Channel.│ │ │ └──> return NULL;│ │ ├──> softSerial->rxIO = rxIO;│ │ ├──> softSerial->timerHardware = timerRx;│ │ └──> <!((mode & MODE_TX) && rxIO == txIO)>│ │ └──> IOInit(rxIO, OWNER_SOFTSERIAL_RX, RESOURCE_INDEX(portIndex));│ └──> <mode & MODE_TX>│ ├──> <!tagTx>│ │ │ // Need a pin on TX│ │ └──> return NULL;│ ├──> softSerial->txIO = txIO;│ ├──> <!(mode & MODE_RX)>│ │ ├──> <!timerTx> return NULL;│ │ │ // TX Simplex, must have a timer│ │ └──> softSerial->timerHardware = timerTx;│ ├──> < else > // Duplex│ │ └──> softSerial->exTimerHardware = timerTx;│ └──> IOInit(txIO, OWNER_SOFTSERIAL_TX, RESOURCE_INDEX(portIndex));││ // port configuration├──> softSerial->port.vTable = &softSerialVTable;├──> softSerial->port.baudRate = baud;├──> softSerial->port.mode = mode;├──> softSerial->port.options = options;├──> softSerial->port.rxCallback = rxCallback;├──> softSerial->port.rxCallbackData = rxCallbackData;│├──> resetBuffers(softSerial);│├──> softSerial->softSerialPortIndex = portIndex;│├──> softSerial->transmissionErrors = 0;├──> softSerial->receiveErrors = 0;│├──> softSerial->rxActive = false;├──> softSerial->isTransmittingData = false;││ // Configure master timer (on RX); time base and input capture├──> serialTimerConfigureTimebase(softSerial->timerHardware, baud);├──> timerChConfigIC(softSerial->timerHardware, (options & SERIAL_INVERTED) ? ICPOLARITY_RISING : ICPOLARITY_FALLING, 0);││ // Initialize callbacks├──> timerChCCHandlerInit(&softSerial->edgeCb, onSerialRxPinChange);├──> timerChOvrHandlerInit(&softSerial->overCb, onSerialTimerOverflow);││ // Configure bit clock interrupt & handler.│ // If we have an extra timer (on TX), it is initialized and configured│ // for overflow interrupt.│ // Receiver input capture is configured when input is activated.├──> <(mode & MODE_TX) && softSerial->exTimerHardware && softSerial->exTimerHardware->tim != softSerial->timerHardware->tim>│ ├──> softSerial->timerMode = TIMER_MODE_DUAL;│ ├──> serialTimerConfigureTimebase(softSerial->exTimerHardware, baud);│ ├──> timerChConfigCallbacks(softSerial->exTimerHardware, NULL, &softSerial->overCb);│ └──> timerChConfigCallbacks(softSerial->timerHardware, &softSerial->edgeCb, NULL);├──> < else >│ ├──> softSerial->timerMode = TIMER_MODE_SINGLE;│ └──> timerChConfigCallbacks(softSerial->timerHardware, &softSerial->edgeCb, &softSerial->overCb);│├──> <USE_HAL_DRIVER>│ └──> softSerial->timerHandle = timerFindTimerHandle(softSerial->timerHardware->tim);││ // antivate port├──> <!(options & SERIAL_BIDIR)>│ ├──> serialOutputPortActivate(softSerial);│ └──> setTxSignal(softSerial, ENABLE);├──> serialInputPortActivate(softSerial);└──> return &softSerial->port;
2.2 onSerialRxPinChange
通过边沿中断记录bit数据流。
onSerialRxPinChange├──> softSerial_t *self = container_of(cbRec, softSerial_t, edgeCb);├──> bool inverted = self->port.options & SERIAL_INVERTED;│├──> <(self->port.mode & MODE_RX) == 0>│ └──> return; // 无接收模式,直接返回│├──> <self->isSearchingForStartBit>│ │ // Synchronize the bit timing so that it will interrupt at the center│ │ // of the bit period.│ ├──> <USE_HAL_DRIVER>│ │ └──> __HAL_TIM_SetCounter(self->timerHandle, __HAL_TIM_GetAutoreload(self->timerHandle) / 2);│ ├──> <else>│ │ └──> TIM_SetCounter(self->timerHardware->tim, self->timerHardware->tim->ARR / 2);│ ││ │ // For a mono-timer full duplex configuration, this may clobber the│ │ // transmission because the next callback to the onSerialTimerOverflow│ │ // will happen too early causing transmission errors.│ │ // For a dual-timer configuration, there is no problem.│ ├──> <(self->timerMode != TIMER_MODE_DUAL) && self->isTransmittingData>│ │ └──> self->transmissionErrors++;│ ││ ├──> timerChConfigIC(self->timerHardware, inverted ? ICPOLARITY_FALLING : ICPOLARITY_RISING, 0);│ ├──> <defined(STM32F7) || defined(STM32H7) || defined(STM32G4)>│ │ └──> serialEnableCC(self);│ ││ ├──> self->rxEdge = LEADING;│ ││ ├──> self->rxBitIndex = 0;│ ├──> self->rxLastLeadingEdgeAtBitIndex = 0;│ ├──> self->internalRxBuffer = 0;│ ├──> self->isSearchingForStartBit = false;│ └──> return;││ // handle leveled signal├──> <self->rxEdge == LEADING>│ └──> self->rxLastLeadingEdgeAtBitIndex = self->rxBitIndex;├──> applyChangedBits(self);│├──> <self->rxEdge == TRAILING>│ ├──> self->rxEdge = LEADING;│ └──> timerChConfigIC(self->timerHardware, inverted ? ICPOLARITY_FALLING : ICPOLARITY_RISING, 0);├──> < else >│ ├──> self->rxEdge = TRAILING;│ └──> timerChConfigIC(self->timerHardware, inverted ? ICPOLARITY_RISING : ICPOLARITY_FALLING, 0);└──> <defined(STM32F7) || defined(STM32H7) || defined(STM32G4)>└──> serialEnableCC(self);
2.3 onSerialTimerOverflow
串行数据从原理上属于字符流协议,从实际应用角度,还是一包一包的数据(通常不会密集到头尾相连)。
因此,超时机制相当于处理:
- 数据帧
- 异常中断
onSerialTimerOverflow├──> softSerial_t *self = container_of(cbRec, softSerial_t, overCb);├──> <self->port.mode & MODE_TX> processTxState(self);└──> <self->port.mode & MODE_RX> processRxState(self);
2.4 processTxState
Tx数据处理存在三种情况:
- 发送数据前处理
- 发送数据
- 发送数据后处理
processTxState│ // 发送数据前处理├──> <!softSerial->isTransmittingData>│ ├──> <isSoftSerialTransmitBufferEmpty((serialPort_t *)softSerial)>│ │ │ // Transmit buffer empty.│ │ │ // Start listening if not already in if half-duplex│ │ ├──> <!softSerial->rxActive && softSerial->port.options & SERIAL_BIDIR) {│ │ │ ├──> serialOutputPortDeActivate(softSerial);│ │ │ └──> serialInputPortActivate(softSerial);│ │ └──> return;│ │ │ │ // data to send│ ├──> uint8_t byteToSend = softSerial->port.txBuffer[softSerial->port.txBufferTail++];│ ├──> <softSerial->port.txBufferTail >= softSerial->port.txBufferSize>│ │ └──> softSerial->port.txBufferTail = 0;│ │ │ │ // build internal buffer, MSB = Stop Bit (1) + data bits (MSB to LSB) + start bit(0) LSB│ ├──> softSerial->internalTxBuffer = (1 << (TX_TOTAL_BITS - 1)) | (byteToSend << 1);│ ├──> softSerial->bitsLeftToTransmit = TX_TOTAL_BITS;│ ├──> softSerial->isTransmittingData = true;│ └──> <softSerial->rxActive && (softSerial->port.options & SERIAL_BIDIR)>│ │ // Half-duplex: Deactivate receiver, activate transmitter│ ├──> serialInputPortDeActivate(softSerial);│ ├──> serialOutputPortActivate(softSerial);│ ││ │ // Start sending on next bit timing, as port manipulation takes time,│ │ // and continuing here may cause bit period to decrease causing sampling errors│ │ // at the receiver under high rates.│ │ // Note that there will be (little less than) 1-bit delay; take it as "turn around time".│ │ // XXX We may be able to reload counter and continue. (Future work.)│ └──> return;││ // 发送bit数据:高/低 电平├──> <softSerial->bitsLeftToTransmit>│ ├──> mask = softSerial->internalTxBuffer & 1;│ ├──> softSerial->internalTxBuffer >>= 1;│ ││ ├──> setTxSignal(softSerial, mask);│ ├──> softSerial->bitsLeftToTransmit--;│ └──> return;││ // 发送数据后处理└──> softSerial->isTransmittingData = false;
2.5 processRxState
RX_TOTAL_BITS 10 bits format: start bit + 8 bits for one byte + stop bit

processRxState│ //Start bit处理├──> <softSerial->isSearchingForStartBit>│ └──> return;├──> softSerial->rxBitIndex++;││ //1 Byte数据处理├──> <softSerial->rxBitIndex == RX_TOTAL_BITS - 1>│ ├──> applyChangedBits(softSerial);│ └──> return;│ //Stop bit处理└──> <softSerial->rxBitIndex == RX_TOTAL_BITS>├──> softSerial->rxEdge == TRAILING>│ └──> softSerial->internalRxBuffer |= STOP_BIT_MASK;├──> extractAndStoreRxByte(softSerial);└──> prepareForNextRxByte(softSerial);
注:上述函数过程存在10bit缺损卡死的情况,代码还不够robust。
3. 辅助函数
3.1 applyChangedBits
1~9 bit数据将通过该函数进行存储,最后10bit数据将在processRxState中进行保存。
applyChangedBits└──> <softSerial->rxEdge == TRAILING>└──> for (bitToSet = softSerial->rxLastLeadingEdgeAtBitIndex; bitToSet < softSerial->rxBitIndex; bitToSet++)└──> softSerial->internalRxBuffer |= 1 << bitToSet;
3.2 extractAndStoreRxByte
从10 bit格式中抽取1Byte有效数据。
extractAndStoreRxByte│ //仅TX模式,无需进行任何接收字节的保存工作├──> <(softSerial->port.mode & MODE_RX) == 0>│ └──> return;│ ├──> uint8_t haveStartBit = (softSerial->internalRxBuffer & START_BIT_MASK) == 0;├──> uint8_t haveStopBit = (softSerial->internalRxBuffer & STOP_BIT_MASK) == 1;│ │ //起止bit位,若一项不符合规格,则丢弃数据├──> <!haveStartBit || !haveStopBit>│ ├──> softSerial->receiveErrors++;│ └──> return;│ │ //保存1Byte数据├──> uint8_t rxByte = (softSerial->internalRxBuffer >> 1) & 0xFF;│ ├──> <softSerial->port.rxCallback> //回调接收函数│ └──> softSerial->port.rxCallback(rxByte, softSerial->port.rxCallbackData);└──> < else > //无接收注册函数情况下,将数据存入缓冲buffer中,并采用循环方式覆盖保存├──> softSerial->port.rxBuffer[softSerial->port.rxBufferHead] = rxByte;└──> softSerial->port.rxBufferHead = (softSerial->port.rxBufferHead + 1) % softSerial->port.rxBufferSize;
3.3 prepareForNextRxByte
收录下一字节数据做预处理工作。
prepareForNextRxByte├──> softSerial->rxBitIndex = 0;├──> softSerial->isSearchingForStartBit = true;└──> <softSerial->rxEdge == LEADING>├──> softSerial->rxEdge = TRAILING;├──> timerChConfigIC(softSerial->timerHardware, (softSerial->port.options & SERIAL_INVERTED) ? ICPOLARITY_RISING : ICPOLARITY_FALLING, 0);└──> serialEnableCC(softSerial);
4. 总结
从SoftSerial代码角度,采用定时器、边沿中断的方式,随机使用CPU资源。如果应用在高速、大数据量通信场景,将会影响和打扰CPU正常业务逻辑,尤其是在CPU资源紧张时。
相关文章:
BetaFlight模块设计之三十六:SoftSerial
BetaFlight模块设计之三十六:SoftSerial 1. 源由2. API接口2.1 openSoftSerial2.2 onSerialRxPinChange2.3 onSerialTimerOverflow2.4 processTxState2.5 processRxState 3. 辅助函数3.1 applyChangedBits3.2 extractAndStoreRxByte3.3 prepareForNextRxByte 4. 总结…...
PC访问华为昇腾开发板的摸索过程
作者:朱金灿 来源:clever101的专栏 为什么大多数人学不会人工智能编程?>>> 最近要折腾华为昇腾开发板(官方名称叫:Atlas 200I DK)。先是按照官方教程折腾:Atlas200DK环境部署。我发现…...
C++学习之路(六)C++ 实现简单的工具箱系统命令行应用 - 示例代码拆分讲解
简单的工具箱系统示例介绍: 这个示例展示了一个简单的工具箱框架,它涉及了几个关键概念和知识点: 面向对象编程 (OOP):使用了类和继承的概念。Tool 是一个纯虚类,CalculatorTool 和 FileReaderTool 是其派生类。 多态࿱…...
redis运维(十四) hash缓存案例
一 缓存案例 ① 需求 ② 个人理解 策略:不更新缓存,而是删除缓存大部分观点认为:1、做缓存不应该是去更新缓存,而是应该删除缓存2、然后由下个请求去缓存,发现不存在后再读取数据库,写入redis缓存 高并发场景下,到底先更新缓存还是先更…...
Rust UI开发(三):iced如何打开图片(对话框)并在窗口显示图片?
注:此文适合于对rust有一些了解的朋友 iced是一个跨平台的GUI库,用于为rust语言程序构建UI界面。 这是一个系列博文,本文是第三篇,前两篇的链接: 1、Rust UI开发(一):使用iced构建…...
网络爬虫(Python:Requests、Beautiful Soup笔记)
网络爬虫(Python:Requests、Beautiful Soup笔记) 网络协议简要介绍一。OSI参考模型二、TCP/IP参考模型对应关系TCP/IP各层实现的协议应用层传输层网络层 HTTP协议HTTP请求HTTP响应HTTP状态码 Requests(Python)Requests…...
【Kotlin】内联函数
文章目录 内联函数noinline: 避免参数被内联非局部返回使用标签实现Lambda非局部返回为什么要设计noinline crossinline具体化参数类型 Kotlin中的内联函数之所以被设计出来,主要是为了优化Kotlin支持Lambda表达式之后所带来的开销。然而,在Java中我们似…...
Unity技美35——再URP管线环境下,配置post后期效果插件(post processing)
前两年在我的unity文章第10篇写过,后效滤镜的使用,那时候大部分项目用的还是unity的基础管线,stander管线。 但是现在随着unity的发展,大部分项目都用了URO管线,甚至很多PC端用的都是高效果的HDRP管线,这就…...
Redis:持久化RDB和AOF
目录 概述RDB持久化流程指定备份文件的名称指定备份文件存放的目录触发RDB备份redis.conf 其他一些配置rdb的备份和恢复优缺点停止RDB AOF持久化流程AOF启动/修复/恢复AOF同步频率设置rewrite压缩原理触发机制重写流程no-appendfsync-on-rewrite 优缺点 如何选择 概述 Redis是…...
基于python协同过滤推荐算法的音乐推荐与管理系统
欢迎大家点赞、收藏、关注、评论啦 ,由于篇幅有限,只展示了部分核心代码。 文章目录 一项目简介 二、功能三、系统四. 总结 一项目简介 基于Python的协同过滤推荐算法的音乐推荐与管理系统是一个集成了音乐推荐和管理的系统,它使用协同过滤算…...
【极客技术】真假GPT-4?微调 Llama 2 以替代 GPT-3.5/4 已然可行!
近日小编在使用最新版GPT-4-Turbo模型(主要特点是支持128k输入和知识库截止日期是2023年4月)时,发现不同商家提供的模型回复出现不一致的情况,尤其是模型均承认自己知识库达到2023年4月,但当我们细问时,Fak…...
STK Components 二次开发-创建地面站
1.地面站只需要知道地面站的经纬高。 // Define the location of the facility using cartographic coordinates.var location new Cartographic(Trig.DegreesToRadians(-75.596766667), Trig.DegreesToRadians(40.0388333333), 0.0); 2.创建地面站 创建方式和卫星一样生成对…...
数据结构与算法(三)贪心算法(Java)
目录 一、简介1.1 定义1.2 基本步骤1.3 优缺点 二、经典示例2.1 选择排序2.2 背包问题 三、经典反例:找零钱3.1 题目3.2 解答3.3 记忆化搜索实现3.4 动态规划实现 一、简介 1.1 定义 贪心算法(Greedy Algorithm),又名贪婪法&…...
057-第三代软件开发-文件监视器
第三代软件开发-文件监视器 文章目录 第三代软件开发-文件监视器项目介绍文件监视器实现原理关于 QFileSystemWatcher实现代码 关键字: Qt、 Qml、 关键字3、 关键字4、 关键字5 项目介绍 欢迎来到我们的 QML & C 项目!这个项目结合了 QML&…...
二十七、微服务案例
目录 一、实现输入搜索功能 1、下载代码,在idea上打开 2、新建RequestParams类,用于接收解析请求 3、在启动类中加入客户端地址Bean,以便实现服务 4、编写搜索方法 5、新建返回分页结果类 6、实现搜索方法 7、编写控制类,…...
(C++)string类的模拟实现
愿所有美好如期而遇 前言 我们模拟实现string类不是为了去实现他,而是为了了解他内部成员函数的一些运行原理和时间复杂度,在将来我们使用时能够合理地去使用他们。 为了避免我们模拟实现的string类与全局上的string类冲突(string类也在std命名空间中)&…...
处理数据中的缺失值--删除缺少值的行
两个最主要的处理缺失值的方法是: ❏ 删除缺少值的行; ❏ 填充缺失值; 我们首先将serum_insulin的中的字段值0替换为None,可以看到缺失值的数量为374个; print(pima[serum_insulin].isnull().sum()) pima[serum_insu…...
Kotlin学习——kt里的集合,Map的各种方法之String篇
Kotlin 是一门现代但已成熟的编程语言,旨在让开发人员更幸福快乐。 它简洁、安全、可与 Java 及其他语言互操作,并提供了多种方式在多个平台间复用代码,以实现高效编程。 https://play.kotlinlang.org/byExample/01_introduction/02_Functio…...
MIT 6.824 -- MapReduce Lab
MIT 6.824 -- MapReduce Lab 环境准备实验背景实验要求测试说明流程说明 实验实现GoLand 配置代码实现对象介绍协调器启动工作线程启动Map阶段分配任务执行任务 Reduce 阶段分配任务执行任务 终止阶段 崩溃恢复 注意事项并发安全文件转换golang 知识点 测试 环境准备 从官方gi…...
创新研报|顺应全球数字化,能源企业以“双碳”为目标的转型迫在眉睫
能源行业现状及痛点分析 挑战一:数字感知能力较弱 挑战二:与业务的融合度低 挑战三:决策响应速度滞后 挑战四:价值创造有待提升 挑战五:安全风险如影随形 能源数字化转型定义及架构 能源行业数字化转型体系大体…...
基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真
目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销,平衡网络负载,延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...
AtCoder 第409场初级竞赛 A~E题解
A Conflict 【题目链接】 原题链接:A - Conflict 【考点】 枚举 【题目大意】 找到是否有两人都想要的物品。 【解析】 遍历两端字符串,只有在同时为 o 时输出 Yes 并结束程序,否则输出 No。 【难度】 GESP三级 【代码参考】 #i…...
连锁超市冷库节能解决方案:如何实现超市降本增效
在连锁超市冷库运营中,高能耗、设备损耗快、人工管理低效等问题长期困扰企业。御控冷库节能解决方案通过智能控制化霜、按需化霜、实时监控、故障诊断、自动预警、远程控制开关六大核心技术,实现年省电费15%-60%,且不改动原有装备、安装快捷、…...
HTML 列表、表格、表单
1 列表标签 作用:布局内容排列整齐的区域 列表分类:无序列表、有序列表、定义列表。 例如: 1.1 无序列表 标签:ul 嵌套 li,ul是无序列表,li是列表条目。 注意事项: ul 标签里面只能包裹 li…...
【C语言练习】080. 使用C语言实现简单的数据库操作
080. 使用C语言实现简单的数据库操作 080. 使用C语言实现简单的数据库操作使用原生APIODBC接口第三方库ORM框架文件模拟1. 安装SQLite2. 示例代码:使用SQLite创建数据库、表和插入数据3. 编译和运行4. 示例运行输出:5. 注意事项6. 总结080. 使用C语言实现简单的数据库操作 在…...
ardupilot 开发环境eclipse 中import 缺少C++
目录 文章目录 目录摘要1.修复过程摘要 本节主要解决ardupilot 开发环境eclipse 中import 缺少C++,无法导入ardupilot代码,会引起查看不方便的问题。如下图所示 1.修复过程 0.安装ubuntu 软件中自带的eclipse 1.打开eclipse—Help—install new software 2.在 Work with中…...
C# 求圆面积的程序(Program to find area of a circle)
给定半径r,求圆的面积。圆的面积应精确到小数点后5位。 例子: 输入:r 5 输出:78.53982 解释:由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982,因为我们只保留小数点后 5 位数字。 输…...
深度学习习题2
1.如果增加神经网络的宽度,精确度会增加到一个特定阈值后,便开始降低。造成这一现象的可能原因是什么? A、即使增加卷积核的数量,只有少部分的核会被用作预测 B、当卷积核数量增加时,神经网络的预测能力会降低 C、当卷…...
Android第十三次面试总结(四大 组件基础)
Activity生命周期和四大启动模式详解 一、Activity 生命周期 Activity 的生命周期由一系列回调方法组成,用于管理其创建、可见性、焦点和销毁过程。以下是核心方法及其调用时机: onCreate() 调用时机:Activity 首次创建时调用。…...
【Go语言基础【13】】函数、闭包、方法
文章目录 零、概述一、函数基础1、函数基础概念2、参数传递机制3、返回值特性3.1. 多返回值3.2. 命名返回值3.3. 错误处理 二、函数类型与高阶函数1. 函数类型定义2. 高阶函数(函数作为参数、返回值) 三、匿名函数与闭包1. 匿名函数(Lambda函…...
