飞思卡尔单片机教学第5章_C语言程序设计_第1页
飞思卡尔单片机教学第5章_C语言程序设计_第2页
飞思卡尔单片机教学第5章_C语言程序设计_第3页
飞思卡尔单片机教学第5章_C语言程序设计_第4页
飞思卡尔单片机教学第5章_C语言程序设计_第5页
已阅读5页,还剩35页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、第五章 C语言程序设计1第五章 C语言程序设计 5-1 C5-1 C语言程序设计基础语言程序设计基础5-2 5-2 MC9S12的的C编程与编程与ANSI C的不同的不同5-3 5-3 C C程序设计举例程序设计举例内容提要内容提要: :第五章 C语言程序设计2单片机编程语言单片机编程语言 汇编语言 优点:执行效率高,时序控制精确 C语言 优点: 程序开发速度快,提高开发工作效率; 软件调试直观; 可维护性好; 可移植性好(与汇编语言相比较)。单片机单片机C语言语言单片机C语言和标准C语言的用法基本相同,但是单片机C语言是针对于资源少的MCU,它的编程方法和编程手段与PC机上使用C语言还是有很

2、大差别。 5-1 C语言程序设计基础第五章 C语言程序设计3多文件多文件C语言工程的头文件语言工程的头文件当代码量非常大时,程序员一般会把代码分成几个部分,然后写入到多个文件中。这些文件一般分为C文件和H文件。作为一般规则,以下内容应该放到H文件中:预处理和宏定义结构、联合和枚举声明typedef声明外部函数声明全局变量声明如果定义的变量仅仅被一个C文件所私有,那么不可放到H文件中。第五章 C语言程序设计4其它其它C语言基础知识参见补充课件:语言基础知识参见补充课件:“补充补充(自己看自己看)_C语言基础语言基础.PPT”第五章 C语言程序设计5CodeWarrior数据类型数据类型 5-2

3、MC9S12的C编程与ANSI C的不同第五章 C语言程序设计6自定义自定义CodeWarrior数据类型数据类型 在CodeWarrior环境下按ALT+F7打开工程的通用设置,选择“Compiler for HC12”面板然后点按钮“Type Sizes”。 建议不要随意更改数据类型的设置第五章 C语言程序设计7数据类型的事实数据类型的事实 代码大小和执行时间的最大节约可通过为变量选择最合适的数据类型而得到。16位微控制器内部的数据长度是16位(2字节),所以首选的数据类型是“int”。16位机处理16位数据比8位数据的效率更高。 对于9S12单片机来说,16位数据类型效率最高,因此在使用

4、中,尽量选择int类型数据。第五章 C语言程序设计8存贮类修饰符存贮类修饰符以下关键字用于声明变量,以指定特定需要或内存中变量存贮的相关条件。static(静态变量) volatile(可变变量) const(只读变量)这三个关键字,一起让我们不仅可写出好的代码,而且可写出紧凑的代码。第五章 C语言程序设计9static在函数体声明的静态变量,在函数调用期间保持其值;在模块内声明静态的变量(但在函数体之外) ,能被模块内所有函数访问;在模块内声明静态的函数,只能被模块内其它函数调用。 如:static int func(int x,int y);当一个C语言工程由多个程序员进行编写时,就不用担

5、心自己所定义的函数与别人定义的重名了。 如果在函数名和函数类型前加extern,则表示此函数是外部函数,可以被其他文件中的函数调用。如:extern int func(int x,int y)。第五章 C语言程序设计10File1.c#include /* 包含文件FILE2.c中的函数 */void main (void)MyFunction(); /* 第一次进入MyFunction之前,myVar=0 */MyFunction(); /* 第二次进入MyFunction之前,myVar=1 */File2.cvoid MyFunction (void)static char myVar

