嵌入式C语言代码

合集下载

粤嵌知识:嵌入式C编程技巧

粤嵌知识:嵌入式C编程技巧

粤嵌知识:嵌入式C编程技巧预处理器(Preprocessor)1 . 用预处理指令#define 声明一个常数,用以表明1年中有多少秒(忽略闰年问题)#define SECONDS_PER_YEAR (60 * 60 * 24 * 365)UL●#define 语法的基本知识(例如:不能以分号结束,括号的使用,等等)●懂得预处理器将为你计算常数表达式的值,因此,直接写出你是如何计算一年中有多少秒而不是计算出实际的值,是更清晰而没有代价的。

●意识到这个表达式将使一个16位机的整型数溢出-因此要用到长整型符号L,告诉编译器这个常数是的长整型数。

●如果你在你的表达式中用到UL(表示无符号长整型),那么你有了一个好的起点。

记住,第一印象很重要。

2 . 写一个“标准”宏MIN ,这个宏输入两个参数并返回较小的一个。

#define MIN(A,B) ((A)<= (B) ? (A) : (B))这个测试是为下面的目的而设的:●标识#define在宏中应用的基本知识。

这是很重要的,因为直到嵌入(inline)操作符变为标准C的一部分,宏是方便产生嵌入代码的唯一方法,对于嵌入式系统来说,为了能达到要求的性能,嵌入代码经常是必须的方法。

●三重条件操作符的知识。

这个操作符存在C语言中的原因是它使得编译器能产生比if-then-else更优化的代码,了解这个用法是很重要的。

●懂得在宏中小心地把参数用括号括起来●我也用这个问题开始讨论宏的副作用,例如:当你写下面的代码时会发生什么事?least = MIN(*p++, b);3. 预处理器标识#error的目的是什么?死循环(Infinite loops)4. 嵌入式系统中经常要用到无限循环,怎么样用C编写死循环呢?这个问题用几个解决方案。

首选的方案是:while(1){}一些程序员更喜欢如下方案:for(;;){}这个语法没有确切表达到底怎么回事。

第三个方案是用gotoLoop:...goto Loop;这是一个汇编语言程序员的思路。

嵌入式系统C语言编程基础PPT课件

嵌入式系统C语言编程基础PPT课件

精选ppt
小测验?
精选ppt
Quiz 1
• 所有嵌入式系统的主流程最后都进入一个 死循环,怎样用C语言实现一个死循环?
精选ppt
Quiz 2
• while(){….}和do{….}while()有什么区别?
精选ppt
Quiz 3
• 用变量a给出下列定义:
a) 一个整型数 b) 一个指向整型数的指针 c) 一个有10个整型数的的数组 d) 一个有10个指针的数组,该指针是指向一个整型
精选ppt
Quiz 10
• 请评论下面一段程序代码: void test() { char string[10]; char *str = “0123456789”; strcpy(string,str); }
精选ppt
Quiz 11
• 请评论下面一段程序代码: void GetMemory(char *p){ p = (char *)malloc(0x20); } void Test(void){ char *str = NULL; GetMemory(str); strcpy(str,”Hello World!”); printf(str); }
数的
精选ppt
Quiz 4
• 关键字static的作用是什么?
精选ppt
Quiz 5
• 关键字const的作用是什么?
精选ppt
Quiz 6
• 定义一个标准宏MIN ,这个宏输入两个参 数并返回较小的一个。
精选ppt
Quiz 7
• 嵌入式系统中经常要对变量或寄存器进行 位操作。给定一个int型变量a,写两段代码, 第一个将a的bit 3置为1,第二个将a的bit 3 置为0。以上两个操作中,要保持其它位不 变。

嵌入式Linux下C程序设计--02输入输出语句

嵌入式Linux下C程序设计--02输入输出语句

