PIC单片机C语言编程教程(1)

发布者:画意人生最新更新时间:2016-03-28 来源: eefocus关键字:PIC  单片机  C语言编程 手机看文章 扫描二维码
随时随地手机看文章
PIC 单片机 C 语言编程简介

 

 

用  语言来开发单片机系统软件最大的好处是编写代码效率高、软件调试直观、维护升级方便、

代码的重复利用率高、便于跨平台的代码移植等等,因此 C 语言编程在单片机系统设计中已得到越

来越广泛的运用。针对 PIC 单片机的软件开发,同样可以用 C 语言实现。

但在单片机上用 C 语言写程序和在 PC 机上写程序绝对不能简单等同。现在的 PC 机资

源十分丰富,运算能力强大,因此程序员在写 PC 机的应用程序时几乎不用关心编译后的可

执行代码在运行过程中需要占用多少系统资源,也基本不用担心运行效率有多高。写单片机

的  C 程序最关键的一点是单片机内的资源非常有限,控制的实时性要求又很高,因此,如

果没有对单片机体系结构和硬件资源作详尽的了解,以笔者的愚见认为是无法写出高质量实

用的 C 语言程序。这就是为什么前面所有章节中的的示范代码全部用基础的汇编指令实现

的原因,希望籍此能使读者对  PIC  单片机的指令体系和硬件资源有深入了解,在这基础之

上再来讨论 C 语言编程,就有水到渠成的感觉。

本书围绕中档系列 PIC 单片机来展开讨论,Microchip 公司自己没有针对中低档系列 PIC

单片机的 C 语言编译器,但很多专业的第三方公司有众多支持 PIC 单片机的 C 语言编译器

提供,常见的有 Hitech、CCS、IAR、Bytecraft 等公司。其中笔者最常用的是 Hitech 公司的

PICC 编译器,它稳定可靠,编译生成的代码效率高,在用 PIC 单片机进行系统设计和开发

的工程师群体中得到广泛认可。其正式完全版软件需要购置,但在其网站上有限时的试用版

供用户评估。另外,Hitech 公司针对广大 PIC 的业余爱好者和初学者还提供了完全免费的学

习版 PICC-Lite 编译器套件,它的使用方式和完全版相同,只是支持的 PIC 单片机型号限制

在 PIC16F84、PIC16F877 和 PIC16F628 等几款。这几款 Flash 型的单片机因其所具备的丰富

的片上资源而最适用于单片机学习入门,因此笔者建议感兴趣的读者可从 PICC-Lite 入手掌

握 PIC 单片机的 C 语言编程。

在此列出几个主要的针对 PIC 单片机的 C 编译器相关连接网址,供读者参考:

Hitech-PICC:       www.htsoft.com


IAR:www.iar.com

CCS:www.ccsinfo.com/picc.shtml

ByteCraft:www.bytecraft.com/mpccaps.html


本章将介绍 Hitech-PICC 编译器的一些基本概念,由于篇幅所限将不涉及 C 语言的标准

语法和基础知识介绍,因为在这些方面都有大量的书籍可以参考。重点突出针对  PIC  单片

机的特点而所需要特别注意的地方。

11.2

Hitech-PICC 编译器

PICC 基本上符合 ANSI 标准,除了一点:它不支持函数的递归调用。其主要原因是因

为 PIC 单片机特殊的堆栈结构。在前面介绍 PIC 单片机架构时已经详细说明了 PIC 单片机

中的堆栈是硬件实现的,其深度已随芯片而固定,无法实现需要大量堆栈操作的递归算法;

另外在 PIC 单片机中实现软件堆栈的效率也不是很高,为此,PICC 编译器采用一种叫做“静

态覆盖”的技术以实现对    语言函数中的局部变量分配固定的地址空间。经这样处理后产

生出的机器代码效率很高,按笔者实际使用的体会,当代码量超过 4K 字后,C 语言编译出

的代码长度和全部用汇编代码实现时的差别已经不是很大(<10%),当然前提是在整个  C

代码编写过程中须时时处处注意所编写语句的效率,而如果没有对 PIC 单片机的内核结构、

各功能模块及其汇编指令深入了解,要做到这点是很难的。

11.3

MPLAB-IDE 内挂接 PICC

PICC 编译器可以直接挂接在 MPLAB-IDE 集成开发平台下,实现一体化的编译连接和

原代码调试。使用 MPLAB-IDE 内的调试工具 ICE2000、ICD2 和软件模拟器都可以实现原

代码级的程序调试,非常方便。

首先必须在你的计算机中安装PICC编译器,无论是完全版还是学习版都可以和