6、= 0; /* 本地变量声明为static */myVar = myVar + 1; /* myVar是本地变量,但它保持了自己的值 */第五章 C语言程序设计11可变(可变(volatile)变量)变量 volatile的本意是“易变的”, 就是该变量会以编译器无法预知的方式发生变化,请编译器不要做优化(所有的编译器的优化均假设编译器知道变量的变化规律)。也就是说是其值在正常程序流程以外可能改变的变量。在嵌入式系统中,这种情况通过两种主要途径发生:一是中断服务程序,二是硬件动作。 例如,通过串口接收到一个字符,然后串口状态寄存器的值会发生改变,这完全在程序流程之外发生。在嵌入式设备中,最好将

7、所有外设寄存器声明为volatile。 第五章 C语言程序设计12例子例子由于访问寄存器的速度要快过RAM,所以编译器一般都会作减少存取外部RAM的优化。比如: static int i=0; int main(void) . while (1) if (i) dosomething(); /* Interrupt service routine. */ void ISR_2(void) i=1; 第五章 C语言程序设计13程序的本意是希望ISR_2中断产生时,在main当中调用dosomething函数,但是,由于编译器判断在main函数里面没有修改过i,因此可能只执行一次对从i到某寄存器的

8、读操作,然后每次if判断都只使用这个寄存器里面的“i副本”,导致dosomething永远也不会被调用。如果将将变量加上volatile修饰,则编译器保证对此变量的读写操作都不会被优化(肯定执行)。此例中i也应该如此说明。 第五章 C语言程序设计14Const变量变量关键字“const”,C语言中命名最差的关键字,并不表示恒量,而是代表“只读”。在嵌入式系统中,有很大的不同,这一会应会明白。const是C+中最常用的几个关键字之一,对确保程序的完整性有着重要的意义。它在调用者和被调用者之间传递这样一种信息:Baby,我不会改变你的,放心吧。 Const声明可用于任何变量,它告诉编译器将其存贮在

9、ROM代码。编译器保留了那个位置程序存贮器地址。由于位于ROM中,其值不能改变。 第五章 C语言程序设计15Const的用法:的用法:const unsigned short a;unsigned short const a;const unsigned short *a;unsigned short * const a;第五章 C语言程序设计16Const volatile 变量变量 现在讨论一个深奥的问题,一个变量既能是常量,又能是可变量吗?如果是这样,这意味什么,怎样使用?答案是“能”。这个修饰符应该用于能出乎意料地改变的任何存贮器位置,因此需要volatile限定语,由于const该变

10、量是只读的。 第五章 C语言程序设计17最明显的例子是硬件状态寄存器,象SCI状态寄存器SCS1。这个寄存器包含信号状态标志,如发送空、发送完成、接收满以及其它。这是一个可变寄存器由于这些标志的改变依赖于串行通信的状态,这也是只读,由于标志不能被程序直接改写,它们只对模块的状态作出响应。这个状态寄存器最佳声明方法是:#define SCS1 ( * (const volatile unsigned char * ) 0 x0016 )第五章 C语言程序设计18访问固定内存位置与PC机不同,嵌入式系统通常的特点是需要编程者访问一个指定的存贮器位置。练习:在某个项目中需要将绝对地址0 x2FFA处

11、整型变量的值设为0 xAA55(编译器为纯粹的ANSI编译器)。完成这个任务的代码是:int * ptr;ptr = (int *)0 x2FFA;*ptr = 0 xAA55; 第五章 C语言程序设计19访问访问I/O寄存器寄存器 一个普通而有用的形式是使用如下的#define指示:#define PortA ( * ( volatile unsigned char * ) 0 x0000 )这种情况下,Port A为地址0 x0000处字符型变量。#define实际做的是每次发现PortA时放置一个构件。也就是说在代码中写:PortA = 0 x3F,实际做的就是告诉编译器0 x0000是

12、一个volatile-unsigned-char类型的指针,它的内容等于0 x3F。第五章 C语言程序设计20数组数组C语言允许程序员用几种不同方法存取数组的内容。选择最适合的方法来存取,可以提高代码的效率。数组的访问方法有:硬编码:Array0=12*UNIT_VOLTS;编译时决定地址,执行速度快。变址增加Arrayindex+=12*UNIT_VOLTS;快速,比硬编码灵活。数组指针*(ArrayPtr+)=12*UNIT_VOLTS;执行速度快,可读性差,可和循环一起使用。 第五章 C语言程序设计21C语言与汇编语言的混合编程语言与汇编语言的混合编程 在绝大多数场合采用C语言编程可完成