getchar函数(字符输入函数) 此函数的作用是从终端(或系统隐含指定的输入设备)输 入一个字符。getchar函数没有参数,其一般形式为 getchar() 函数的值就是从输入设备得到的字符。例如: 例:输入单个字符 #include <stdio.h> main() {char c; c=getchar(); putchar(c); }
嵌入式Linux下C程序设计
主讲:成宝宗
字符数据的输入输出
putchar函数(字符输出函数)
putchar函数的作用是向终端输出一个字符:例如 putchar(c);它输出字符变量c的值。c可以是字 符型变量或整型变量。
例:输出单个字符。
#include <stdio.h> int main(void) {char a,b,c; a='b';b='o';c='y'; putchar(a);putchar(b); putchar(‘\n’); putchar(c) ; putchar(0x63);puthar(0143);puthar(10); Putchar(500); }
如果是 scanf("%d %d",&a,&b); 输入时两个数据间应空2个或更多的空格字符。如: 10 34或10 34 如果是 scanf("%d∶%d∶%d",&h,&m,&s); 输入应该用以 下形式: 12∶23∶36 如果是 scanf(“a=%d,b=%d,c=%d”,&a,&b,&c); 输入应为以下形式: a=12,b=24,c=36 这种形式为了使用户输入数据时添加必要的信息以帮助理解,不 易发生输入数据的错误。

C语言嵌入式

C语言嵌入式

C语言嵌入式系统编程修炼之一:背景篇不同于一般形式的软件编程,嵌入式系统编程建立在特定的硬件平台上,势必要求其编程语言具备较强的硬件直接操作能力。

无疑,汇编语言具备这样的特质。

但是,归因于汇编语言开发过程的复杂性,它并不是嵌入式系统开发的一般选择。

而与之相比,C语言--一种"高级的低级"语言,则成为嵌入式系统开发的最佳选择。

笔者在嵌入式系统项目的开发过程中,一次又一次感受到C语言的精妙,沉醉于C语言给嵌入式开发带来的便利。

图1给出了本文的讨论所基于的硬件平台,实际上,这也是大多数嵌入式系统的硬件平台。

它包括两部分:(1)以通用处理器为中心的协议处理模块,用于网络控制协议的处理;(2)以数字信号处理器(DSP)为中心的信号处理模块,用于调制、解调和数/模信号转换。

本文的讨论主要围绕以通用处理器为中心的协议处理模块进行,因为它更多地牵涉到具体的C语言编程技巧。

而DSP编程则重点关注具体的数字信号处理算法,主要涉及通信领域的知识,不是本文的讨论重点。

着眼于讨论普遍的嵌入式系统C编程技巧,系统的协议处理模块没有选择特别的CPU,而是选择了众所周知的CPU芯片--80186,每一位学习过《微机原理》的读者都应该对此芯片有一个基本的认识,且对其指令集比较熟悉。

80186的字长是16位,可以寻址到的内存空间为1MB,只有实地址模式。

C语言编译生成的指针为32位(双字),高16位为段地址,低16位为段内编译,一段最多64KB。

图1 系统硬件架构协议处理模块中的FLASH和RAM几乎是每个嵌入式系统的必备设备,前者用于存储程序,后者则是程序运行时指令及数据的存放位置。

系统所选择的FLASH和RAM的位宽都为16位,与CPU一致。

实时钟芯片可以为系统定时,给出当前的年、月、日及具体时间(小时、分、秒及毫秒),可以设定其经过一段时间即向CPU提出中断或设定报警时间到来时向CPU提出中断(类似闹钟功能)。

基于嵌入式系统中c语言代码运行效率探析

基于嵌入式系统中c语言代码运行效率探析

基于嵌入式系统中c语言代码运行效率探析摘要:本文以c语言为例,通过一些具体的例子,探讨了在进行程序设计语言代码编写过程中不同的编写语句产生不同的代码运行效率,从而提高c语言程序设计的质量,提升c语言程序设计的能力培养。

关键词: c 语言;程序设计;运行效率中图分类号:tp312.1 文献标识码:a 文章编号:1007-9599 (2012) 17-0000-02嵌入式程序设计是结合 c 语言知识为基础,是利用基本的 c 语言知识,面向嵌入式工程实际应用进行程序设计语言。