MPLAB-IDE挂接。安装成功后可以进入IDE,选择菜单项Project Set Language Tool

Locations…,打开语言工具挂接设置对话框,如图 11-1 所示:

PIC单片机C语言编程教程(1)

图 11-1  MPLAB-IDE 语言工具设置对话框

在对话框中选择“HI-TECH PICC Toolsuite”栏,展开可执行文件组“Executable”后,

列出了将被  MPLAB-IDE   后台调用的编译器所用到的所有可执行文件,其中有汇编编译器

“PICC Assembler”、C 原程序编译器“PICC Compiler”和连接定位程序“PICC Linker”。同

时在此列表中还显示了对应的可执行程序名,请注意在这里都是“PICC.EXE”。用鼠标分别

点击选中这三项可执行文件,观察对话框下面“Location”一栏中显示的文件路径,用

“Browse…”按纽,从计算机中已经安装的 PICC 编译器文件夹中选择 PICC.EXE 文件。实

际上 PICC.EXE 只是一个调度管理程序,它会按照所输入的文件扩展名自动调用对应的编译

器和连接器,用户要注意的是 C 语言原程序扩展名用“.c”,汇编原程序用“.as”即可。

工具挂接完成后,在建立项目时可以选择语言工具为“HI-TECH PICC”,具体步骤可以

参阅第三章 3.1.3 节,此处不再重复。项目建立完成后可以加入 C 或汇编原程序,也可以加

入已有的库文件或已经编译的目标文件。最常见的是只加入 C 原程序。用 C 语言编程的好

处是可以实现模块化编程。程序编写者应尽量把相互独立的控制任务用多个独立的 C 原程序文件实

现,如果程序量较大,一般不要把所有的代码写在一个文件内。

图 11-2 列出的是笔者建立的一个项目中所有 C 原程序模块,其中主控、数值计算、I2C 总线操

作、命令按键处理和液晶显示驱动等不同的功能分别在不同的独立的原程序模块中实现。

PIC单片机C语言编程教程(1)

图 11-2  C 语言多模块编程

11.4         PIC 单片机的 C 语言原程序基本框架

基于 PICC 编译环境编写 PIC 单片机程序的基本方式和标准 C 程序类似,程序一般由以

下几个主要部分组成:

&O1540;    在程序的最前面用#include 预处理指令引用包含头文件,其中必须包含一个编译器

提供的“pic.h”文件,实现单片机内特殊寄存器和其它特殊符号的声明;

&O1540;    用“__CONFIG”预处理指令定义芯片的配置位;

&O1540;    声明本模块内被调用的所有函数的类型,PICC 将对所调用的函数进行严格的类型

匹配检查;

&O1540;    定义全局变量或符号替换;

&O1540;    实现函数(子程序),特别注意 main 函数必须是一个没有返回的死循环。

 

下面的例 11-1 为一个 C 原程序的范例,供大家参考。

#include          //包含单片机内部资源预定义

#include “pc68.h”       //包含自定义头文件

//定义芯片工作时的配置位

__CONFIG (HS & PROTECT & PWRTEN & BOREN & WDTDIS);

//声明本模块中所调用的函数类型

void SetSFR(void);

void Clock(void);

void KeyScan(void);

void Measure(void);

void LCD_Test(void);

void LCD_Disp(unsigned char);

//定义变量

unsigned char second, minute, hour;

bit flag1,flag2;

//函数和子程序

void main(void)

{

  SetSFR();

  PORTC =  0x00;

  TMR1H +=  TMR1H_CONST;

  LED1  = LED_OFF;

 

 

  LCD_Test();

 

 

  //程序工作主循环

  while(1) {

     asm(“clrwdt”); 

     Clock();  

     KeyScan();

     Measure();

     SetSFR(); 

  }

}

//清看门狗

//更新时钟

//扫描键盘

//数据测量

//刷新特殊功能寄存器

11.5

PICC 中的变量定义


例 11-1  C 语言原程序框架举例

11.5.1     PICC 中的基本变量类型


PICC 遵循 Little-endian  标准,多字节变量的低字节放在存储空间的低地址,高字节放

在高地址。

11.5.2     PICC 中的高级变量

基于表 11-1 的基本变量,除了 bit 型位变量外,PICC 完全支持数组、结构和联合等复

合型高级变量,这和标准的 C 语言所支持的高级变量类型没有什么区别。例如:

数组:unsigned int data[10];

结构:struct commInData {

         unsigned char  inBuff[8];

         unsigned char  getPtr, putPtr;

      };

联合:union int_Byte {

         unsigned char  c[2];

         unsigned int i;

      };

例 11-2  C 语言高级变量举例

