Pic单片机C语言编程.pdf
《Pic单片机C语言编程.pdf》由会员分享,可在线阅读,更多相关《Pic单片机C语言编程.pdf(29页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、初谈如何从汇编转向初谈如何从汇编转向 PICC 因为 HIDE-TECH PICC 破解版很多,所以 HIDE PICC 有比其它 PICC 有更多的用户,虽然它的编译效率不是最好。最好的是 CCS,但没破戒版。,不过用 HIDE PICC 精心安排函数一样可以获得很高的编译效率,还是人脑是第一的。当然要求你要有 C 语言的基础。PICC 不支持 C+,这对于习惯了 C+的朋友还得翻翻 C 语言的书。C 代码的头文件一定要有#include 它是很多头文件的集合,C 编译器在 pic.h 中根据你的芯片自动栽入相应的其它头文件。这点比汇编好用。载入的头文件中其实是声明芯片的寄存器和一些函数。顺
2、便摘抄一个片段:static volatile unsigned char TMR0 0 x01;static volatile unsigned char PCL 0 x02;static volatile unsigned char STATUS 0 x03;可以看出和汇编的头文件中定义寄存器是差不多的。如下:TMR0 EQU 0X01;PCL EQU 0X02;STATUS EQU 0X03;都是把无聊的地址定义为大家公认的名字。一:怎么附值?如对 TMR0 附值:汇编中:MOVLW 200;MOVWF TMR0;当然得保证当前页面在 0,不然会出错。C 语言:TMR0=200;/无论在
3、任何页面都不会出错。可以看出来 C 是很直接了当的。并且最大好处是操作一个寄存器时候,不用考虑页面的问题。一切由 C 自动完成。二:怎么位操作?汇编中的位操作是很容易的。在 C 中更简单。C 的头文件中已经对所有可能需要位操作的寄存器的每一位都有定义名称:如:PORTA 的每一个 I/O 口定义为:RA0、RA1、RA2。RA7。OPTION 的每一位定义为:PS0、PS1、PS2、PSA、T0SE、T0CS、INTEDG、RBPU。可以对其直接进行运算和附值。如:RA0=0;RA2=1;在汇编中是:BCF PORTA,0;BSF PORTA,2;可以看出 2 者是大同小异的,只是 C 中不需
4、要考虑页面的问题。三:内存分配问题:在汇编中定义一个内存是一件很小心的问题,要考虑太多的问题,稍微不注意就会出错。比如 16 位的运算等。用 C 就不需要考虑太多。下面给个例子:16 位的除法(C 代码):INT X=5000;INT Y=1000;INT Z=X/Y;而在汇编中则需要花太多精力。给一个小的 C 代码,用 RA0 控制一个 LED 闪烁:#include void main()int x;CMCON=0B111;file:/关掉 A 口比较器,要是有比较器功能的话。ADCON1=0B110;file:/关掉 A/D 功能,要是有 A/D 功能的话。TRISA=0;file:/A
5、 口全为输出。loop:RA0=!RA0;for(x=60000;-x;);file:/延时 goto loop;说说 RA0=!RA0 的意思:PIC 对 PORT 寄存器操作都是先读取-修改-写入。上句的含义是程序先读 RA0,然后取反,最后把运算后的值重新写入 RA0,这就实现了闪烁的功能。Pic 对位的操作对位的操作 由于 PIC 处理器对位操作是最高效的,所以把一些 BOOL 变量放在一个内存的位中,既可以达到运算速度快,又可以达到最大限度节省空间的目的。在 C 中的位操作有多种选择。*如:char x;x=x|0B00001000;/*对 X 的 4 位置 1。*/char x;x
6、=x&0B11011111;/*对 X 的 5 位清 0。*/把上面的变成公式则是:#define bitset(var,bitno)(var|=1bitno)#define bitclr(var,bitno)(var&=(1 bool.b0=1;in_mode-bool.b5=1;/*也可这样写 in_mode-BYTE|=0 x21;*/*/void main(void)mode.BYTE=0X00;while(1)mode_task(&mode);/*/这样写多爽!这里涉及了结构,联合,位段,及指针;可得先把基础概念搞清楚!在在 PICC 中使用常数指针中使用常数指针 常数指针使用非常灵
7、活,可以给编程带来很多便利。我测试过,PICC 也支持常数指针,并且也会自动分页,实在是一大喜事。定义一个指向 8 位 RAM 数据的常数指针(起始为 0 x00):#define DBYTE(unsigned char volatile*)0)定义一个指向 16 位 RAM 数据的常数指针(起始为 0 x00):#define CWORD(unsigned int volatile*)0)(unsigned char volatile*)0)中的 0 表示指向 RAM 区域的起始地址,可以灵活修改它。DBYTEx中的 x 表示偏移量。下面是一段代码 1:char a1,a2,a3,a4;#d
8、efine DBYTE(unsigned char volatile*)0)void main(void)long cc=0 x89abcdef;a1=DBYTE0 x24;a2=DBYTE0 x25;a3=DBYTE0 x26;a4=DBYTE0 x27;while(1);2:char a1,a2,a3,a4;#define DBYTE(unsigned char volatile*)0)void pp(char y)a1=DBYTEy+;a2=DBYTEy+;a3=DBYTEy+;a4=DBYTEy;void main(void)long cc=0 x89abcdef;char x;x=&
9、cc;pp(x);while(1);3:char a1,a2,a3,a4;#define DBYTE(unsigned char volatile*)0)void pp(char y)a1=DBYTEy+;a2=DBYTEy+;a3=DBYTEy+;a4=DBYTEy;void main(void)bank1 static long cc=0 x89abcdef;char x;x=&cc;pp(x);while(1);用用 PICC 写高效的位移操作写高效的位移操作 在许多模拟串行通信中需要用位移操作。以 1-W 总线的读字节为例,原厂的代码是:unsigned char read_byte(
10、void)unsigned char i;unsigned char value=0;for(i=0;i 8;i+)if(read_bit()value|=0 x 01i;/reads byte in,one byte at a time and then /shifts it left delay(10);/wait for rest of timeslot return(value);虽然可以用,但编译后执行效率并不高效,这也是很多朋友认为 C 一定不能和汇编相比的认识提供了说法。其实完全可以深入了解 C 和汇编之间的关系,写出非常高效的 C 代码,既有 C 的便利,又有汇编的效率。首先对
11、 for(i=0;i 8;i+)做手术,改成递减的形式:for(i=8;i!=0;i-),因为 CPU 判断一个数是否是 0(只需要一个指令),比判断一个数是多大来的快(需要 3 个指令)。再对 value|=0 x 01i;做手术。value|=0 x 01i;其实是一个低水平的代码,效率低,DALLAS 的工程师都是 NO1,奇怪为什么会如此疏忽。I;语句其实是一个低水平的写法,效率非常低。奇怪 DALLAS 的工程师都是 NO1,怎么会如此疏忽。仔细研究 C 语言的位移操作,可以发现 C 总是先把标志位清 0,然后再把此位移入字节中,也就是说,当前移动进字节的位一定是 0。那么,既然已经
12、是 0 了,我们就只剩下一个步骤:判断总线状态是否是高来决定是否改写此位,而不需要判断总线是低的情况。于是改写如下代码:for(i=8;i!=0;i-)value=1;/先右移一位,value 最高位一定是 0 if(read_bit()value|=0 x80;/判断总线状态,如果是高,就把 value 的最高位置1 这样一来,整个代码变得极其高效,编译后根本就是汇编级的代码。再举一个例子:在采集信号方面,经常是连续采集 N 次,最后求其平均值。一般的,无论是用汇编或 C,在采集次数上都推荐用 8,16,32、64、128、256 等次数,因为这些数都比较特殊,对于 MCU 计算有很大好处。
13、我们以 128 次采样为例:注:sampling()为外部采样函数。unsigned int total;unsigned char i,val;for(i=0;i7);再观察下去:total7 还可以变通成(total8,先左移动一位,再右移动 8 位,不就成了右移 7 位了么?可知道位移 1,4,8 的操作只需要一个指令哦。有上面的概验了,就可以写出如下的代码:unsigned int total;unsigned char i=0 unsigned char val;while(!(i&0 x80)/判断 i 第 7 位,只需要一个指令。total+=sampling();i+;val=
14、(unsigned char)(total8);/几个指令就代替了几十个指令的除法运算 哈哈,发现什么?代码量竟然可以减少一大半,运算速度可以提高几倍。再回头,就可以理解为什么采样次数要用推荐的一些特殊值了。数据类型和变量数据类型和变量 算术数据类型:单字节字符型、16 位整型、32 位长整型、24 位改进型 IEEE 标准浮点型、双精度型(24位改进型或 32 位 IEEE 浮点型、联合类型。集合类型:任何数组类型、结构类型、支持位域。其他:指向数据和函数的指针、常数类型会被自动放在 ROM 区、可变类型。Hi-TECH 的特殊数据类型:用于全局或静态变量的位(布尔)类型,不能用指针进行访问
15、,通过 截断操作可以把非位操作整型转换为位操作类型,位操作尽量使用 PIC 的位处理指令,显示的位变量地趾就是本身的地址。bit address=(byte address in which defined)*8+(offset into byte)static near bit GIE(unsigned)&INTCON*8)+7 例如:bit sent_flag;/definition sent_flag=1;/assign zero or one 数据类型-小结:type (bits)Range bit 1 boolean char 8 -128 to 127 unsigned char
16、8 0 to 255 short 16 -32768 to 32767 unsigned short 16 0 to 65535 int 16 -32768 to 32767 unsigned int 16 0 to 65535 long 32 -2147483648 to 2147483647 unsigned long 32 0 to 4294967925 foat 24 real double 24or32 real char is unsigned by default.double defaults to 24-bit.Floating point is implemented us
17、ing the IEEE754 32-bit.存储对象种类限定符:1.Auto 对局部变量位缺省.一个局部变量总是自动(auto)类型,除非明确声明位静态(Static)类型.2.Static 按照 ANSI-C,静态变量在函数调用时值保持不变,除非 被指针修改.3.Extern 该存储类型表明一个变量是在另外的源文件中定义的.对于外部变量(extern)而言,本程序是不会给它分配存储空间的.类型限定符:1.Const 常数类型限定符通知编译器一个变量是常数而且不能被改 变.任何对该变量的值的改变都会产生一条警告信息.2.Volatile 可变类型告诉编译器一个变量在连续的操作过程中不 会保持
18、其原来的值.这就可以防止程序优化器删除表面上对可变类型的 冗余引用,因为这将改变程序执行的结果.所有的输入/输出口以及那些 可能被中断修改的变量都应定义为可变类型.特殊类型限定符:1.persistent 用于定义不需在程序启动时自动清除的变量.另外,任何持续类型(persistent)变量都被放在与其他变量不同的存储空间.2.Bank1,Bank2,Bank3 用于 Bank1,Bank2,Bank3 区分别定义静态变量,没有 Bank 限定符意味着变量在 Bank0(Mid-range)在 Baseline 单片机中,此类限定符不影响指针变量.3.(PIC18)Near 近类型限定符表明该
19、类型的数据存储在直接存取区域(ACCESS BANK).近类型的对象访问无须 bank 的切换,可节省更多的空间.绝对变量与 SFR:Absolue 通过construct address 实现.编译器不给该变量予留 存储空间,而是仅仅让变量等于该地址.编译器和链接器不会对绝对变量和其它变量的重叠进行检查.例如:static volatile near unsigned char WDTCON 0XFD1;这样,特殊功能寄存器(SFRS)就可以同一般的 C 变量一样进行访问.编译器的头文件所有 PICmicro MCU 特殊功能寄存器的予定义.,分别包含了 PIC16,18 系列 MCU 各自
20、所对应的头文件.结构及其成员的访问:例 1:struct filtered_data char Fbandgap4;char Frefhi4;char Freflo4;char Ftemp4;Fcount;/成员的访问通过.操作符 Fcount.Fbandgap1=0 x34;Fbandgap数组的第二个元素被赋值为 0 x34.例 2:利用例 1 中的结构变量 filtered_data:而成员的操作用-操作符 声明:struct filtered_data*ptr;和 ptr=&Fcount;ptr-Frefhi0=0 x87;Frefhi 数组的确第一个元素会被赋值为 0X87.结构数组
21、:例:struct control char mode;char state;char sign;drive3;访问该数组第一个成员中的变量mode的值:drive0.mode=0 x33;访问该数组第三个成员中的变量sign的值:drive2.sign=0 xFF;联合及其成员的访问:例 1:union u_tag char abc;/8bits int value;/16bits utemp;成员的访问用.操作符 utemp.abc=A;utemp.value=0 x1234;例 2:声明:union u_tag*uptr;和 uptr=&utemp;成员的访问用-操作符 uptr-val
22、ue=0 x5678;例 3:整型变量的字节访问:union unsigned int var;structchar var_lo;char var_hi;hilo;mix;char a,b;void main(void)mix.var=0 x4321;a=mix.hilo.var_lo;b=mix.hilo.var_hi;结构中的位域:例 1:位域结构-char size struct unsigned int :3;/填充位 unsigned int b3:1;/位 3 unsigned int b4:1;/位 4 unsigned int :3;/填充位 LATCbit 0 xF8B;下
23、面的 C 语句用于结构中的位域b3,其地址为 0 xF8B:LATCbit.b3=1;注意:如果结构中的位域被分配了绝对地址(通过construct 方式),就不会被分配存储空间.例 2:位域结构-integer size struct status unsigned int high:1;/LSb unsigned int low :1;unsigned int :5;/填充位 unsigned int dir :1;unsigned int rate:1;unsigned int :6;/填充位 unsigned int fault:1;/MSb pressure;下面的 C 语句用于结构
24、变量 pressure 位域dir:pressure.dir=1;注意:第一个被分配的位是整形数据的最低位.内存会分 配给该结构相应的空间.其它的位的定义方式:例 1:union unsigned char var;struct unsigned int bit0 :1;unsigned int :6;/填充位 unsigned int :1;bits;uvar;现在可以:uvar.var -前部 8 位 uvar.bits.bit7-只是位 7 例 2:声明:static bit Flow(unsigned)&LAB*8+4;以下语句置位 LATB 的第 4 位“FLOW”Flow=1;例
25、3:声明:static bit Switch(unsigned)&PORTC*8+3;检查 PORTC 第 3 位Switch的状态:if(Switch)else 例 4:也可以用宏定义方式:#define PortBit(port,bit)(unsigned)&(port)*8+(bit)然后用下面的定义来声明任何寄存器的任位:static bit led8 PortBit(LATB,8);static bit pulse PortBit(LATB,7);例 5:bit sent_flag1;void main(void)sent_flag=1;.while(1);1-w 总线读写函数总线读
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Pic 单片机 语言 编程
限制150内