嵌入式C编程
文章平均质量分 89
个人C编程过程中一些总结和摘录!
Frey_Liu
软件工程师
展开
-
C++常见问题
防止内存泄露。原创 2024-02-24 21:33:29 · 960 阅读 · 0 评论 -
嵌入式C常用的几个宏定义
链表宏在linux内核、鸿蒙内核、rtos和一些开源代码中用的非常多。链表宏是双向链表的经典实现方式,总代码不超过50行,相当精炼。宏的定义如下,其作用是将所传入指针N的两个指针域和都指向N。目的是完成单个节点的初始化工作,如下图示意了该过程。宏的定义如下,直接将宏展开,其意图很明显是定义一个新链表(H表示为传入宏的参数名),并且将H的两个指针域,都初始化为H地址本身,如下图示意了该过程。宏的定义如下,其依赖于宏。宏功能描述为:为了更好的理解宏,下面按照宏的定义来进行拆解说明。由于该结构体转载 2023-03-14 22:14:00 · 1320 阅读 · 1 评论 -
协程Protothread
Protothread在contiki os 的 process中有广泛的应用!contiki 的作者Adam Dunkels,同时也是uip,lwip的作者。原创 2023-03-05 21:23:27 · 1077 阅读 · 0 评论 -
基于RTOS的软件开发理论
基于RTOS的软件开发理论RTOS的特点任务设计任务的特性任务划分的方法设备依赖性任务关键任务紧迫任务数据处理任务触发条件相同的任务运行周期相同的任务顺序操作任务任务的可调度性分析任务类型单次执行的任务周期性执行的任务事件触发执行的任务任务优先级公共函数的设计互斥调用可重入设计运行效率中断服务程序的设计中断优先级中断优先级原则中断与关联任务的通信行为同步行为同步的通信方式二值信号置计数信号量事件标志组消息邮箱消息队列通信方式的选择行为同步ISR 与任务之间的同步两个任务之间的单向同步两个任务之间的双向同步多转载 2022-04-21 10:01:01 · 860 阅读 · 0 评论 -
C 语言高效编程与代码优化
C 语言高效编程与代码优化)整形数除法和取余数合并除法和取余数通过2的幂次进行除法和取余数取模的一种替代方法使用数组下标全局变量使用别名变量的生命周期分割变量类型局部变量指针指针链条件执行布尔表达式和范围检查布尔表达式和零值比较懒检测开发用switch()函数替代if…else…二分中断switch语句vs查找表循环函数设计使用查找表浮点运算其他技巧参考:程序优化最重要的就是找出待优化的地方,也就是找出程序的哪些部分或者哪些模块运行缓慢亦或消耗大量的内存。只有程序的各部分经过了优化,程序才能执行的更快。程转载 2022-04-19 21:25:38 · 1053 阅读 · 0 评论 -
C语言一些实用技巧
C语言一些实用技巧指定的初始化数组结构体与联合体宏的使用宏列表编译时断言静态断言获取偏移量获取容器地址获取数组元素数目头文件保护符符号转字符串符号拼接泛型编程掩码判断机器的字节顺序整数任意进制数转换统计整数中为1的位的个数静态表-4bit静态表-8bit平行算法完美法参考文档,不,抄袭文档指定的初始化C99标准实际上支持一种更为直观简单的方式来初始化各种不同的集合类数据(如:结构体,联合体和数组)。数组我们可以指定数组的元素来进行初始化。这非常有用,特别是当我们需要根据一组#define来保持某种映原创 2022-01-29 00:31:58 · 2504 阅读 · 2 评论 -
C语言常用转换函数实现原理
字符串转十六进制void StrToHex(char *pbDest, char *pbSrc, int nLen){ char h1,h2; char s1,s2; int i; for (i=0; i<nLen/2; i++) { h1 = pbSrc[2*i]; h2 = pbSrc[2*i+1]; s1 = toupper(h1) - 0x30; //toupper 转换为大写字母 if (s转载 2022-01-28 16:36:44 · 652 阅读 · 0 评论 -
常见嵌入式C问题
常见嵌入式C问题进程与线程的区别进程与线程的区别进程,是对操作系统正在运行程序的一个抽象。操作系统会把每个运行中的程序封装成独立的实体,分配各自所需要的资源,在根据调度算法切换执行,这个抽象的实体就是进程。因此进程是操作系统机型资源分配和调度的一个基本单位。进程是任务调度的最小单位,每个进程有自己的独立代码和数据空间,使得各个进程之间内存地址相互隔离。随着应用程序功能设计的越来越复杂,应用程序中的某种活动可能被阻塞,自然而然的想着能不能把这些应用程序分解成更细的粒度,能“并行”的执行多个执行实体,并原创 2022-01-28 13:13:49 · 1782 阅读 · 0 评论 -
MPU与MMU
MPU MPU 有以下能力可以增加系统的健壮性可以阻止用户去破坏操作系统需要使用的数据可以防止一个任务去非法访问其他任务的数据,将任务完全隔离开可以把关键数据区设为只读,从而不被破坏检测其他意外访问,比如,堆栈溢出,数组越界等。原理通常MPU功能这个是由操作系统提供的服务。在嵌入式调试的时候,我们经常会遇到 hardfault,这个时候一般情况可能是某个指针指到未知的地方,然后对该地址进行修改赋值,会触发 hardfault。MPU的功能其实和这个功能基本类似。比如,RTOS中的一些特.原创 2022-01-24 17:42:32 · 2887 阅读 · 0 评论 -
优雅代码的设计原则
优雅代码的设计原则代码设计原则SRPOCPLSPISPLOD总结本文通过阐述优雅代码的设计原则来和大家聊聊怎么写好代码。代码设计原则好代码是设计出来的,也是重构出来的,更是不断迭代出来的。在我们接到需求,经过概要设计过后就要着手进行编码了。但是在实际编码之前,我们还需要进行领域分层设计以及代码结构设计。那么怎么样才能设计出来比较优雅的代码结构呢?有一些大神们总结出来的优雅代码的设计原则,我们分别来看下。SRP所谓SRP(Single Responsibility Principle)原则就是职责单转载 2022-01-21 14:28:25 · 504 阅读 · 0 评论 -
嵌入式C开发中编程模型——重点事件驱动和表驱动
嵌入式C开发中编程模型事件驱动消息驱动事件驱动vs消息驱动数据驱动1. 表驱动法(Table-Driven)用表驱动法来实现Unix设计原则中的“分离原则”和“表示原则”2. 基于数据模型编程**数据驱动思考**总结事件驱动事件驱动架构(Event-Driven Architecture)是一种用于设计应用的软件架构和模型,程序的执行流由外部事件来决定,它的特点是包含一个事件循环,当外部事件发生时使用回调机制来触发相应的处理。主要包括 4 个基本组件:事件队列(event queue):接收事件原创 2022-01-19 21:58:05 · 4289 阅读 · 0 评论 -
C代码中的#、##用法
C代码中的#、##用法#和##基础#的用法##的用法#和##基础对于这两个语法的功能都比较简单,且都是在预处理阶段做一些工作 :#主要是将宏参数转化为字符串##主要是将两个标识符拼接成一个标识符#include <stdio.h>#include <stdlib.h>//#的简单使用 #define STR(str) #str//##的简单使用#define CMB(a,b) a##bint main(int argc, char *argv[]) {转载 2021-12-19 21:35:40 · 2297 阅读 · 0 评论 -
ADC常用的滤波算法
ADC常用的滤波算法限幅滤波中位值滤波算数平均滤波递推平均滤波中位值平均滤波限幅平均滤波一阶滞后滤波加权递推平均滤波消抖滤波限幅消抖滤波限幅滤波方法根据经验判断两次采样允许的最大偏差值A每次采新值时判断:若本次值与上次值之差<=A,则本次有效;若本次值与上次值之差>A,本次无效,用上次值代替本次。优缺点克服脉冲干扰,无法抑制周期性干扰,平滑度差。代码/* A值根据实际调,Value有效值,new_Value当前采样值,程序返回有效的实际值 */#define A 10c转载 2021-12-19 19:47:03 · 1864 阅读 · 1 评论 -
嵌入式 C语言上下文的快速切换
前言我们通常认为,在中断中,不能执行耗时的操作,否则会影响系统的稳定性,尤其对于嵌入式编程。对于带操作系统的程序而言,可以通过操作系统的调度,将中断处理分成两个部分,耗时的操作可以放到线程中去执行,但是对于没有操作系统的情况,又应该如何处理呢比较常见的,我们可能会定义一些全局变量,作为flag,然后在mainloop中不停的判断这些flag,再在中断中修改这些flag,最后在mainloop中执行具体的逻辑,但是这样,无疑会增加耦合,增加程序维护成本。cpostcpost链接:https://git转载 2021-12-19 19:23:24 · 537 阅读 · 0 评论 -
C常用库函数实现
void *memcpy(void* dest, const void* src, size_t n){ assert(dest != NULL && src != NULL && n > 0); if ((src < dest) && ((char*)src + n > dest)) { char* d = (char*)dest+n-1; char* s = (char*)src+n-1原创 2021-12-05 21:56:09 · 2877 阅读 · 0 评论 -
程序是如何运行的——编译、链接、装入
1、地址概念和程序如何运行在多道程序环境下,要使程序运行,必须先为之创建进程。而创建进程的第一件事,便是将程序和数据装入内存。如何将一个用户源程序变为一个可在内存中执行的程序,通常都要经过以下几个步骤:首先是要编译由编译程序(Compiler)将用户源代码编译成cpu可执行的目标代码,产生了若干个目标模块(Object Module)(即若干程序段),形成的目标代码,每个目标代码都是以0为基址顺序进行编址,原来用符号名访问的单元用具体的数据——单元号取代。这样生成的目标程序占据一定的地址空间,称为作转载 2021-12-03 23:39:00 · 1156 阅读 · 0 评论 -
嵌入式软件错误的五个主要原因
嵌入式软件错误的五个主要原因在嵌入式开发软件中查找和消除潜在的错误是一项艰巨的任务。通常需要英勇的努力和昂贵的工具才能从观察到的崩溃,死机或其他计划外的运行时行为追溯到根本原因。在最坏的情况下,根本原因会破坏代码或数据,使系统看起来仍然可以正常工作或至少在一段时间内仍能正常工作。工程师常常放弃尝试发现不常见异常的原因,这些异常在实验室中不易再现,将其视为用户错误或“小故障”。然而,机器中的这些鬼魂仍然存在。这是难以重现错误的最常见根本原因指南。每当您阅读固件源代码时,请查找以下五个主要错误。并遵转载 2021-11-21 01:13:32 · 1302 阅读 · 0 评论 -
嵌入式软件可靠性设计
设备的可靠性涉及多个方面:稳定的硬件、优秀的软件架构、严格的测试以及市场和时间的检验等等。这里着重谈一下作者自己对嵌入式软件可靠性设计的一些理解,通过一定的技巧和方法提高软件可靠性。1、判错工欲善其事必先利其器。判错的最终目的是用来暴露设计中的Bug并加以改正,所以将错误信息提供给编程者是必要的。有时候需要将故障信息储存于非易失性存储器中,便于查看。这里以使用串口打印错误信息到PC显示屏为例,来说明一般需要显示什么信息。编写或移植一个类似C标准库中的printf函数,可以格式化打印字符、字符串、十进原创 2021-10-13 21:21:18 · 1428 阅读 · 0 评论 -
基于硬件 SPI 的数据抽象实例
1.写在前面spi(Serial Peripheral Interface)即串行外设接口。与i2c一样,spi也常用外设设备通信的总线,从事嵌入式开发必不可少的掌握。根据本人以往的经历,对spi进行总结(主要是MCU范畴,Linux已有成熟的驱动设备),主要目的及实现:spi总线与spi设备分离;快速使用新的硬件spi或者模拟spi;方便移植spi总线设备及spi外设程序到不同mcu平台。2.spi总线抽象此部分实现源码为:spi_core.c spi_core.h2.1转载 2021-10-12 19:24:39 · 344 阅读 · 0 评论 -
基于模拟 I2C 的数据抽象实例
1.写在前面i2c总线是由PHILIPS公司开发的一种简单、「双向二线制同步串行总线」。关于i2c的使用,并不陌生,C51、ARM、MSP430等,都基本集成硬件i2c,或者不集成i2c的,可以根据总线时序图使用普通IO口翻转模拟一根i2c总线。对于流行的stm32饱受诟病的硬件i2c,相信很多人都是使用模拟i2c。模拟i2c的源码比较多,大多都是大同小异,对于各类例程,提供的模拟i2c似乎都不是太规范(个人见解),特别是一根i2c总线挂多个外设、模拟多根i2c总线、以及更换一个i2c外设时,都需要大幅转载 2021-10-11 15:58:52 · 230 阅读 · 0 评论 -
嵌入式系统开发的7大技巧
今天给大家介绍7个易操作且可以长久使用的技巧,它们对于确保系统更加可靠地运行并捕获异常行为大有帮助。1. 用已知值填充ROM软件开发人员往往都是非常乐观的一群人,只要让他们的代码忠实地长时间地运行就可以了,仅此而已。微控制器跳出应用程序空间并在非预想的代码空间中执行这种情况似乎是相当少有的。然而,这种情况发生的机会并不比缓存溢出或错误指针失去引用少。它确实会发生!发生这种情况后的系统行为将是不确定的,因为默认情况下内存空间都是0xFF,或者由于内存区通常没有写过,其中的值可能只有上帝才知道。不转载 2021-09-15 21:15:41 · 345 阅读 · 0 评论 -
嵌入式系统开发:驱动程序设计的5个窍门
本文由资深嵌入式软件开发专家Jacob Beningo撰写,总结了设计驱动程序开发者应该掌握的五个技巧。每一个嵌入式应用软件都会在某些时候访问最底层的固件和进行一些硬件控制。 驱动的设计和实施是确保一个系统能够满足其实时性要求的关键。以下五个窍门是每一个开发者在设计驱动程序时应该考虑的。1 - 使用设计模式设计模式是一个用来处理那些在软件中会重复出现的问题的解决方案。 开发人员可以选择浪费宝贵的时间和预算,从无到有地重新发明一个解决方案,也可以从他的解决方案工具箱中选择一个最适合解决这个问题的方案。在转载 2021-09-15 20:50:44 · 276 阅读 · 0 评论 -
从零开始开发一款嵌入式产品的一些经验
从零开始开发一款嵌入式产品的一些经验1.需求定义2.处理器的选择3.开发成本的预测和估计4.产品开发设计文档(需要包括硬件和软件两个方面)4.1 硬件文档撰写思路4.2 软件文档撰写思路5.嵌入式高手对技术的理解(含辛茹苦这么多年的精华体验)分享一位前辈的一些产品开发经验,那么由此开始我们充满知识的旅程吧,最重要的一点,就是在一个产品或项目的开发过程中,如果没有明确的目标,那么成功将无从谈起,做任何事的第一步必须明确目标。与日常生活中的大多数事务一样,设计一个嵌入式产品的过程也必须从确定目标开始,对生产转载 2021-09-15 20:31:10 · 378 阅读 · 0 评论 -
嵌入式产品开发流程详解
嵌入式产品开发流程详解阶段1:产品需求阶段2:产品规格说明阶段3:产品总体设计方案阶段4:产品概要设计阶段5:产品详细设计阶段6&7:产品调试与验证阶段8:测试阶段9:产品附录:嵌入式硬件开发流程硬件阶段1:硬件产品需求硬件阶段2:硬件总体设计方案硬件阶段3:硬件电路原理图设计硬件阶段4:PCB图设计硬件阶段5:PCB加工文件制作与PCB打样硬件阶段6:硬件产品的焊接与调试硬件阶段7:硬件产品测试硬件阶段8:硬件产品参考:嵌入式产品,与普通电子产品一样,开发过程都需要遵循一些基本的流程,都是一个从转载 2021-09-15 15:30:23 · 5047 阅读 · 0 评论 -
嵌入式项目要在设计时考虑的缺陷
嵌入式项目要在设计时考虑的缺陷概述缺陷模式规则分类2.1 规则分类2.1.1 按照错误类别分类2.1.2 按照严重程度分类2.2 规则解析2.2.1 数值检查2.2.2 空指针解引用2.2.3 变量定义未使用就再次赋值2.2.4 if elseif分支语句末尾缺少else分支2.2.5 使用未初始化变量2.2.6 数据类型不一致引入的隐式类型转换2.2.7 操作符使用不当代码抽样及结果分析3.1 抽样代码情况及指标3.2 工具分析结果3.3 建议参考:概述在高质量、高转载 2021-09-11 17:32:31 · 258 阅读 · 0 评论 -
如何编写更高层次嵌入式C代码?
如何编写更高层次嵌入式C代码?1. 简介2. C语言特性2.1处处都是陷阱2.1.1 无心之过2.1.2 数组下标2.1.3 容易被忽略的break关键字2.1.4 意想不到的八进制2.1.5 指针加减运算2.1.6 关键字sizeof2.1.7 增量运算符’++’和减量运算符‘--‘2.1.8 逻辑与’&&’和逻辑或’||’的陷阱2.1.9 结构体的填充2.2 不可轻视的优先级2.3 隐式转换3. 编译器3.1 不能简单的认为是个工具3.2 不能依赖编译器的语义检查3.2.1 莫名的死机3转载 2021-09-10 18:06:16 · 743 阅读 · 1 评论 -
C++头文件包含顺序
使用标准的头文件包含顺序可增强可读性, 避免隐藏依赖。《Google C++ Style Guide》推荐顺序:(对xxx.cpp)xxx.hC 系统文件C++ 系统文件其他库的 .h 文件本项目内 .h 文件《C++编程思想》推荐顺序:(对xxx.cpp)从最特殊到最一般。xxx.h本项目内 .h 文件其他库的 .h 文件C++ 系统文件C 系统文件两者...转载 2019-10-18 19:41:45 · 4591 阅读 · 0 评论 -
代码中易混单词的区分
代码中易混单词的区分Satus Vs StateState 表达的是形态,而 Status 表达的是从一种形态转换成另一种形态的过程中,那些有显著特征的离散中间值。举一个旅馆房间的例子,一个房间可以是婚房、普通房、豪华总统房,这些都是用 State 来表达。把一个普通房改造成豪华总统房,这个过程就有设计、材料准备、工人就位、施工、验收等步骤,这个时候就用 Status 来表达。那么,区分点在...原创 2019-08-24 20:40:57 · 215 阅读 · 0 评论 -
嵌入式应用软件任务划分的原则
嵌入式应用软件任务划分的原则参考文章“嵌入式应用软件任务划分的原则”在基于实时操作系统(RTOS,RealTime Operating System)的单片机应用软件设计中,“任务”是一个很重要的概念。对于任务的划分,并没有一个人人都要遵守的规则,不同的人来设计一个同样规格要求的系统,会有不同的方案。本文将深入研究划分任务的方法,并在此基础上,从实用的角度给出编写基于RTX51 Tiny实时...原创 2019-07-28 20:22:31 · 2912 阅读 · 1 评论 -
调度器,极小资源单片机值得一用
调度器,极小资源单片机值得一用本文转载于“调度器,极小资源单片机值得一用(转)”及“再出个调度器,极小资源单片机值得一用 ”自认为有如下特点:超级可以移植性,与CPU无关,几乎任何支持C语言编程的CPU都可以用!(本文仅仅以51单片机为例而已,但实际上可以任意移植)小之又小, 原理很简单,一看就懂。省之又省, 可以说对RAM和ROM省到极致。取protothread之精华,将定时器与...转载 2019-05-26 14:40:39 · 2368 阅读 · 0 评论 -
C语言的代码内存布局详解
C语言的代码内存布局详解文章摘录自《C语言的代码内存布局详解》一个程序本质上都是由 BSS 段、data段、text段三个组成的。这样的概念在当前的计算机程序设计中是很重要的一个基本概念,而且在嵌入式系统的设计中也非常重要,牵涉到嵌入式系统运行时的内存大小分配,存储单元占用空间大小的问题。BSS段:在采用段式内存管理的架构中,BSS段(bss segment)通常是指用来存放程序中未初始化...转载 2019-02-23 23:23:17 · 1079 阅读 · 0 评论 -
C学习:const修饰、结构体指针及位域使用
C学习:const修饰、结构体指针及位域使用const的临近修饰用法const在前面const int nValue; // nValue是constconst char *pContent; // *pContent是const, pContent可变const char* const pContent; // pContent 和 *pContent都是const...原创 2018-06-13 22:36:24 · 4621 阅读 · 0 评论 -
大小端及堆栈增长——测试方法
大小端测试方法这里提供了两种常用的大小端测试方法:void EndianTest(void){ unsigned int i = 0x12345678; unsigned char *c = (unsigned char *)&i; union{ unsigned int union_i; unsigned char union_c[4];原创 2017-05-18 18:32:21 · 402 阅读 · 0 评论 -
typedef定义函数类型的用法
typedef定义函数类型的用法最近在CodeProject上看了段关于COM in plain C项目的代码,其中的一段关于typedef使用的代码一时让人有点模糊,代码如下:typedef long SetStringPtr(char *);typedef long GetStringPtr(char *, long);typedef struct { SetStringPtr * Se原创 2017-02-03 11:27:19 · 19602 阅读 · 0 评论