11.5.3     PICC 对数据寄存器 bank 的管理

 

为了使编译器产生最高效的机器码,PICC 把单片机中数据寄存器的 bank 问题交由编程

员自己管理,因此在定义用户变量时你必须自己决定这些变量具体放在哪一个 bank 中。如

果没有特别指明,所定义的变量将被定位在 bank0,例如下面所定义的这些变量:

unsigned char buffer[32];

bit flag1,flag2;

float val[8];

 

 

除了 bank0 内的变量声明时不需特殊处理外,定义在其它 bank 内的变量前面必须加上

相应的 bank 序号,例如:

bank1 unsigned char buffer[32];        //变量定位在 bank1 中


bank2 bit flag1,flag2;

bank3 float  val[8];


//变量定位在 bank2 中

//变量定位在 bank3 中


 

 

中档系列 PIC 单片机数据寄存器的一个 bank 大小为 128 字节,刨去前面若干字节的特

殊功能寄存器区域,在 C 语言中某一 bank 内定义的变量字节总数不能超过可用 RAM 字节

数。如果超过 bank 容量,在最后连接时会报错,大致信息如下:

Error[000]   : Can't find 0x12C words for psect rbss_1 in segment BANK1

 

 

连接器告诉你总共有 0x12C(300)个字节准备放到 bank1 中但 bank1 容量不够。显然,只

有把一部分原本定位在 bank1 中的变量改放到其它 bank 中才能解决此问题。

 

虽然变量所在的 bank 定位必须由编程员自己决定,但在编写原程序时进行变量存取操

作前无需再特意编写设定 bank 的指令。C 编译器会根据所操作的对象自动生成对应 bank 设

定的汇编指令。为避免频繁的 bank 切换以提高代码效率,尽量把实现同一任务的变量定位

在同一个 bank 内;对不同 bank 内的变量进行读写操作时也尽量把位于相同 bank 内的变量

归并在一起进行连续操作。

11.5.4     PICC 中的局部变量

 

PICC 把所有函数内部定义的 auto 型局部变量放在 bank0。为节约宝贵的存储空间,它

采用了一种被叫做“静态覆盖”的技术来实现局部变量的地址分配。其大致的原理是在编译

器编译原代码时扫描整个程序中函数调用的嵌套关系和层次,算出每个函数中的局部变量字

节数,然后为每个局部变量分配一个固定的地址,且按调用嵌套的层次关系各变量的地址可

以相互重叠。利用这一技术后所有的动态局部变量都可以按已知的固定地址地进行直接寻

址,用 PIC 汇编指令实现的效率最高,但这时不能出现函数递归调用。PICC 在编译时会严

格检查递归调用的问题并认为这是一个严重错误而立即终止编译过程。

既然所有的局部变量将占用 bank0 的存储空间,因此用户自己定位在 bank0 内的变量字

节数将受到一定的限制,在实际使用时需注意。

 

11.5.5     PICC 中的位变量

 

bit 型位变量只能是全局的或静态的。PICC 将把定位在同一 bank 内的 8 个位变量合并

成一个字节存放于一个固定地址。因此所有针对位变量的操作将直接使用  PIC  单片机的位

操作汇编指令高效实现。基于此,位变量不能是局部自动型变量,也无法将其组合成复合型

高级变量。

 

PICC 对整个数据存储空间实行位编址,0x000 单元的第 0 位是位地址 0x0000,以此后

推,每个字节有 8 个位地址。编制位地址的意义纯粹是为了编译器最后产生汇编级位操作指

令而用,对编程人员来说基本可以不管。但若能了解位变量的位地址编址方式就可以在最后

程序调试时方便地查找自己所定义的位变量,如果一个位变量 flag1 被编址为 0x123,那么

实际的存储空间位于:

字节地址=0x123/8 = 0x24

位偏移      =0x123%8 = 3

即 flag1 位变量位于地址为 0x24 字节的第 3 位。在程序调试时如果要观察 flag1 的变化,必

须观察地址为 0x24 的字节而不是 0x123。

 

PIC  单片机的位操作指令是非常高效的。因此,PICC 在编译原代码时只要有可能,对

普通变量的操作也将以最简单的位操作指令来实现。假设一个字节变量  tmp  最后被定位在

地址 0x20,那么


tmp |= 0x80

tmp &= 0xf7


=>   bsf

=>   bcf


0x20,7

0x20,3


if (tmp&0xfe)


=>   btfsc 0x20,0


即所有只对变量中某一位操作的 C 语句代码将被直接编译成汇编的位操作指令。虽然编程

时可以不用太关心,但如果能了解编译器是如何工作的,那将有助于引导我们写出高效简介