13、预期的目的,但是对一些特殊情况进行编程时要结合汇编语言。汇编语言具有直接和硬件打交道、执行代码的效率高等特点,可以做到C语言所不能做到的一些事情:一个程序中的关键部分对执行速度有很高要求,实时性强。用汇编编程可以更有效的利用CPU的寄存器和指令集,用其产生的代码比用编译器产生的代码运行更快。对特定硬件接口的访问。例如对I/O端口的访问,或者用于禁止、启用中断系统。因此,选用C语言编程时,还需要夹杂一些汇编程序,通过这种混合编程的方法将C语言和汇编语言的优点结合起来,这已经成为MCU开发最流行的编程方法。第五章 C语言程序设计22C中使用汇编中使用汇编 目前大多数MCU系统,在C语言中使用汇编语

14、言有两种情况:一种是汇编程序部分和C程序部分为不同模块或不同的文件,通常由C程序调用汇编程序模块的变量和函数(也可称为子程序或过程);另一种是嵌入式汇编,即在C语言程序中嵌入一段汇编语言程序。C语言中嵌入汇编语句:_asm AssemblyInstuction;asm (AssemblyInstruction);asm AssemblyInstruction AssemblyInstruction 第五章 C语言程序设计23C中调用汇编指令构成的子程序:当汇编程序和C程序为不同模块时,程序一般可分为若干个C程序模块和汇编程序模块,C程序模块通常是程序的主体框架,而汇编程序模块通常是若用C语言实

15、现则效率不高的函数组成,也可以是已经成熟的、没有必要再转化成C语言的汇编子程序。在这种混合编程技术中,关键是参数的传递和函数的返回值。它们必须有完整的约定,否则数据的交换就可能出错。定义汇编子程序,定义格式如下:_子程序名代码rts第五章 C语言程序设计24注意:第一,在子程序名前加_;第二,在C代码中调用汇编子程序时可直接调用:子程序名();第三,在子程序中不能使用映象寄存器的宏定义,只能用它们的直接地址;第四,汇编子程序的编写时,对于使用过的寄存器需要进行保护。在汇编中使用C语言在汇编中也可以调用C代码中的变量与子程序。使用C代码中定义的变量:在变量名前加_或%,例如unsigned ch

16、ar PortA; asm(LDAA %PortA)调用C代码中定义的函数:在函数名前加_,例如:function1();asm(BRA _function1);第五章 C语言程序设计25C语言的中断语言的中断 CodeWarrior编译器提供了一个非ANSI的变通的方法,在源码中直接指定中断向量号t。表达式以interrupt关键字开始, 接着是中断向量号,最后是函数原型。interrupt 7 void RTI_ISR (void)/* RTI_ISR Function Codes */9S12所有的中断源共分成55个优先级。处在最高优先级的中断是复位中断,它的中断向量号为0,第二位的是时

17、钟监视器复位中断,它的中断向量号为1,以此类推。 第五章 C语言程序设计26标准标准C库库 标准库如stdio.h通常包含在编译器中。Getchar()、gets()、printf()、putchar()、puts()、scanf()、sprintf()、sscanf()等,都是这些库中的常用函数。 当给PC机写这段代码, printf()缺省的控制台是显示器,但HC12没有显示器作为片外外设,如果这样调用库函数,哪个端口用于显示?什么时候我们定义它?在哪儿?在嵌入式编程中,通常printf()调用putchar()执行打印,这假定控制台缺省为片上串行口(SCI)。如果需要使用这个功能,则需要