在很多理工科专业,特别是计算机专业学生必修的一门非常重要的专业课基础课,学生可以通过嵌入式程序设计,掌握程序设计的基本方法,形成正确的编程思、掌握正确的编程技巧、具备一定的程序调适能力。

程序设计能力,特别是问题的分析解决能力、语言的开发和环境的综合应用能力以及如何能够在嵌入式系统开发中熟练、正确地运用c语言开发出高质量的应用程序,是学习嵌入式程序设计的关键。

下面介绍基于c语言的嵌入式程序设计中存在几个方面问题:1 定义变量先看下面一个例子:char char1;short short1;char char2;int int1;这里定义的 4 个变量形式都一样,但是它们的次序不同,产生了数据存储结构中的不同的数据布局,如下图所示。

显然,第2种方式节约了更多的存储空间。

第一种数据布局:第二种数据布局:由此可见,我们在作变量声明的时候,尽量把所有相同类型的变量放在一起定义,一种相同类型的变量定义一行,从而在数据的存储上更加的合理。

对于局部变量类型的定义,通常情况下,习惯使用短整型 short 或字符型char 来定义变量,达到节省存储空间的目的[1];但是,当一个函数的局部变量数目为数不多时,反而达不到节省存储空间的意图。

因为程序的编译器会把局部变量分配给内寄存器,使得每一个局部变量占用一个寄存器,假定 a 是任意可能的寄存器存储函数的局部变量,分别去执行加1的运算,32 位的 int 型变量最快,只需要用到 1 条加法指令。

C语言第7讲嵌入式C与汇编语言混合编程

C语言第7讲嵌入式C与汇编语言混合编程

7.1 内嵌汇编器的使用
在C/C++程序中使用内嵌的汇编指令注意事项 程序中使用内嵌的汇编指令注意事项

对于内嵌汇编器可能会用到的寄存器, 对于内嵌汇编器可能会用到的寄存器,编译器自己会保存 和恢复这些寄存器,用户不用保存和恢复这些寄存器。 和恢复这些寄存器,用户不用保存和恢复这些寄存器。常 量寄存器CPSR和寄存器 和寄存器SPSR外,别的寄存器必须先赋值 量寄存器 和寄存器 外 然后再读取,否则编译器将会报错。如下例中, 然后再读取,否则编译器将会报错。如下例中,第一条指 令在没有给寄存器r0赋值前读取其值 是错误的; 赋值前读取其值, 令在没有给寄存器 赋值前读取其值,是错误的;最后一 条指令恢复寄存器r0的值 的值, 条指令恢复寄存器 的值,也是没有必要的
7.1 内嵌汇编器的使用
内嵌的汇编器和armasm的区别 的区别 内嵌的汇编器和
使用内嵌的 汇编器不能 通过寄存器 PC返回当前 返回当前 指令的地址
内嵌的汇编器不 支持伪指令LDR 支持伪指令 Rn,=expression可 可 以使用mov来代替 以使用 来代替
不支持标号 表达式
不支持ADR、 、 不支持 ADRL 伪指令
7.1 内嵌汇编器的使用
内嵌的汇编指令用法——标号 标号 内嵌的汇编指令用法
C/C++程序中的标号可以被内嵌的汇编指令使用。但 程序中的标号可以被内嵌的汇编指令使用。 程序中的标号可以被内嵌的汇编指令使用 是只有指令B可以使用 可以使用C/C++程序中的标号,指令 程序中的标号, 是只有指令 可以使用 程序中的标号 指令BL 不能使用C/C++程序中的标号。指令 使用 程序中的标号。 使用C/C++程 不能使用 程序中的标号 指令B使用 程 序中的标号时,语法格式如下所示: 序中的标号时,语法格式如下所示:

c语言fft函数库 嵌入式

c语言fft函数库 嵌入式

C语言FFT函数库与嵌入式傅里叶变换(FFT)是一种重要的信号分析工具,广泛应用于声音处理、图像处理、无线通信等领域。

C语言作为一种比较底层的编程语言,常常用于嵌入式系统中的信号处理任务。

因此,编写一个适用于嵌入式系统的C语言FFT函数库,成为CPU资源有限的嵌入式系统开发中的一个重要需求。