的 C 语言原程序。

 

在有些应用中需要将一组位变量放在同一个字节中以便需要时一次性地进行读写,这一

功能可以通过定义一个位域结构和一个字节变量的联合来实现,例如:

 

union {

   struct  {

      unsigned  b0:  1;

      unsigned  b1:  1;

      unsigned  b2:  1;

      unsigned  b3:  1;

      unsigned  b4:  1;

      unsigned  b5:  1;

      unsigned   : 2; //最高两位保留

   } oneBit;

   unsigned char allBits;

} myFlag;

例 11-3      定义位变量于同一字节

需要存取其中某一位时可以

myFlag.oneBit.b3=1; //b3 位置 1

一次性将全部位清零时可以

myFlag.allBits=0;          //全部位变量清 0

 

 

当程序中把非位变量进行强制类型转换成位变量时,要注意编译器只对普通变量的最低

位做判别:如果最低位是 0,则转换成位变量 0;如果最低位是 1,则转换成位变量 1。而标

准的 ANSI-C 做法是判整个变量值是否为 0。另外,函数可以返回一个位变量,实际上此返

回的位变量将存放于单片机的进位位中带出返回。

 

11.5.6     PICC 中的浮点数

 

PICC 中描述浮点数是以 IEEE-754 标准格式实现的。此标准下定义的浮点数为 32 位长,

在单片机中要用 4 个字节存储。为了节约单片机的数据空间和程序空间,PICC 专门提供了

一种长度为 24 位的截短型浮点数,它损失了浮点数的一点精度,但浮点运算的效率得以提

高。在程序中定义的 float 型标准浮点数的长度固定为 24 位,双精度 double 型浮点数一般

也是 24 位长,但可以在程序编译选项中选择 double 型浮点数为 32 位,以提高计算的精度。

 

一般控制系统中关心的是单片机的运行效率,因此在精度能够满足的前提下尽量选择

24 位的浮点数运算。


关键字:PIC  单片机  C语言编程 引用地址:PIC单片机C语言编程教程(1)

上一篇:PIC 单片机 C 语言编程简介(2)
下一篇:用PIC18F458的CAN模块实现CAN总线通讯

推荐阅读最新更新时间:2024-03-16 14:48

51单片机串行口及存储器工作原理分析
一、 51单片机串行口工作原理 MCS-51系列单片机片内有一个串行I/O端口,通过引脚RXD(P3.0)和TXD(P3.1)可与外设电路进行全双工的串行异步通信。 1.串行端口的基本特点 8031单片机的串行端口有4种基本工作方式,通过编程设置,可以使其工作在任一方式,以满足不同应用场合的需要。其中,方式0主要用于外接移位寄存器,以扩展单片机的I/O电路;方式1多用于双机之间或与外设电路的通信;方式2,3除有方式l的功能外,还可用作多机通信,以构成分布式多微机系统。 串行端口有两个控制寄存器,用来设置工作方式、发送或接收的状态、特征位、数据传送的波特率(每秒传送的位数)以及作为中断标志等。 串行端口有一个数据寄存器S
[单片机]
51<font color='red'>单片机</font>串行口及存储器工作原理分析
有关51单片机有关晶振的问题总结(干货)
在初学51单片机的时候,总是伴随很多有关于晶振的问题,其实晶振就是如同人的心脏,是血液的脉搏,把单片机的晶振问题搞明白了,51单片机的其他问题迎刃而解…… 有关51单片机有关晶振的问题一并总结出来,希望对学51的童鞋来说能有帮助。 一、为什么51单片机爱用11.0592MHZ晶振? 其一:因为它能够准确地划分成时钟频率,与UART(通用异步接收器/发送器)量常见的波特率相关。特别是较高的波特率(19600,19200),不管多么古怪的值,这些晶振都是准确,常被使用的。 其二:用11.0592晶振的原因是51单片机的定时器导致的。用51单片机的定时器做波特率发生器时,如果用11.0592Mhz的晶振,根据公式算下来需要定时器
[单片机]
基于单片机的FIash存储器坏块自动检测
  随着电子技术飞速发展,智能电子产品随处可见,如PC机、移动电话、PDA、数码相机、游戏机、数字电视等,而诸如此类的电子产品的核心器件往往离不开存储器。无论是从存储器的物理结构、存储容量、数据读写速度、可靠性、耐用性,还是产品的实用性方面。其种类繁多。然而由于种种原因,越来越多的电子产品采用数据传输快、容量大的NAND型Flash存储器。虽然NAND型Flash具有许多优点,但其有随机产生不可避免的坏块,如果不能很好解决该坏块将导致高故障率。因此,这里提出一种基于DSP的Flash存储器坏块自动检测系统。    1 系统设计方案   图l为Flash存储器坏块自动检测系统结构框图。   本系统设计采用AT89C51自动