18、修改基础库函数putchar()才能正确输出。 第五章 C语言程序设计27C语言入口语言入口 在MC9S12的C程序中,程序的入口在什么地方?程序是怎样起动的呢?在工作站或PC上操作系统从磁盘上装入程序并建立环境。而在嵌入式系统中没有操作系统。对程序员来说,程序员必须处理程序起动的每个方面。嵌入式应用,特别是用C或C+写的代码,需要一个起动模块,在起动main()之前配置硬件和代码。通常不可避免地用汇编语言写成,这个模块是处理器离开复位状态第一个执行的代码。第五章 C语言程序设计28C起动代码通常执行下列动作起动代码通常执行下列动作(1) 关中断;(2) 将初始化数据从ROM复制到RAM;(3

19、) 将未初始化数据区清零;(4) 为堆栈定位空间以及初始化堆栈;(5) 创建并初始化堆;(6) 执行构造函数并初始化所有全局变量(仅C+);(7) 开中断;第五章 C语言程序设计29最后,起动代码调用main(),启动应用的剩余部分。当然针对于MC9S12来说,启动代码可以不必这么麻烦。可以只初始化堆,初始化硬件然后直接跳转到main函数,下面是一个启动代码的例子 第五章 C语言程序设计30void _Startup() asm LDS 0 x1000 JSR HardInit JSR main 程序员可以自己编写启动代码,可以将应用程序中的硬件初始化程序都放在启动代码里面,这样就可以比较专注

20、地在应用程序中做要做的事情。 第五章 C语言程序设计31程序的链接与定位程序的链接与定位 对于MC9S12单片机来说,由于RAM,EEPROM,寄存器可以重新映射,而且不同型号的单片机内部FLASH大小也不一样,这样程序编译后存放在什么位置,成了我们必须告诉链接器的内容,因为链接器不知道你用的单片机RAM放在什么地方,ROM放在什么地方。为了方便管理,CodeWarrior自动生成一个.prm文件,此文件用来管理程序的定位。但是该文件并不一定与用户的实际情况相符,因此在链接前,必须自己核对该文件是否与实际的硬件相符。看书的192页。第五章 C语言程序设计325-3 C程序设计举例第五章 C语言

21、程序设计33例例1 对从RAM中0 x1000地址开始的10个无符号字节型数进行由小到大排序 程序分析:可以使用C语言把一个unsigned char类型的数组存储到从0 x1000开始的内存空间中,数组的大小为10个字节,内容由程序员自定义。由小到大的排序使用冒泡法完成。unsigned char data10 0 x1000,i,j,temp;/* 定义数组 */void main(void) for(i=0;i10;i+)/* 初始化数组 */datai=20-i; for(i=0;i9;i+)/* 使用冒泡法排序 */for(j=0;jdataj+1) temp=dataj; data

22、j=dataj+1; dataj+1=temp;for(;) ; 注:若在函数内定义变量,须在函数体开始处定义第五章 C语言程序设计34例例2 求求1+2+100的和然后分成低、高字节存放在的和然后分成低、高字节存放在0 x1000和和0 x1001地地址单元中址单元中 程序分析:求1+2+100可以用100次循环来实现,因为求出来的和不可以用一个字节表示,所以必须分成高低字节存储。下面先给一个错误的程序。unsigned int sum 0 x1000=0,i=0;void main(void)for(;i=100;i+)sum+=i;for(;) 第五章 C语言程序设计35下面给出正确的程

23、序:unsigned char sum_lowbyte 0 x1000 =0,sum_highbyte 0 x1001=0,i=0;unsigned int sum;void main(void) for(;i8;for(;) 第五章 C语言程序设计36例例3 产生一个随机数,然后返回结果产生一个随机数,然后返回结果程序分析:产生随机数可以调用一个函数rand(),使用它可以返回一个0到32767之间的随机数。然后使用switch-case进行处理。注意使用rand()函数,必须包含标准库stdlib.h。此头文件在CodeWarrior安装目录“libHC12cinclude”目录中。#include int i,j;void main(void) i=rand();i=i/10000;switch(i)case 0:j=1000;break;case 1:j=2000;break;case 2:j=3000;break;case 3:j=4000;break;default:j=5000;for(;) 第五章

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论