C语言FFT函数库的基本原理C语言FFT函数库的基本原理是将时域信号转换到频域,实现的方法是通过DFT(离散傅里叶变换)算法进行计算。

DFT算法本质上是通过FFT算法实现离散序列的频域计算,因此FFT算法也成为嵌入式应用中最常用的FFT计算方法。

FFT算法通过分治算法将DFT的时间复杂度从O(n^2)优化为O(nlogn),因此FFT算法也成为实现高效计算的核心算法。

在C语言FFT函数库的实现中,主要包括以下几个模块:•输入模块:将离散时间域信号输入到程序中,其中包括时间和幅值。

•映射模块:通过快速傅里叶变换(FFT)算法,将时间域信号映射到频域中。

•输出模块:将映射结果进行输出,其中包括频率和相应的幅值。

•控制模块:整合以上三个模块,控制FFT计算的流程和计算过程中内存资源的分配和释放。

C语言FFT函数库的性能优化C语言FFT函数库的性能优化是嵌入式系统应用中最重要的考虑因素之一。

常见的性能优化策略如下:算法选型在C语言FFT函数库的实现中,对DFT算法进行优化是实现高效计算的基础。

其中,FFT算法采用减少运算次数、提高计算精度、改进算法结构等方式进行优化,常见的FFT算法有蝶形运算法、位逆序置换法等。

位运算优化C语言编译器支持位运算指令,通过对数据进行位操作可以提高运算速度。

在C语言FFT函数库的计算过程中,可以通过位逆序置换法减少运算次数,提高运算速度。

缓存优化在嵌入式系统中,内存资源是十分有限的,因此,合理利用缓存空间是一个重要的考虑因素。

在C语言FFT函数库中,可以通过预先分配缓存空间,减少内存分配和释放的次数。

常见的嵌入式编程案列

常见的嵌入式编程案列

常见的嵌入式编程案列
【1】用#define声明一个常数,用以表示一年中有多少秒
#define SECONDS_PER_YEAR (60*60*24*365)UL
说明:首先,末尾#define语法末尾不能有分号;
其次,计算式最好带括号;
第三,这个表达式会使16位机的整型数溢出,因此需要用长整型符号L告诉编译器这个常数是长整型数,末尾用UL(无符号长整型)。

【2】用C编写死循环
第一种方案:while(1){}
第二种方案:for(;;){}
第三种方案:Loop:
goto Loop; //这种方案是用汇编写的
【3】访问特定内存位置:
在某工程中,一个整型变量的绝对地址是0x67a9,请将其设置为0xaa55,并且已知编译器是一个纯粹的ANSI编译器,请编写代码
int* ptr;
ptr=(int*)0x67a9;
*ptr=0xaa55;
【4】对中断服务代码的评论
以上程序有如下几个错误:
1、ISR不能返回一个值;
2、ISR不能传递参数,即不能有形参;
3、在许多处理器或编译器中,浮点数一般是不可重入的。

有些处理器或编译器需要使用额外的寄存器入栈,有些处理器或编译器是不允许在ISR中做浮点运算。

此外,ISR应该。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

• 同步头 -- 帧(信息)头 -- 数据区 -- 校验字节
USTC
1、无操作系统代码的编写
• 有限状态机接收非定长帧3
• 通常接收状态机定义这样几个状态:空闲、等待帧头、 接收帧头、接收数据 • 状态机根据接收字节的内容,在这几个状态中来回切换
• 空闲状态下,必须接收到帧引导符,才进入等待帧头状态,其它 数据一律丢弃 • 等待帧头状态下,一旦发现引导符结束,立即进入接收帧头状态, 并将数据存入缓冲区 • 接收帧头状态下,进行字节倒计数(帧头是定长的),完毕后解 析出后续数据的长度,进入接收数据状态 • 接收数据状态下,进行字节倒计数,计数完毕,回到空闲状态
USTC
3、uCOS在33209上的移植
• 当这两个步骤完成以后,uCOS的移植工作 基本完成,剩下的即是测试系统是否工作稳 定,以后充分体验引入uCOS给我们后续开 发带来的方便
USTC
4、嵌入式C语言代码的编写风格
• 1、关于const、static、volatile、extern等关键字的 使用
USTC
1、无操作系统代码的编写
• 综合例子1,无操作系统代码编写的要领:
• 1、中断函数响应异步事件,但一般只做最简单的处理, 只要高实时性的动作可以放在中断中 • 2、耗时的操作,实时性要求不强的处理,尽量放在主函 数中 • 3、消息处理一般可以采用位变量的方式,除了用在前后 台之间的通信,还可以用在任务间的通信 • 4、当两个异步事件同时发生的时候,主函数中靠前的消 息处理函数优先执行(优先级) • 5、不管优先级如何,下一个“就绪” 的任务只能等到 前一个处理完成之后,才能得到执行(非抢占式调度)
USTC
1、无操作系统代码的编写
• 串口接收中断程序的编写
• • • • • • • • • • • • •
• •
#pragma vector = USART0RX_VECTOR __interrupt void UartRxISR(void) { static int stateFlg; // 空闲状态下, 连续接收到两个帧引导符, 即清空缓冲区, 进入等待帧头状态 if ( stateFlg == RXD_STATE_IDLE ) {} // 等待帧头状态下, 接收到帧头, 并把接收到第四个字节作为帧长 else if ( stateFlg == RXD_STATE_WAIT_HEAD ) {} // 等待数据状态下, 等待计数完毕, 进入等待奇偶校验位状态 else if ( stateFlg == RXD_STATE_CNT_DOWN ) {} // 等待奇偶校验位状态下, 接收一个字节, 发送收到帧消息, 并回到空闲状态 else if ( stateFlg == RXD_STATE_WAIT_PARITY ) SendMsg( MSG_REV_FRAME );
USTC
2、有操作系统代码的编写
• 例子 3:
• 实验二中 按键+LED+定时器的实验,在uCOS可以如此 划分:
• 开辟4个任务,新建4个信号量,每个任务控制一只LED,等待按 键消息,打开后,延迟1秒钟 • void Task0 (void *pdata) • { • while (1) { • OSSEMPend(KEY_UP); • LED0 = Enable; • OSTimeDly(100); • LED0 = Disable; • } • }
USTC
1、无操作系统代码的编写
• 示例 2:串行通信接收代码
• 通信是嵌入式系统最常用的功能,串行通信是最 简单的一种(符合RS232标准) • 处理器会在每接收到一个字节的时候,触发一个 串行中断 • 实际通信一般要把数据封装成有意义的数据帧, 以维持数据接收的完整性(数据链路层) • 如何用接收单字节的中断函数构造出数据帧的接 收功能呢?
• Const 表示“只读”,嵌入式中,用const定义大型只读数 组,编译器会将其放入ROM中 • Static 表示“静态、局部”,可修饰函数内的静态局部变 量,也可以修饰函数或模块内的全局变量,用于限定其 作用范围 • Volatile 表示“易变”,防止编译器按照普通C语言进行 意外的优化 • Extern 表示“外部”,当在某个模块内需要使用其他模 块的变量或函数时,需要用这个词修饰 USTC
USTC
3、uCOS在33209上的移植
• 移植要修改的文件
• OS_CPU.H • OS_CPU_A.ASM • OS_CPU_C.C
USTC
3、uCOS在33209上的移植
• OS_CPU.H
• 定义各种数据类型 • 定义进出临界区的几种方式 • 定义了TASK_SW宏,可以用软中断实现,一般 设置为一个汇编函数的入口 • 这是UCOS移植要做的第一步工作
嵌入式代码的一般编写方法
主讲人:潘浩 助教
计算机视觉实验室
panhao@
USTC
提纲
• • • • 1、无操作系统代码的编写 2、有操作系统代码的编写 3、uCOS在33209上的移植 4、嵌入式C语言代码的编写风格
USTC
1、无操作系统代码的编写
• 无操作系统——前后台程序 • 应用背景
• • • • 功能需求特别简单,如:家电 执行的功能相对单一,如:红绿灯 片内资源受限(RAM),如:51单片机系统 开发过程,如:测试某个模块
USTC
1、无操作系统代码的编写
• 优点:
• 代码结构简单 • 占用资源少,没有操作系统的开销
• 缺点:
• 嵌入式系统完备的实时性难以达到 • 要手工维护多个任务的同时运行、共享资源的访 问、任务间通信,程序流程难以控制
USTC
1、无操作系统代码的编写
• 数据帧示例: (工业仪表HART协议)
• 下行命令帧(上位机到下位机),查询配置:
• => FF FF FF FF FF 02 80 0D 00 8F
• 上行命令帧,返回厂家、型号、生产日期:
• <= FF FF FF FF FF 06 80 0D 08 00 00 64 23 D5 07 0A 09 15
USTC
1、无操作系统代码的编写
• 数据帧的三种基本方式:
• 1、定长帧,所有的数据都凑成固定的长度,附 以帧头帧尾,缺点:效率低。用等长度的队列进 行接收。 • 2、非定长帧,以固定结束符标志帧的结束,类 似于C语言的字符串,缺点:帧内不可出现结束 符。 • 3、非定长帧,在帧头信息区标志后续数据的长 度,类似于Pascal语言的字符串。非定长帧一般 用有限状态机接收。
USTC
4、嵌入式C语言代码的编写风格
• 3、工程文件的管理
• 通常按照功能模块,将函数分门别类放在多个源文件中, 为了便于管理,更好的方法是使用:.h和.c文件对 • c文件中是函数的实现代码,h文件则是这些函数的声明, 以及函数可能会用到的一些宏 • 在工程中,往往有一个公共头文件,一般为config.h,在 其中,#include所有模块的h文件,即可方便的实现模块 之间的相互调用 • 没有对应h文件的一般只有两个,main.c和interrput.c
USTC
2、有操、等待函数,否则无法进行 任务切换 • 任务之间的通信采用OS提供的接口解决,通常 用信号量、消息队列等,不要擅自定义全局变量 • 任务的功能划分要简明清晰,不要混杂其他模块 的功能 • 当不需要某些系统提供的功能时,应当通过OS 配置文件去除掉,以降低系统对资源的消耗
USTC
1、无操作系统代码的编写
• 例子 1:
• __interrupt void TIMER_ISR(void) • { • SendMsg(MSG_UPDATE_OUT ); • }
• 对于比较耗时的中断函数,如键盘去抖,需 要在进入中断函数时允许中断嵌套,以免丢 失异步事件
USTC
1、无操作系统代码的编写
USTC
3、uCOS在33209上的移植
• OS_CPU_A.ASM 和 OS_CPU_C.C
• 移植工作重点1:可以入手的是OS_CPU_C.C中 的OSTaskStkInit函数,即:伪造中断现场,使得 OSStart函数最后的中断返回指令,能够准确的从 伪造的中断现场中,恢复到起始任务运行的状态 • 移植工作重点2:第一步完成了以后,仔细观察 调整一个任务切换到另一个任务时的各自堆栈的 变化,要始终维持一个正确的可恢复的中断现场
• 例子 1:
• 前后台程序的消息处理宏
• #define MSG_SOME_KEY_DOWN • #define MSG_UPDATE_OUT • unsigned int MsgQueue; • #define SendMsg(msgId) • #define TestMsg(msgId) • #define ClearMsg(msgId) ( MsgQueue |= msgId ) ( MsgQueue & msgId ) ( MsgQueue &= ~msgId ) 0x0000000F 0x00000010
USTC
1、无操作系统代码的编写
• 例子 1:
• • • •
• • • • • • • • • •
void main (void) { // 初始化 Initial();
// 主循环 while(1) { if ...... else if ...... } // 清看门狗,进低功耗 }
USTC
1、无操作系统代码的编写
// 如果发现连续3个引导符, 不管当前处于什么状态, 都立即进入等待帧头状态 }
USTC
2、有操作系统代码的编写
• uCOS下,代码的一般格式如下:
USTC
2、有操作系统代码的编写
• uCOS的启动代码:
相关文档
最新文档