[单片机]
MCS - 51单片机寄存器功能
21个特殊功能寄存器(52系列是26个)不连续地分布在128个字节的SFR存储空间中,地址空间为80H-FFH,在这片SFR空间中,包含有128个位地址空间,地址也是80H-FFH,但只有83个有效位地址,可对11个特殊功能寄存器的某些位作位寻址操作(这里介绍一个技巧:其地址能被8整除的都可以位寻址)。 在51单片机内部有一个CPU用来运算、控制,有四个并行I/O口,分别是P0、P1、P2、P3,有ROM,用来存放程序,有RAM,用来存放中间结果,此外还有定时/计数器,串行I/O口,中断系统,以及一个内部的时钟电路。在单片机中有一些独立的存储单元是用来控制这些器件的,被称之为特殊功能寄存器(SFR)。这样的特殊功能寄存器51单片机
[单片机]
MCS - 51<font color='red'>单片机</font>寄存器功能
Atmel推出面向汽车的Cortex-M7 MCU
Atmel面向汽车、物联网和工业市场推出最高性能的ARM Cortex-M7系列MCU,具备优越的内存架构和连接能力 拓展了Atmel | SMART MCU产品系列,超越行业最高性能的ARM Cortex -M处理器系列MCU,CoreMark评分高达1500分 具备性能卓越的连接能力和独特内存架构,针对实时决定性代码执行和低延迟外设数据访问实现了优化 业内首款符合汽车使用要求的Cortex-M7系列MCU,为实现汽车联网和音频应用程序提供了以太网AVB和媒体LB外设功能 全球微控制器(MCU)和触控解决方案领域的领导者Atmel 公司(NASDAQ:ATML)近日发布了4个新系列产品,均
[汽车电子]
8051单片机指令定义详解——AJMP addr11(4)
8051单片机指令定义详解 (AJMP addr11) AJMP addr11 功能:绝对跳转。 描述:AJMP指令用于将程序转到相应的目的地址去执行,该地址在程序执行过程之中产生,由PC值(两次递增之后)的高5位、操作码的7-5位和指令的第2字节连接形成。要求跳转的目的地址和AJMP指令的后一条指令的第1字节位于同一2KB的程序存储页内。 示例:假设标号AJMADR位于程序存储器的0123H,指令 AJMP JMPADR 位于0345H,执行完该指令后PC值变为0123H。 AJMP addr11 字节数:2 执行周期:2 机器码:aaa00001 aaaaaaaa 注意:目的地
[单片机]
MCU价格腰斩,汽车芯片慌“拐点”已至?
一度价格攀高的半导体芯片近日出现拐点。据媒体报道,半导体芯片砍单降价风暴愈演愈烈,即便是之前供不应求的MCU的报价也开始出现大幅度降价。更有报道直指,全球前五大MCU厂出厂产品价格腰斩。至于台湾芯片代工行业的龙头老大——台积电更是下调了其营收目标。而背后的原因是台积电的前三大客户——苹果、AMD和英伟达纷纷下调了订单。 曾经不起眼的汽车MCU为什么突然会短缺? 其实之前车企普遍缺少的是制程较低的MCU芯片,相反被三星、台积电等少数芯片代工企业掌握的高制程芯片产能反倒非常充足。其实之前汽车芯片短缺是由多个因素共同作用的结果: 不期而至的新冠疫情撕开了芯片短缺的口子。全球大部分汽车芯片的产能都位于东南亚以及日韩、台湾
[汽车电子]
<font color='red'>MCU</font>价格腰斩,汽车芯片慌“拐点”已至?
单片机开发调试应注意的问题
1、使用总线不外引的单片机 ·是最正统的单片机使用模式 ·符合小型、简单、可靠、廉价的单片机设计初衷 ·总线封闭的产品最可靠 2、使用单片机C语言编程 * C语言是简洁、高效、而又最贴近硬件的高级编程语言 * 90年代初单片机C语言就已成熟为专业水平的高级语言,不应再有顾虑 * 当前厂商在推出新的单片机产品时纷纷配套C语言编译器 3、使用中、高档的单片机仿真工具 * 只有中、高档仿真工具才能仿真总线封闭式的单片机 * 仿真器必须使用band-out chip或hooks chip * 应支持高级语言的调试,提供全数据类型的查看和修改 * 支持多家软件公司汇编和编译产生的目标代码格式 * 中档仿真器的起步要求是至少解决了上
[单片机]
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved