pic 单片机 ccs 之c 语言 中文版权归芜湖联合大学 94 电气张功勤...

164
PIC 单片机 CCS C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任 联系电话:13662655920 1 #BIT 语法: #bit id=x.y id 是一个有效的 C 标识符; x 是一个常数或是一个 C 变量; y 是一个常数(0~7) 目的:创建一个新的 C 变量(是一位),放置在存储区中,对应的是字节 x y ,有益于在 C 语言 中只接存取 CPU 特殊功能寄存器中的一位.它也可用来存取标准 C 变量的一位. 例子: #bit T0IF = 0xb.2 //定义 T0IF 的位地址为 0xb.2 T0IF=0; //清除 Timer0 的中断标志位 int result; #bit result_odd = result.0 //定义 result_odd 的位地址为 result.0 if(result_odd){;} //result_odd 1,则空操作 例子文件: ex_glint.c #if defined(__PCM__) //若使用了 PCM 编译器,defined(__PCM__)返回值为 1 #include <16F877.h> //包含 16F877.h 头文件 #fuses HS,NOWDT,NOPROTECT,NOLVP //HS:高速晶振/谐振器, NOWDT:不使用 WDT // NOPROTECT:程序存储器代码不保护 #use delay(clock=20000000) //使能内置函数的功能:delay_ms()delay_us() //#USE DELAY()必须在#use rs232()使用之前出现. #use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7) //使用波特率为 9600, //发送脚为 PIN_C6 //接收脚为 PIN_C7 //使能内置函数:GETC,PUTC PRINTF; #elif defined(__PCH__) #include <18F452.h> #fuses HS,NOWDT,NOPROTECT,NOLVP #use delay(clock=20000000) #use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7) #endif //结束 if long counter; //counter 定义为 long 型变量 #if defined(__PCM__) //若使用了 PCM 编译器,defined(__PCM__)返回值为 1 int save_w; //save_w 定义为 int 型变量 #locate save_w=0x7f //save_w 定位在 RAM ,0x7f 的地址处, 用来暂存 W 的内容 int save_status; //save_status 定义为 int 型变量, 用来暂存 status 的内容 #locate save_status=0x20 //save_status 定位在 RAM , 0x20 的地址处, #byte status = 3 //定义 status 的地址为 3,即状态寄存器的地址 #bit zero_flag = status.2 //定义 zero_flag 的位地址为 status.2,status Z #bit t0if = 0xb.2 //定义 t0if 的位地址为 0xb.2,timer0 的溢出标志位 #elif defined(__PCH__)

Upload: others

Post on 20-Mar-2020

28 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 1

#BIT 语法: #bit id=x.y

id 是一个有效的 C 标识符; x 是一个常数或是一个 C 变量; y 是一个常数(为 0~7)

目的:创建一个新的 C 变量(是一位),放置在存储区中,对应的是字节 x 中 y 位,有益于在 C 语言

中只接存取 CPU 特殊功能寄存器中的一位.它也可用来存取标准 C 变量的一位. 例子:

#bit T0IF = 0xb.2 //定义 T0IF 的位地址为 0xb.2 … T0IF=0; //清除 Timer0 的中断标志位 int result; #bit result_odd = result.0 //定义 result_odd 的位地址为 result.0 … if(result_odd){;} //若 result_odd 为 1,则空操作

例子文件: ex_glint.c #if defined(__PCM__) //若使用了 PCM 编译器,则 defined(__PCM__)返回值为 1 #include <16F877.h> //包含 16F877.h 头文件 #fuses HS,NOWDT,NOPROTECT,NOLVP //HS:高速晶振/谐振器, NOWDT:不使用 WDT // NOPROTECT:程序存储器代码不保护 #use delay(clock=20000000) //使能内置函数的功能:delay_ms()和 delay_us() //#USE DELAY()必须在#use rs232()使用之前出现. #use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7) //使用波特率为 9600,

//发送脚为 PIN_C6 //接收脚为 PIN_C7 //使能内置函数:GETC,PUTC 和 PRINTF;

#elif defined(__PCH__) #include <18F452.h> #fuses HS,NOWDT,NOPROTECT,NOLVP #use delay(clock=20000000) #use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7) #endif //结束 if long counter; //将 counter 定义为 long 型变量 #if defined(__PCM__) //若使用了 PCM 编译器,则 defined(__PCM__)返回值为 1 int save_w; //将 save_w 定义为 int 型变量 #locate save_w=0x7f //将 save_w 定位在 RAM 中,0x7f 的地址处, 用来暂存 W 的内容 int save_status; //将 save_status 定义为 int 型变量, 用来暂存 status 的内容 #locate save_status=0x20 //将 save_status 定位在 RAM 中, 0x20 的地址处, #byte status = 3 //定义 status 的地址为 3,即状态寄存器的地址 #bit zero_flag = status.2 //定义 zero_flag 的位地址为 status.2,即 status 的 Z 位 #bit t0if = 0xb.2 //定义 t0if 的位地址为 0xb.2,即 timer0 的溢出标志位 #elif defined(__PCH__)

Page 2: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 2

int save_w; #locate save_w=0x80 int save_status; #locate save_status=0xFF #byte status = 0xFD8 #bit zero_flag = status.2 //status 的全 0 位,即 Z #bit t0if = 0xFF2.2 #endif //结束 if #INT_GLOBAL //指示下面的函数代替编译器产生中断 void isr() { #asm //插入汇编开始 //store current state of processor MOVWF save_w //将 W 的内容存到 save_w 中,目的是保存 W,即将 W 入栈 SWAPF status,W //将 status 内容高半字节和低半字节进行交换,存入 W 中 BCF status,5 //将 status 的第 5 位清 0,即将 RP0=0 BCF status,6 //将 status 的第 6 位清 0, 即将 RP1=0,两句是用来选择 bank0 MOVWF save_status //将 W 的内容存到 save_status 中,目的是保存 status,即将 status 入栈 BCF t0if //将 timer0 的中断标志位 t0if 清 0 INCF counter,F // counter 加 1 后存到 counter BTFSC zero_flag //若 counter 不等于 0x00, 则 zero_flag=0,跳过下一句;

//若 counter=0x00,zero_flag=1,则执行下一句; INCF (&counter+1),F // counter 的地址加 1, (&counter+1)的内容加 1 SWAPF save_status,W //将 save_status 内容高半字节和低半字节进行交换,存入 W 中 MOVWF status //将 W 的内容存到 status 中, status 出栈 SWAPF save_w,F //将 save_w内容高半字节和低半字节进行交换,其结果存入 save_w中 SWAPF save_w,W //将 save_w 内容高半字节和低半字节进行交换,存入 W 中, W 出栈 #endasm //插入汇编结束 } void main() {

printf("\r\nStarting the counter.\r\n\n"); counter = 0;

setup_counters(RTCC_INTERNAL,RTCC_DIV_32); //设置 Timer0 的时钟源为内部时钟源 //每隔 32 个脉冲,TMR0 计数 1 次

enable_interrupts(INT_RTCC); //允许 Timer0(RTCC)溢出,建立中断标志位 enable_interrupts(GLOBAL); //使能总中断 while(TRUE) { printf("The counter value is currently: %5lu\r\n", counter); delay_ms(1000); //延时 1000ms } } //上面的例子只是说明用 timer0 对内部时钟源进行 32 分频后计数.

Page 3: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 3

#BYTE 语法: #byte id=x

id 是一个有效的 C 标识符; x 是一个常数或是一个 C 变量;

目的:如果 id 是一个已知 C 的变量,那么它将定位在地址 x 处,在这种情况下,变量类型的 初

定义不会被改变.若 id 不是已知的 C 变量,则利用#byte id=x 就可创建一个新的 C 变量,且放

在地址 x 处,类型为整型(8 位). 主意:在两个不同的存储区里,x 不是唯一对应这个变量(id)的地址.其它变量可能和它拥

有相同的地址.实际上,当 x 是一个变量时,那么 id 和 x 就共享有相同的地址存储单元. 例子:

#byte status=3 //定义 status 的地址为 3 #byte b_port=6 //定义 b_port 的地址为 6 struct{ short int r_w; //定义位变量 short int c_d; //定义位变量 int unused :2; //保留两位 int data :4; //保留 4 位 }a_port //将 a_port 定义为结构变量, r_w 对应 a_port.0, c_d 对应 a_port.1 #byte a_port=5 //定义 a_port 的地址为 5,即端口 RA 口 … a_port.c_d=1;

例子文件: ex_glint.c #DEFINE 语法: #define id text

or #define id(x,y…) text

id 是一个预处理器标识符;text 是任意字符文字;x,y 等是被定位于预处理器中的标识符,在这中形式下,有一个或更多的标识符被逗号隔开. 目的:利用简单的字符来规定代替 id,这个所给的字符来自于程序指针.

在第二种形式下,原来的标识符要同 text 中的那个简单的标识符相匹配,用 text 代替原

来的标识符; 如果 text 包含#idx 形式的字符,那么赋值后的结果是参数 id 和字符 x 连接; 如果 text 包含 idx##idy 形式的字符,那么参数 idx 就和参数 idy 连接形成一个新的标识

符; 例子: #define BITS 8 //用 BITS 代替 8

a=a+BITS; //相当于 a=a+8 #define hi(x) (x<<4) //将(x<<4) 用 hi(x) 代替 a=hi(a); //相当于 a=(a<<4)

例子文件:ex_stwt.c, ex_macro.c 文件:ex_stwt.c 如下: #if defined(__PCM__) //若使用了 PCM 编译器,则 defined(__PCM__)返回值为 1 #include <16F877.h> //包含 16F877.h 头文件 #fuses HS, NOWDT, NOPROTECT, NOLVP //HS:高速晶振/谐振器, NOWDT:不使用 WDT

Page 4: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 4

// NOPROTECT:程序存储器代码不保护 #use delay(clock=20000000) //使能内置函数的功能:delay_ms()和 delay_us() //#USE DELAY()必须在#use rs232()使用之前出现. #use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7) //使用波特率为 9600,

//发送脚为 PIN_C6 //接收脚为 PIN_C7 //使能内置函数:GETC,PUTC 和 PRINTF;

#elif defined(__PCH__) #include <18F452.h> #fuses HS,NOWDT,NOPROTECT,NOLVP #use delay(clock=20000000) #use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7) // Jumpers: 8 to 11, 7 to 12 #endif //结束 if #define INTS_PER_SECOND 76 // (20000000/(4*256*256)) 用 INTS_PER_SECOND代替 76 BYTE seconds; //秒计数器,1 秒=(4/20000000)*256*256* INTS_PER_SECOND BYTE int_count; // 在 1 秒未到之前,还要经过多少次中断,才够 1 秒; #int_rtcc //Timer0(RTCC)溢出, 指定下面的函数是一个中断服务函数 void clock_isr() { // the RTCC (timer0) overflows (255->0),For this program this is apx 76 times

if(--int_count==0) { // per second. ++seconds; //1 秒到, seconds 加 1; int_count=INTS_PER_SECOND; ////给 int_count 赋初值 } } void main() { BYTE start; int_count=INTS_PER_SECOND; //给 int_count 赋初值 set_timer0(0); //设定实时时钟/计数器的计数初值

setup_counters( RTCC_INTERNAL, RTCC_DIV_256 | RTCC_8_BIT); //设置 Timer0 的时钟源为内部时钟源

//每隔 256 个脉冲,TMR0 计数 1 次 //在 PIC18XXXX 中,RTCC_8_BIT 设置 Timer0 为 8 位定时器方式; enable_interrupts(INT_RTCC); //允许 Timer0(RTCC)溢出,建立中断标志位 enable_interrupts(GLOBAL); //使能总中断 do { printf("Press any key to begin.\n\r"); getc(); //从 RS232 口读入 1 个字符 start=seconds; printf("Press any key to stop.\n\r"); getc(); //从 RS232 口读入 1 个字符 printf("%u seconds.\n\r",seconds-start); } while (TRUE); } 上面的文件是利用 Timer0 采用内部指令周期作为时钟源,再 256 分频,构成 1 秒发生齐器.

Page 5: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 5

文件: ex_macro.c 如下: #define BUFFERSIZE 10 //用 BUFFERSIZE 代替 10 #define BUFFER_EMPTY (next_in==next_out)

//用 BUFFER_EMPTY 代替表达式(next_in==next_out) #define min(x,y) ((x<y)?x:y) //用 min(x,y)代替表达式((x<y)?x:y),若 x<y,则返回 x #define max(x,y) ((x>y)?x:y) //用 max(x,y)代替表达式((x>y)?x:y) ,若 x>y,则返回 x #define forever while(1); //用 forever 代替表达式 while(1) #define MHZ(x) x##000000 //用 MHZ(x)代替 x##000000 #ifndef __PCB__ //若没有定义__PCB__,则执行下面的语句; #define NORMAL_RS232 baud=9600, xmit=PIN_C6, rcv=PIN_C7 // #else //若有定义__PCB__,则执行下面的语句; #define NORMAL_RS232 baud=9600, xmit=PIN_B1, rcv=PIN_B0 #endif //结束 if 定义 #define set_options(value) {#ASM \ MOVLW value \ OPTION \ #ENDASM} #define debug(x) printf("%s variable value is %d\r\n",#x,x); //用 debug(x)代替 printf("%s variable value is %d\r\n",#x,x);; #define TOSTRING(s) #s //用 TOSTRING(s)代替#s #define DEVICE_FILE_FOR(chip) TOSTRING(chip##.h) #ifdef __pcb__ //若有定义__PCB__,则执行下面的语句; #define IDLE {if(kbhit()) isr();} //用 IDLE 代替{if(kbhit()) isr();}

//若 getc()读到数据,则 kbhit()返回 1,否则, kbhit()返回 0 #else //若没有定义__PCB__,则执行下面的语句; #define IDLE ; //用 IDLE 代替; ; #endif //结束 if 定义 #include DEVICE_FILE_FOR(16C74) //包含 16C74.h 头文件 #fuses HS,NOPROTECT //HS:高速晶振/谐振器, NOPROTECT:程序存储器代码不保护 #use delay(clock=MHZ(20)) //使能内置函数的功能:delay_ms()和 delay_us() //#USE DELAY()必须在#use rs232()使用之前出现. #use RS232(NORMAL_RS232) //使用波特率为 9600,

//发送脚为 PIN_C6 //接收脚为 PIN_C7 //使能内置函数:GETC,PUTC 和 PRINTF, kbhit();

int buffer[BUFFERSIZE]; //声明 buffer[10]数组 int next_in, next_out; //声明整型变量 next_in 和 next_out #ifndef __pcb__ //若没有定义__PCB__,则执行下面的语句; #int_rda //RS232 接收到的数据有用,指定下面的函数是一个中断函数 #endif //结束 if 定义

Page 6: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 6

void isr() { buffer[next_in]=getc(); //从 RS232 口读数据 next_in=(next_in+1)%BUFFERSIZE; //将 next_in 加 1 后,除以 10,将商赋给 next_in } void main() { int x, largest; //声明整型变量 x 和 largest

set_options(0x34); //用汇编设置 option 寄存器,将预分频器留给 Timer0 使用 //分频比为 1:32, Timer0 的时钟源选择外部时钟; // Timer0 在下降沿递增计数;INT 脚电平下降沿触发中断 //使能 GPIO 上拉

#ifndef __pcb__ //若没有定义__PCB__,则执行下面的语句; enable_interrupts(INT_RDA); //使能 UART 接收中断 enable_interrupts(GLOBAL); //使能总中断 #endif //结束 if 定义 next_in=next_out=0; //初始化变量 next_in 和 next_out largest=0; //初始化变量 largest do { while(BUFFER_EMPTY) //当 next_in=next_out 时

IDLE; //若定义__PCB__,则用 IDLE 代替{if(kbhit()) isr();} //若 getc()读到数据,则 kbhit()返回 1,否则, kbhit()返回 0 //若没有定义__PCB__,则用 IDLE 代替;

x=buffer[next_out]; next_in=(next_out+1)%BUFFERSIZE; //将 next_out 加 1 后,除以 10,将商赋给 next_in largest = max(largest,x); //求 大值 debug(next_in); //用 debug(x)代替 printf("%s variable value is %d\r\n",#x,x);; debug(next_out) //用 debug(x)代替 printf("%s variable value is %d\r\n",#x,x);; } forever; //用 forever 代替表达式 while(1) } 上面的例子是通过 UART 接收 10 个数据,求其 大值 #DEVICE 语法: #device chip options

chip 是一个特殊的处理器名字(如:PIC16C74),目的是取得支持设备的当前列表: START | RUN | CCSC +Q Option 是设备标准操作的限定句.有效的可选项是: *=5 使用 5 位指针(适合所有的器件) *=8 使用 8 位指针(适合 14 和 16 位的器件) *=16 使用 16 位指针(适合 14 位的器件) ADC=x 这里的 x 是 read_adc()函数返回的位数. ICD=TRUE 产生兼容 Microchips ICD 硬件调试代码 WRITE_EEPROM=ASYNC 当写 EEPROM 时,防止 EEPROM 写暂停.当使用时,不会从

Page 7: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 7

ISR 和外部的 ISR 写入 EEPROM chip 和 options 是可选项,若干个#device 行可全部用来定义这个设备.注意: 带有`芯片标识符

的#device 将会清除先前的#device 和#fuse 的设定. 目的:定义目标处理器,每个程序必须有一个正确的带有 chip 的#device. 例子:

#device PIC16C74 //定义目标处理器为 PIC16C74 #device PIC16C67 *=16 //定义目标处理器为 PIC16C67,使用 16 位指针 #device *=16 ICD=TRUE //使用 16 位指针,产生兼容的 ICD 硬件调试代码 #device PIC16F877 *=16 ADC=10 // read_adc()函数返回的位数为 10 位

例子文件:ex_mxram.c, ex_icd.c, 16c74.h 文件: ex_mxram.c 如下: #if defined( __PCB__) //若使用了 PCB 编译器,则 defined( __PCB__)返回值为 1 #include <16C57.H> //包含 16C57.H 头文件 #device *=8 // This allows auto variables over location 0x1F //使用 8 位指针(适合 14 和 16 位的器件) #fuses HS, NOWDT, NOPROTECT //HS:高速晶振/谐振器, NOWDT:不使用 WDT // NOPROTECT:程序存储器代码不保护 #use delay(clock=20000000) //使能内置函数的功能:delay_ms()和 delay_us() //#USE DELAY()必须在#use rs232()使用之前出现. #use rs232(baud=9600, xmit=PIN_A3, rcv=PIN_A2) //使用波特率为 9600,

//发送脚为 PIN_A3 //接收脚为 PIN_A2

//使能内置函数:GETC,PUTC 和 PRINTF, kbhit(); #define BUFFSIZE 16 //用 BUFFERSIZE 代替 10 #elif defined(__PCM__) #include <16F877.H> #device *=16 // This allows auto variables over location 0xFF #fuses HS,NOWDT,NOPROTECT,NOLVP #use delay(clock=20000000) #use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7) // Jumpers: 8 to 11, 7 to 12 #define BUFFSIZE 64 #endif //结束 if 定义 byte buffer1[BUFFSIZE],buffer2[BUFFSIZE],buffer3[BUFFSIZE]; // Three buffers are allocated because C requires arrays elements to be in // consecutive memory locations and the PIC memory has holes. //声明 buffer1[BUFFSIZE]数组, buffer2[BUFFSIZE]数组, buffer3[BUFFSIZE]数组 // The following allows reads and writes to the three arrays like they are // one large array. void write_buffer(char * index, char value) { if(index<BUFFSIZE) buffer1[index]=value; //若 index<BUFFSIZE,则执行该句;

Page 8: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 8

else if(index<(BUFFSIZE*2)) //否则,若 BUFFSIZE <index<(BUFFSIZE*2) ,则执行该句; buffer2[index%BUFFSIZE]=value; else buffer3[index%BUFFSIZE]=value; //否则,若 index>(BUFFSIZE*2) ,则执行该句; } char read_buffer(char * index) { if(index<BUFFSIZE) return(buffer1[index]); //若 index<BUFFSIZE,则执行该句; else if(index<(BUFFSIZE*2)) //否则,若 BUFFSIZE <index<(BUFFSIZE*2) ,则执行该句; return(buffer2[index%BUFFSIZE]); else return(buffer3[index%BUFFSIZE]); //否则,若 index>(BUFFSIZE*2) ,则执行该句; } void main() { char * i; //声明字符型指针变量 i char c; //声明字符型变量 c do { i=0; printf("\r\nEnter string: "); do{ c=getc(); //读 UART write_buffer(i++,c); //写数组 } while(c!='\r'); i=0; printf("\r\nString from buffer: "); do{ c=read_buffer(i++); //读数组 putc(c); //写 UART,通过 RS232 发送 } while(c!='\r'); } while(1); } 上面的例子通过 UART 读/写三个数组. 文件: ex_icd.c 如下: #if defined(__PCM__) //若使用了 PCM 编译器,则 defined( __PCM__)返回值为 1 #include <16F877.h> //包含 16F877.h 头文件 #device ICD=TRUE //产生兼容 Microchips ICD 硬件调试代码 #fuses HS,NOWDT,NOPROTECT,NOLVP //HS:高速晶振/谐振器, NOWDT:不使用 WDT // NOPROTECT:程序存储器代码不保护 #use delay(clock=20000000) //使能内置函数的功能:delay_ms()和 delay_us() //#USE DELAY()必须在#use rs232()使用之前出现. #endif //结束 if 定义

Page 9: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 9

#define TOGGLE_PIN PIN_B0 //用 TOGGLE_PIN 代替 PIN_B0 // This function turns the LEDs on and off 这个函数是用来开关 LED void flash_led() { output_low(TOGGLE_PIN); // TOGGLE_PIN 脚(PIN_B0)输出低电平 delay_ms(500); //延时 500ms output_high(TOGGLE_PIN); // TOGGLE_PIN 脚(PIN_B0)输出高电平 delay_ms(500); //延时 500ms } void main() { int a, b, c; //声明整型变量 a, b 和 c long al, bl, cl; //声明 Long 型变量 a1, b1 和 c1 a=10; //将 a 初始为 10 b=25; //将 b 初始为 25 al=300; //将 a1 初始为 300 bl=525; //将 b1 初始为 525 c=a+b; //简单数学加法 c=a*b; //简单的数学乘法 cl=al+bl; cl=al*bl; while(TRUE) flash_led(); //LED 的闪烁频率为 1Hz } 上面的例子介绍 delay_ms(), output_high(), output_low()函数的用法 #FUSES 语法: #fuse options

options 要根据设备改变.一系列有效的可选项都要放在每个 devices.h 文件的顶部,注释

用来参考.PCW 能有效编辑修改特殊的设备 fuses.PCW 下拉菜单 VIEW|Valid fuses 将会显示

所有的 fuses 描写. 一些公共的可选项如下: LP, XT, HS, RC WDT, NOWDT PROTECT, NOPROTECT PUT, NOPUT, (Power Up Timer) BROWNOUT, NOBROWNOUT

目的:这种指示定义要 fuses 的东西在编程时设定在器件中.这种指示不影响编辑,可是信息放

在输出文件中.如果在 Parallax 格式中需要 fuses,则添加 PAR 可选项.SWAP 有将在 Hex 文件

的不用编程的数据的高和低字节进行交换的功能.对于一些可编程的设备,这将被要求. 带有某些 fuses一些处理器允许有不同的电平,为了接受这些电平,就将一个值赋给 fuse.

例如 18F452.这个 fuse PROTECT=6 就将 6 这个值赋给 CONFIG5L,保护代码块 0 和代码块 3 例子:

#fuses HS, NOWDT 例子文件:ex_sqw.c

Page 10: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 10

文件: ex_sqw.c 如下: #if defined(__PCM__) //若使用了 PCM 编译器,则 defined( __PCM__)返回值为 1 #include <16F877.h> //包含 16F877.h 头文件 #fuses HS,NOWDT,NOPROTECT //HS:高速晶振/谐振器, NOWDT:不使用 WDT // NOPROTECT:程序存储器代码不保护 #use delay(clock=20000000) //使能内置函数的功能:delay_ms()和 delay_us() //#USE DELAY()必须在#use rs232()使用之前出现. #use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)

//使用波特率为 9600, //发送脚为 PIN_C6 //接收脚为 PIN_C7 //使能内置函数:GETC,PUTC 和 PRINTF, kbhit();

#elif defined(__PCB__) #include <16c56.h> #fuses HS,NOWDT,NOPROTECT,NOLVP #use delay(clock=20000000) #use rs232(baud=9600, xmit=PIN_A3, rcv=PIN_A2) // Jumpers: 11 to 17, 12 to 18 #elif defined(__PCH__) #include <18F452.h> #fuses HS,NOWDT,NOPROTECT,NOLVP #use delay(clock=20000000) #use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7) // Jumpers: 8 to 11, 7 to 12 #endif //结束 if 定义 void main() { printf("Press any key to begin\n\r"); getc(); printf("1 khz signal activated\n\r"); while (TRUE) { output_high(PIN_B0); //脚(PIN_B0)输出高电平 delay_us(500); //延时 500us output_low(PIN_B0); //脚(PIN_B0)输出低电平 delay_us(500); //延时 500us } } 上面的例子介绍 delay_us(), output_high(), output_low()函数的用法 #IF expr #ELSE #ELIF #ENDIF 语法: #if expr

code

Page 11: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 11

#elif expr code #else code #endif expr 是一个常数表达式,标准算子或预处理器标识符; Code 是任意的标准 C 源程序.

目的: 预处理器求出常数表达式的值,如果这个值是非 0 值,就处理可选项#ELSE 或#ENDIF的上面的所有行.

注意:你不可在#IF 里使用 C 变量,只有预处理器通过#define 创造的才可使用. 若 id 被定义了,则预处理器表达式 DEFINED(id)可用来返回 1,若没有定义 id,则

DEFINED(id)返回的值为 0. 例子:#if MAX_VALUE>255

long value; //若 MAX_VALUE>255,则将 value 定义为长整型变量 #else int value; //若 MAX_VALUE 不大于 255, 则将 value 定义为整型变量 #endif

例子文件:ex_extee.c 文件: ex_extee.c 如下: #if defined(__PCB__) //若使用了 PCB 编译器,则 defined( __PCB__)返回值为 1 #include <16c56.h> //包含 16c56.h 头文件 #fuses HS, NOWDT, NOPROTECT //HS:高速晶振/谐振器, NOWDT:不使用 WDT // NOPROTECT:程序存储器代码不保护 #use delay(clock=20000000) //使能内置函数的功能:delay_ms()和 delay_us() //#USE DELAY()必须在#use rs232()使用之前出现. #use rs232(baud=9600, xmit=PIN_A3, rcv=PIN_A2)

//使用波特率为 9600, //发送脚为 PIN_A3 //接收脚为 PIN_A2 //使能内置函数:GETC,PUTC 和 PRINTF, kbhit();

#elif defined(__PCM__) #include <16F877.h> #fuses HS,NOWDT,NOPROTECT,NOLVP #use delay(clock=20000000) #use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7) // Jumpers: 8 to 11, 7 to 12 #elif defined(__PCH__) #include <18F452.h> #fuses HS,NOWDT,NOPROTECT,NOLVP #use delay(clock=20000000) #use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7) // Jumpers: 8 to 11, 7 to 12 #endif //结束 if 定义 #include <input.c> //包含 input.c 头文件 #include <2416.c> //包含 2416.c 头文件 void main() {

Page 12: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 12

BYTE value, cmd; //声明字节型变量 value, cmd EEPROM_ADDRESS address; //用 EEPROM_ADDRESS 代替 long int,为 16 位 init_ext_eeprom(); //初始化连接到 eeprom 的 I/O 脚 do { do { printf("\r\nRead or Write: "); cmd=getc(); //从 RS232 口读一个字节 cmd=toupper(cmd); //将 cmd 中的小写字母转换成大写字母送给 cmd putc(cmd); } while ( (cmd!='R') && (cmd!='W') ); //直到输入 R 或 W 为止

printf("\n\rLocation: ");

#if sizeof(EEPROM_ADDRESS)==1 //若定义 EEPROM_ADDRESS 是 1 个字节,则 sizeof(EEPROM_ADDRESS)==1 返回 1 address = gethex(); #else //若定义 EEPROM_ADDRESS 是大于 1 个字节 #if EEPROM_SIZE>0xfff address = gethex(); #else // EEPROM_SIZE 小于 0xfff address = gethex1(); //从 RS232 口读一个字节,为 eeprom 存储高字节地址 #endif //结束 if 定义 address = (address<<8)+gethex(); //从 RS232 口读 2 个字节,为 eeprom 存储低字节地址 #endif //结束 if 定义 if(cmd=='R') //若输入 R,则执行下面 printf("\r\nValue: %X\r\n",READ_EXT_EEPROM( address ) ); if(cmd=='W') { printf("\r\nNew value: "); value = gethex(); //从 RS232 输入,为写入 eeprom 的值做准备 printf("\n\r"); WRITE_EXT_EEPROM( address, value ); } } while (TRUE); } 文件: input.c 如下: #include <CTYPE.H> //包含 CTYPE.H 头文件 BYTE gethex1() { char digit; //声明字节型变量 digit digit = getc(); //从 RS232 口读一个字节 putc(digit); //向 RS232 口写一个字节 if(digit<='9') //将读到的字节以 16 进制返回 return(digit-'0'); //若读到的 ascii 码小于或等于 39,则将其减 30,以 16 进制返回 else

Page 13: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 13

return((toupper(digit)-'A')+10); //若读到的 ascii 码大于 39,则将其减 41,再加 10 返回 } BYTE gethex() { int lo, hi; //声明整型变量 lo, hi hi = gethex1(); //从 RS232 口读一个字节,存储到 hi 中 lo = gethex1(); //从 RS232 口读一个字节,存储到 lo 中 if(lo==0xdd) return(hi); else return( hi*16+lo ); } void get_string(char* s, int max) { int len; //声明整型变量 len char c; //声明字节型变量 c --max; //初始化 max 值 len=0; //初始化 len 值 do { c=getc(); //从 RS232 口读一个字节,存储到 c 中 if(c==8) { // Backspace 若是空格键 if(len>0) { len--; putc(c); //向 RS232 写 c putc(' '); putc(c); } } else if ((c>=' ')&&(c<='~')) if(len<max) { s[len++]=c; putc(c); } } while(c!=13); s[len]=0; } // stdlib.h is required for the ato_ conversions // in the following functions #ifdef _STDLIB //若定义_STDLIB,则执行下面 signed int get_int() { char s[5]; //声明字符型数组 s[5] signed int i; //声明有符号整型变量 i get_string(s, 5); //从 RS232 口读 5 个字节,存储到 s 数组中 i=atoi(s); //将数组 s[]的字符串转换成整型数送给 i

Page 14: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 14

return(i); } signed long get_long() { char s[7]; //声明字符型数组 s[7] signed long l; //声明有符号长整型变量 l get_string(s, 7); //从 RS232 口读 7 个字节,存储到 s 数组中 l=atol(s); //将数组 s[]的字符串转换成长整型数送给 l return(l); } float get_float() { char s[20]; //声明字符型数组 s[7] float f; //声明符点型变量 l get_string(s, 20); //从 RS232 口读 20 个字节,存储到 s 数组中 f = atof(s); //将数组 s[]的字符串转换成符点数送给 f return(f); } #endif //结束 if 定义 文件: 2416.c 如下: //// Library for a MicroChip 24LC16B //// //// init_ext_eeprom(); Call before the other functions are used //// //// write_ext_eeprom(a, d); Write the byte d to the address a //// //// d = read_ext_eeprom(a); Read the byte d from the address a //// //// b = ext_eeprom_ready(); Returns TRUE if the eeprom is ready //// //// to receive opcodes //// //// The main program may define EEPROM_SDA //// //// and EEPROM_SCL to override the defaults below. //// //// Pin Layout //// //// ----------------------------------------------------------- //// //// | | //// //// | 1: NC Not Connected | 8: VCC +5V | //// //// | 2: NC Not Connected | 7: WP GND | //// //// | 3: NC Not Connected | 6: SCL EEPROM_SCL and Pull-Up | //// //// | 4: VSS GND | 5: SDA EEPROM_SDA and Pull-Up | //// //// ----------------------------------------------------------- //// #ifndef EEPROM_SDA //若没有定义 EEPROM_SDA,则执行下面 #define EEPROM_SDA PIN_C4 //用 EEPROM_SDA 代替 PIN_C4 #define EEPROM_SCL PIN_C3 //用 EEPROM_SCL 代替 PIN_C3 #endif //结束 if 定义 #use i2c(master, sda=EEPROM_SDA, scl=EEPROM_SCL) // master 设置成主机方式 //除非指定了 FORCE_HW,否则会产生模拟 I2C 的软件函数.

Page 15: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 15

//使能 I2C_START, I2C_STOP 直到下一个#USE I2C 的出现为止. //使能 I2C_READ, I2C_WRITE 直到下一个#USE I2C 的出现为止. //使能 I2C_POLL 直到下一个#USE I2C 的出现为止.

//指定 sda 脚为 EEPROM_SDA, 指定 scl 脚为 EEPROM_SCL #define EEPROM_ADDRESS long int //用 EEPROM_ADDRESS 代替 long int #define EEPROM_SIZE 2048 //用 EEPROM_SIZE 代替 2048 void init_ext_eeprom() { output_float(EEPROM_SCL); //将 EEPROM_SCL 引脚设为输入,开集电极连接 output_float(EEPROM_SDA); //将 EEPROM_SDA 引脚设为输入,开集电极连接 } BOOLEAN ext_eeprom_ready() { int1 ack; //声明位变量 ack i2c_start(); //发送启动条件 ack = i2c_write(0xa0); //发送从机地址 0xa0;若 ack=0,表示从机应答(ACK);

//若 ack=1,表示从机不应答(NO ACK); i2c_stop(); //发送停止条件 return !ack; } // ext_eeprom_ready()函数,若返回 1,表示从机准备好; 若返回 0,表示从机忙或 eeprom 坏了 void write_ext_eeprom(long int address, BYTE data) { while(!ext_eeprom_ready()); //若从机忙,则主机等待 i2c_start(); //发送启动条件 i2c_write( (0xa0|(BYTE)(address>>7))&0xfe); //发送命令字的高字节(发送写命令) i2c_write(address); //发送命令字的低字节 i2c_write(data); //发送数据 i2c_stop(); //发送停止条件 } BYTE read_ext_eeprom(long int address) { BYTE data; //声明字节变量 data while(!ext_eeprom_ready()); //先发器件地址,若从机忙,则主机等待 i2c_start(); //在此处是:发送重新启动条件 i2c_write( (0xa0|(BYTE)(address>>7))&0xfe); //发送命令字的高字节(发送写命令) i2c_write(address); //发送命令字的低字节 i2c_start(); //发送启动条件 i2c_write( (0xa0|(BYTE)(address>>7))|1); //发送命令字的高字节(发送读命令) data=i2c_read(0); //读 I2C 数据,然后发送 ack=0(不用从机应答) i2c_stop(); //发送停止条件 return(data); //返回所读到的 I2C 数据 } 上面的例子主要用来读写 24C16,通过 PC 机 RS232 进行验证

Page 16: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 16

#IFDEF #IFNDEF #ELSE #ELIF #ENDIF 语法: #ifdef id

cide #elif code #else code #endif 和 #ifndef id code #elif code #else code #endif

id 是一个预处理器标识符,code 是一段有效的 C 源程序. 目的:这个指示的执行同#IF 相似.在#IF 里,如果指定的 ID(用#DEFINE 创建的 ID)对预处理器

来说是已知的, 预处理器完全可以检查到它;而在#IFDEF 里,如果 ID 被定义了,则预处理器可

以检查到它,若没有定义 ID,则#IFNDEF 可以检查到它. 例子:

#define debug //定义 debug … #ifdef debug //因为 debug 在前面已定义,所以可执行 printf printf(“debug poit a”); #endif

例子文件:ex_sqw.c 在前面已介绍过了 #INCLUDE 语法: #include <filename>

或 #include “filename” filename 是一个有效的 PC 文件名.它包括标准的驱动和路径信息.带有”.encrypted”扩展

名的是一个有效的 PC 文件名.标准的编译器#include directive 会接受带有这种扩展名的文件,将它们译成可读的.这允许包含的文件被分配,但不释放出其源程序代码. 目的:来自指定文件的的字符用作编辑的指针.如果没有将完整的路径指定给编译器, 编译器

将使用指定的目录的列表为 project 搜查文件.若文件名在“…”里,那么主源程序文件所在的目

录首先被搜查.若文件名在<…>里, 那么主源程序文件所在的目录 后被搜查. 例子:#include <16c54.h>

Page 17: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 17

#include <c:\includes\comlib\myrs232.c> 例子文件:ex_sqw.c 在前面已介绍过了 #INT_GLOBAL 语法: #int_global 目的:这种指示将引起下面的函数代替编译器产生中断. 函数通常不要求,而用来产生警告.当使用#int_global 时,编译器不产生启动代码或清除代码,也不存入寄存器. 例子:#int_global

isr(){ //将被定位在地址 0x0004 处 #asm bsf isr_flug retfie #endasm }

例子文件:ex_glint.c 在前面已介绍过了 #INT_DEFAULT 语法: #int_default 目的:如果 PIC 触发一个中断且没有设置任何中断标志位, 则下面的函数将被调用.如果有一

个中断标志,但一次都没触发,则#int_default 函数也可被调用. 例子:#int_default

default_isr(){ printf(“Unexplained interrupt\r\n”);

#INT_XXXX 语法: #INT_AD //AD 转换完成

#INT_ADOF //AD 转换时间溢出 #INT_BUSCOL //总线冲突 #INT_BUTTON //按钮 #INT_CCP1 //捕获或比较器 1 #INT_CCP2 //捕获或比较器 1 #INT_COMP //比较器探测 #INT_EEPROM //EEPROM 写完成 #INT_EXT //外部中断 #INT_EXT1 //外部中断 1 #INT_EXT2 //外部中断 2 #INT_I2C //I2C 中断(只用于 14000) #INT_LCD //LCD 行动 #INT_LOWVOLT //低电压探测 #INT_PSP //并行端口 PSP 数据输入 #INT_RB //端口 B 在 B4~B7 的电平变化

Page 18: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 18

#INT_RC //端口 C 在 C4~C7 的电平变化 #INT_RDA //RS232 接收到的数据有用, 使能 UART 接收中断 #INT_RTCC //Timer0(RTCC)溢出 #INT_SSP //SPI 口或 I2C 被激活 #INT_TBE //RS232 发送缓冲区是空的 #INT_TIMER0 //Timer0(RTCC)溢出 #INT_TIMER1 //Timer1 溢出 #INT_TIMER2 //Timer2 溢出 #INT_TIMER3 //Timer3 溢出 注意:大多数#INT_options 在指定的芯片上是有用的. 在 devices.h 文件中,检查所给芯

片的全部列表. 目的:这些指令指定下面的函数是一个中断服务函数,中断函数可以没有任何参数.不是所有

指令都可用于所有的元件,为了获得元件的有效中断,请参阅 devices.h 文件或在 PCW 中,点击

VIEW|Valid ints 也可查得有哪些中断. 当中断被检测到时,编译器将产生代码跳到中断服务函数.它将产生代码来存储或重新

存储机器状态,并且清除中断标志位.为了防止标志位被清除,请在#INT_XXXX 后面添加

NOCLEAR 语句即可. ENABLE_INTERRUPTS(INT_XXXX) 在 中 断 前 初 始 化 时 要 被 激 活 , 并 且

ENABLE_INTERRTUPTS(GLOBAL)也要使能中断,才可进入中断. 关键字 HIGH 和 FAST 可用于 PCH 编译中,用来标志高中断优先权.一个高优先权的中断

可在另一中断正在进行的情况下产生中断.一个标有 FAST 中断在执行时,它不存储或重新存

储任何寄存器,这就要你尽可能地存储你自己需要的存储器.标有HIGH的中断能够正常使用.在建立高优先权中断时,请参阅#DEVICE 以获取更多的信息.

例子:#int_ad adc_handler(){ adc_active=FALSE; }

#int_rtcc noclear isr(){

… }

例子文件:参阅 ex_sisr.c 和 ex_stwt.c 以获取完全的例子 文件: ex_stwt.c 在前面已经介绍过了,这里不再重述 文件: ex_sisr.c 如下: #if defined(__PCM__) //若使用了 PCM 编译器,则 defined( __PCM__)返回值为 1 #include <16F877.h> //包含 16F877.h 头文件 #fuses HS, NOWDT, NOPROTECT, NOLVP //HS:高速晶振/谐振器, NOWDT:不使用 WDT // NOPROTECT:程序存储器代码不保护 #use delay(clock=20000000) //使能内置函数的功能:delay_ms()和 delay_us() //#USE DELAY()必须在#use rs232()使用之前出现. #use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)

//使用波特率为 9600, //发送脚为 PIN_C6 //接收脚为 PIN_C7

Page 19: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 19

//使能内置函数:GETC,PUTC 和 PRINTF, kbhit(); #elif defined(__PCH__) #include <18F452.h> #fuses HS,NOWDT,NOPROTECT,NOLVP #use delay(clock=20000000) #use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7) // Jumpers: 8 to 11, 7 to 12 #endif //结束 if 定义 #define BUFFER_SIZE 32 //用 BUFFER_SIZE 代替 32 BYTE buffer[BUFFER_SIZE]; //声明字符型数组 buffer[BUFFER_SIZE] BYTE next_in = 0; //声明字符型变量 next_in,并赋初值为 0 BYTE next_out = 0; //声明字符型变量 next_out,并赋初值为 0 #int_rda //RS232 接收到的数据有用,指定下面的函数是一个中断函数 void serial_isr() { int t; //声明整型变量 t; buffer[next_in]=getc(); //从 RS232 接口读 1 个字节,存到数阻 buffer[]中 t=next_in; //将 next_in 赋给暂态变量 t next_in=(next_in+1) % BUFFER_SIZE; //%用来求余数 if(next_in==next_out) next_in=t; // Buffer full !! } #define bkbhit (next_in!=next_out) //用 bkbhit 代替表达式(next_in!=next_out); BYTE bgetc() { BYTE c; //声明字符型变量 c; while(!bkbhit) ; //当 next_in=next_out 时,空操作,等待 next_in 不等于 next_out c=buffer[next_out]; next_out=(next_out+1) % BUFFER_SIZE; //%用来求余数 return(c); //函数返回暂态变量 c 的值,并退出该函数 } void main() { enable_interrupts(global); //使能总中断 enable_interrupts(int_rda); //使能 UART 在接收到 1 个字节时,中断允许 printf("\r\n\Running...\r\n"); // The program will delay for 10 seconds and then display // any data that came in during the 10 second delay do { delay_ms(10000); //延时 10 秒 printf("\r\nBuffered data => "); while(bkbhit) //当接收缓冲区没有满,则执行下面语句 putc( bgetc() ); //将接收到的数据再通过 UART 发送出去显示 } while (TRUE); } 上面的例子主要介绍 UART 接收中断的设计,将接收到的数据及时送去显示.

Page 20: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 20

#TYPE 语法: #type standard-type=size

#type default=area standard-type 是 short,int,long 或用户定义尺寸中的之一; size 是 1,8,16 或 32; area 是#TYPE 使用 typemod 命令定义的存储区. 目的:编译器默认将 short 看作 1 位, 将 int 看作 8 位, 将 long 看作 16 位.传统的 C 习惯为目标

处理器而将 INT 定义成更高效率的尺寸.在 PIC 中,INT 是 8 位.为了有助于代码兼容,#type 命令允许改变这些关键字. #TYPE 能重新定义这些关键字. 注意:逗号是可选项.当然#TYPE 可能使一些尺寸得不到 4 种关键字的描绘(如上面的 1 位整

型),下面的 4 种整型可能总是被用来表示:INT1,INT8,INT16 和 INT32.如果在你的程序使用了

#TYPE,在 CCS 中的例子程序和包含的文件被警告而可能不正确工作. 这个命令也常用来将默认的有用 RAM 区改变成变量存储区.通过指定 default=area 就可

实现,这里的 area 是一个 typemod 地址空间. 例子:TYPE SHORT=8, INT=16, LONG=32

#TYPE default=area typemod<,,,0x100,0x1ff>user_ram_block; #type default= user_ram_block //所有的变量将在 0x100~0x1ff 这个区进行声明 #type default= //将存储器重新存回通常的状态

例子文件:ex_cust.c 文件: ex_cust.c 如下: #pragma case //保持 C 编译器之间的兼容性,它必须出现在其它任意预处理器命令之前 #pragma type short=8,int=16,long=32 //重新定义 short, int, long #define version 0x0001 //用 version 代替 0x0001 #if defined(__PCB__) //若使用了 PCB 编译器,则 defined( __PCB__)返回值为 1 #include <16C56.H> //包含 16F877.h 头文件 #pragma fuses HS, NOWDT, NOPROTECT //HS:高速晶振/谐振器, NOWDT:不使用 WDT // NOPROTECT:程序存储器代码不保护 #pragma use delay(clock=20000000) //使能内置函数的功能:delay_ms()和 delay_us() //#USE DELAY()必须在#use rs232()使用之前出现. #pragma use rs232(baud=9600, xmit=PIN_A3, rcv=PIN_A2)

//使用波特率为 9600, //发送脚为 PIN_A3 //接收脚为 PIN_A2 //使能内置函数:GETC,PUTC 和 PRINTF, kbhit();

#define compiler __PCB__ //用 compiler 代替__PCB__ #elif defined(__PCM__) #include <16F877.H>

Page 21: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 21

#pragma fuses HS,NOWDT,NOPROTECT,NOLVP #pragma use delay(clock=20000000) #pragma use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7) // Jumpers: 8 to 11, 7 to 12 #define compiler __PCM__ #elif defined(__PCH__) #include <18F452.H> #pragma fuses HS,NOWDT,NOPROTECT,NOLVP #pragma use delay(clock=20000000) #pragma use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7) // Jumpers: 8 to 11, 7 to 12 #define compiler __PCH__ #endif //结束 if 定义 #pragma id version #reserve 0x20:0x2f //将 RAM 从地址 0x20 到 0x2f 的单元保留下来不被使用 //#reserve 必须出现在#DEVICE 命令之后,否则,没有用 int CYCLES; // Global cycles (note upper case)将 CYCLES 定义为 16 位全局整型变量 #inline //告诉编译器,下面的函数立即被执行 void pulse_B0() { #pragma use fast_io(B) //执行 I/O 的快速方法将使编译器不用对 I/O 方向寄存器进行编程就

//可执行 I/O 操作,但用户必须保证通过 set_tris_X()来设置 I/O 方向寄

//存器. output_low(PIN_B0); //脚(PIN_B0)输出低电平 delay_ms(100); //延时 100ms output_high(PIN_B0); //脚(PIN_B0)输出高电平 delay_ms(100); //延时 100ms #pragma use standard_io(B) //告诉编译器,以后每次使用 I/O,原来是输出设置就永远是输出

//设置,直到下一个#USE XXX_io 出现为止 } #separate //告诉编译器,下面的程序立即被分开执行,

//常用来阻止编译器自动制造一个 INLINE程序,也就说#inline到此为止,不再有效 void send_pulses() { int cycles; // Local cycles (note lower case) for(cycles=CYCLES; cycles!=0; --cycles) { pulse_B0(); } } #pragma zero_ram // #zero_ram 将所有的内部寄存器清 0,I/O 口为输出设置 void main() { output_low(PIN_B0); //脚(PIN_B0)输出低电平

Page 22: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 22

output_low(PIN_B1); //脚(PIN_B1)输出低电平 printf("Firmware version is %4X\r\n",version); printf("Compiled on %s with compiler version %s\r\n", __DATE__, compiler); printf("Pulsing B0 and B1..."); for(CYCLES=100;CYCLES<=300;CYCLES+=100) { printf("\r\nMajor cycle #%c...",(CYCLES/100)+'0'); output_low(PIN_B1); //脚(PIN_B1)输出低电平 output_high(PIN_B1); //脚(PIN_B1)输出高电平 send_pulses(); } printf("\r\nAll Done."); delay_ms(3); // Allow UART to finish } #USE DELAY 语法: #use delay(clock=speed)

或 #use delay(clock=speed, restart_wdt)

speed 是一个常数,范围为 1~100000000(1hz~100mhz) 目的: 将处理器的速度告诉给编译器,使能内置函数的功能:delay_ms()和 delay_us().速度是每

秒周期数.可选项 restart_wdt 使编译器在延时的时候重新启动 WDT. 例子:#use delay(clock=20000000)

#use delay(clock=32000,RESTART_WDT) 例子文件:ex_sqw.c;该文件在前面已经叙述过了 #USE FAST_IO 语法:#use fast_io(port) port 是 A~G 目的:影响编译器如何产生输入输出代码,说明如下.这种指令有效,直到出现下一个#use xxxx_io 为止.执行 I/O 的快速方法将使编译器不用对 I/O 方向寄存器进行编程就可执行 I/O操作,但用户必须保证通过 set_tris_X()来设置 I/O 方向寄存器. 例子:#use fast_io(A) 例子文件:ex_cust.c;该文件在前面已经叙述过了 #USE FIXED_IO 语法:#use fixed_io(port_outputs=pin.pin?) port 是 A~G. pin 是在 device.h 文件中定义的脚数之一. 目的: 影响编译器如何产生输入输出代码,说明如下. 这种指令有效,直到出现下一个#use xxxx_io 为止. 执行设置 I/O 的方法将使编译器产生代码,这种代码使 I/O 在每次使用的时候,要么是输入,要么是输出.根据 I/O 方向寄存器中的信息对引脚进行编程(I/O 方向寄存器实际

Page 23: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 23

上被执行但不操作),这将存储一个字节到标准 I/O 使用的 RAM 中. 例子:#use fixed_io(a_outputs=PIN_A2,PIN_A3) //将 PINA2 和 PIN_A3 设置为输出 #UNDEF 语法:#undef id id 是通过#define 定义的预处理机 id 目的:指定预处理机 id 对预处理机来说不再有意义. 例子:#if MAXSIZE<100 //若 MAXSIZE<100,则执行下面的语句

#undef MAXSIZE // MAXSIZE 对预处理机来说不再有意义. #define MAXSIZE 100 //将用 MAXSIZE 代替 100 endif //结束 if

#USE I2C 语法:#use i2c(options) options 被逗号隔开,可能是: MASTER //设置成主机方式 SLAVE //设置成从机方式 SCL=pin //指定 SCL 引脚(pin 是一个位地址) SDA=pin //指定 SDA 引脚 ADDRESS=nn //指定从机方式地址 FAST //使用 fast I2C 规范 SLOW //使用 slow I2C 规范 RESTART_WDT //在 I2C_READ 等待的时候,重新启动 WDT FORCE_HW //使用硬件 I2C 函数 NOFLOAT_HIGH //不允许信号漂浮至高,从低到高驱动信号 SMBUS //总线不使用 I2C,但很相似,即模拟 I2C 目的:I2C的零件库包含了一个实现 I2C总线的函数, #USE I2C使得 I2C_START, I2C_STOP, I2C_READ, I2C_WRITE 和 I2C_POLL 函数保持有效,直到下一个#USE I2C 的出现为止.除非指定了 FORCE_HW,否则会产生模拟 I2C 的软件函数.SLAVE 方式只能同内置的 SSP 一起

被使用. 例子:#use I2C(master, sda=PIN_B0, scl=PIN_B1)

#use I2C(slave, sda=PIN_C4, scl=PIN_C3, address=0xa0, FORCE_HW) #use i2c(master,sda=EEPROM_SDA, scl=EEPROM_SCL) // init_ext_eeprom(); Call before the other functions are used // // write_ext_eeprom(a, d); Write the byte d to the address a // // d = read_ext_eeprom(a); Read the byte d from the address a // #define EEPROM_ADDRESS long int #define EEPROM_SIZE 32768 void init_ext_eeprom() { output_float(EEPROM_SCL); output_float(EEPROM_SDA); } void write_ext_eeprom(long int address, BYTE data)

Page 24: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 24

{ short int status; i2c_start(); i2c_write(0xa0); i2c_write(address>>8); i2c_write(address); i2c_write(data); i2c_stop(); i2c_start(); status=i2c_write(0xa0); while(status==1) { i2c_start(); status=i2c_write(0xa0); } }

BYTE read_ext_eeprom(long int address) { BYTE data; i2c_start(); i2c_write(0xa0); i2c_write(address>>8); i2c_write(address); i2c_start(); i2c_write(0xa1); data=i2c_read(0); i2c_stop(); return(data); }

void Long_write_ext_eeprom(long int address, Long data) { int A; for (A=0;A<4;A++) write_ext_eeprom(A + address, *(&data + A)); }

Long Long_read_ext_eeprom(long int address) { int A; Long Data; for (A=0;A<4;A++) *(&Data + A) = read_ext_eeprom( A + address); return(Data); }

例子文件:ex_extee.c 同 2464.c 一起使用. 在前面已介绍过了.

Page 25: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 25

#USE RS232 语法:#use rs232(options) options 被逗号隔开,可能是: STREAM=id //使一串标识符同这个 RS232 端口发生联系,那么这个标识符就可被使用了 BUAD=x //将波特率设置为 x XMIT=pin //设置发送引脚 RCV=pin //设置接收引脚 FORCE_SW //即便 UART 脚被指定,也会产生软件串行 I/O 中断服务程序 BRGH1OK //允许芯片上的波特率劣质,即有波特率问题 ENABLE=pin //在发送期间将指定的脚置高,这使得采用 485 发送成为可能 DEBUGGER //指出这串用于通过 CCS ICD 进行接收/发送数据,用 B3 作为默认脚;采用

XMIT=和 RCV=来改变使用的引脚, XMIT=和 RCV=是同一个脚 RESTART_WDT //当 GETC()在等待一个字符时,会引起 GETC()清除 WDT INVERT //颠倒串行脚的极性(当采用电平转换器,如 MAX232 时,通常不需颠倒),

不可同内部的 UART 一起使用 PARITY=x //奇偶校验,这儿的 x 是 N,E 或 O, 偶数的(even), 奇数的(odd) BITS=X //这儿的 x 是 5~9(5~7 不可同 SCI 一起使用) FLOAT_HIGH //这个脚不可驱动成高,常用来开集电极输出.如果这脚在末位的时间不

是高电平,RS232_ERRORS 的位 6 被置 1. ERRORS //常用于编译器将接收到错误保持在变量 RS232_ERRORS 中,当有错误

存在时,将 errors 复位. SAMPLE_EARLY //getc()通常在一位时间的中间时刻采样数据,这个可选项使得在一位

时间的开始时刻进行采样.不可同 UART 一起使用 RETURN=pin //对于 FLOAT_HIGH 和 MULTI_MASTER,这个脚常用于读回信号,

FLOAT_HIGH 的默认是 XMIT 脚, MULTI_MASTER 的默认是 RCV 脚. MULTI_MASTER //采用 RETURN 脚判断是否总线上还有一台主机在同时发送数据,若

有冲突,RS232_ERRORS 的位 6 被置 1,所有后来的 PUTC 都被忽略直到

RS232_ERRORS 的位 6 被清除.在一位时间的开端和末尾处检测这个信

号.不可同 UART 一起使用. LONG_DATA //使用 getc()返回一个 16 位整型数, 使用 putc 发送一个 16 位整型数.这

是 9 位数据格式 DISABLE_INTS //当 get 或 put 一个字符时,不使能中断.对于软件执行 I/O 来说, 是防止

字符畸变,而当采用 UART 时,是防止中断处理程序和主程序的 I/O 口干

扰. 目的:这种命令是将波特率和用作串行 I/O 口的引脚告诉给编译器. 这种命令有效,直到下一 RS232 命令出现为止.#USE DELAY 命令必须在这种命令使用之前出现. 这种命令使能了内 置函数的功能,如:GETC,PUTC 和 PRINTF. 当带有内置 SCI 的元件被使用时,SCI 被指定,那么 SCI 才将被使用. 在使用当前时钟速 率的情况下,如果波特率达不到要求值的 3%之内.,那么将会产生一个错误.RS232_ERRORS 的定义如下: NO UART: Bit7 对于 9 位数据模式说(get 和 put),是第 9 位; Bit6 在 float high 模式里,置 1 表示一个 put 失败; With a UART:

Page 26: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 26

Used only by get: 只能用于 get; Copy of RCSTA register except: Bit0 用来表明奇偶错误; 例子:#use rs232(baud=9600,xmit=PIN_A2,rcv=PIN_A3) //使用波特率为 9600,

//发送脚为 PIN_A2 //接收脚为 PIN_A3

例子文件:ex_sqw.c 在前面已介绍过了. #USE RTOS RTOS(the CCS Real Time Operating System)是CCS实时操作系统,它允许PIC微控制器在不需

要中断的情况下,有规律地执行时间表任务.这由担任调度的函数 RTOS_RUN()来完成.当一

个任务被按时执行时, 调度函数会把处理器的控制权交给任务.当任务执行完了或不再需要

处理器时, 处理器的控制权就返回给调度的函数.接着,调度函数将处理器的控制权交给下一

个任务,使得这个任务在适当时间被按时执行,这个过程称为合作的多任务. 语法:#use rtos(options) options 被逗号隔开,可能是: timer=X //这里的 X 是 0~4,用来指出定时器用于 RTOS 实时操作系统 minor_cycle=time //这里的 time 是下面的数字:s,ms,us,ns.任意任务执行的 长时间.每个任

//务的执行速率必须是这个 time 的倍数.若 time 没有被指定,编译器能够计 //算它的值.

Statistics // 维持每个任务所使用的 小时间, 大时间和总时间. 目的:这种指令告诉编译器 PIC 上的定时器用来监控,随时同意控制一个任务.改变指定的定

时器预分频值将会影响任务的执行速度. 当带有 minor_cycle 可选项执行时,这条指令也可用来指定一个任务执行所花费 长时

间.在 project 编译通过之前,这只是强迫所有任务的执行时间是 minor_cycle 倍数.如果

minor_cycle 这个可选项没有被指定,编译器将使用尽可能小的执行 RTOS 任务速率的因子

minor_cycle 值, 如果 Statistics 可选项被指定,那么编译器将会保持对执行每个任务所花费的 小处理时

间, 大处理时间和总处理时间的跟踪. 例子:#use rtos(timer=0, minor_cycle=20ms) //将 timer0 用于 RTOS 实时操作系统

//强迫所有任务的执行时间是 minor_cycle 倍数 #TASK 每个RTOS任务同函数一样可被指定,没有参数,没有返回值.为了能够告诉编译器这个函数是

一个 RTOS 任务,只须将#TASK 命令放在每个 RTOS 任务之前即可.RTOS 任务不能象函数那

样被调用. 语法:#TASK(options) 元素: options 被逗号隔开,如下: rate=time 这里的 time 是下面的数据:s, ms, us 或 ns. 它指定一个 RTOS 任务执行的频率. max=time 这里的 time 是下面的数据:s, ms, us 或 ns.它指定这个 RTOS 任务的预算时间. queue=bytes 指定要分配多少个字节给这个 RTOS 任务, bytes 的默认值是 0. 目的:这个命令告诉编译器,下面的函数是一个 RTOS 任务. rate 可选项常用来指定执行一个RTOS任务的频率(多久一次). rate必须是minor_cycle的倍

Page 27: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 27

数, minor_cycle 可选项是在#use rtos 命令里指定的. max 可选项用来指定一个 RTOS 任务在执行期间花费处理器多长时间.在 max 中指定的

time 必须等 queue 于或小于 minor_cycle 可选项指定的时间.在项目编译成功之前,要用#use rtos命令指定 minor_cycle可选项的时间.编译器无法执行这个限定的处理器时间,所以编程器

小心 RTOS 任务执行要使用处理器多少时间.这个可选项不必被指定. queue 可选项用来指定要保留多少个字节给这个 RTOS 任务,为的是让这个 RTOS 任务能接

收来自其它函数或任务的信息. queue 的默认值是 0. 例子:#task(rate=1s, max=20ms, queue=5) EX_LCDKB.C 文件如下: #if defined(__PCB__) #include <16c56.h> #fuses HS,NOWDT,NOPROTECT #use delay(clock=20000000) #elif defined(__PCM__) #include <16F877.h> #fuses HS,NOWDT,NOPROTECT,NOLVP #use delay(clock=20000000) #elif defined(__PCH__) //若使用了 PCH 编译器,则 defined( __PCH__)返回值为 1 #include <18F452.h> //包含 18F452.h 头文件 #fuses HS, NOWDT, NOPROTECT, NOLVP //HS:高速晶振/谐振器, NOWDT:不使用 WDT // NOPROTECT:程序存储器代码不保护 #use delay(clock=20000000) //使能内置函数的功能:delay_ms()和 delay_us() //#USE DELAY()必须在#use rs232()使用之前出现. #endif //结束 if 定义 #include <lcd.c> //包含 lcd.c 文件 #include <kbd.c> //包含 kbd.c 文件 void main() { char k; //声明字符型变量 k lcd_init(); //初始化 LCD kbd_init(); //键盘初始化 lcd_putc("\fReady...\n"); //LCD 先走纸换页,接着将 Ready...送给 LCD 显示,然后换行 while (TRUE) { k=kbd_getc(); //读键盘 if(k!=0) if(k=='*') lcd_putc('\f'); //若 k 是'*',则 LCD 走纸换页

Page 28: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 28

else lcd_putc(k); //将 K 值送给 LCD 显示 } } KBD.C 文件如下: #if defined(__PCH__) //若使用了 PCH 编译器,则 defined( __PCH__)返回值为 1 #if defined use_portb_kbd //若使用了 use_portb_kbd,则 defined use_portb_kbd 返回 1 #byte kbd = 0xF81 //将 kbd 对应端口为 PORT B (at address 0xF81) #else #byte kbd = 0xF83 //如果没有使用,将 kbd 对应端口为 PORT D (at address 0xF83) #endif //结束 if 定义 #else #if defined use_portb_kbd //若使用了 use_portb_kbd,则 defined use_portb_kbd 返回 1 #byte kbd = 6 //将 kbd 对应端口为 port B (at address 6) #else #byte kbd = 8 //将 kbd 对应端口为 port D (at address 8) #endif //结束 if 定义 #endif //结束 if 定义 #if defined use_portb_kbd //若使用了 use_portb_kbd,则 defined use_portb_kbd 返回 1 #define set_tris_kbd(x) set_tris_b(x) //用 set_tris_kbd(x)代替 set_tris_b(x) #else #define set_tris_kbd(x) set_tris_d(x) //用 set_tris_kbd(x)代替 set_tris_d(x) #endif //结束 if 定义 //Keypad connection: (for example column 0 is B2) // Bx: #ifdef blue_keypad //若使用了 blue_keypad,则定义如下 #define COL0 (1 << 2) //用 COL0 代替表达式(1 << 2) #define COL1 (1 << 3) //用 COL1 代替表达式(1 << 3) #define COL2 (1 << 6) //用 COL2 代替表达式(1 << 6) #define ROW0 (1 << 4) //用 ROW0 代替表达式(1 << 4) #define ROW1 (1 << 7) //用 ROW1 代替表达式(1 << 7) #define ROW2 (1 << 1) //用 ROW2 代替表达式(1 << 1) #define ROW3 (1 << 5) //用 ROW3 代替表达式(1 << 5) #else #define COL0 (1 << 5) //用 COL0 代替表达式(1 << 5) #define COL1 (1 << 6) //用 COL1 代替表达式(1 << 6) #define COL2 (1 << 7) //用 COL2 代替表达式(1 << 7) #define ROW0 (1 << 1) //用 ROW0 代替表达式(1 << 1)

Page 29: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 29

#define ROW1 (1 << 2) //用 ROW1 代替表达式(1 << 2) #define ROW2 (1 << 3) //用 ROW2 代替表达式(1 << 3) #define ROW3 (1 << 4) //用 ROW3 代替表达式(1 << 4) #endif //结束 if 定义 #define ALL_ROWS (ROW0|ROW1|ROW2|ROW3) //用 ALL_ROWS 代替表达式 #define ALL_PINS (ALL_ROWS|COL0|COL1|COL2) //用 ALL_PINS 代替表达式 // Keypad layout: char const KEYS[4][3] = {{'1','2','3'}, {'4','5','6'}, {'7','8','9'}, {'*','0','#'}}; #define KBD_DEBOUNCE_FACTOR 33 // Set this number to apx n/333 where // n is the number of times you expect // to call kbd_getc each second void kbd_init() { } char kbd_getc( ) { static BYTE kbd_call_count; //声明静态变量 kbd_call_count static short int kbd_down; //声明静态变量 kbd_down static char last_key; //声明静态变量 last_key static BYTE col; //声明静态变量 col BYTE kchar; //声明暂态变量 kchar BYTE row; //声明暂态变量 row kchar='\0'; //给暂态变量 kchar 赋初值'\0'(空字符'\0') if(++kbd_call_count>KBD_DEBOUNCE_FACTOR) { switch (col) { case 0 : set_tris_kbd(ALL_PINS&~COL0); kbd=~COL0&ALL_PINS; break; case 1 : set_tris_kbd(ALL_PINS&~COL1); kbd=~COL1&ALL_PINS; break; case 2 : set_tris_kbd(ALL_PINS&~COL2); kbd=~COL2&ALL_PINS; break; } if(kbd_down) { if((kbd & (ALL_ROWS))==(ALL_ROWS)) { kbd_down=FALSE;

Page 30: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 30

kchar=last_key; last_key='\0'; //(空字符'\0') } } else { if((kbd & (ALL_ROWS))!=(ALL_ROWS)) { if((kbd & ROW0)==0) row=0; else if((kbd & ROW1)==0) row=1; else if((kbd & ROW2)==0) row=2; else if((kbd & ROW3)==0) row=3; last_key =KEYS[row][col]; kbd_down = TRUE; } else { ++col; if(col==3) col=0; } } kbd_call_count=0; } set_tris_kbd(ALL_PINS); return(kchar); } LCD.C 文件如下: // As defined in the following structure the pin connection is as follows: // D0 enable // D1 rs // D2 rw // D4 D4 // D5 D5 // D6 D6 // D7 D7 // // LCD pins D0-D3 are not used and PIC D3 is not used. // Un-comment the following define to use port B

Page 31: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 31

// #define use_portb_lcd TRUE struct lcd_pin_map { BOOLEAN enable; // enable 为 1 位,对应 B0 BOOLEAN rs; // rs 为 1 位,对应 B1 BOOLEAN rw; // rw 为 1 位,对应 B2 BOOLEAN unused; // unused 为 1 位,对应 B3 int data : 4; // 声明 data 为 4 位,对应 B4,B5,B6,B7 } lcd; // lcd 为全局变量,对应端口为 PORT B #if defined(__PCH__) //如果定义了 PCH, 则 #if defined use_portb_lcd #byte lcd = 0xF81 //如果定义了 use_portb_lcd, 则定义 lcd 为全局变量,对应端口为

PORT B (at address 0xF81) #else #byte lcd = 0xF83 //如果没有定义 use_portb_lcd, 则定义 lcd 为全局变量,对应端口为 PORT D (at address 0xF83) #endif //结束 if 定义 #else //若没有定义 PCH, 则 #if defined use_portb_lcd #byte lcd = 6 //如果没有定义 use_portb_lcd, 则定义 lcd 为全局变量,对应端口为 port B (at address 6) #else #byte lcd = 8 //如果没有定义 use_portb_lcd, 则定义 lcd 为全局变量,对应端口为 port D (at address 8) #endif //结束 if 定义 #endif //结束 if 定义 #if defined use_portb_lcd //若使用了 use_portb_lcd,则 defined use_portb_lcd 返回 1 #define set_tris_lcd(x) set_tris_b(x) //用 set_tris_lcd(x)代替 set_tris_b(x) #else #define set_tris_lcd(x) set_tris_d(x) //用 set_tris_lcd(x)代替 set_tris_d(x) #endif //结束 if 定义 #define lcd_type 2 // 0=5x7, 1=5x10, 2=2 lines,用 lcd_type 代替 2 #define lcd_line_two 0x40 // LCD RAM address for the second line 用 lcd_line_two 代替 0x40 BYTE const LCD_INIT_STRING[4] = {0x20 | (lcd_type << 2), 0xc, 1, 6}; // These bytes need to be sent to the LCD // to start it up. struct lcd_pin_map const LCD_WRITE = {0,0,0,0,0};

// For write mode all pins are out , 用 const 声明 LCD_WRITE 常数 struct lcd_pin_map const LCD_READ = {0,0,0,0,15};

// For read mode data pins are in ,用 const 声明 LCD_READ 为常数 BYTE lcd_read_byte() {

BYTE low,high; //声明暂态变量 low,high, //high 用来存字节的高 4 位,low 用来存字节的低 4 位

set_tris_lcd(LCD_READ); //设置端口的低 4 位为输出口,端口的高 4 位为输入口

Page 32: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 32

lcd.rw = 1; //发 LCD 读命令 delay_cycles(1); //相当于 1 个 NOP 指令 lcd.enable = 1; //LCD 使能 delay_cycles(1); //相当于 1 个 NOP 指令 high = lcd.data; //读端口的高 4 位 lcd.enable = 0; // LCD 不使能 delay_cycles(1); //相当于 1 个 NOP 指令 lcd.enable = 1; //LCD 使能 delay_us(1); //延时 1us low = lcd.data; //读端口的低 4 位 lcd.enable = 0; // LCD 不使能 set_tris_lcd(LCD_WRITE); //设置控制 LCD 端口为输出口 return( (high<<4) | low); //合并字节的高 4 位和字节的低 4 位,组成 1 个字节,返回 } void lcd_send_nibble( BYTE n ) { lcd.data = n; delay_cycles(1); //相当于 1 个 NOP 指令 lcd.enable = 1; //LCD 使能 delay_us(2); //延时 2us lcd.enable = 0; // LCD 不使能 } void lcd_send_byte( BYTE address, BYTE n ) { lcd.rs = 0; //选择 LCD 的地址寄存器 while ( bit_test( lcd_read_byte(), 7) ) ; //bit_test(X,b)位测试涵数 lcd.rs = address; //选择 LCD 的地址寄存器 delay_cycles(1); //相当于 1 个 NOP 指令 lcd.rw = 0; //发送 LCD 写命令 delay_cycles(1); //相当于 1 个 NOP 指令 lcd.enable = 0; // LCD 不使能 lcd_send_nibble(n >> 4); //送出 n 的高 4 位 lcd_send_nibble(n & 0xf); //送出 n 的低 4 位 } void lcd_init() { BYTE i; //声明暂态变量 i set_tris_lcd(LCD_WRITE); //设置控制 LCD 端口为输出口 lcd.rs = 0; //选择 LCD 的地址寄存器 lcd.rw = 0; //发送 LCD 写命令 lcd.enable = 0; //LCD 使能

Page 33: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 33

delay_ms(15); //延时 15ms for(i=1;i<=3;++i) { lcd_send_nibble(3); //将 0x333 送给 LCD delay_ms(5); //延时 5ms } lcd_send_nibble(2); //将 0x2333 送给 LCD for(i=0;i<=3;++i) lcd_send_byte(0,LCD_INIT_STRING[i]); } void lcd_gotoxy( BYTE x, BYTE y) { BYTE address; //声明暂态变量 address if(y!=1) address=lcd_line_two; //将 0x40 送给 address else address=0; address+=x-1; lcd_send_byte(0,0x80|address); } void lcd_putc( char c) { switch (c) { case '\f' : lcd_send_byte(0,1); //若 c 是走纸换页符('\f'),则执行该行 delay_ms(2); break;

case '\n' : lcd_gotoxy(1,2); //若 c 是换行符('\n'),则执行该行 break;

case '\b' : lcd_send_byte(0,0x10); //若 c 是退格符('\b'),则执行该行 break;

default : lcd_send_byte(1,c); break; } } char lcd_getc( BYTE x, BYTE y) { char value; lcd_gotoxy(x,y); while ( bit_test(lcd_read_byte(),7) ); // wait until busy flag is low lcd.rs=1; value = lcd_read_byte(); lcd.rs=0; return(value); }

Page 34: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 34

数据内型: 下面的表格显示了数据定义的语法.如果关键字 TYPEDEF 在定义之前被使用的话,那么标识

符不会被分配空间,但是,更合适的方法是在其它数据定义期间使用指定的内型.如果关键字

CONST 用在标识符的前面,那么这个标识符被看作是一个常数. 常数必须有一个初始化值,可不随运行时间而改变.指向常数的指针是不允许的. SHORT 是一个特殊的内型,常用来替位操作和 I/O 操作产生有效的代码. SHORT 的数组和

SHORT 的指针不允许的. 注意:下面表格的[]所包含的可选项. DATA DECLARATIONS(数据声明)

[type-qualifier] [type-specifier] [declarator];

enum [id] { [ id [ = cexpr]] }

One or more comma

separated

struct or

union

[*]

[id]

{ [ type-qualifier [ [*]

One or more semi-colon

separated

[*]id cexpr

[ cexpr ] ]]}

Zero or more

typedef [type-qualifier] [type-specifier] [declarator];

enum 后的 id 造成一个足够大的内型,以至最大的常数放在 list 列表里, list 列表里的 id 每一个

自成是一个常数.由默认,第一个 id 被设置成 0,接着她们自加 1,放在 list 列表里.若 a= cexpr 紧

跟在一个 id 的后面,那么这个 id 将有了这个常数表达式的值.接下来列表 id 将在前面值的基

础上加 1;

在 struct or union 里, id 后面的 cexpr 表达式指定的是当前 id 的位数,这个数据可能是 1~8.方挎

号[ ]可被用来定义数组.结构和联合可被嵌套. struct 后面的 id 可被用在另一个 struct 里面.而{ }

不再用来重新使用相同的结构形式. 内型限定词 static 变量是全局激活,初始化为 0 auto 只有当该程序是处于活动状态,变量才存在.默认为 auto 变量, auto 不必用 double 是一个保留字,但不是一个受支持的数据内型 extern 允许当作一个限定词,但没有结果 register 允许当作一个限定词,但没有结果 内型指定 int1 定义成 1 位数据 int8 定义成 8 位数据(1 个字节) int16 定义成 16 位数据(两个字节) int32 定义成 32 位数据(4 个字节)

Page 35: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 35

char 定义成 8 位数据(1 个字节) float 定义成 32 位浮点数 short 默认同 int1 一样,定义成 1 位数据 int 默认同 int8 一样,定义成 8 位数据(1 个字节) long 默认同 int16 一样,定义成 16 位数据(两个字节) void 指出没有具体内型 例子: int a, b, c, d; //声明为整型变量, 定义成 8 位数据(1 个字节) typedef short bit; //将 short 重新定义为 bit typedef int byte; //将 int 重新定义为 byte bit e, f; //声明为位型变量 byte g[3][2]; //声明为字节型数组 char *h; //声明为字节型指针 enum boolean {false, true}; //将 false, true 定义为位量, false 为 0, true 为 1 boolean j; //声明为位变量 byte k=5; //声明为字节型变量,并赋初值 byte const WEEKS=52; //定义为 WEEKS 常数 byte const FACTORS[4]={8, 16, 64, 128}; struct data_recort{

byte a[2]; byte b:2; //两位空间 byte c:3; //3 位空间 int d;

} Typemod 编译器提供 typemod 命令,它常用来定义存储区, 存储区可能是 RAM, program eeprom, data eeprom 或外部存储器. typemod<, read_function, write function, start_address, end_ address>name; 这里的 read_function 和 write function 见下面的范例: void write function(int32 addr, int8 *ram, int nbytes){//从存储器 addr 地址开始读 n 个字节 } 注意:如果这个区定义在 RAM 中,那么 read_function 和 write function 没有要求.由 typemod 定

义,分配在存储区的变量,在所有的有效表达式中,能被看作合格的变量. 例子: void DataEE_Read(int32 addr, int8 *ram, int bytes){

int i; for(i=0; i<bytes; i++, ram++, addr++) *ram=read_eeprom(addr);

Page 36: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 36

} void DataEE_Write(int32 addr, int8 *ram, int bytes){

int i; for(i=0; i<bytes; i++, ram++, addr++) write_eeprom(addr, *ram);

} typemod<, DataEE_Read, DataEE_Write, 5, 0xff> DataEE //在芯片的 data Eeprom 中,从地址 0x5 到 0xff 定义一个供 DataEE 访问的区, void main { int DataEE test; int x, y; x=12; test=x; //将 x 写入 Data EEPROM 中 y=test; //读 Data EEPROM 中的数据 }

Page 37: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 37

ABS() 语法: value=abs(x) 参数: x 是一个有符号的 8,16 或 32 位的整型数或是一个浮点型数. 返回值: 同参数的内型相同. 功能: 计算一个数的绝对值. 有效性: 适合所有设备. 要求: #include<stdlib.h> 例子: signed int target, actual; …

error=abs(target- actual); 例子文件: 没有 ASSERT() 语法: assert(condition) 参数: condition 是任意相关的表达式; 返回值: 没有 功能: 该函数用来测试 condition,如果是 FALSE,在 STDERR 上将产生一个错误信息(程序

默认第一个 USE RS232). 错误信息将包含这个文件和 assert( )的行 .若你使用#define NODEBUG的话,对于 assert( )这个函数将不产生代码.这样,你可将 assert( )包含在你的测试代

码里,就可迅速从 终的程序里排除错误. 有效性: 适合所有设备. 要求: #include<assert.h>和#use rs232 例子: assert(number_of_entries<TABLE_SIZE); //如果 number_of_entries>= TABLE_SIZE,那么下面的内容将在 RS232 输出: //Assertion failed,file myfile.c, line 56 例子文件: 没有 ATOF() 语法: result=atof (string) 参数: string 是指向字符串中没有结束符的那部分文字的指针; 返回值: 结果是一个 32 位的浮点指针数. 功能: 将符合要求的那一串文字转换成浮点表示方式.结果不能表示,则行为没有定义. 有效性: 适合所有设备. 要求: #include<stdlib.h> 例子: char string[10];

Page 38: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 38

float x; strcpy(string,”123.456”); //将”123.456”拷贝到 string 数组 x=atof(string); //x 现在是 123.456 例子文件: ex_tank.c 文件 ex_tank.c 如下: //// This example uses a trig function to calculate the volume of //// //// a fluid in a tank. The tank is in the shape of a large //// //// propane tank. The ends are half of an ellipsoid and the //// //// main body part is a horizontal cylinder. //// #if defined(__PCM__) //若使用了 PCM 编译器,则 defined( __PCM__)返回值为 1 #include <16F877.h> //包含 16F877.h 头文件 #fuses HS, NOWDT, NOPROTECT, NOLVP //HS:高速晶振/谐振器, NOWDT:不使用 WDT // NOPROTECT:程序存储器代码不保护 #use delay(clock=20000000) //使能内置函数的功能:delay_ms()和 delay_us() //#USE DELAY()必须在#use rs232()使用之前出现. #use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)

//使用波特率为 9600, //发送脚为 PIN_ C6 //接收脚为 PIN_ C7 //使能内置函数:GETC,PUTC 和 PRINTF, kbhit();

#elif defined(__PCH__) //若使用了 PCH 编译器,则 defined( __PCH__)返回值为 1 #include <18F452.h> //包含 18F452.h 头文件 #fuses HS, NOWDT, NOPROTECT, NOLVP #use delay(clock=20000000) #use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7) // Jumpers: 8 to 11, 7 to 12 #endif //结束 if 定义 #include <math.h> //包含 math.h 头文件 #include <input.c> //包含 input.c 头文件 #include <stdlib.h> //包含 stdlib.h 头文件 #define NUM_LENGTH 8 //用 NUM_LENGTH 代替 8 main() { float volume, cap_vol, tube_vol, diameter, length=1, cap_length, height, offset_height, tube_length, temp1; //声明浮点型变量 char string[NUM_LENGTH]; //声明数组 string[] short error=FALSE; //声明 error 为位变量,并赋初值 while(TRUE) { do { if(error) printf("\r\nERROR MADE, PLEASE ENTER VALID NUMBERS!!"); printf("\r\n\n***NOTE: ALL DIMENSIONS ARE IN METERS***\r\n"); printf( "Enter dimensions of tank... \r\n Overall length: ");

Page 39: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 39

get_string(string, NUM_LENGTH); length = atof(string); //将符合要求的那一串文字转换成浮点表示方式 printf( "\r\n Cap length: "); get_string(string, NUM_LENGTH); cap_length = atof(string); //将符合要求的那一串文字转换成浮点表示方式 printf( "\r\n Diameter of tank: "); //通过 RS232 送出”桶的直径” get_string(string, NUM_LENGTH); //通过 RS232 读”桶的直径” diameter = atof(string); //将符合要求的那一串文字转换成浮点表示方式 printf("\r\n\nEnter the height of the fluid: "); //通过 RS232 送出”液体的高度” get_string(string, NUM_LENGTH); //通过 RS232 读”液体的高度” height = atof(string); //将符合要求的那一串文字转换成浮点表示方式 tube_length = length - 2*cap_length; if(height>diameter||length<=0||cap_length<0||height<0||tube_length<0) error = TRUE; else error = FALSE; } while(error); offset_height = height - diameter/2; temp1 = pwr(offset_height,3) - 3*diameter*diameter*offset_height/4 - pwr(diameter,3)/4; cap_vol = -PI*cap_length*temp1/(3*diameter); temp1 = sqrt(diameter*diameter/4-offset_height*offset_height); temp1 = PI/2 + 4*offset_height*temp1/(diameter*diameter) + asin(2*offset_height/diameter); tube_vol = tube_length*diameter*diameter*temp1/4; volume = tube_vol + 2*cap_vol; printf("\r\n\nTotal volume of water is: %f gallons\n\n", volume*264.2); } } 文件: input.c 如下: #include <CTYPE.H> //包含 CTYPE.H 头文件 BYTE gethex1() { char digit; //声明字节型变量 digit digit = getc(); //从 RS232 口读一个字节 putc(digit); //向 RS232 口写一个字节 if(digit<='9') //将读到的字节以 16 进制返回 return(digit-'0'); //若读到的 ascii 码小于或等于 39,则将其减 30,以 16 进制返回 else return((toupper(digit)-'A')+10); //若读到的 ascii 码大于 39,则将其减 41,再加 10 返回 } BYTE gethex() {

Page 40: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 40

int lo, hi; //声明整型变量 lo, hi hi = gethex1(); //从 RS232 口读一个字节,存储到 hi 中 lo = gethex1(); //从 RS232 口读一个字节,存储到 lo 中 if(lo==0xdd) return(hi); else return( hi*16+lo ); } void get_string(char* s, int max) { int len; //声明整型变量 len char c; //声明字节型变量 c --max; //初始化 max 值 len=0; //初始化 len 值 do { c=getc(); //从 RS232 口读一个字节,存储到 c 中 if(c==8) { // Backspace 若是空格键 if(len>0) { len--; putc(c); //向 RS232 写 c putc(' '); putc(c); } } else if ((c>=' ')&&(c<='~')) if(len<max) { s[len++]=c; putc(c); } } while(c!=13); s[len]=0; } // stdlib.h is required for the ato_ conversions // in the following functions #ifdef _STDLIB //若定义_STDLIB,则执行下面 signed int get_int() { char s[5]; //声明字符型数组 s[5] signed int i; //声明有符号整型变量 i get_string(s, 5); //从 RS232 口读 5 个字节,存储到 s 数组中 i=atoi(s); //将数组 s[]的字符串转换成整型数送给 i return(i); } signed long get_long() {

Page 41: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 41

char s[7]; //声明字符型数组 s[7] signed long l; //声明有符号长整型变量 l get_string(s, 7); //从 RS232 口读 7 个字节,存储到 s 数组中 l=atol(s); //将数组 s[]的字符串转换成长整型数送给 l return(l); } float get_float() { char s[20]; //声明字符型数组 s[7] float f; //声明符点型变量 f get_string(s, 20); //从 RS232 口读 20 个字节,存储到 s 数组中 f = atof(s); //将数组 s[]的字符串转换成符点数送给 f return(f); } #endif //结束 if 定义 ATOI() ATOL() ATOI32() 语法: ivalue=atoi(string) 或

lvalue=atol(string) 或

i32value=atoi32(string) 参数: string 是指向字符串中没有结束符的那部分文字的指针; 返回值: 结果 ivalue 是一个 8 位整型值.

结果 lvalue 是一个 16 位整型值. 结果 i32value 是一个 32 位整型值.

功能: 将所指向的 string 转换成由 ptr 指向的整型表示方式.符合十进制和十六进制的数都

可接受转换. 结果不能表示的,则行为没有定义. 有效性: 适合所有设备. 要求: #include<stdlib.h> 例子: char string[10]; int x; strcpy(string,”123”); //将”123.456”拷贝到 string 数组 x=atof(string); //x 现在是 123.456 例子文件: input.c BIT_CLEAR() 语法: bit_clear(var, bit) 参数: var 可能是一个 8 位,16 位或 32 位的变量(任意的整型变量);bit 是 0~31 中的一个数,

Page 42: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 42

表示 1 位数.0 是 小的一位,也是 重要的的一位. 返回值: 没有 功能: 只是将所给的变量指定的位(位 0~位 7, 位 0~位 15, 位 0~位 31)进行清 0.该函数相

当于 var&=~(1<<bit). 有效性: 适合所有设备. 要求: 没有 例子: int x; x=5; bit_clear(x, 2); //x 现在是 1 bit_clear(*11, 7); //一个笨方法,不使能 ints(中断); 例子文件: ex_patg.c 文件: ex_patg.c 如下: #if defined(__PCM__) //若使用了 PCM 编译器,则 defined( __PCM__)返回值为 1 #include <16F877.h> //包含 16F877.h 头文件 #fuses HS, NOWDT, NOPROTECT, NOLVP //HS:高速晶振/谐振器, NOWDT:不使用 WDT // NOPROTECT:程序存储器代码不保护 #use delay(clock=20000000) //使能内置函数的功能:delay_ms()和 delay_us() //#USE DELAY()必须在#use rs232()使用之前出现. #elif defined(__PCH__) #include <18F452.h> #fuses HS, NOWDT, NOPROTECT, NOLVP #use delay(clock=20000000) #endif //结束 if 定义 #define NUM_OUTPUTS 7 //用 NUM_OUTPUTS 代替 7 //NOTE: periods MUST be multiples of 400 注意:周期必须是 400 的倍数 //Periods are in microseconds 周期的单位是微秒(us) #define PERIOD_0 400 //用 PERIOD_0 代替 400 #define PERIOD_1 800 //用 PERIOD_1 代替 800 #define PERIOD_2 1600 //用 PERIOD_2 代替 1600 #define PERIOD_3 2000 //用 PERIOD_3 代替 2000 #define PERIOD_4 20000 //用 PERIOD_4 代替 20000 #define PERIOD_5 64000 //用 PERIOD_5 代替 64000 #define PERIOD_6 2000000 //用 PERIOD_6 代替 2000000 const long wave_period[NUM_OUTPUTS] = { PERIOD_0/400, PERIOD_1/400, PERIOD_2/400, PERIOD_3/400, PERIOD_4/400, PERIOD_5/400, PERIOD_6/400}; //声明常数数组 wave_period[7] long counter[NUM_OUTPUTS] = {0,0,0,0,0,0,0}; //声明长整型数组 counter[7] int port_b_image; //声明 port_b_image 为整型变量 // This interrupt is used to output the waveforms.这个中断用来输出波形 // The interrupt is automatically called ever 200us.这个中断每 200us 自动被雕用一次 #INT_TIMER1 //指定下面的函数是 timer1 的中断服务函数 void wave_timer() { int i; //声明 i 为整型变量 set_timer1(0xFC4F); // sets timer to interrupt in 200us(预置值为:65535-200/(4/20)=0xfc17 )

Page 43: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 43

output_b(port_b_image); // b 口输出波形 for(i=0; i<NUM_OUTPUTS; i++) // sets up next output for each pin { if((++counter[i]) == wave_period[i]) // counter[i]加 1 后同 wave_period[i]相等吗? { counter[i] = 0; //counter[i]加 1 后存到 counter[i]中,若同 wave_period[i]相等,则清 0 if(bit_test(port_b_image,i)) //测试 port_b_image 的第 i 位 bit_clear(port_b_image,i); //若 port_b_image 的第 i 位为 1,则将该位清 0 else bit_set(port_b_image,i); //若 port_b_image 的第 i 位为 0,则将该位置 1 } } } void main() { setup_timer_1(T1_INTERNAL|T1_DIV_BY_1);

//初始化定时器 1, //时钟源为内部指令时钟 //不用分频器,即每一指令时钟到来,T1 计数一次 enable_interrupts(INT_TIMER1); // timer1 中断允许位置 1 enable_interrupts(GLOBAL); //开总中断允许位 port_b_image=0; //初始化变量 port_b_image 给其赋初值 0 output_b(port_b_image); //b 口全部输出 0 while(TRUE); //循环等待 } 上面的例子告诉我们 B0 输出 400us 周期的方波, B1 输出 800us 周期的方波, B2 输出 1600us周期的方波, B3 输出 2000us 周期的方波, B4 输出 20000us 周期的方波, B5 输出 64000us 周期

的方波, B6 输出 2000000us 周期的方波. BIT_SET() 语法: bit_set(var, bit) 参数: var 可能是一个 8 位,16 位或 32 位的变量(任意的整型变量);bit 是 0~31 中的一个数,表示 1 位数.0 是 小的一位,也是 重要的的一位. 返回值: 没有 功能: 只是将所给的变量指定的位(位 0~位 7, 位 0~位 15, 位 0~位 31)进行置 1.该函数相

当于 var|=(1<<bit). 小的一位,也是 重要的的一位是 0. 有效性: 适合所有设备. 要求: 没有 例子: int x; x=5; bit_set(x, 3); //x 现在是 13 bit_ set (*6, 1); //一个笨方法将 pin_B1 置高;

Page 44: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 44

例子文件: ex_patg.c,在前面已介绍过了,不再叙述. BIT_TEST() 语法: value=bit_test(var, bit) 参数: var 可能是一个 8 位,16 位或 32 位的变量(任意的整型变量);bit 是 0~31 中的一个数,表示 1 位数.0 是 小的一位,也是 重要的的一位. 返回值: 0 或 1 功能: 只是对所给的变量指定的位(位 0~位 7, 位 0~位 15, 位 0~位 31)进行 test. 小的一

位,也是 重要的的一位是 0.该函数比前面的更能干.但在其它方面相当于((var&(1<bit))!=0). 有效性: 适合所有设备. 要求: 没有 例子: if( bit_test(x, 3) || !bit_test(x, 1) ){; } //位 3 是 1 或位 1 是 0,则空操作一次 if(data!=0) for(i=31; !bit_test(data,i); i--);

//i 现在有了许多有意义的位,直到 data 中的一位被置 1 例子文件: ex_patg.c,在前面已介绍过了,不再叙述. BSEARCH() 语法: ip=bsearch(&key, base, num, width, compare) 参数: key: 是要搜寻的目标;

base: 是搜寻数据的数组的指针; num: 是在搜寻数据中的元素的个数; width: 是在搜寻数据中的元素的宽度; compare: 是在搜寻数据中,两个元素进行比较;

返回值: 在由 base 指向的数组里,若出现 key,则将返回 key 所对应的指针;若没有发现 key,函数将返回 NULL.若数组不整齐或不包含同 key 一样的副本记录,则结果是不可预知的. 功能: 执行一种数组的二进制搜寻. 有效性: 适合所有设备. 要求: #include<stdlib.h> 例子: int nums[5]={1,2,3,4,5}; int compar(const void *arg1,const void *arg2) void main(){ int *ip, key; key=3; ip=bsearch(&key, nums, 5, sizeof(int), compar);

} int compar(const void *arg1, const void *arg2){ if( *(int*)arg1<( *(int*)arg2 ) ) return –1; else if( *(int*)arg1==( *(int*)arg2 ) ) return 0;

Page 45: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 45

else return 1; 例子文件: 没有 CALLOC() 语法: ptr=calloc(nmen, size) 参数: nmen: 是一个整数,表示目标成员的个数; size: 是分配给每一个成员的字节数. 返回值: 若有,则返回的是一个分配给存储器的指针;否则,返回 null. 功能: calloc 函数是替数组 nmen 个目标分配空间, 每个目标的字节数大小由 size 指定,空间所有位都被初始成 0. 有效性: 适合所有设备. 要求: #include<stdlibm.h> 例子: int *iptr; iptr=calloc(5,10); //iptr 将指向一个有 50 个字节的存储区,且所有值都初始为 0 例子文件: 没有 CEIL() 语法: result=ceil(value) 参数: value 是一个浮点数; 返回值: 是一个浮点数; 功能: 计算 小的整数值,但比所给的 value 值要大.如:CEIL(12.67)就是 13.00; 有效性: 适合所有设备. 要求: #include<math.h> 例子: cost=ceil(weight)*DollarsPerPound; 例子文件: 没有 CLEAR_INTERRUPT() 语法: clear_interrupt(level) 参数: level 是一个在 device.h 文件中定义的常数. 返回值: 没有. 功能: 将指定的中断标志位清 0.该函数同特定的中断一起被使用.这样,就会除去 GLOBAL的位和相应的中断标志位清 0. 有效性: 适合所有设备. 返回值: 没有 例子: clear_interrupt(int_timer1); //清除 GLOBAL 和相关的 timer1 中断标志位. 例子文件: 没有 DELAY_CYCLES() 语法: delay_cycles(count)

Page 46: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 46

参数: count 是一个常数(1~255); 返回值: 没有. 功能: 执行指定数的指令时钟(1~255) 延时,一个指令时钟等于 4 个晶振时钟.在延时期间,若有中断产生, 延时时间比指定数的指令时钟要长.由于时间花费在 ISR 中断程序上,所以延

时时间不向前计数. 有效性: 适合所有设备. 返回值: 没有 例子: delay_cycles(1); //相当于一个 NOP delay_cycles(25);

//在晶振为 20MHz 时,执行的是 5us 的延时{(1/(20*1000000)*4*25)秒}; 例子文件: ex_cust.c,在前面已介绍过了,不再叙述. DELAY_MS() 语法: delay_ms(time) 参数: time 是一个变量(变量值范围 0~255)或是一个常数(常数值范围 0~65535); 返回值: 没有 功能: 执行指定长度的延时.被指定为 time 个毫秒.该函数工作由执行精确数的指令个数,产生符合要求的延时.它不使用任何定时器.如果有中断服务程序被执行,由于时间花费在中

断服务程序上而使时间不向前计数. 在延时期间,若有中断产生, 延时时间要比要求的时间要长. 由于时间花费在 ISR中断程序上,所以延时时间不向前计数. 有效性: 适合所有设备. 要求: 必须使用#use delay,才能使能函数 delay_ms(time). 例子: #use delay(clock=20000000) delay_ms(2); void delay_seconds(int n){ for(; n!=0; n--) delay_ms(1000); } 例子文件: ex_sqw.c,在前面已介绍过了,不再叙述. DELAY_US() 语法: delay_us(time) 参数: time 是一个变量(变量值范围 0~255)或是一个常数(常数值范围 0~65535); 返回值: 没有 功能: 执行指定长度的延时.被指定为 time 个微秒.短延时出现在 INLINE 代码中,而长延时

和变量延时是出现在调用函数中. 该函数工作由执行精确数的指令个数,产生符合要求的延

时.它不使用任何定时器.如果有中断服务程序被执行,由于时间花费在中断服务程序上而使

时间不向前计数. 在延时期间,若有中断产生, 延时时间要比要求的时间要长. 由于时间花费在 ISR

Page 47: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 47

中断程序上,所以延时时间不向前计数. 有效性: 适合所有设备. 要求: 必须使用#use delay,才能使能函数 delay_ms(time). 例子: #use delay(clock=20000000) do{ output_high(PIN_B0); delay_us(duty); output_low(PIN_B0); delay_us(period-duty); }while(TRUE); 例子文件: ex_sqw.c,在前面已介绍过了,不再叙述. DISABLE_INTERRUPTS() 语法: disable_interrupts(level) 参数: level 是一个定义在 device.h 的头文件中. 返回值: 没有 功能: 不使能指定的 level 中断.GLOBAL 位将不是不使能任何具体的中断,而是阻止任何

具体的中断 ,先前使能的中断还是可以被激活的 .要使具体的中断允许位有效 ,同使用

#INT_XXX 是一样的, 具体的中断允许位列表在 device.h 的头文件中. GLOBAL 也会不使能

外部中断(设备要有外部中断,才可以).注意:当然中断自动不使能,在中断服务程序里不使能

中断,这已经不太重要了. 有效性: 适合 PCM 和 PCH 带有中断的设备. 要求 : 必须使用#int_xxxx,才能使能函数 disable_interrupts(level). level 是一个定义在

device.h 的头文件中. 例子: disable_interrupts(GLOBAL); //关闭所有的中断 disable_interrupts(INT_RDA); //关闭 RS232 中断 enable_interrupts(ADC_DONE); //AD 转换中断使能,但 GLOBAL 位没有置 1 enable_interrupts(RB_CHANGE); //RB口电平变化中断使能,但GLOBAL位没有置 1 enable_interrupts(GLOBAL); //开总中断允许位 例子文件: ex_sisr.c 和 ex_stwt.c,在前面已介绍过了,不再叙述. DIV() LDIV() 语法: idiv=div(num, denom) ldiv=ldiv(lnum, ldenom) idiv=ldiv(lnum, ldenom) 参数: num 和 denom 是有符号的整型数; num 是分子, denom 是分母; lnum 和 ldenom 是有符号的长整型数; lnum 是分子, ldenom 是分母;

Page 48: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 48

返回值: idiv 是 div_t 型的目标,而 ldiv 是 ldiv_t 型的目标; div 函数返回的是 div_t 型的结构,由商和余数两部分组成; ldiv 函数返回的是 ldiv_t 型的结构,由商和余数两部分组成;

功能: div和 ldiv函数用来通过分子除以分母来计算商和余数.如果除以不精确,结果商是较

接近代数商的整型数量或是较接近代数商的长整型数量.如果结果不存在,则不进行除法运算,否则,num(分子)=quot(商)* denom(分母)+rem(余数);

lnum(分子)= quot (商)* ldenom(分母)+rem(余数); lnum(分子)= quot (商)* ldenom(分母)+rem(余数);这些等式必须存在.

有效性: 适合所有设备. 要求: #include<STDLIB.h> 例子: div_t idiv; ldiv_t lidiv; idiv=div(3, 2); //idiv 包含 quot (商)=1, rem(余数)=1; lidiv=ldiv(300, 250); //lidiv 包含 quot (商)=1, rem(余数)=50; 例子文件: 没有 ENABLE_ITERRRUPTS() 语法: enable_interrupts(level) 参数: level 是一个定义在 device.h 的头文件中. 返回值: 没有 功能: 将指定的中断允许位使能,定义一个中断程序表示中断.GLOBAL 位不会使能任意具

体的中断,只是允许先前使能的具体中断才能被激活. 有效性: 适合 PCM 和 PCH 带有中断的设备. 要求 : 必须使用#int_xxxx,才能使能函数 enable_interrupts(level). level 是一个定义在

device.h 的头文件中. 例子: enable_interrupts(GLOBAL);

enable_interrupts(INT_TIMER0); enable_interrupts(INT_TIMER1);

例子文件: ex_sisr.c 和 ex_stwt.c,在前面已介绍过了,不再叙述. ERASE_PROGRAM_EEPROM() 语法: erase_program_eeprom(address) 参数: address 在 PCM 器件中是 16 位,而在 PCH 器件中是 32 位.不太重要的可能被忽略. 返回值: 没有 功能: 将程序存储器中的 EEPROM 擦除 FLASH_ERASE_SIZE 个字节,使其变为 0xffff, FLASH_ERASE_SIZE随器件不同而变化.例如:如果 FLASH_ERASE_SIZE是 64个字节,那么

地址中的不太重要的 6 位被忽略. 参考 write_program_memory 可获取关于程序存储器入口的更多信息. 有效性: 只适合允许写程序存储器的器件. 要求: 没有

Page 49: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 49

例子: for(i=0x1000; i<0x1fff; i+=getenv(“FLASH_ERASE_SIZE”) ) erase_program_ memory(i); 例子文件: 没有 EXP() 语法: result=exp(value) 参数: value 是一个浮点数; 返回值: 是一个浮点数; 功能 : 计算幂的函数 , 这里是计算 e 的幂函数 . 这里的 e 是自然对数的底

数.exp(1)=2.7182818. 注意:若有错误,就会挂起: 如果包含了 errno.h 头文件,那么错误范围被存入 errno 变量里.用户能通过检查 errno

变量可发现是否有错误存在,并可用 perror 函数打印这个错误. 错误范围是由下面的原因产生: exp: 当结果太大.

有效性: 适合所有设备. 要求: 必须包含 math.h 的头文件,才能使能函数 result=exp(value). 例子: x_power_y=exp( y * log(x) ); //计算 x 的 y 次幂,这里的 log(x)是代数中的 ln(x) 例子文件: 没有 EXT_INT_EDGE() 语法: ext_int_edge(source, edge) 参数: source 在 PIC18XXX 中是 0, 1,或 2 的常数,除 PIC18XXX 之外 source 是一个 0 的常

数,除此之外 source 是一个可选项;在通常情况下, source 的默认值为 0. edge 是 H_TO_L 或 L_TO_H 的常数. H_TO_L 代表“high to low”, L_TO_H 代表“low to high”. 返回值: 没有 功能: 决定什么时候产生外部中断. L_TO_H 指定上升沿产生外部中断; H_TO_L 指定下降

沿产生外部中断; 有效性: 只适合 PCM 和 PCH 带有外部中断的器件. 要求: 必须包含 devices.h 的头文件,常数 H_TO_L 和 L_TO_H 位于 devices.h 的头文件中. 例子: ext_int_edge(2, L_TO_H); //设定 PIC18 外部中断 2(EXT2) ext_int_edge(H_TO_L); //由于 source 的默认值为 0,所以设定的是外部中断 0 例子文件: ex_wakeup.c 文件: ex_wakeup.c 如下: #if defined(__PCM__) //若使用了 PCM 编译器,则 defined( __PCM__)返回值为 1 #include <16F877.h> //包含 16F877.h 头文件 #fuses HS, NOWDT, NOPROTECT, NOLVP //HS:高速晶振/谐振器, NOWDT:不使用 WDT // NOPROTECT:程序存储器代码不保护 #use delay(clock=20000000) //使能内置函数的功能:delay_ms()和 delay_us()

Page 50: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 50

//#USE DELAY()必须在#use rs232()使用之前出现. #use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)

//使用波特率为 9600, //发送脚为 PIN_ C6 //接收脚为 PIN_ C7 //使能内置函数:GETC,PUTC 和 PRINTF, kbhit();

#elif defined(__PCH__) #include <18F452.h> #fuses HS, NOWDT, NOPROTECT, NOLVP #use delay(clock=20000000) #use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7) // Jumpers: 8 to 11, 7 to 12 #endif //结束 if 定义 // global flag to send processor into sleep mode short sleep_mode; //声明位变量 sleep_mode // external interrupt when button pushed and released #INT_EXT //指定下面的函数是 int0 的外部中断服务函数 void ext_isr() { static short button_pressed=FALSE; //声明静态位变量 button_pressed,并赋初值 FALSE if(!button_pressed) // if button action and was not pressed { button_pressed=TRUE; //若 button_pressed 为低电平,则将 button_pressed 赋值 TRUE sleep_mode=TRUE; // activate sleep 设置睡眠软件标志位 printf("The processor is now sleeping.\r\n"); ext_int_edge(L_TO_H); // L_TO_H 指定 int0 上升沿产生外部中断 } else // if button action and was pressed { button_pressed=FALSE; //若 button_pressed 为高电平,则将 button_pressed 赋值 FALSE sleep_mode=FALSE; // reset sleep flag ext_int_edge(H_TO_L); // H_TO_L 指定下降沿产生外部中断 } if(!input(PIN_B0)) // keep button action sychronized wth button flag button_pressed=TRUE; //若 PIN_B0 脚为低电平,则将 button_pressed 赋值 TRUE delay_ms(100); // debounce button 按键去抖 } // main program that increments counter every second unless sleeping void main() { long counter; //声明长整型变量 counter sleep_mode=FALSE; // init sleep flag 将 sleep_mode 置为 FALSE ext_int_edge(H_TO_L); // H_TO_L 指定下降沿产生外部中断 enable_interrupts(INT_EXT); //外部中断允许位置 1 enable_interrupts(GLOBAL); //开总中断允许 printf("\n\n");

Page 51: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 51

counter=0; // reset the counter 将 counter 置 0 while(TRUE) { if(sleep_mode) // if sleep flag set 若睡眠软件标志位为 1,则执行睡眠 sleep(); // make processor sleep 使 CPU 进入睡眠状态 printf("The count value is: %5ld \r\n",counter); counter++; // display count value and increment delay_ms(1000); // every second } } 上面的例子通过外部中断来唤醒 CPU. FABS() 语法: result=fabs(value) 参数: value 是一个浮点数; 返回值: 返回值 result 是一个浮点数; 功能: fabs 函数是用来计算一个浮点数的绝对值; 有效性: 适合所有设备. 要求: 必须包含 math.h 的头文件; 例子: float result; result=fabs(-40.0); // result 现在是 40.0 例子文件: 没有 FLOOR() 语法: result=floor(value) 参数: value 是一个浮点数; 返回值: 返回值 result 是一个浮点数; 功能: floor 函数是用来计算一个浮点数的 大整数值,但不比这个浮点数大.floor(12.67)的返回值是 12.00; 有效性: 适合所有设备. 要求: 必须包含 math.h 的头文件; 例子: frac=value-floor(value); // frac 是 value的小数部分, floor(value)是计算 value的 大

整数值部分 例子文件: 没有 FMOD() 语法: result=fmod(val1, val2) 参数: val1 和 val2 是两个浮点数;

Page 52: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 52

返回值: 返回值 result 是一个浮点数; 功能: fmod 函数返回的是 val1/ val2 的余数,为浮点型.返回值为 val1-i* val2,这里的 i 是val1/ val2 的商;若 val2 是非 0 的数,则 result 的符号同 val1 相同,在数值上要比 val2 的值小. 有效性: 适合所有设备. 要求: 必须包含 math.h 的头文件; 例子: float result; result=fmod(3, 2); // result 为 3/2 的余数,是 1; 例子文件: 没有 FREE() 语法: free(ptr) 参数: ptr 是由 calloc, malloc 或 realloc 返回的指针; 返回值: 没有 功能: free 函数将产生由 ptr 指针指向分离的分配空间,创造可利用的更远的分配空间.若ptr 不是指针,则不执行该函数,若 ptr 不是由函数 calloc, malloc 或 realloc 返回的指针或不是由

free 访问的分离的分配空间,则该行为没有定义. 有效性: 适合所有设备. 要求: 必须包含 stdlibm.h 的头文件; 例子: int *iptr; iptr= malloc (10); free(iptr); 例子文件: 没有. FREXP() 语法: result=frexp(value, &exp); 参数: value 是一个浮点数; exp 是一个有符号的整型数; 返回值: 返回值 result 是一个浮点数; GET_TIMERx() 语法: value=get_timer0() same as: value=get_rtcc() value=get_timer1() value=get_timer2() value=get_timer3() value=get_timer4() value=get_timer5()

Page 53: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 53

参数: 没有 返回值: 定时器 1,3 和 5 的返回值是 16 位的整型值; 定时器 2 和 4 的返回值是 8 位的整型值; Timer0(也就是 RTCC) 的返回值是 8 位的整型值,而在 PIC18XXX 中,Timer0(也就是

RTCC) 的返回值是 16 位的整型值. 功能: 返回的是实时时钟/计数器的计数值.RTCC 同 timer0 是相同的.所有的 timer 向上计

数.当 timer 到达 大值,它将跳到 0,继续计数(254,255,0,1,2,3…) 有效性: 适合所有设备的 timer0. Timer1 和 Timer2 适合大多数器件,但不适合 PCM 的 MCU 器件; Timer3 只适合 PIC18XXX 的的 MCU 器件;

Timer4 只适合部分的 PCH 的的 MCU 器件; Timer5 只适合 PIC18XX31 的的 MCU 器件;

返回值: 没有 要求: 没有 例子: set_timer0(0); while(get_timer0() <200); 例子文件: ex_stwt.c,在前面已介绍过了,不再叙述. GETC() GETCH() GETCHAR() FGETC() 语法: value=getc()

value=fgetc(stream) value=getch() value=getchar()

参数: stream 是一串标识符(一个常数字节). 返回值: 返回值是一个 8 位字符; 功能: 该函数等待一个字符,通过 RS232 的 RCV 脚接收进来,并且返回这个字符.如果你不

想为接收一个字符而永远等待挂起的话,可使用 kbhit()来测试一个字符是否有效.如果内置的

USART 使用的是硬件串行中断的话,缓冲区为 3 个字符空间,否则,当这个字符正被 PIC 接收

的时候, getc()必须被激活. 如果 fgetc(stream)被使用的话,那么指定的 stream 就被使用了,这里的 fgetc(stream)默

认为 STDIN( 后一次使用的 USE RS232) 有效性: 适合所有的设备 要求: 必须使用#use rs232 才可使能上面的函数. 例子: printf(“Continue (Y,N)?”);

do{ answer=getch(); }while(answer!=’Y’ && answer!=’N’); #use rs232(baud=9600, ximt=pin_c6, rcv=pin_c7, stream=GPS) #use rs232(baud=1200, ximt=pin_b1, rcv=pin_b0, stream=GPS)

Page 54: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 54

#use rs232(baud=9600, ximt=pin_b3, stream=DEBUG) … while(TRUE){ c=fgetc(GPS); fputc(c, HOSTPC); if(c==13) fprintf(DEBUG, “Got a CR\r\n”); }

例子文件: ex_stwt.c,在前面已介绍过了,不再叙述. GETENV() 语法: value=getenv(cstring); 参数: cstring 是公认的关键字,为一个常数文字. 返回值: 返回值是一个常数, 一个常数文字,或 0; 功能: 该函数用来获取执行环境的信息.下面是公认的关键字.如果关键字不是公认的, 函数的返回值是 0. FUSE_SET 若 fuse ffff 使能的话, ffff 返回 1 FUSE_VALID 若 fuse ffff 正确的话, ffff 返回 1 INT:iiiii 若中断 iiiii 正确的话, 则返回 1 ID 返回设备 ID(采用#ID 设定) DEVICE 返回设备名字文字(如”PIC16C74”) VERSION 返回编译器的版本,是浮点数 VERSION_STRING 返回编译器的版本,是文字 PROGRAM_MEMORY 返回存放代码的存储器大小(用字为单位) STACK 返回堆栈的大小 DATA_EEPROM 返回 data EEPROM 的字节数 READ_PROGRAM 若代码存储器可读的话,则返回 1 PIN:pb 若元件上有端口 p 的 b 位,则返回 1 ADC_CHANNELS 返回 A/D 通道的数量 ADC_RESOLUTION 从 read_adc()返回的位的位数 ICD 若 ICD 被编译的话,则返回 1 SPI 若设备上有 SPI,则返回 1 USB 若设备上有 USB,则返回 1 CAN 若设备上有 CAN,则返回 1 I2C_SLAVE 若设备上有 I2C slave H/W,则返回 1 I2C_MASTER 若设备上有 I2C master H/W,则返回 1 PSP 若设备上有 PSP,则返回 1 COMP 若设备上有比较器,则返回 1 VREF 若设备上有参考电压,则返回 1 LCD 若设备上有 direct LCD H/W,则返回 1 UART 返回 H/W UART 的数量 CCPx 若设备上有 CCPx(x 是数字),则返回 1 TIMERx 若设备上有 TIMERx (x 是数字),则返回 1

Page 55: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 55

FLASH_WRITE_SIZE 能被写入 FLASH 里 小字节数 FLASH_ERASE_SIZE FLASH 可被擦除的 小字节数 BYTES_PER_ADDRESS 返回地址处的字节数 BITS_PER_INSTRUCTION 返回一条指令的位数大小 有效性: 适合所有的设备 要求: 没有 例子: #if getenv(“VERSION”)<3.050

#ERROR Compiler version too old #endif for(i=0, i<getenv(“DATA_EEPROM”); i++) write_eeprom(i, 0); #if getenv(“FUSE_VALID:BROWNOUT”) #FUSE BROWNOUT #endif 例子文件: 没有; GETS() FGETS() 语法: gets(string) value=fgets(string, stream) 参数: string 是一个指向字符数组的指针. stream 是一串标识符(为一个常数字节) 返回值: 没有; 功能: 该函数用来将字符读入 string 里(如同使用 GETC()一样),直到 RETURN 出现为止. string 以 0 为结束符.注意:INPUT.C 里有一个较通用的 GET_STRING()的函数. 如果 fgets()被使用的话 ,那么指定的 stream 就被使用了 ,这里的 gets()默认为

STDIN( 后的 USE RS232). 有效性: 适合所有的设备. 要求: #use rs232 例子: char string[30]; printf(“Password: ”); gets(string); if(strcmp(string, password) ) printf(“OK”); 例子文件: 没有; GOTO_ADDRESS() 语法: goto_address(location) 参数: location 是一个 ROM 的地址,16 位整型数或 32 位整型数; 返回值: 没有;

Page 56: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 56

功能: 该函数用来跳到由 location 指定的 ROM 地址处.只是跳到当前函数的外部去执行,应该会产生严重警告.这不是一种普通的使用函数方式,除非是在很特殊的情况下才使用. 有效性: 适合所有的设备. 要求: 没有. 例子: #define LOAD_REQUEST PIN_B1 #define LOADER 0x1f00

if(input(LOAD_REQUEST) ) goto_address(LOADER)

例子文件: setjmp.h I2C_ISR_STATE() 语法: state=i2c_isr_state( ); 参数: 没有. 返回值: 返回值是一个 8 位整型. 0---接收地址匹配,R/W 位被清除; 1~0x7F---主机已写数据;i2c_read()将立即返回这个数据; 0x80---接收地址匹配,R/W 位被置 1;同 i2c_write()响应; 0x81~0xff---发送完成; i2c_write()响应应答. 功能: 在一个 SSP 中断之后,在 i2c 的从机方式里,该函数返回的是 i2c 通讯的状态,该返回

值在每次发送或接收一个字节时,都会产生中断. 有效性: 适合带有 i2c 硬件的设备. 要求: 必须使用#use i2c,才可使能 i2c_isr_state( ); 例子: #INT_SSP //SPI 口或 I2C 被激活,指出下面的函数是一个中断服务函数 void i2c_isr(){

state=i2c_isr_state(); if(state>=0x80) i2c_write( send_buffer[state-0x80] ); else if(state>0) rcv_buffer[state-1]=i2c_read();

} 例子文件: ex_slave.c 文件 ex_slave.c 如下: #if defined(__PCM__) //若使用了 PCM 编译器,则 defined( __PCM__)返回值为 1 #include <16F877.h> //包含 16F877.h 头文件 #fuses HS, NOWDT, NOPROTECT, NOLVP //HS:高速晶振/谐振器, NOWDT:不使用 WDT // NOPROTECT:程序存储器代码不保护 #use delay(clock=20000000) //使能内置函数的功能:delay_ms()和 delay_us() //#USE DELAY()必须在#use rs232()使用之前出现. #use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)

//使用波特率为 9600, //发送脚为 PIN_ C6 //接收脚为 PIN_ C7

Page 57: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 57

//使能内置函数:GETC,PUTC 和 PRINTF, kbhit(); #elif defined(__PCH__) #include <18F452.h> #fuses HS,NOWDT,NOPROTECT,NOLVP #use delay(clock=20000000) #use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7) // Jumpers: 8 to 11, 7 to 12 #endif //结束 if 定义 #use i2c(SLAVE, SDA=PIN_C4, SCL=PIN_C3, address=0xa0) // SLAVE 指定本机为从机方式 //除非指定了 FORCE_HW,否则会产生模拟 I2C 的软件函数.

//使能 I2C_START, I2C_STOP 直到下一个#USE I2C 的出现为止. //使能 I2C_READ, I2C_WRITE 直到下一个#USE I2C 的出现为止. //使能 I2C_POLL 直到下一个#USE I2C 的出现为止.

//指定 SDA 脚为 PIN_C4, 指定 SCL 脚为 PIN_C3; // address 指定从机方式的地址为 0xa0; typedef enum {NOTHING, CONTROL_READ, ADDRESS_READ, READ_COMMAND_READ} I2C_STATE; I2C_STATE fState; BYTE address, buffer[0x10]; //声明字节变量 address,数组 buffer[0x10] #INT_SSP //SPI 口或 I2C 被激活,指出下面的函数是一个中断服务函数 void ssp_interupt () { BYTE incoming; //声明字节变量 incoming; if (i2c_poll() == FALSE) { //若主机读本从机时, i2c_poll()返回 FALSE 值,执行下面的语句 if (fState == ADDRESS_READ) { //若已读到数据的地址, 则执行下面的语句 i2c_write (buffer[address]); //将指定地址(address)处的数据发给主机 fState = NOTHING; //为接收下一个数据的地址做准备 } } else { // 若 SSP 缓冲器接收到一个字节,i2c_poll()的返回值为 TRUE,执行下面的语句

incoming = i2c_read(); //通过 i2c 口读一个字节(该字节可能是器件的地址,数据的地址或数据,也可能什么都不是) if (fState == NOTHING){ fState = CONTROL_READ; } else if (fState == CONTROL_READ) { address = incoming; //接收存放数据的地址 fState = ADDRESS_READ; } else if (fState == ADDRESS_READ) { buffer[address] = incoming; //向 address 地址处写数据 fState = NOTHING;

Page 58: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 58

} } } void main () { int i; //声明整型变量 i; fState = NOTHING; //给 fState 赋初值 address = 0x00; //给 address 赋初值 for (i=0;i<0x10;i++) buffer[i] = 0x00; //给数组 buffer[0x10] 赋初值 enable_interrupts(GLOBAL); //开总中断允许 enable_interrupts(INT_SSP); //SPI 口或 I2C 中断允许位置 1 while (TRUE) {} //循环等待中断 } 上面的程序用 PIC 从机方式来模拟 EEPROM(24C01),只能向地址 0x00~0x10 写数据. I2C_POLL() 语法: i2c_poll( ); 参数: 没有. 返回值: 返回值为 1(TRUE)或 0(FALSE); 功能: i2c_poll()函数只可用于内置的 SSP 被使用的情况下.如果 SSP 硬件中有一个接收的

字节在 buffer 中,则该函数返回 TRUE.当一个 TRUE 被返回时,必须立即调用 i2c_read()函数,返回接收到的字节. 有效性: 适合带有 i2c 硬件的设备. 要求: 必须使用#use i2c,才可使能 i2c_poll( ); 例子: i2c_start(); //i2c 发送启动条件 i2c_write(0xc1); //发送器件地址 count=0; while(count!=4){

while( !i2c_poll() ); //等待接收数据,若收到数据,则执行下一句; buffer[count++]=i2c_read(); //将读到的数据存到 buffer[]中;

} i2c_stop(); //i2c 发送停止条件; 例子文件: ex_slave.c;文件 ex_slave.c 在前面已经介绍过了,在此不在叙述. I2C_READ() 语法: data=i2c_read( ); 或

Page 59: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 59

data= i2c_read(ack); 参数: ack---可选项 ack 的默认值为 1. 0 表示不应答; 1 表示应答. 返回值: data---是一个 8 位整型数. 功能: 通过 I2C 接口读一个字节.在主机方式下,该函数将产生 I2C 的时钟;在从机方式下, 该函数将等待时钟.为了防止死循环,使用 I2C_POLL 函数,从机就没有时间休息等待.在#USE I2C 中使用 RESART_WDT,为的是在从机方式中等待时,重新起动看门狗顶事期. 有效性: 适合带有 i2c 硬件的设备. 要求: 必须使用#use i2c,才可使能 i2c_read( ); 例子: i2c_start(); //i2c 发送启动条件 i2c_write(0xa1); //发送器件地址 0xa1 data1=i2c_read(); //将读到的数据存到 data1 中,ack 的默认值为 1, 表示应答; data1=i2c_read(); //将读到的数据存到 data2 中; i2c_stop(); //i2c 发送停止条件; 例子文件: ex_extee.c 和 2416.c;这两个文件在前面已做介绍,这里不在介绍. I2C_START( ) 语法: i2c_start( ); 参数: 没有. 返回值: 没有定义; 功能: 在 i2c 主机方式中,i2c_start()函数用来发布一个启动条件.在启动条件之后,时钟被控

制在低电平,直到 i2c _write()函数被调用为止.如果在 i2c_stop()函数被调用之前,又有一个

i2c_start()函数被调用,那么这种特定的重起条件就被发布了.注意:专用的 I2 协议依靠从机设

备. 启动条件: 在 SCL 脚为高电平时,SDA 脚出现一个下降沿,则启动 I2C 总线; 停止条件: 在 SCL 脚为高电平时,SDA 脚出现一个上升沿,则停止使用 I2C 总线; 接收应答 ACK: 发送器保持 SDA 为高电平,由接收器将 SDA 拉低,称为应答信号 ACK; 非应答信号 NOT ACK: 当主器件为接收器时,在接收了 后一个字节之后,它不发应答信号; 有效性: 适合所有的设备. 要求: 必须使用#use i2c,才可使能 i2c_start( ) 函数; 例子: i2c_start(); //i2c 发送启动条件 i2c_write(0xa0); //发送器件地址 0xa0 i2c_write(address); //i2c 发送数据给从机设备 i2c_start(); //i2c 发送重新启动条件 i2c_write(0xa1); //发送器件地址 0xa1 给另外一个从机设备

data=i2c_read(0); //将读到的数据存到 data 中, 0 表示不应答; i2c_stop(); //i2c 发送停止条件;

例子文件: ex_extee.c 和 2416.c;这两个文件在前面已做介绍,这里不在介绍. I2C_STOP( ) 语法: i2c_stop( );

Page 60: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 60

参数: 没有. 返回值: 没有定义; 功能: 在 i2c 主机方式中, i2c_stop( )函数用来发布一个停止条件. 启动条件: 在 SCL 脚为高电平时,SDA 脚出现一个下降沿,则启动 I2C 总线; 停止条件: 在 SCL 脚为高电平时,SDA 脚出现一个上升沿,则停止使用 I2C 总线; 接收应答 ACK: 发送器保持 SDA 为高电平,由接收器将 SDA 拉低,称为应答信号 ACK; 非应答信号 NOT ACK: 当主器件为接收器时,在接收了 后一个字节之后,它不发应答信号; 有效性: 适合所有的设备. 要求: 必须使用#use i2c,才可使能 i2c_stop( )函数; 例子: i2c_start(); //i2c 发送启动条件 i2c_write(0xa0); //发送 0xa0(即从机器件地址)给从机 i2c_write(5); //i2c 发送设备命令 5(即从机子地址)给从机设备 i2c_write(12); //i2c 发送 12(即数据)给从机设备

i2c_stop(); //i2c 发送停止条件; 例子文件: ex_extee.c 和 2416.c;这两个文件在前面已做介绍,这里不在介绍. I2C_WRITE( ) 语法: i2c_write(data); 参数: data 是一个 8 位整型数据; 返回值: 该函数 i2c_write( )的返回值是 ack 位,0 表示 ACK(应答);1 表示 NO ACK(不应答); 功能: 通过 I2C 接口发送单一字节;在主机方式中, 该函数 i2c_write( )将在发送数据时,产生时钟给从机; 该函数 i2c_write( )的返回值是 ack 位;在从机方式中,该函数 i2c_write( )将等

待来自主机的时钟;由启动条件决定数据的传送方向(0 表示由主机发给从机)之后,首先写入

的是数据的 LSB 位(低位). 注意:专用的 I2 协议依靠从机设备. 有效性: 适合所有的设备. 要求: 必须使用#use i2c,才可使能 i2c_write( )函数; 例子: long cmd; ….

i2c_start(); //i2c 发送启动条件 i2c_write(0xa0); //发送 0xa0(即从机器件地址)给从机 i2c_write(cmd); //i2c 发送命令的低字节给从机设备 i2c_write(cmd>8); //i2c 发送命令的高字节给从机设备

i2c_stop(); //i2c 发送停止条件; 例子文件: ex_extee.c 和 2416.c;这两个文件在前面已做介绍,这里不在介绍. INPUT( ) 语法: value=iput(pin); 参数: 读 pin 脚的值;pin 被定义在 device.h 的头文件中,其实际值是一个位地址;例如:端口

a(byte 5)位 3 将有一个值为 5*8+3 或 43,这种定义如下: #define PIN_A3 43; 返回值: 若 pin 脚为低,则该函数返回为 0(或 FALSE); 若 pin 脚为高,则该函数返回为 1(或 TRUE); 功能: 该函数返回所指脚(pin)的状态.I/O 口的工作方式由 后使用的#USE*_IO 命令决定;在默认方式下,为标准 I/O 口,在 input()被执行之前,数据方向被默认设为输入方式.

Page 61: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 61

有效性: 适合所有的设备. 要求: pin 常数必须被定义在 device.h 的头文件中. 例子: while( !input(PIN_B1) ); //等待 B1 脚变高 if( input(PIN_A0) ) printf(“A0 is now high\r\n”); 例子文件: ex_pulse.c; 文件 ex_pulse.c 如下: #if defined(__PCB__) //若使用了 PCB 编译器,则 defined( __PCB__)返回值为 1 #include <16c56.h> //包含 16c56.h 头文件 #fuses HS, NOWDT, NOPROTECT //HS:高速晶振/谐振器, NOWDT:不使用 WDT // NOPROTECT:程序存储器代码不保护 #use delay(clock=20000000) //使能内置函数的功能:delay_ms()和 delay_us() //#USE DELAY()必须在#use rs232()使用之前出现. #use rs232(baud=9600, xmit=PIN_A3, rcv=PIN_A2)

//使用波特率为 9600, //发送脚为 PIN_A3 //接收脚为 PIN_A2 //使能内置函数:getc(),putc()和 printf(), kbhit();

#elif defined(__PCM__) #include <16F877.h> #fuses HS, NOWDT, NOPROTECT, NOLVP #use delay(clock=20000000) #use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7) // Jumpers: 8 to 11, 7 to 12 #elif defined(__PCH__) #include <18F452.h> #fuses HS, NOWDT, NOPROTECT, NOLVP #use delay(clock=20000000) #use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7) // Jumpers: 8 to 11, 7 to 12 #endif //结束 if 定义 #include <ctype.h> //包含 ctype.h 头文件 char get_scale() { char scale; //声明字符型暂态变量 scale do {

printf("\n\rPress S for short or L for long: "); //先换行,接着回车,打印 Press S for short or L for long:

scale = getc(); //从 RS232 口读一个字节,存到 scale scale = toupper(scale); //转换成大写字母,存入 scale } while ( (scale!='S') && (scale!='L') ); return(scale); //返回 scale 的值,退出 get_scale()函数 } void wait_for_low_to_high() { while(input(PIN_B1)) ; //读 PIN_B1 脚,若为 1,则等待;若为 0,则跳出该 while 循环 delay_us(3); //延时 3us /* account for fall time */

Page 62: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 62

while(!input(PIN_B1)); //读 PIN_B1 脚,若为 0,则等待;若为 1,则跳出该 while 循环 } void wait_for_low() { delay_us(3); //延时 3us /* account for rise time */ while( input(PIN_B1) ); //读 PIN_B1 脚,若为 1,则等待;若为 0,则跳出该 while 循环 } void main() { char scale; //声明字符型全局变量 scale BYTE time; //声明字节型全局变量 time do { scale = get_scale(); //从串口 RS232 读一个字节(要么是'S'要么是'L') if(scale=='S')

setup_counters( RTCC_INTERNAL, RTCC_DIV_64 ); //设置 Timer0 的时钟源为内部时钟源

//每隔 64 个脉冲,TMR0 计数 1 次 else

setup_counters( RTCC_INTERNAL, RTCC_DIV_256 ); //设置 Timer0 的时钟源为内部时钟源

//每隔 256 个脉冲,TMR0 计数 1 次 printf("\n\rWaiting...\n\r"); //先换行,接着回车,打印 Waiting...,然后换行,接着回车 wait_for_low_to_high(); //等待 PIN_B1 脚由低电平变为高电平 set_rtcc(0); //设定实时时钟的计数初值,(256-0)*(4y/20000000)=0.0000512y 秒=5.12yus wait_for_low(); //等待 PIN_B1 脚由高电平变为低电平 time = get_rtcc(); // get_rtcc()返回的是实时时钟/计数器的计数值. printf("Counter value: %2X\n\n\r", time); } while (TRUE); } 上述程序在当 PIN_B1 脚为高电平时,才开始设置 RTCC 计数器初值为 0,当 PIN_B1 脚变为低

电平时,才开始读实时时钟/计数器的计数值.,接着将计数值打印出来; INPUT_STATE() 语法: value=iput_state(pin); 参数: 读 pin 脚的值;pin 被定义在 device.h 的头文件中,其实际值是一个位地址;例如:端口

a(byte 5)位 3 将有一个值为 5*8+3 或 43,这种定义如下: #define PIN_A3 43; 返回值: 返回值 value 是 1 位值,表示 pin 脚是输入还是输出;若为 1,则表是该脚为输入,若为

0,则表示该脚为输出. 功能: 该函数用来读 I/O 口脚的状态,同 iput( )一样,不会改变脚的输入/输出方向; 有效性: 适合所有的设备. 要求: pin 常数必须被定义在 device.h 的头文件中. 例子: dir=input_state(pin_A3); //若 A3 为输入状态,则 dir=1,否则 dir=0; printf(“Direction: d%,dir); 例子文件: 没有;

Page 63: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 63

INPUT_x() 语法: value=iput_a(); value=iput_b(); value=iput_c(); value=iput_d(); value=iput_e(); value=iput_f(); value=iput_g(); value=iput_h(); value=iput_i(); value=iput_k(); 参数: 没有; 返回值: 返回值 value 是一个 8 位整型值,表示端口的输入数据; 功能: 该函数用来从一个端口读入一个整型字节.方向寄存器的值改变同 后一次使用

#USE*_IO命令指定的保持一致. 在默认方式下,为标准 I/O口,在 input_x()被执行之前,数据方

向被默认设为输入方式. 例子: data=input_b( ); //读端口 B 的值 例子文件: ex_psp.c;文件 ex_psp.c 如下: //// Configure the CCS prototype card as follows: //// //// Connect pin 23 to 27 and pin 21 to 28. //// //// Connect one end of the parrallel printer cable to the PC. //// //// Also make the following connections: //// //// IBM parallel //// //// cable pin Protoboard //// //// 1 22 E1 //// //// 2 32 D0 //// //// 3 33 D1 //// //// 4 34 D2 //// //// 5 35 D3 //// //// 6 36 D4 //// //// 7 37 D5 //// //// 8 38 D6 //// //// 9 39 D7 //// //// 11 1 C0 //// //// 12 27 gnd //// //// 13 28 +5V //// //// 15 28 +5V //// //// 18 27 gnd //// #if defined(__PCM__) //若使用了 PCM 编译器,则 defined( __PCM__)返回值为 1 #include <16F877.h> //包含 16F877.h 头文件 #fuses HS, NOWDT, NOPROTECT, NOLVP //HS:高速晶振/谐振器, NOWDT:不使用 WDT

Page 64: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 64

// NOPROTECT:程序存储器代码不保护 #use delay(clock=20000000) //使能内置函数的功能:delay_ms()和 delay_us() //#USE DELAY()必须在#use rs232()使用之前出现. #use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)

//使用波特率为 9600, //发送脚为 PIN_C6 //接收脚为 PIN_C7 //使能内置函数:getc(),putc()和 printf(), kbhit();

#elif defined(__PCH__) #include <18F452.h> #fuses HS, NOWDT, NOPROTECT, NOLVP #use delay(clock=20000000) #use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7) // Jumpers: 8 to 11, 7 to 12 #error For PIC18 change read/write _bank to use a buffer #endif //结束 if 定义 #define BUSY_LINE PIN_C0 //用 BUSY_LINE 代替 PIN_C0 #define BUFFER_SIZE 96 //用 BUFFER_SIZE 代替 96 int next_in = 0; //声明整型全局变量 next_in,并赋初值 0; int next_out = 0; //声明整型全局变量 next_out,并赋初值 0; short data_lost = TRUE; //声明短型(位)全局变量 data_lost,并赋初值 TRUE; #int_psp //并行端口 PSP 数据输入,指出下面的函数是一个中断服务函数 void psp_isr() { if( psp_overflow( ) ) //当 CS=0,WR=0,写 PSP 口,若上次写入的字节还没被读出,又发生第二次写入 PSP,则 IBOV 位置 1,表示溢出;

//当 CS=0,RD=0,读 PSP 口,若一个字节还没被读入,PSP 又有新的数据被锁存进来,则 IBOV 位置 1,表示溢出;

data_lost=TRUE; if( psp_input_full( ) ) { //当 CS=0 且 WR=0,发生写 PSP 口,当 CS=1 且 WR=1 时,输入缓冲器满标志位 IBF=1,中断标志位 PSPIF=1 write_bank( 2, next_in++, input_D( ) ); //从 PSP 口(端口 D)读入数据,存入 bank2 if( next_in == BUFFER_SIZE ) next_in = 0; if( next_in == next_out ) output_high( BUSY_LINE ); // PIN_C0 脚输出高电平,表示 PSP 口忙 } } void main( ) { setup_adc_ports( NO_ANALOGS ); //不使用模拟端口 setup_psp( PSP_ENABLED ); //使用 PSP 口 enable_interrupts( GLOBAL ); //开总中断允许位 enable_interrupts( INT_PSP ); //PSP 口中断使能 output_low( BUSY_LINE ); // PIN_C0 脚输出低电平,表示 PSP 口不忙 printf( "Waiting for print data... \r\n\n" ); //从 RS232 口输出

Page 65: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 65

while( true ) { if( next_in!=next_out ) { putc( read_bank( 2,next_out) );

//将以 bank2 为基址, next_out 为变址,其地址处的数据通过 RS232 口发送出去, if( ++next_out==BUFFER_SIZE ) next_out=0; if(data_lost) { printf( "\r\nData Lost!!!\r\n" ); data_lost = FALSE; } output_low( BUSY_LINE ); // PIN_C0 脚输出低电平,表示 PSP 口不忙 } } } 上面的程序通过 PSP 口每读入一个数据,立即存入 bank2,然后从 bank2 读出数据,通过 RS232口发送出去;当 next_in 自加到 96 时,则清 0,同样 next_out 自加到 96 时,也清 0; ISALNUM(char) ISALPHA(char) ISDIGIT(char) ISLOWER(char) ISSPACE(char) ISUPPER(char) ISXDIGIT(char) ISCNTRL(x) ISGRAPH(x) ISPRINT(x) ISPUNCT(x) 语法: value=isalnum(datac); value=isalpha(datac); value=isdigit(datac); value=islower(datac); value=isspace(datac); value=isupper(datac); value=isxdigit(datac); iscntrl(x); x 比 space 键值小; isgraph(x); x 比 space 键值大; isprint(x); x 比 space 键值大或等于 space 键值; ispunct(x); x 比 space 键值大,且它既不是字母,也不是数据; 参数: datac 是一个 8 位字符;

Page 66: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 66

返回值: 如果 datac 不匹配要求标准,返回值 value 是 0(或 FALSE); 如果 datac 匹配要求标准,返回值 value 是 1(或 TRUE); 功能: 该函数用来测试一个字符是否符合特定的要求标准,如下说明: isalnum(x); 若 x 是 0~9, ’A’ ~ ’Z’ 或’a’ ~ ’z’ 的值,则 isalnum(x)的返回值为 1; isalpha(x); 若 x 是’A’ ~ ’Z’ 或’a’ ~ ’z’ 的值,则 isalpha(x)的返回值为 1; isdigit(x); 若 x 是 0~9 的值,则 isdigit(x)的返回值为 1; islower(x); 若 x 是’a’ ~ ’z’ 的值,则 islower(x)的返回值为 1; isupper(x); 若 x 是’A’ ~ ’Z’的值,则 isupper(x)的返回值为 1;

isspace(x); 若 x 是 space 键值,则 isspace(x)的返回值为 1; isxdigit(x); 若 x 是’0’ ~ ’9’, ’A’ ~ ’F’ 或 ’a’ ~ ’f’ 的值,则 isalnum(x)的返回值为 1;

有效性: 适合所有的设备. 要求: 必须包含 ctype.h 的头文件,才可使能上面的函数; 例子: char id[20]; //声明数组 id[20] ………….. if( isalpha(id[0]) ) { valid_id=TRUE; //若 id[0]是’A’ ~ ’Z’ 或’a’ ~ ’z’ 的值,则将 valid_id 赋予 TRUE for(i=1; i<strlen(id); i++) // strlen(id)用来计算数组 id[]的长度 valid_id= valid_id && isalnum( id[i] ); } else valid_id=FALSE; 例子文件: ex_srr.c; ISAMOUNG() 语法: result=isamoung(value, cstring); 参数: value 是一个字符; cstring 是一个字符串常数 返回值: 如果字符 value 不在字符串常数 cstring 中,则返回 0(或 FALSE); 如果字符 value 在字符串常数 cstring 中,则返回 1(或 TRUE); 功能: 如果一个字符是一串字符中的其中之一, 则返回 1(或 TRUE);

例如:isamoung(‘x’, ‘Cxcx’)的值是 1. 有效性: 适合所有的设备. 要求: 没有; 例子: char x; //声明数组 x 为字符型变量; ………………… x=’F’; if( isamoung(x, “ABCDEFXYZ”) ) printf(“The character is valid”);

//若 x 是字符串中其中之一,打印 The character is valid 例子文件: ctype.h;

Page 67: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 67

ITOA() 语法: string=itoa(i32value, i8base,string); 参数: i32value 是一个 32 位整型数; i8base 是一个 8 位整型数; string 是一个指向字符串非结束的指针. 返回值: 返回值 string 是一个指向字符串非结束的指针. 功能: 将有符号的 32 位整型数 i32value,根据所提供的基准数 i8base 转换成字符串后,把字

符串所对应的指针送给 string;若需要的话,则返回转换后的值;若结果不能表示,则该函数返回

0. 有效性: 适合所有的设备. 要求: 必须包含#include<stdlib.h>这样的语句,既包含头文件 stdlib.h,才可使能 itoa()函数; 例子: int32 x=1234; //声明变量 x 为 32 位整型变量,并赋值为 0x1234 char string[5]; //声明字符型数组 string[],分配 5 个字符空间; itoa(x, 10, string); //将 x 左起向右 10 个字节转换成字符串,并将其指针赋给 string //string 现在指向”1234”的首地址. 例子文件: 没有 KBHIT( ) 语法: value=kbhit( ); value=kbhit( stream ); 参数: 将 stream 这个 id 分配成可访问的 RS232 端口;若没有参数 stream,该函数将 getc()用作 初的 stream,即默认参数为 getc(); 返回值: 如果 getc()将要等待一个字符进来,则 kbhit( )的返回值为 0(或 FALSE); 如果一个字符对于接收函数 getc()来说已经准备好了,则 kbhit( )的返回值为 1(或TRUE); 功能: 如果一个字符的开始位已经通过 RS232 的 RCV 脚发送出去,RS232 在软件控制下,使 kbhit( )返回 TRUE; 如果一个字符已经被接收了,且在硬件缓冲区等待 getc()来读取时,则RS232采用硬件使得 kbhit( )返回TRUE; kbhit( )常用来检测不带停止位的数据,且等待数据出

现.注意:在 RS232 软件控制的情况下, kbhit( )函数至少被调用 10 次,目的是保证数据不被丢

失. 有效性: 适合所有的设备. 要求: 必须包含#use rs232 这样的语句,才可使能 kbhit( )函数; 例子: char timed_getc(){

long timeout; //声明暂态长整型变量 timeout timeout_error=FALSE; //将 timeout_error 赋初值 FALSE timeout=0; while(!kbhit( ) && (++timeout<50000) ) delay_us(10); //延时为 10usX50000,即 0.5s if( kbhit( ) ) return( getc() ); //如果一个字符已经被接收了 kbhit()返回 1; else{ timeout_error=TRUE; //若没有接收到数据,则将 timeout_error 赋 TRUE

Page 68: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 68

return(0); }

} 例子文件: ex_tgetc.c; LABEL_ADDRESS() 语法: value=label_address( label); 参数: 在该函数中的 label,是位于任意处的一个 C 标志(C 标号). 返回值: 在 PCB 和 PCM 编译器中,返回值是一个 16 位整型数;而在 PCH 编译中, 返回值是

一个 32 位整型数. 功能: 该函数用来获得位于标号后的下一条指令在 ROM 中的地址.该函数不常使用,只有

在特殊情况下,才使用该函数. 有效性: 适合所有的设备. 要求: 没有. 例子: start: //标号 start a=(b+c)<<2; //将 b+c 所得的值左移两位后,赋给 a 这个变量 end: //标号 end printf("It take 1%u ROM locations. \r\n", label_address(end)-label_address(start) ); 例子文件: setjmp.h; LABS( ) 语法: result=labs( value); 参数: value 是一个有符号的 16 位长整型数; 返回值: 返回值 result 是一个有符号的 16 位长整型数; 功能: 该函数用来计算一个有符号的 16 位长整型数的绝对值. 有效性: 适合所有的 CPU 设备. 要求: 必须包含 stdlib.h 头文件,才可使能 labs( )函数; 例子: if( labs( target_value-actual_value) > 500 ) printf("Error is over 500 points \r\n"); 例子文件: 没有. LCD_LOAD() 语法: lcd_load( buffer_pointer, offset, length); 参数: buffer_pointer 指向发送给 LCD 的用户数据; offset 是用来将该数据写入 LCD,用作进入 LCD segment memory 的偏移量; length 是传送的字节数. 要求: 没有. 功能: 该函数将从 CPU 的 buffer_pointer 存储区取 length 个字节,装载到 923/924 LCD 的

Page 69: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 69

segment data area(段数据区),起始偏移量 offset 范围为 0~15. LCD_symbol( )函数提供一个简

易的方法将数据写入 LCD segment memory(LCD 段码存储区),这样,LCD 就可显示数据了. 有效性: 该函数只对带有 LCD 驱动硬件的 CPU 器件有效; 要求: 常数被定义在 devices.h 的头文件中. 例子: lcd_load( buffer, 0, 16 ); 例子文件: ex_92lcd.c; 文件 ex_92lcd.c 如下: #if defined( __PCM__ ) //若使用了 PCM 编译器,则 defined( __PCM__)返回值为 1 #include <16c924.h> //包含 16c924.h 头文件 #fuses HS, NOWDT, PUT //HS:高速晶振/谐振器, NOWDT:不使用 WDT // NOPROTECT:程序存储器代码不保护 #use delay(clock=20000000) //使能内置函数的功能:delay_ms()和 delay_us() //#USE DELAY()必须在#use rs232()使用之前出现. #endif //结束 if 定义

// LCD Configuration(LCD 配置) //

// Digit segments(数字段) A B C D E F G DP

// b7 b6 b5 b4 b3 b2 b1 b0

#define DIGIT4 COM1+26, COM1+17, COM2+17, COM3+26, COM2+25, COM1+25, COM2+26, COM3+17

#define DIGIT3 COM1+24, COM1+16, COM2+16, COM3+24, COM2+23, COM1+23, COM2+24, COM3+16

#define DIGIT2 COM1+22, COM1+19, COM2+19, COM3+22, COM2+21, COM1+21, COM2+22, COM3+19

#define DIGIT1 COM1+20, COM1+18, COM2+18, COM3+20, COM2+28, COM1+28, COM2+20, COM3+18 // character 0 1 2 3 4 5 6 7 8 9 byte const Digit_Map[10] = {0xFC,0x60,0xDA,0xF2,0x66,0xB6,0xBE,0xE0,0xFE,0xE6}; #define BLANK 0 //用 BLANK 代替 0 #define DASH 11 //用 DASH 代替 11 byte lcd_pos; //声明字节变量 lcd_pos void lcd_putc(char c) { byte segments; //声明字节型暂态变量 segments if(c=='\f') // '\f'表示走纸换页 lcd_pos=0; //如果 c 是'\f'(走纸换页符),则将 lcd_pos 赋给 0; else { if( (c>='0') && (c<='9') ) //若 c 是 0~9 的 ASCII 码值,则执行下面语句 segments=Digit_Map[c-'0']; //根据 c-'0' 的值查表,求得 c 对应 LCD 显示的代码值 else segments=BLANK; //若 c 不是 0~9 的 ASCII 码值,则将 segments 赋值为 0 switch(lcd_pos) { case 1 : lcd_symbol( segments, DIGIT4 ); break; // fill 1000s place case 2 : lcd_symbol( segments, DIGIT3 ); break; // fill 100s place case 3 : lcd_symbol( segments, DIGIT2 ); break; // fill 10s place case 4 : lcd_symbol( segments, DIGIT1 ); break; // fill 1s place } }

Page 70: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 70

lcd_pos++; } void main() { long number = 0; //声明长整型变量 number,并赋值为 0 setup_lcd( LCD_MUX14|STOP_ON_SLEEP, 2, ALL_LCD_PINS ); while(TRUE) { printf(lcd_putc,"\f%4lu",number); if(number++==10000) number=0; delay_ms(100); //延时 100ms } } LCD_SYMBOL( ) 语法: lcd_ symbol (symbol, b7_addr, b6_addr, b5_addr, b4_addr, b3_addr, b2_addr, b1_addr, b0_addr); 参数: symbol 是一个 8 位常数; b7_addr 是一个位地址,表示 LCD 的段位置,用作 symbol 的第 7 位; b6_addr 是一个位地址,表示 LCD 的段位置,用作 symbol 的第 6 位; b5_addr 是一个位地址,表示 LCD 的段位置,用作 symbol 的第 5 位; b4_addr 是一个位地址,表示 LCD 的段位置,用作 symbol 的第 4 位; b3_addr 是一个位地址,表示 LCD 的段位置,用作 symbol 的第 3 位; b2_addr 是一个位地址,表示 LCD 的段位置,用作 symbol 的第 2 位; b1_addr 是一个位地址,表示 LCD 的段位置,用作 symbol 的第 1 位; b0_addr 是一个位地址,表示 LCD 的段位置,用作 symbol 的第 0 位; 返回值: 没有; 功能: 该函数用来将 8位数据装载到LCD每个特定的位地址处的 segment data area(段数据

区).如果 symbol 中的第 7位被设置为 1,则在 b7_addr地址处的段就被设置 1,相反, 在 b7_addr地址处的段就被清除;所有在 symbol 中的其它位设置方法同 b7_addr 的设置方法相同; b7_addr 是一个位地址,被写入到 LCD RAM 中. 有效性: 该函数只对带有 LCD 驱动硬件的 CPU 器件有效; 要求: 常数被定义在 devices.h 的头文件中. 例子: #define DIGIT_1_CONFIG

COM0+2,COM0+4,COM0+5,COM2+4,COM2+1,COM1+4,COM1+5 for(i=1; I<=9; ++i ){ lcd_ symbol(DIGIT_MAP[i], DIGIT_1_CONFIG); delay_ms(1000); }

例子文件: ex_92lcd.c; 文件 ex_92lcd.c 在前面已经介绍,这里不重述.

Page 71: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 71

SETUP_LCD( ) 语法: setup_lcd (mode, prescale, [segments]); 参数: mode 可能是来自 devices.h 头文件如下常数: LCD_DISABLED, LCD_STATIC, LCD_MUX12, LCD_MUX13, LCD_MUX14

下面的参数 :STOP_ON_SLEEP, USE_TIMER_1 可同上面的 LCD_DISABLED, LCD_STATIC, LCD_MUX12, LCD_MUX13, LCD_MUX14中的任意一个进行或( 或符号| )操作;可见 devices.h 头文件留给其它器件的特殊可选项.

Prescale 可能值为 0~15,用作 LCD clock segment,而 LCD clock segment 可能是下面的

任意常数,可进行或( 或符号| )操作; LCD clock segment 常数如下: SEGO_4, SEG5_8, SEG9_11, SEG12_15, SEG16_19, SEGO_28, SEG29_31, ALL_LCD_PINS; 如果省略 segments,编译器将在程序里使用所有的 segments. 返回值: 没有; 功能: 该函数用来初始化 923 的 LCD 驱动器或 924 的 LCD 驱动器; 有效性: 该函数只对带有 LCD 驱动硬件的 CPU 器件有效; 要求: 常数被定义在 devices.h 的头文件中. 例子: setup_lcd( LCD_MUX14 | STOP_ON_SLEEP, 2 ); 例子文件: ex_92lcd.c; 文件 ex_92lcd.c 在前面已经介绍,这里不重述. LDEXP( ) 语法: result=ldexp (value, exp); 参数: value 是一个浮点数; exp 是一个有符号的整型数; 返回值: result 同 value 保持一致,是一个浮点数,结果是 value 乘以 2 的 exp 次方. 功能: ldexp( ) 该函数是用一个浮点数乘以 2 的多少(整数)次方. 有效性: 适合所有的 CPU 设备. 要求: 必须包含头文件 math.h; 例子: float result; signed int exp; result=ldexp( 0.5, 0 ); // result 现在是 0.5 例子文件: 没有; LOG( ) 语法: result=log (value); 参数: value 是一个浮点数; 返回值: result 等于返回值,是一个浮点数; 功能: 该函数是用来计算浮点数 x 的自然对数(即 ln x);如果 x 小于或等于 0,或 x 太大,则行

为没有定义; 注意:存在 error 挂起; 如果在编写程序里包含了 errno.h 头文件,则范围和等级错误存储在 errno 变量里.用户通过检测 errno 变量,可发现是否有错误存在,且用 perror 函数打印出这个错误.

Page 72: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 72

范围错误存在下面的原因: log( x ); x 是一个负数; 有效性: 适合所有的 CPU 设备. 要求: 必须包含头文件 math.h; 例子: lnx=log( x ); //计算以 e 为底数,x 的对数,即计算 x 的自然对数; 例子文件: 没有; LOG10( ) 语法: result=log10 (value); 参数: value 是一个浮点数; 返回值: result 等于返回值,是一个浮点数; 功能: 该函数是用来计算浮点数 x 以 10 为底数的对数(即数学式 log x);如果 x 小于或等于

0,或 x 太大,则行为没有定义; 注意:存在 error 挂起; 如果在编写程序里包含了 errno.h 头文件,则范围和等级错误存储在 errno 变量里.用户通过检测 errno 变量,可发现是否有错误存在,且用 perror 函数打印出这个错误. 范围错误存在下面的原因: log10 ( x ); x 是一个负数; 有效性: 适合所有的 CPU 设备. 要求: 必须包含头文件 math.h; 例子: db=log10 ( read_adc()*(5.0/255) )*10; //计算以 10 为底数,x 的对数; 例子文件: 没有; LONGJMP( ) 语法: longjmp ( env, val ); 参数: env: 将被 longjmp( )这个函数重新存储的目的数据; val: 函数 setjmp 将要返回的值,若 val 为 0,则函数 setjmp 将返回 1; 返回值: longjmp( )这个函数被执行之后,程序继续执行,并且函数 setjmp只返回由 val指定的

值; 功能: 该函数是用来执行非局部控制的传送; 有效性: 适合所有的 CPU 设备. 要求: 必须包含头文件 #include <setjmp.h> 例子: longjmp( jmpbuf, 1 ); 例子文件: 没有; MAKE8( ) 语法: i8=make8( var, offset); 参数: var 是 16 位或 32 位整数; offset 是字节的偏移量,为 1,2 或 3;

Page 73: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 73

返回值: 返回值是一个 8 位整数; 功能: 该函数用来摘取以 var 为基址, offset 为偏移量,所指向单元的字节;除了执行单字节

复制之外,还相当于 i8=( ( var>>(offset*8) ) &0xff ); 有效性: 适合所有的 CPU 设备. 要求: 没有 例子: int32 x; int y; y=make8(x, 3); //将 x 的 高 8 位(即 x 的第 3 个字节)送给 y; 例子文件: 没有; MAKE16( ) 语法: i16=make16( varhigh, varlow); 参数: varhigh 和 varlow 是 8 位整数; 返回值: 返回值是一个 16 位整数; 功能: 该函数用来将两个分离的字节制成一个 16 位的数;如果参数中其中之一是 16位, 或是 32 位,或两个都是 16 位/32 位,则只有 LSB(即低 8 位)可用, 除了执行单字节复制之外,还相

当于 i16=(int16)( ( varhigh &xff)*0x100 )+( varlow&0xff ); 有效性: 适合所有的 CPU 设备. 要求: 没有; 例子: long x; int hi, lo; x=make16(hi, lo); //若 hi=0x07, lo=0x02,则 x=0x0702; 例子文件: ltc1298.C;文件 ltc1298.c 如下: #ifndef ADC_CS //如果没有定义 ADC_CS,则执行下列语句; #define ADC_CLK PIN_B0 //采用 ADC_CLK 代替 PIN_B0; #define ADC_DOUT PIN_B1 //采用 ADC_DOUT 代替 PIN_B1; #define ADC_DIN PIN_B2 //采用 ADC_DIN 代替 PIN_B2; #define ADC_CS PIN_B3 //采用 ADC_CS 代替 PIN_B3; #endif //结束 if 定义; void adc_init() { output_high(ADC_CS); //将 ADC_CS 引脚输出为高电平, 不使能 SPI 口;; } /*用软件模拟法,写 SPI 接口,要写入的数据为:data,先写 低位,共写 number_of_bits 位*/ void write_adc_byte(BYTE data_byte, BYTE number_of_bits) { BYTE i; //声明暂态变量 i; delay_us(2); //软件延时 2us; for(i=0; i<number_of_bits; ++i) { if((data_byte & 1)==0) //若 data_byte 的 低位为 0,则执行下面语句; output_low(ADC_DIN); //将 ADC_DIN 引脚输出为低电平;

Page 74: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 74

else output_high(ADC_DIN); //将 ADC_DIN 引脚输出为高电平; data_byte=data_byte>>1; //将 data_byte 右移一位 output_high(ADC_CLK); //将 ADC_CLK 引脚输出为高电平; delay_us(50); //软件延时 50us; output_low(ADC_CLK); //将 ADC_CLK 引脚输出为低电平; delay_us(50); //软件延时 50us; } } /*用软件模拟法,读 SPI 接口,共读 number_of_bits 位*/ BYTE read_adc_byte(BYTE number_of_bits) { BYTE i, data; //声明暂态变量 i, data; data=0; //给 data 赋初值 for(i=0;i<number_of_bits;++i) { output_high(ADC_CLK); //将 ADC_CLK 引脚输出为高电平; delay_us(50); //软件延时 50us; shift_left(&data,1,input(ADC_DOUT)); //将 ADC_DOUT 脚的电平左移入 data 中 output_low(ADC_CLK); //将 ADC_CLK 引脚输出为低电平; delay_us(50); //软件延时 50us; } return(data); //返回 data 的值; } long int read_analog( BYTE channel ) { int l; //声明暂态整型变量 l; long int h; //声明暂态长整型变量 h; delay_us(200); //软件延时 50us; output_low(ADC_CLK); //将 ADC_CLK 引脚输出为低电平; output_high(ADC_DIN); //将 ADC_DIN 引脚输出为高电平; output_low(ADC_CS); //将 ADC_CS 引脚输出为低电平, 使能 SPI 口;; if(channel==0) channel=0x1b; else channel=0x1f; write_adc_byte( channel, 5); h=read_adc_byte(8); //从 SPI 口读 8 位值,送给 h; l=read_adc_byte(4)<<4; //从 SPI 口读 4 位值,左移 4 位后送给 l; output_high(ADC_CS); //将 ADC_DIN 引脚输出为高电平,不使能 SPI 口; return((h<<8)|l); //将读到的 h 和 l 合并为一个字,返回;

Page 75: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 75

} void convert_to_volts( long int data, char volts[6]) { BYTE i; //声明暂态整型变量 i; long int temp,div; //声明暂态长整型变量 temp, div; div=0x3330; //给 div 赋初值 for(i=0;i<=4;i++) { temp=data/div; volts[i]=(BYTE)temp+'0'; //先将 temp 强制转换为整型值,然后变为 ASCII 码 if(i==0) { volts[1]='.'; i++; } temp=div*(BYTE)temp; //先将 temp 强制转换为整型值,再乘以 div,即商 X 除数; data=data-temp; //求余数 div=div/10; //将除数缩小 10 倍; } volts[i]='\0'; } //上面的程序,用软件模拟法,读写 SPI 接口 MAKE32( ) 语法: i32=make32( var1, var2, var3, var4); 参数: var1, var2, var3 和 var4 是一个 8 位或 16 位整数; var2, var3 和 var4 是可选项; 返回值: 返回值是一个 32 位整数; 功能: 该函数将任意结合的 8位和 16位数制造成 32位的数据;注意:参数的个数可能是 1~4中的任意值, var1 为 高 8 位(即 msb);若提供的总位数比 32 少,则 0 被添加到 msb 位; 有效性: 适合所有的 CPU 设备. 要求: 没有; 例子: int32 x; int y; long z; x=make32(1, 2, 3, 4); //x 现在是 0x01020304; y=0x12; z=0x4321; x=make32(y, z); // x 现在是 0x00124321; x=make32(y, y, z); // x 现在是 0x12124321; 例子文件: ex_freqc.c; ex_freqc.c 如下: #include <16F877.h> //包含头文件 #fuses HS, NOWDT, NOLVP //HS:高速晶振/谐振器, NOWDT:不使用 WDT // NOPROTECT:程序存储器代码不保护 #use delay(clock=20000000) //one instruction=0.2us

Page 76: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 76

//使能内置函数的功能:delay_ms()和 delay_us() //#USE DELAY()必须在#use rs232()使用之前出现. #use rs232(baud=9600, xmit=PIN_c6, rcv=PIN_c7)

//使用波特率为 9600, //发送脚为 PIN_ C6 //接收脚为 PIN_ C7 //使能内置函数:GETC,PUTC 和 PRINTF, kbhit();

#bit t1_overflow=0x0C.0 //使用#bit 设置 timer1 溢出标志位; // #bit t1_overflow=0xF9E.0 (PIC18, Reminder) void main() { int cycles8, cycles; int32 freq; //声明 32 位整型变量 long freqc_high; //声明长整型全局变量 freqc_high long freqc_low; //声明长整型全局变量 freqc_low while (TRUE) { cycles8=0; cycles=0; freqc_high=0; t1_overflow=0; //timer1 溢出标志位清 0; set_timer1(0); //设置 timer1 的初始计数值为 0;

setup_timer_1(T1_EXTERNAL|T1_DIV_BY_1); //初始化定时器 1,

//时钟源为外部时钟 //不用分频器,即每来时钟到来,T1 计数一次

/* ___ wait one second ___ 1 秒开始 */ while (cycles!=0xFF) { //true=3, false=4 cycles8=0; //1 cycle //start inner loop while (cycles8!=0xFF) { //true=3, false=4 if (t1_overflow) //true=2,false=3 //----| {t1_overflow=0;freqc_high++;} //6 cycles // | else // |-- 8 cycles {delay_cycles(5);} //----| delay_cycles(62); //x cycles8++; //1 ///2 cycles to jump to top //math: end inner loop //math: total inner loop=((3+8+x+1+2)*255 + 4)*255 //math: if x=62.87781 then inner loops takes 5mil instructions //math: if x=62 then inner loop takes 4942920, have to fill 57080 cycles }

Page 77: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 77

delay_cycles(216); //y cycles++; ///1 cycle ///2 cylces to jump to top //math: outer=(3+1+y+1+2)*255+4=57080 //math: y=(57080-4)/255)-(3+1+0+0+1+2) //math: if y=216.827450980392156862745098039216 then outer loop cylces is 57080 //math: if y=216 then outer loop cycles is off by 211 cycles. z=211 } delay_cycles(211); //z /* ___ end waiting 1 second ___ 1 秒结束*/ setup_timer_1(T1_DISABLED); //不使能 timer1 if (t1_overflow) //check one last time for overflow freqc_high++; freqc_low=get_timer1(); //get timer1 value as the least sign. 16bits of freq counter freq=make32(freqc_high,freqc_low); //use new make32 function to join lsb and msb printf("%LU Hz\r\n",freq); //and print frequency } } //上面的程序,采用定时器 1 计算频率,上面的方法太笨; MALLOC( ) 语法: ptr=malloc(size) 参数: size 是一个整数,表示被分配的字节个数; 返回值: 如果允许的话,返回值是一个指向被分配存储器的指针;否则的话, 返回值是一个

非指针; 功能: 该函数用来分配一定大小的空间给一个对象,其大小为 size,但该空间的值为不确定

值; 有效性: 适合所有的 CPU 设备. 要求: 必须包含头文件 STDLIBM.H,即用语句: #include <stdlibm.h>; 例子: int *iptr; iptr=malloc(10); //iptr 将指向一块 10 个字节的存储区; 例子文件: 没有; MEMCPY( ) MEMMOVE( ) 语法: memcpy(destination, source, n); memmove(destination, source, n); 参数: destination 是一个指向目的存储区的指针; source 是一个指向源存储区的指针; n 是要传送的字节个数; 返回值: 没有;

Page 78: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 78

功能: 该函数从 RAM 中的源存储区复制 n 个字节到 RAM 中的目的存储区;我们知道数组

的名字是指针,而其它变量名和结构名不是指针,因此,它们的名字前面要有&’ memmove 执行的是一个安全 copy(与目标存储区重叠不会产生任何问题),拷贝产生

如:首先从源存储区拷贝 n 个字节,存放到一个含有 n 个字节的临时数阻中,该临时数阻不会同

源存储区和目的存储区重叠; 有效性: 适合所有的 CPU 设备. 要求: 没有; 例子: memcpy( &structA, &structB, sizeof (structA) ); memcpy( arrayA, arrayB, sizeof (arrayA) ); memcpy(&structA, &databyte, 1); char a[20]= "hello"; memmove(a, a+2, 5); //a 现在是"llo" 例子文件: 没有; MEMSET( ) 语法: memset(destination, value, n); 参数: destination 是一个指向存储区的指针; value 是一个 8 位整型数; n 是一个 8 位整型数; 返回值: 没有; 功能: 该函数是用来将 n 字节个 value 值送到由 destination 为指针所指向的存储区; 我们

知道数组的名字是指针,而其它变量名和结构名不是指针,因此,它们的名字前面要有&; 有效性: 适合所有的 CPU 设备. 要求: 没有; 例子: memset(arrayA, 0, sizeof (arrayA) ); //将数阻 arrayA 中的内容全部设置为 0; memset(arrayB, '?', sizeof (arrayB) ); //将数阻 arrayB 中的内容全部设置为'?'; memset(&structA, 0xff, sizeof (structA) ); //将结构 structA 中的内容全部设置为 0xff; 例子文件: 没有; MODF( ) 语法: result=modf( value, &integral ); 参数: value 和 integral 是浮点数; 返回值: 返回值是一个浮点数; 功能: 该函数将浮点数 value 的值分成整数部分和小数部分,其中,每一部分的符号都与

value 的符号保持相同;在 integral 中,存储的是 value 值的整数部分; 有效性: 适合所有的 CPU 设备. 要求: 必须包含头文件 math.h, 即用#include <math.h>包含头文件 例子: float result, integral; result=modf(123.987, &integral); // result 是.987, integral 为 123.0000 例子文件: 没有;

Page 79: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 79

MUL( ) 语法: prod=_mul(val1, val2); 参数: val1 和 val2 为两个都是 8 位整型数或 16 位整型数; 返回值: 如果 val1 和 val2 两个都是 8 位整型数,则返回值是一个 16 位整型数; 如果 val1 和

val2 两个都是 16 位整型数,则返回值是一个 32 位整型数; 功能: 该函数执行一个 优化乘法; 有效性: 适合所有的 CPU 设备. 要求: 没有; 例子: int a=50, b=100; long int c: c=_mul(a, b); //c 拥有 5000 例子文件: 没有; OFFSETOF( ) OFFSETOFBIT( ) 语法: value=offsetof( stype, field ); value=offsetofbit( stype, field ); 参数: stype 是一个结构型名字; field 是来自结构上的一个区段; 返回值: 返回值是一个 8 位字节; 功能 : 该函数用来返回指定结构的域的偏移量 ;offsetof( )返回的是字节的偏移

量;offsetofbit( )返回的是位的偏移量; 有效性: 适合所有的 CPU 设备. 要求: 必须包含头文件 stddef.h,即用语句 #include < stddef.h > 例子: struct time_structure{ int hour, min, sec; //在结构中,声明变量元素,为 8 位整型 int zone : 4; //在结构中,声明变量元素,为 4 位整型 short daylight_savings; //在结构中,声明位变量元素,为 short 型; } x=offsetof( time_structure, sec); //x 将是 2 x=offsetofbit( time_structure, sec); // x 将是 16 x=offsetof( time_structure, daylight_savings ); // x 将是 3 x=offsetofbit( time_structure, daylight_savings ); // x 将是 28 例子文件: 没有;

Page 80: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 80

OUTPUT_A( ) OUTPUT_B( ) OUTPUT_C( ) OUTPUT_D( ) OUTPUT_E( ) OUTPUT_F( ) OUTPUT_G( ) OUTPUT_H( ) OUTPUT_J( ) OUTPUT_K( ) 语法: output_a( value ) output_b( value ) output_c( value ) output_d( value ) output_e( value ) output_f( value ) output_g( value ) output_h( value ) output_j( value ) output_k( value ) 参数: value 是一个 8 位整型数; 返回值: 返回值未定义; 功能: 该函数用来输出某个端口的全部字节,方向寄存器的改变与 后指定的#USE *_IO的指定保持一致; 有效性: 适合所有的 CPU 设备,然而不是所有的设备都具有端口 A 到端口 E; 要求: 没有; 例子: output_b(0xf0);//让端口 B 输出 0xf0; 例子文件: ex_patg.c; 文件: ex_patg.c 如下: #if defined(__PCM__) //若使用了 PCM 编译器,则 defined( __PCM__)返回值为 1 #include <16F877.h> //包含 16F877.h 头文件 #fuses HS, NOWDT, NOPROTECT, NOLVP //HS:高速晶振/谐振器, NOWDT:不使用 WDT // NOPROTECT:程序存储器代码不保护 #use delay(clock=20000000) //使能内置函数的功能:delay_ms()和 delay_us() //#USE DELAY()必须在#use rs232()使用之前出现. #elif defined(__PCH__) #include <18F452.h> #fuses HS, NOWDT, NOPROTECT, NOLVP #use delay(clock=20000000) #endif //结束 if 定义 #define NUM_OUTPUTS 7 //用 NUM_OUTPUTS 代替 7 //NOTE: periods MUST be multiples of 400 注意:周期必须是 400 的倍数 //Periods are in microseconds 周期的单位是微秒(us)

Page 81: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 81

#define PERIOD_0 400 //用 PERIOD_0 代替 400 #define PERIOD_1 800 //用 PERIOD_1 代替 800 #define PERIOD_2 1600 //用 PERIOD_2 代替 1600 #define PERIOD_3 2000 //用 PERIOD_3 代替 2000 #define PERIOD_4 20000 //用 PERIOD_4 代替 20000 #define PERIOD_5 64000 //用 PERIOD_5 代替 64000 #define PERIOD_6 2000000 //用 PERIOD_6 代替 2000000 const long wave_period[NUM_OUTPUTS] = { PERIOD_0/400, PERIOD_1/400, PERIOD_2/400, PERIOD_3/400, PERIOD_4/400, PERIOD_5/400, PERIOD_6/400}; //声明常数数组 wave_period[7] long counter[NUM_OUTPUTS] = {0,0,0,0,0,0,0}; //声明长整型数组 counter[7] int port_b_image; //声明 port_b_image 为整型变量 // This interrupt is used to output the waveforms.这个中断用来输出波形 // The interrupt is automatically called ever 200us.这个中断每 200us 自动被雕用一次 #INT_TIMER1 //指定下面的函数是 timer1 的中断服务函数 void wave_timer() { int i; //声明 i 为整型变量 set_timer1(0xFC4F); // sets timer to interrupt in 200us(预置值为:65535-200/(4/20)=0xfc17 ) output_b(port_b_image); // b 口输出波形 for(i=0; i<NUM_OUTPUTS; i++) // sets up next output for each pin { if((++counter[i]) == wave_period[i]) // counter[i]加 1 后同 wave_period[i]相等吗? { counter[i] = 0; //counter[i]加 1 后存到 counter[i]中,若同 wave_period[i]相等,则清 0 if(bit_test(port_b_image,i)) //测试 port_b_image 的第 i 位 bit_clear(port_b_image,i); //若 port_b_image 的第 i 位为 1,则将该位清 0 else bit_set(port_b_image,i); //若 port_b_image 的第 i 位为 0,则将该位置 1 } } } void main() { setup_timer_1(T1_INTERNAL|T1_DIV_BY_1);

//初始化定时器 1, //时钟源为内部指令时钟 //不用分频器,即每一指令时钟到来,T1 计数一次 enable_interrupts(INT_TIMER1); // timer1 中断允许位置 1 enable_interrupts(GLOBAL); //开总中断允许位 port_b_image=0; //初始化变量 port_b_image 给其赋初值 0 output_b(port_b_image); //b 口全部输出 0 while(TRUE); //循环等待 } 上面的例子告诉我们 B0 输出 400us 周期的方波, B1 输出 800us 周期的方波, B2 输出 1600us

Page 82: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 82

周期的方波, B3 输出 2000us 周期的方波, B4 输出 20000us 周期的方波, B5 输出 64000us 周期

的方波, B6 输出 2000000us 周期的方波. OUTPUT_BIT( ) 语法: output_bit( pin, value ); 参数: pin 是定义在 devices.h 头文件中的 CPU 引脚名字,实际数值是一个位地址;例如:端口

a 的位 3,其位地址是 5*8+3 或 43,采用下面方法定义: #define PIN_A3 43 value 的值可能是 1 或 0;

返回值: 返回值未定义; 功能: 该函数将指定的 I/O脚输出指定的值(0或1),设置方向寄存器的方法是由 后使用的

#USE *_IO 的指定决定; 有效性: 适合所有的 CPU 设备; 要求: Pin 常数被定义在 devices.h 的头文件中; 例子: output_bit( PIN_B0, 0 ); //相当于 output_low(PIN_B0); output_bit(PIN_B0, input(PIN_B1) ); //将 PIN_B1 脚的输入电平通过 PIN_B0 脚输出 output_bit(PIN_B0, shift_left( &data,1, input(PIN_B1) ) );

//将 data 的 高位(MSB)通过 PIN_B0 脚输出, //同时将 PIN_B1 的输入电平移入 data 的 低位(LSB);

设置方向寄存器的方法: #use fixed_io(a_outputs=PIN_A2,PIN_A3) //将 PINA2 和 PIN_A3 设置为输出; #use fast_io(A) //但用户必须先保证通过 set_tris_A(0x00)来设置 I/O 方向寄存器; //将端口 A 全设置为输出

例子文件: ex_extee.c 和 9356.c; 文件: ex_extee.c 如下: #if defined(__PCB__) //若使用了 PCB 编译器,则 defined( __PCB__)返回值为 1 #include <16c56.h> //包含 16c56.h 头文件 #fuses HS, NOWDT, NOPROTECT //HS:高速晶振/谐振器, NOWDT:不使用 WDT // NOPROTECT:程序存储器代码不保护 #use delay(clock=20000000) //使能内置函数的功能:delay_ms()和 delay_us() //#USE DELAY()必须在#use rs232()使用之前出现. #use rs232(baud=9600, xmit=PIN_A3, rcv=PIN_A2)

//使用波特率为 9600, //发送脚为 PIN_A3 //接收脚为 PIN_A2 //使能内置函数:GETC,PUTC 和 PRINTF, kbhit();

#elif defined(__PCM__) #include <16F877.h> #fuses HS,NOWDT,NOPROTECT,NOLVP #use delay(clock=20000000) #use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7) // Jumpers: 8 to 11, 7 to 12 #elif defined(__PCH__) #include <18F452.h>

Page 83: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 83

#fuses HS,NOWDT,NOPROTECT,NOLVP #use delay(clock=20000000) #use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7) // Jumpers: 8 to 11, 7 to 12 #endif //结束 if 定义 #include <input.c> //包含 input.c 头文件 #include <2416.c> //包含 2416.c 头文件 void main() { BYTE value, cmd; //声明字节型变量 value, cmd EEPROM_ADDRESS address; //用 EEPROM_ADDRESS 代替 long int,为 16 位 init_ext_eeprom(); //初始化连接到 eeprom 的 I/O 脚 do { do { printf("\r\nRead or Write: "); cmd=getc(); //从 RS232 口读一个字节 cmd=toupper(cmd); //将 cmd 中的小写字母转换成大写字母送给 cmd putc(cmd); } while ( (cmd!='R') && (cmd!='W') ); //直到输入 R 或 W 为止

printf("\n\rLocation: ");

#if sizeof(EEPROM_ADDRESS)==1 //若定义 EEPROM_ADDRESS 是 1 个字节,则 sizeof(EEPROM_ADDRESS)==1 返回 1 address = gethex(); #else //若定义 EEPROM_ADDRESS 是大于 1 个字节 #if EEPROM_SIZE>0xfff address = gethex(); #else // EEPROM_SIZE 小于 0xfff address = gethex1(); //从 RS232 口读一个字节,为 eeprom 存储高字节地址 #endif //结束 if 定义 address = (address<<8)+gethex(); //从 RS232 口读 2 个字节,为 eeprom 存储低字节地址 #endif //结束 if 定义 if(cmd=='R') //若输入 R,则执行下面 printf("\r\nValue: %X\r\n",READ_EXT_EEPROM( address ) ); if(cmd=='W') { printf("\r\nNew value: "); value = gethex(); //从 RS232 输入,为写入 eeprom 的值做准备 printf("\n\r"); WRITE_EXT_EEPROM( address, value ); } } while (TRUE); } 文件: input.c 如下: #include <CTYPE.H> //包含 CTYPE.H 头文件

Page 84: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 84

BYTE gethex1() { char digit; //声明字节型变量 digit digit = getc(); //从 RS232 口读一个字节 putc(digit); //向 RS232 口写一个字节 if(digit<='9') //将读到的字节以 16 进制返回 return(digit-'0'); //若读到的 ascii 码小于或等于 39,则将其减 30,以 16 进制返回 else return((toupper(digit)-'A')+10); //若读到的 ascii 码大于 39,则将其减 41,再加 10 返回 } BYTE gethex() { int lo, hi; //声明整型变量 lo, hi hi = gethex1(); //从 RS232 口读一个字节,存储到 hi 中 lo = gethex1(); //从 RS232 口读一个字节,存储到 lo 中 if(lo==0xdd) return(hi); else return( hi*16+lo ); } void get_string(char* s, int max) { int len; //声明整型变量 len char c; //声明字节型变量 c --max; //初始化 max 值 len=0; //初始化 len 值 do { c=getc(); //从 RS232 口读一个字节,存储到 c 中 if(c==8) { // Backspace 若是空格键 if(len>0) { len--; putc(c); //向 RS232 写 c putc(' '); putc(c); } } else if ((c>=' ')&&(c<='~')) if(len<max) { s[len++]=c; putc(c); } } while(c!=13); s[len]=0; } // stdlib.h is required for the ato_ conversions

Page 85: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 85

// in the following functions #ifdef _STDLIB //若定义_STDLIB,则执行下面 signed int get_int() { char s[5]; //声明字符型数组 s[5] signed int i; //声明有符号整型变量 i get_string(s, 5); //从 RS232 口读 5 个字节,存储到 s 数组中 i=atoi(s); //将数组 s[]的字符串转换成整型数送给 i return(i); } signed long get_long() { char s[7]; //声明字符型数组 s[7] signed long l; //声明有符号长整型变量 l get_string(s, 7); //从 RS232 口读 7 个字节,存储到 s 数组中 l=atol(s); //将数组 s[]的字符串转换成长整型数送给 l return(l); } float get_float() { char s[20]; //声明字符型数组 s[7] float f; //声明符点型变量 l get_string(s, 20); //从 RS232 口读 20 个字节,存储到 s 数组中 f = atof(s); //将数组 s[]的字符串转换成符点数送给 f return(f); } #endif //结束 if 定义 文件: 2416.c 如下: //// Library for a MicroChip 24LC16B //// //// init_ext_eeprom(); Call before the other functions are used //// //// write_ext_eeprom(a, d); Write the byte d to the address a //// //// d = read_ext_eeprom(a); Read the byte d from the address a //// //// b = ext_eeprom_ready(); Returns TRUE if the eeprom is ready //// //// to receive opcodes //// //// The main program may define EEPROM_SDA //// //// and EEPROM_SCL to override the defaults below. //// //// Pin Layout //// //// ----------------------------------------------------------- //// //// | | //// //// | 1: NC Not Connected | 8: VCC +5V | //// //// | 2: NC Not Connected | 7: WP GND | //// //// | 3: NC Not Connected | 6: SCL EEPROM_SCL and Pull-Up | //// //// | 4: VSS GND | 5: SDA EEPROM_SDA and Pull-Up | //// //// ----------------------------------------------------------- ////

Page 86: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 86

#ifndef EEPROM_SDA //若没有定义 EEPROM_SDA,则执行下面 #define EEPROM_SDA PIN_C4 //用 EEPROM_SDA 代替 PIN_C4 #define EEPROM_SCL PIN_C3 //用 EEPROM_SCL 代替 PIN_C3 #endif //结束 if 定义 #use i2c(master, sda=EEPROM_SDA, scl=EEPROM_SCL) // master 设置成主机方式 //除非指定了 FORCE_HW,否则会产生模拟 I2C 的软件函数.

//使能 I2C_START, I2C_STOP 直到下一个#USE I2C 的出现为止. //使能 I2C_READ, I2C_WRITE 直到下一个#USE I2C 的出现为止. //使能 I2C_POLL 直到下一个#USE I2C 的出现为止.

//指定 sda 脚为 EEPROM_SDA, 指定 scl 脚为 EEPROM_SCL #define EEPROM_ADDRESS long int //用 EEPROM_ADDRESS 代替 long int #define EEPROM_SIZE 2048 //用 EEPROM_SIZE 代替 2048 void init_ext_eeprom() { output_float(EEPROM_SCL); //将 EEPROM_SCL 引脚设为输入,开集电极连接 output_float(EEPROM_SDA); //将 EEPROM_SDA 引脚设为输入,开集电极连接 } BOOLEAN ext_eeprom_ready() { int1 ack; //声明位变量 ack i2c_start(); //发送启动条件 ack = i2c_write(0xa0); //发送从机地址 0xa0;若 ack=0,表示从机应答(ACK);

//若 ack=1,表示从机不应答(NO ACK); i2c_stop(); //发送停止条件 return !ack; } // ext_eeprom_ready()函数,若返回 1,表示从机准备好; 若返回 0,表示从机忙或 eeprom 坏了 void write_ext_eeprom(long int address, BYTE data) { while(!ext_eeprom_ready()); //若从机忙,则主机等待 i2c_start(); //发送启动条件 i2c_write( (0xa0|(BYTE)(address>>7))&0xfe); //发送命令字的高字节(发送写命令) i2c_write(address); //发送命令字的低字节 i2c_write(data); //发送数据 i2c_stop(); //发送停止条件 } BYTE read_ext_eeprom(long int address) { BYTE data; //声明字节变量 data while(!ext_eeprom_ready()); //先发器件地址,若从机忙,则主机等待 i2c_start(); //在此处是:发送重新启动条件 i2c_write( (0xa0|(BYTE)(address>>7))&0xfe); //发送命令字的高字节(发送写命令) i2c_write(address); //发送命令字的低字节 i2c_start(); //发送启动条件 i2c_write( (0xa0|(BYTE)(address>>7))|1); //发送命令字的高字节(发送读命令)

Page 87: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 87

data=i2c_read(0); //读 I2C 数据,然后发送 ack=0(不用从机应答) i2c_stop(); //发送停止条件 return(data); //返回所读到的 I2C 数据 } 上面的例子主要用来读写 24C16,通过 PC 机 RS232 进行验证 文件: 9356.c 如下: #ifndef EEPROM_SELECT //若没有定义 EEPROM_SELECT,则执行下面 #define EEPROM_SELECT PIN_B4 //用 EEPROM_SELECT 代替 PIN_B4 #define EEPROM_CLK PIN_B2 //用 EEPROM_CLK 代替 PIN_B2 #define EEPROM_DI PIN_B1 //用 EEPROM_DI 代替 PIN_B1 #define EEPROM_DO PIN_B0 //用 EEPROM_DO 代替 PIN_B0 #endif //结束 if 定义 #define EEPROM_ADDRESS BYTE //用 EEPROM_ADDRESS 代替 BYTE #define EEPROM_SIZE 256 //用 EEPROM_SIZE 代替 256 void init_ext_eeprom() { BYTE cmd[2]; //声明字节型数组 cmd[2]; BYTE i; //声明暂态字节型变量 i; output_low(EEPROM_DI); //将 EEPROM_DI 脚输出低电平; output_low(EEPROM_CLK); //将 EEPROM_CLK 脚输出低电平; output_low(EEPROM_SELECT); //将 EEPROM_SELECT 脚输出低电平; cmd[0]=0x80; //给数组赋初值 cmd[1]=0x9; //给数组赋初值 for(i=1;i<=4;++i)

shift_left(cmd,2,0); //将 cmd 所指的字单元左移 1 位, 低位移入 0; //左移 4 次后,数组 cmd 变为 0x08,0x00

output_high(EEPROM_SELECT); //将 EEPROM_SELECT 脚输出高电平; for(i=1;i<=12;++i) {

output_bit( EEPROM_DI, shift_left(cmd,2,0) ); //将 cmd 所指的字单元左移 1 位, 低位移入 0,移出的 高位通过 EEPROM_DI 脚输出;

output_high(EEPROM_CLK); //将 EEPROM_CLK 脚输出高电平; output_low(EEPROM_CLK); //将 EEPROM_CLK 脚输出低电平; } output_low(EEPROM_DI); //将 EEPROM_DI 脚输出低电平; output_low(EEPROM_SELECT); //将 EEPROM_SELECT 脚输出低电平,不片选 9356; } void write_ext_eeprom(EEPROM_ADDRESS address, BYTE data) { BYTE cmd[3]; //声明字节型数组 cmd[3] ; BYTE i; //声明暂态字节型变量 i;

Page 88: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 88

cmd[0]=data; //给数组赋初值 cmd[1]=address; //给数组赋初值 cmd[2]=0xa; //给数组赋初值 for(i=1;i<=4;++i)

shift_left(cmd,3,0); //将 cmd 所指的 3 字节单元左移 1 位, 低位移入 0,左移 4 次; output_high(EEPROM_SELECT); //将 EEPROM_SELECT 脚输出高电平; for(i=1;i<=20;++i) {

output_bit( EEPROM_DI, shift_left(cmd,3,0) ); //将 cmd 所指的 3 字节单元左移 1 位, 低位移入 0,移出的 高位通过 EEPROM_DI 脚输出; output_high(EEPROM_CLK); //将 EEPROM_CLK 脚输出高电平; output_low(EEPROM_CLK); //将 EEPROM_CLK 脚输出低电平; } output_low(EEPROM_DI); //将 EEPROM_DI 脚输出低电平; output_low(EEPROM_SELECT); //将 EEPROM_SELECT 脚输出低电平,不片选 9356; delay_ms(11); //延时 11ms } BYTE read_ext_eeprom(EEPROM_ADDRESS address) { BYTE cmd[3]; //声明字节型数组 cmd[3] ; BYTE i,data; //声明暂态字节型变量 i,data; cmd[0]=0; //给数组赋初值 cmd[1]=address; cmd[2]=0xc; for(i=1;i<=4;++i) shift_left(cmd,3,0); //将 cmd 所指的 3 字节单元左移 1 位, 低位移入 0,左移 4 次; output_high(EEPROM_SELECT); //将 EEPROM_SELECT 脚输出高电平,选择 9356; for(i=1;i<=20;++i) {

output_bit( EEPROM_DI, shift_left(cmd,3,0) ); //将 cmd 所指的 3 字节单元左移 1 位, 低位移入 0,移出的 高位通过 EEPROM_DI 脚输出; output_high(EEPROM_CLK); //将 EEPROM_CLK 脚输出高电平; output_low(EEPROM_CLK); //将 EEPROM_CLK 脚输出低电平; if(i>12) shift_left( &data,1,input(EEPROM_DO) );

//将 EEPROM_DO 脚的电平,左移入 data 所指向字节单元的 低位; } output_low(EEPROM_SELECT); //将 EEPROM_SELECT 脚输出低电平,不片选 9356; return(data); //返回读到的字节; }

Page 89: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 89

OUTPUT_FLOAT() 语法: output_float( pin ); 参数: pin 是定义在 devices.h 头文件中的 CPU 引脚名字,实际数值是一个位地址;例如:端口

a 的位 3,其位地址是 5*8+3 或 43,采用下面方法定义: #define PIN_A3 43; 返回值: 返回值未定义; 功能: 该函数将指定的 I/O 脚设置为输出方式,允许 I/O 脚悬空,表现为高,开集电极连接方

式; 有效性: 适合所有的 CPU 设备; 要求: Pin 常数被定义在 devices.h 的头文件中; 例子: if( ( data&0x80 )==0 ) output_low(PIN_A0); //将 PIN_A0 脚输出为低; else output_float( PIN_A0 ); //将 PIN_A0 脚输出为高,开集电极输出; 例子文件: 没有; OUTPUT_HIGH( ) 语法: output_high( pin ); 参数: pin 是定义在 devices.h 头文件中的 CPU 引脚名字,实际数值是一个位地址;例如:端口

a 的位 3,其位地址是 5*8+3 或 43,采用下面方法定义: #define PIN_A3 43; 返回值: 返回值未定义; 功能: 该函数将指定的 I/O 脚输出为高电平,设置方向寄存器的方法是由 后使用的#USE *_IO 的指定决定; 有效性: 适合所有的 CPU 设备; 要求: Pin 常数被定义在 devices.h 的头文件中; 例子: output_high( PIN_A0 ); //将 PIN_A0 脚设置为 1 输出; //在没有使用#USE *_IO 时,编译时会自动设置 I/O 方向寄存器 //这是我的理解 例子文件: ex_sqw.c 文件: ex_sqw.c 如下: #if defined(__PCM__) //若使用了 PCM 编译器,则 defined( __PCM__)返回值为 1 #include <16F877.h> //包含 16F877.h 头文件 #fuses HS,NOWDT,NOPROTECT //HS:高速晶振/谐振器, NOWDT:不使用 WDT // NOPROTECT:程序存储器代码不保护 #use delay(clock=20000000) //使能内置函数的功能:delay_ms()和 delay_us() //#USE DELAY()必须在#use rs232()使用之前出现. #use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)

//使用波特率为 9600, //发送脚为 PIN_C6 //接收脚为 PIN_C7 //使能内置函数:GETC,PUTC 和 PRINTF, kbhit();

#elif defined(__PCB__) #include <16c56.h> #fuses HS,NOWDT,NOPROTECT,NOLVP

Page 90: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 90

#use delay(clock=20000000) #use rs232(baud=9600, xmit=PIN_A3, rcv=PIN_A2) // Jumpers: 11 to 17, 12 to 18 #elif defined(__PCH__) #include <18F452.h> #fuses HS,NOWDT,NOPROTECT,NOLVP #use delay(clock=20000000) #use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7) // Jumpers: 8 to 11, 7 to 12 #endif //结束 if 定义 void main() { printf("Press any key to begin\n\r"); getc(); printf("1 khz signal activated\n\r"); while (TRUE) { output_high(PIN_B0); //脚(PIN_B0)输出高电平 delay_us(500); //延时 500us output_low(PIN_B0); //脚(PIN_B0)输出低电平 delay_us(500); //延时 500us } } 上面的例子介绍 delay_us(), output_high(), output_low()函数的用法 OUTPUT_LOW( ) 语法: output_low( pin ); 参数: pin 是定义在 devices.h 头文件中的 CPU 引脚名字,实际数值是一个位地址;例如:端口

a 的位 3,其位地址是 5*8+3 或 43,采用下面方法定义: #define PIN_A3 43; 返回值: 返回值未定义; 功能: 该函数将指定的 I/O 脚输出为低电平,设置方向寄存器的方法是由 后使用的#USE *_IO 的指定决定; 有效性: 适合所有的 CPU 设备; 要求: Pin 常数被定义在 devices.h 的头文件中; 例子: output_low( PIN_A0 ); //将 PIN_A0 脚设置为 0 输出; //在没有使用#USE *_IO 时,编译时会自动设置 I/O 方向寄存器 //这是我的理解 例子文件: ex_sqw.c,文件: ex_sqw.c 在前面已叙述; OUTPUT_TOGGLE( ) 语法: output_toggle( pin ); 参数: pin 是定义在 devices.h 头文件中的 CPU 引脚名字,实际数值是一个位地址;例如:端口

a 的位 3,其位地址是 5*8+3 或 43,采用下面方法定义: #define PIN_A3 43;

Page 91: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 91

返回值: 返回值未定义; 功能: 该函数将指定的 I/O 脚设置为高电平触发/低电平触发状态; 有效性: 适合所有的 CPU 设备; 要求: Pin 常数被定义在 devices.h 的头文件中; 例子: output_toggle(PIN_B4); //将 PIN_B4 脚设置为高电平触发/低电平触发 例子文件: 没有; PERROR( ) 语法: perror( string ); 参数: string 是一个字符串常数或字符数组(非结束符); 返回值: 返回值未定义; 功能: 该函数通过 RS232 接口输出给 STDERR,所提供的字符串和 后的 system error 描述

(通常为数学错误); 有效性: 适合所有的 CPU 设备; 要求: 必须包含头文件 errno.h,和使用#use rs232,才可使能该函数; 例子: x=sin(y); if( errno!=0 ) perror("Problem in find_area"); 例子文件: 没有; PORT_A_PULLUPS( ) 语法: port_a_pull-ups( value ); 参数: 在大多数 PIC 芯片中,value 为 TRUE 或 FALSE;有的 PIC 芯片允许将指定的个别引

脚上拉,而这儿的 value 就变成 8 位整型数据,其中每一位对应端口的一个引脚; 返回值: 返回值未定义; 功能: 该函数将端口 A 设置为输入上拉,当 value 为 TRUE 时,使能输入上拉; 当 value 为FALSE 时,不使能输入上拉; 有效性: 只适合 14 位和 16 位的 PIC 单片机( 使用 PCM 和 PCH 编译器 ).(注意:在 PCB 编译

下的元件,使用 setup_counters). 要求: 没有; 例子: port_a_pullups( FALSE ); //端口 A 不使能输入上拉; 例子文件: ex_lcdkb.c 和 kbd.c EX_LCDKB.C 文件如下: #if defined(__PCB__) #include <16c56.h> #fuses HS,NOWDT,NOPROTECT #use delay(clock=20000000) #elif defined(__PCM__) #include <16F877.h> #fuses HS,NOWDT,NOPROTECT,NOLVP

Page 92: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 92

#use delay(clock=20000000) #elif defined(__PCH__) //若使用了 PCH 编译器,则 defined( __PCH__)返回值为 1 #include <18F452.h> //包含 18F452.h 头文件 #fuses HS, NOWDT, NOPROTECT, NOLVP //HS:高速晶振/谐振器, NOWDT:不使用 WDT // NOPROTECT:程序存储器代码不保护 #use delay(clock=20000000) //使能内置函数的功能:delay_ms()和 delay_us() //#USE DELAY()必须在#use rs232()使用之前出现. #endif //结束 if 定义 #include <lcd.c> //包含 lcd.c 文件 #include <kbd.c> //包含 kbd.c 文件 void main() { char k; //声明字符型变量 k lcd_init(); //初始化 LCD kbd_init(); //键盘初始化 lcd_putc("\fReady...\n"); //LCD 先走纸换页,接着将 Ready...送给 LCD 显示,然后换行 while (TRUE) { k=kbd_getc(); //读键盘 if(k!=0) if(k=='*') lcd_putc('\f'); //若 k 是'*',则 LCD 走纸换页 else lcd_putc(k); //将 K 值送给 LCD 显示 } } KBD.C 文件如下: #if defined(__PCH__) //若使用了 PCH 编译器,则 defined( __PCH__)返回值为 1 #if defined use_portb_kbd //若使用了 use_portb_kbd,则 defined use_portb_kbd 返回 1 #byte kbd = 0xF81 //将 kbd 对应端口为 PORT B (at address 0xF81) #else #byte kbd = 0xF83 //如果没有使用,将 kbd 对应端口为 PORT D (at address 0xF83) #endif //结束 if 定义 #else #if defined use_portb_kbd //若使用了 use_portb_kbd,则 defined use_portb_kbd 返回 1 #byte kbd = 6 //将 kbd 对应端口为 port B (at address 6) #else #byte kbd = 8 //将 kbd 对应端口为 port D (at address 8) #endif //结束 if 定义 #endif //结束 if 定义 #if defined use_portb_kbd //若使用了 use_portb_kbd,则 defined use_portb_kbd 返回 1

Page 93: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 93

#define set_tris_kbd(x) set_tris_b(x) //用 set_tris_kbd(x)代替 set_tris_b(x) #else #define set_tris_kbd(x) set_tris_d(x) //用 set_tris_kbd(x)代替 set_tris_d(x) #endif //结束 if 定义 //Keypad connection: (for example column 0 is B2) // Bx: #ifdef blue_keypad //若使用了 blue_keypad,则定义如下 #define COL0 (1 << 2) //用 COL0 代替表达式(1 << 2) #define COL1 (1 << 3) //用 COL1 代替表达式(1 << 3) #define COL2 (1 << 6) //用 COL2 代替表达式(1 << 6) #define ROW0 (1 << 4) //用 ROW0 代替表达式(1 << 4) #define ROW1 (1 << 7) //用 ROW1 代替表达式(1 << 7) #define ROW2 (1 << 1) //用 ROW2 代替表达式(1 << 1) #define ROW3 (1 << 5) //用 ROW3 代替表达式(1 << 5) #else #define COL0 (1 << 5) //用 COL0 代替表达式(1 << 5) #define COL1 (1 << 6) //用 COL1 代替表达式(1 << 6) #define COL2 (1 << 7) //用 COL2 代替表达式(1 << 7) #define ROW0 (1 << 1) //用 ROW0 代替表达式(1 << 1) #define ROW1 (1 << 2) //用 ROW1 代替表达式(1 << 2) #define ROW2 (1 << 3) //用 ROW2 代替表达式(1 << 3) #define ROW3 (1 << 4) //用 ROW3 代替表达式(1 << 4) #endif //结束 if 定义 #define ALL_ROWS (ROW0|ROW1|ROW2|ROW3) //用 ALL_ROWS 代替表达式 #define ALL_PINS (ALL_ROWS|COL0|COL1|COL2) //用 ALL_PINS 代替表达式 // Keypad layout: char const KEYS[4][3] = {{'1','2','3'}, {'4','5','6'}, {'7','8','9'}, {'*','0','#'}}; #define KBD_DEBOUNCE_FACTOR 33 // Set this number to apx n/333 where // n is the number of times you expect // to call kbd_getc each second void kbd_init() { } char kbd_getc( ) { static BYTE kbd_call_count; //声明静态变量 kbd_call_count

Page 94: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 94

static short int kbd_down; //声明静态变量 kbd_down static char last_key; //声明静态变量 last_key static BYTE col; //声明静态变量 col BYTE kchar; //声明暂态变量 kchar BYTE row; //声明暂态变量 row kchar='\0'; //给暂态变量 kchar 赋初值'\0'(空字符'\0') if(++kbd_call_count>KBD_DEBOUNCE_FACTOR) { switch (col) { case 0 : set_tris_kbd(ALL_PINS & ~COL0); kbd=~COL0&ALL_PINS; break; case 1 : set_tris_kbd(ALL_PINS&~COL1); kbd=~COL1&ALL_PINS; break; case 2 : set_tris_kbd(ALL_PINS&~COL2); kbd=~COL2&ALL_PINS; break; } if(kbd_down) { if((kbd & (ALL_ROWS))==(ALL_ROWS)) { kbd_down=FALSE; kchar=last_key; last_key='\0'; //(空字符'\0') } } else { if((kbd & (ALL_ROWS))!=(ALL_ROWS)) { if((kbd & ROW0)==0) row=0; else if((kbd & ROW1)==0) row=1; else if((kbd & ROW2)==0) row=2; else if((kbd & ROW3)==0) row=3; last_key =KEYS[row][col]; kbd_down = TRUE; } else { ++col; if(col==3) col=0; } } kbd_call_count=0;

Page 95: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 95

} set_tris_kbd(ALL_PINS); return(kchar); } LCD.C 文件如下: // As defined in the following structure the pin connection is as follows: // D0 enable // D1 rs // D2 rw // D4 D4 // D5 D5 // D6 D6 // D7 D7 // // LCD pins D0-D3 are not used and PIC D3 is not used. // Un-comment the following define to use port B // #define use_portb_lcd TRUE struct lcd_pin_map { BOOLEAN enable; // enable 为 1 位,对应 B0 BOOLEAN rs; // rs 为 1 位,对应 B1 BOOLEAN rw; // rw 为 1 位,对应 B2 BOOLEAN unused; // unused 为 1 位,对应 B3 int data : 4; // 声明 data 为 4 位,对应 B4,B5,B6,B7 } lcd; // lcd 为全局变量,对应端口为 PORT B #if defined(__PCH__) //如果定义了 PCH, 则 #if defined use_portb_lcd #byte lcd = 0xF81 //如果定义了 use_portb_lcd, 则定义 lcd 为全局变量,对应端口为

PORT B (at address 0xF81) #else #byte lcd = 0xF83 //如果没有定义 use_portb_lcd, 则定义 lcd 为全局变量,对应端口为 PORT D (at address 0xF83) #endif //结束 if 定义 #else //若没有定义 PCH, 则 #if defined use_portb_lcd #byte lcd = 6 //如果没有定义 use_portb_lcd, 则定义 lcd 为全局变量,对应端口为 port B (at address 6) #else #byte lcd = 8

Page 96: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 96

//如果没有定义 use_portb_lcd, 则定义 lcd 为全局变量,对应端口为 port D (at address 8) #endif //结束 if 定义 #endif //结束 if 定义 #if defined use_portb_lcd //若使用了 use_portb_lcd,则 defined use_portb_lcd 返回 1 #define set_tris_lcd(x) set_tris_b(x) //用 set_tris_lcd(x)代替 set_tris_b(x) #else #define set_tris_lcd(x) set_tris_d(x) //用 set_tris_lcd(x)代替 set_tris_d(x) #endif //结束 if 定义 #define lcd_type 2 // 0=5x7, 1=5x10, 2=2 lines,用 lcd_type 代替 2 #define lcd_line_two 0x40 // LCD RAM address for the second line 用 lcd_line_two 代替 0x40 BYTE const LCD_INIT_STRING[4] = {0x20 | (lcd_type << 2), 0xc, 1, 6}; // These bytes need to be sent to the LCD // to start it up. struct lcd_pin_map const LCD_WRITE = {0,0,0,0,0};

// For write mode all pins are out , 用 const 声明 LCD_WRITE 常数 struct lcd_pin_map const LCD_READ = {0,0,0,0,15};

// For read mode data pins are in ,用 const 声明 LCD_READ 为常数 BYTE lcd_read_byte() {

BYTE low,high; //声明暂态变量 low,high, //high 用来存字节的高 4 位,low 用来存字节的低 4 位

set_tris_lcd(LCD_READ); //设置端口的低 4 位为输出口,端口的高 4 位为输入口 lcd.rw = 1; //发 LCD 读命令 delay_cycles(1); //相当于 1 个 NOP 指令 lcd.enable = 1; //LCD 使能 delay_cycles(1); //相当于 1 个 NOP 指令 high = lcd.data; //读端口的高 4 位 lcd.enable = 0; // LCD 不使能 delay_cycles(1); //相当于 1 个 NOP 指令 lcd.enable = 1; //LCD 使能 delay_us(1); //延时 1us low = lcd.data; //读端口的低 4 位 lcd.enable = 0; // LCD 不使能 set_tris_lcd(LCD_WRITE); //设置控制 LCD 端口为输出口 return( (high<<4) | low); //合并字节的高 4 位和字节的低 4 位,组成 1 个字节,返回 } void lcd_send_nibble( BYTE n ) { lcd.data = n; delay_cycles(1); //相当于 1 个 NOP 指令 lcd.enable = 1; //LCD 使能 delay_us(2); //延时 2us lcd.enable = 0; // LCD 不使能

Page 97: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 97

} void lcd_send_byte( BYTE address, BYTE n ) { lcd.rs = 0; //选择 LCD 的地址寄存器 while ( bit_test( lcd_read_byte(), 7) ) ; //bit_test(X,b)位测试涵数 lcd.rs = address; //选择 LCD 的地址寄存器 delay_cycles(1); //相当于 1 个 NOP 指令 lcd.rw = 0; //发送 LCD 写命令 delay_cycles(1); //相当于 1 个 NOP 指令 lcd.enable = 0; // LCD 不使能 lcd_send_nibble(n >> 4); //送出 n 的高 4 位 lcd_send_nibble(n & 0xf); //送出 n 的低 4 位 } void lcd_init() { BYTE i; //声明暂态变量 i set_tris_lcd(LCD_WRITE); //设置控制 LCD 端口为输出口 lcd.rs = 0; //选择 LCD 的地址寄存器 lcd.rw = 0; //发送 LCD 写命令 lcd.enable = 0; //LCD 使能 delay_ms(15); //延时 15ms for(i=1;i<=3;++i) { lcd_send_nibble(3); //将 0x333 送给 LCD delay_ms(5); //延时 5ms } lcd_send_nibble(2); //将 0x2333 送给 LCD for(i=0;i<=3;++i) lcd_send_byte(0,LCD_INIT_STRING[i]); } void lcd_gotoxy( BYTE x, BYTE y) { BYTE address; //声明暂态变量 address if(y!=1) address=lcd_line_two; //将 0x40 送给 address else address=0; address+=x-1; lcd_send_byte(0,0x80|address); } void lcd_putc( char c) {

Page 98: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 98

switch (c) { case '\f' : lcd_send_byte(0,1); //若 c 是走纸换页符('\f'),则执行该行 delay_ms(2); break;

case '\n' : lcd_gotoxy(1,2); //若 c 是换行符('\n'),则执行该行 break;

case '\b' : lcd_send_byte(0,0x10); //若 c 是退格符('\b'),则执行该行 break;

default : lcd_send_byte(1,c); break; } } char lcd_getc( BYTE x, BYTE y) { char value; lcd_gotoxy(x,y); while ( bit_test(lcd_read_byte(),7) ); // wait until busy flag is low lcd.rs=1; value = lcd_read_byte(); lcd.rs=0; return(value); } PORT_B_PULLUPS( ) 语法: port_b_pull-ups( value ); 参数: 在大多数 PIC 芯片中,value 为 TRUE 或 FALSE;有的 PIC 芯片允许将指定的个别引

脚上拉,而这儿的 value 就变成 8 位整型数据,其中每一位对应端口的一个引脚; 返回值: 返回值未定义; 功能: 该函数将端口 B 设置为输入上拉,当 value 为 TRUE 时,使能输入上拉; 当 value 为FALSE 时,不使能输入上拉; 有效性: 只适合 14 位和 16 位的 PIC 单片机( 使用 PCM 和 PCH 编译器 ).(注意:在 PCB 编译

下的元件,使用 setup_counters). 要求: 没有; 例子: port_b_pullups( FALSE ); //端口 B 不使能输入上拉; 例子文件: ex_lcdkb.c 和 kbd.c POW( ) PWR( ) 语法: f=pow(x, y); f=pwr(x, y); 参数: x 和 y 是浮点数, x 是底数,y 是指数; 返回值: 返回值是一个浮点数; 功能: 该函数用来计算 x 的 y 次幂;

Page 99: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 99

注意:存在 error 挂起; 如果在编写程序里包含了 errno.h 头文件,则范围和等级错误存储在 errno 变量里.用户通过检测 errno 变量,可发现是否有错误存在,且用 perror 函数打印出这个错误. 范围错误存在下面的原因: 底数 x 是一个负数; 有效性: 适合所有的 CPU 设备; 要求: 必须包含头文件 math.h,即用语句 #include < math.h > 例子: area=(size, 3.0); //计算 size 的 3 次方; 例子: 没有; PRINTF( ) FPRINTF( ) 语法: printf(string); 或 printf(cstring, valves…); 或 printf(fname, cstring, valves…); 或 fprintf(stream, cstring, valves…); 参数: string 是一个字符常数或是一串不带结束符的字符串;

valves 是一系列由逗号隔开的变量; fname是被用作输出的函数名(在没有指定函数名的情况下,默认函数名为putc, putc()

是一个输出单字符的函数); stream 是一串标识符(一个常数字节);

返回值: 返回值未定义; 功能: 该函数用来输出一串字符串给标准的 RS-232 脚或给一个指定的函数;格式上同

string 保持一致;当使用变量时,string 必须是一个常数;%参数被用在里面时,指示变量值将被

格式为 string 的格式进行输出. 在 printf 中的 longs 可能是 16 位或 32 位.; %%表示输出单个%; 下面采用%定义格式化规则: 格式: 格式采用%nt 表示;

n 是可选项,可能为 1~9,用来指定多少字符将被输出;n 也可能是 01~09,用来指定以 0 为

开始,共有多少字符将被输出; n 也可能是 1.1~9.9,用于浮点数和%w 格式输出; t 是下面的一种形式; c 字符 s 字符串或字符 u 无符号整型(无符号十进制) d 有符号整型(有符号十进制) lu 无符号长整型(无符号十进制) ld 有符号长整型(有符号十进制) x 十六进制整型(小写形式:如 ac)

Page 100: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 100

X 十六进制整型(大写形式:如 AC) Lx 十六进制长整型(小写形式:如 00ac) LX 十六进制长整型(大写形式:如 00AC) f 浮点数连同被截去的小数 g 浮点数连同被四舍五入的小数 e 浮点数以指数 格式输出; w 无符号整型,在十进制数中放置插入的小数点,要为 n 指定两个数,第一个数用来指定 十进制数的总位数,第二个数用来指定要得到的小数. 例子格式: 指定格式 Value=0x12 %03u 则 Value 输出为 018 %u 则 Value 输出为 18 %2u 则 Value 输出为 18 %5 则 Value 输出为 18 %d 则 Value 输出为有符号十进制数 18 %x 则 Value 小写十六进制格式输出为 12 %X 则 Value 大写十六进制格式输出为 12 %4X 则 Value 大写十六进制格式输出为 0012 %3.1W 则 Value 输出为 1.8,字宽为 3,一位小数. 指定格式 Value=0xfe %03u 则 Value 输出为 254 %u 则 Value 输出为 254 %2u 则 Value 输出为* %5 则 Value 输出为 254 %d 则 Value 输出为有符号十进制数-2 %x 则 Value 小写十六进制格式输出为 fe %X 则 Value 大写十六进制格式输出为 FE %4X 则 Value 大写十六进制格式输出为 00FE %3.1W 则 Value 输出为 25.4,字宽为 3,一位小数. 有效性: 适合所有的 CPU 设备; 要求: 必须使用语句 #use rs232(除非 fname 被使用,fname 是被用作输出的函数名) 例子: byte x, y, z; printf("HiThere"); //通过 RS232 输出 HiThere printf("RTCCValue=>%2x\n\r",get_rtcc( ) ); printf("%2u %X %4x\n\r",x,y,z); //x 以十进制输出,y 以十六进制大写输出, printf(LCD_PUTC, "n=%u",n); .//通过 LCD_PUTC 函数以十进制字符输出输出 n 例子文件: ex_lcdkb.c 和 ex_admm.c; PSP_OUTPUT_FULL( ) PSP_INPUT_FULL( ) PSP_OVERFLOW( )

Page 101: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 101

语法: result=psp_output_full( ); result=psp_input_full( ); result=psp_overflow( ); 参数: 没有; 返回值: 返回值为 0(FALSE)或 1(TRUE) psp_output_full( )的返回值为 1,表示输出的数据没有被外部读走; psp_output_full( )的返回值为 0,表示输出的数据已被外部读走; psp_input_full( )的返回值为 0,表示输入的数据没有被本机读走; psp_input_full( )的返回值为 1,表示输入的数据被本机读走; psp_overflow( ) 的返回值为 1, 表示 PSP 口缓冲器溢出; 功能: 该函数用来检测并行从属端口(PSP 口)的指示条件,且返回 0(FALSE)或 1(TRUE); 1, 当 CS=0,且 WR=0 时,发生一个写并行从属端口(PSP 口)的写操作; 2, 当 CS=1,且 WR=1 时,输入缓冲器满标志位(IBF)被置 1,同时, PSP 中断标志位

(PSPIF)被设置为 1; 输入缓冲器满标志位(IBF)只能通过读并行从属端口(PSP 口)的输入锁存

器,才可被清 0;若上次写入字节还没有被读走,又发生第二次写入 PSP 口,这时,输入缓冲器溢

出标志位(IBOV)被设置为 1,指出写溢出; 3, 当 CS=0,且 RD=0 时,发生一个读并行从属端口(PSP 口)的读操作,输出缓冲器数

据被外部读走时,输出缓冲器的满标志位(OBF)被立即清 0; 当外部的引脚 CS=1,且 RD=1 时, PSP 中断标志位(PSPIF)被设置为 1,表明读操作才算被完成; 4, 若输出缓冲器在等待外部来读时, 输出缓冲器的满标志位(OBF)被置 1,数据一旦

被读走, 输出缓冲器的满标志位(OBF)被立即清 0;若输出缓冲器正在等待外部来读,这时,又向输出缓冲器写入新的数据, 输出缓冲器溢出标志位(IBOV) 被设置为 1,指出写溢出; 有效性: 只适合带有并行从属端口(PSP 口)的 CPU 设备; 要求: 没有; 例子: while ( psp_output_full() ) ; //若 PSP 口输出缓冲器满标志位为 1,则等待 psp_data=command; while ( !psp_intput_full() ) ; //若 PSP 口输入缓冲器满标志位为 0,则等待 if( psp_overflow() ) //若 PSP 口缓冲器溢出,则将 error=TRUE error=TRUE; else data=psp_data; 例子文件: ex_psp.c 文件 ex_psp.c 如下: #if defined(__PCM__) //若使用了 PCM 编译器,则 defined( __PCM__)返回值为 1 #include <16F877.h> //包含 18F877.h 头文件 #fuses HS,NOWDT,NOPROTECT,NOLVP //HS:高速晶振/谐振器, NOWDT:不使用 WDT // NOPROTECT:程序存储器代码不保护 #use delay(clock=20000000) //使能内置函数的功能:delay_ms()和 delay_us() //#USE DELAY()必须在#use rs232()使用之前出现. #use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)

//使用波特率为 9600, //发送脚为 PIN_C6 //接收脚为 PIN_C7 //使能内置函数:GETC,PUTC 和 PRINTF, kbhit();

Page 102: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 102

#elif defined(__PCH__) #include <18F452.h> #fuses HS,NOWDT,NOPROTECT,NOLVP #use delay(clock=20000000) #use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7) // Jumpers: 8 to 11, 7 to 12 #error For PIC18 change read/write _bank to use a buffer #endif //结束 if 定义 #define BUSY_LINE PIN_C0 //用 BUSY_LINE 代替脚 PIN_C0 #define BUFFER_SIZE 96 //用 BUFFER_SIZE E 代替 96 int next_in = 0; //声明整型全局变量 next_in 并赋初值为 0 int next_out = 0; //声明整型全局变量 next_out 并赋初值为 0 short data_lost = TRUE; //声明 short 型全局位变量 data_lost, 并赋初值为 TRUE #int_psp //并行从机端口(PSP 口)的中断标志位, 指定下面的函数是一个中断服务函数 void psp_isr() { if( psp_overflow() ) //若 PSP 口缓冲器溢出,则数据丢弃 data_lost=TRUE; if( psp_input_full() ) { //若 PSP 口输入缓冲器满标志位为 1,表示数据被本机读走 write_bank( 2, next_in++, input_D() ); //读 PSP 口数据,存到 bank2 区 if( next_in == BUFFER_SIZE ) next_in = 0; if( next_in == next_out ) output_high( BUSY_LINE ); //将 BUSY_LINE 脚输出高 } } void main() { setup_adc_ports(NO_ANALOGS); //不使用 AD 输入 setup_psp(PSP_ENABLED); //使能 PSP 口 enable_interrupts(GLOBAL); //使能总中断允许位 enable_interrupts(INT_PSP); //设置 PSP 口的中断允许位 output_low(BUSY_LINE); //将 BUSY_LINE 脚输出低 printf("Waiting for print data... \r\n\n"); while(true) { if(next_in!=next_out) { putc( read_bank(2,next_out) ); //读 bank2 区,通过 RS232 送出去 if(++next_out==BUFFER_SIZE) next_out=0; if(data_lost) { printf("\r\nData Lost!!!\r\n"); data_lost = FALSE; } output_low(BUSY_LINE); //将 BUSY_LINE 脚输出低

Page 103: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 103

} } } 上面的程序将从 PSP 口读到的数据存到 bank2 区,然后通过 RS232 送出去; PUTC( ) PUTCHAR( ) FPUTC( ) 语法: putc(cdata); putchar(cdata); value=fputc(cdata, stream); 参数: cdata 是一个 8 位字符 stream 是一串标识符(为一个常数字节); 返回值: 返回值没有定义; 功能: 该函数用来通过 RS232 的 XMIT 发送脚发送一个字符;在决定波特率和要用到的引

脚之前,必须先使用#USE RS232 语句,这#USE RS232 语句有效,直到下一个#USE RS232 语句

出现为止; 如果 fputc( )被使用的话,那么指定的串就被使用了,这里的 putc()默认为 STDOUT(由

后使用的#USE RS232 语句决定). 有效性: 适合所有的 CPU 设备; 要求: 必须先使用#USE RS232 语句; 例子: putc('* '); //通过 RS232 的 XMIT 发送脚输出字符”*” for(i=0; i<10; i++) putc(buffer[i]); //通过 RS232 的 XMIT 发送脚输出数阻 buffer[i]的内容 putc(13); 例子文件: ex_tgetc.c 文件 ex_tgetc.c 如下: #if defined(__PCB__) //若使用了 PCB 编译器,则 defined( __PCB__)返回值为 1 #include <16c56.h> //包含 16c56.h 头文件 #fuses HS, NOWDT, NOPROTECT //HS:高速晶振/谐振器, NOWDT:不使用 WDT // NOPROTECT:程序存储器代码不保护 #use delay(clock=20000000) //使能内置函数的功能:delay_ms()和 delay_us() //#USE DELAY()必须在#use rs232()使用之前出现. #use rs232(baud=9600, xmit=PIN_A3, rcv=PIN_A2)

//使用波特率为 9600, //发送脚为 PIN_A3 //接收脚为 PIN_A2 //使能内置函数:GETC,PUTC 和 PRINTF, kbhit();

#elif defined(__PCM__) //若使用了 PCM 编译器,则 defined( __PCM__)返回值为 1 #include <16F877.h> //包含 18F877.h 头文件 #fuses HS,NOWDT,NOPROTECT,NOLVP //HS:高速晶振/谐振器, NOWDT:不使用 WDT // NOPROTECT:程序存储器代码不保护 #use delay(clock=20000000) //使能内置函数的功能:delay_ms()和 delay_us() //#USE DELAY()必须在#use rs232()使用之前出现.

Page 104: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 104

#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7) //使用波特率为 9600, //发送脚为 PIN_C6 //接收脚为 PIN_C7 //使能内置函数:GETC,PUTC 和 PRINTF, kbhit();

#elif defined(__PCH__) #include <18F452.h> #fuses HS,NOWDT,NOPROTECT,NOLVP #use delay(clock=20000000) #use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7) // Jumpers: 8 to 11, 7 to 12 #endif //结束 if 定义 #include <input.c> //包含 input.c 头文件 #define KEYHIT_DELAY 500 //用 KEYHIT_DELAY 代替 500 char timed_getc() { long timeout; //声明暂态长整型变量 timeout char retval; //声明暂态字节整型变量 retval timeout=0; //给 timeout 赋初值 0 while( !kbhit() && ( ++timeout< (KEYHIT_DELAY*100) ) ) delay_us(10); if( kbhit() ) //若 RS232 接口读到数据,则 kbhit()返回 1,否则, kbhit()返回 0 retval = getc(); else retval = 0; return(retval); } void main() { int status; char value; while(TRUE) { status=1; printf("\r\nStart typing:\r\n"); while(!kbhit()); //若 RS232 接口读到数据,则 kbhit()返回 1,否则, kbhit()返回 0 while(status==1) { value=timed_getc(); //从 RS232 口读一个字节 if(value==0) status=0; else { status=1; putc(value); //若读到的字符不是 0,则通过 RS232 发送出去

Page 105: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 105

} } printf("\r\nToo slow!\r\n"); } } 文件 input.c 如下: #include <CTYPE.H> //包含 CTYPE.H 头文件 //从 RS232 口读一字节,再通过 RS232 发出去,将读到的字符转化 16 进制格式 BYTE gethex1() { char digit; //声明字节型暂态变量 digit digit = getc(); //读 RS232 接口 putc(digit); //将读到的数据通过 RS232 口发送出去 if(digit<='9') //将小于等于 9 的字符减去字符 0, 变为 16 进制格式 return(digit-'0'); else

return( (toupper( digit )-'A' )+10 ); //将 digit 转换为大写字符,再减去字符 A,加 10 后,变为 16 进制格式

} BYTE gethex() { int lo,hi; //声明整型暂态变量 lo,hi hi = gethex1(); //将从 RS232 口读的字符,转换为 16 进制数,赋给 hi lo = gethex1(); //将从 RS232 口读的字符,转换为 16 进制数,赋给 lo if(lo==0xdd) return(hi); //若为单字符,则只返回 hi else return( hi*16+lo ); //若为双字符,则将 lo 和 hi 合成一个字输出 } void get_string(char* s, int max) { int len; //声明整型暂态变量 len char c; //声明字节型暂态变量 c --max; //先将 max 自减 1 len=0; //给 len 赋初值 0 do { c=getc(); //读 RS232 接口 if(c==8) { // Backspace 若 c 为退格键 if(len>0) { len--; putc(c); //通过 RS232 输出退格键 putc(' '); //通过 RS232 输出空格字符 putc(c); //通过 RS232 输出退格键 }

Page 106: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 106

} else if ( (c>=' ')&&(c<='~') )

if(len<max) { s[len++]=c; //将从 RS232 口读到的字符,存到数阻 s[]中 putc(c); //将读到的字符,通过 RS232 口发送出去 } } while(c!=13); // s[len]=0; //将数组的 后的字节设置为停止符 } #ifdef _STDLIB signed int get_int() { char s[5]; //声明数组 s[] signed int i; //声明有符号整型 i get_string(s, 5); //从 RS232 口读 4 个字符和一个停止符,存到数组 s[]中 i=atoi(s); //将字符型数组 s[]中的元素转换为 8 位整型送给 i return(i); } signed long get_long() { char s[7]; //声明数组 s[] signed long l; //声明有符号长整型 l get_string(s, 7); //从 RS232 口读 6 个字符和 1 个停止符,存到数组 s[]中 l=atol(s); //将字符型数组 s[]中的元素转换为 16 位整型送给 l return(l); } float get_float() { char s[20]; //声明数组 s[] float f; //声明暂态浮点型变量 f get_string(s, 20); //从 RS232 口读 19 个字符和 1 个停止符,存到数组 s[]中 f = atof(s); //将字符型数组 s[]中的元素转换为浮点型送给 f return(f); } #endif PUTS( ) FPUTS( ) 语法: puts(string); value=fputs(string,stream); 参数: string 是一个常数字符或是一个没有结束符的字符数组. stream 是一串标识符(为一个常数字节); 返回值: 返回值没有定义;

Page 107: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 107

功能: 该函数用来通过 RS232 的 XMIT 发送脚,采用 putc()来发送 string 中的每个字符;这个

string 被发送完后,RETURN(13)和 LINEFEED(10)紧跟着被发送出去;在通常情况下,printf()比puts( )更有用.

如果 fputs( )被使用的话,那么指定的串就被使用了,这里的 puts()默认为 STDOUT(由后使用的#USE RS232 语句决定).

有效性: 适合所有的 CPU 设备; 要求: 必须先使用#USE RS232 语句; 例子: puts("---------"); puts(" | HI | "); puts("---------"); 例子文件: 没有 QSORT( ) 语法: qsort( base,num,width, compar); 参数: base: 为指向数组的指针; num: 为元素的个数; width: 为元素的宽度; compar: 为对两个元素进行比较的函数名; 返回值: 返回值没有; 功能: 该函数; 有效性: 适合所有的 CPU 设备; 要求: 必须先使用#include <stdlib.h>语句; 例子: int nums[5]={2,3,1,5,4}; int compar (const void *arg1, const void *arg2); //声明函数 compar(); void main( ){ qsort( nums, 5, sizeof (int), compar ); } int compar (const void *arg1, const void *arg2){ if( * (int *) arg1<(* (int *) arg2) ) return –1; else if( * (int *) arg1==(* (int *) arg2) ) return 0; else return 1; } 例子文件: 没有 RAND( ) 语法: result =rand( ); 参数: 没有; 返回值: 返回值是任意的虚整数; 功能: 该函数返回的是从 0 到 RAND_MAX 为范围的任意整数序列. 有效性: 适合所有的 CPU 设备; 要求: 必须先使用#include <stdlib.h>语句;

Page 108: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 108

例子: int I; I=rand( ); 例子文件: 没有. READ_ADC( ) 语法: value=read_adc( [mode] ); 参数: mode 是一个可选项参数.它可能是:

ADC_START_AND_READ(这是默认值); ADC_START_ONLY(开始转换,然后返回 AD 转换值); ADC_READ_ONLY(读 后一次的 AD 转换结果).

返回值: 根据#DEVICE ADC=directive,返回值是要么是 8 位值,要么是 16 位值; 功能: 该函数读到的数据是将模拟转换为数据的转换值.在使用 read_adc()之前,有时要先

创建函数:setup_adc( ), setup_adc_ports( ) 和 setup_adc_channal( );返回值的范围要根据芯片的

AD 转换器的位数,在#DEVICE ADC=directive 中设置如下: #DEVICE 8 位 10 位 11 位 16 位 ADC=8 00-FF 00-FF 00-FF 00-FF ADC=10 X 00-3FF X X ADC=11 X X 00-7FF X ADC=16 0-FF00 0-FFC0 0-FFE0 0-FFFF 注意:X 表示没有定义; 有效性: 这些函数只对含有 AD 转换的 CPU 设备有用; 要求: 脚常数必须被定义在设备 devices.h 的头文件中; 例子: setup_adc( ADC_CLOCK_INTERNAL ); //设置 AD 转换采用内部指令时钟 setup_adc_ports( ALL_ANALOG ); //将所有的 AD/IO 口设置为模拟输入口 set_adc_channel( 1 ); //选择 AD 通道 1 准备进行 AD 转换 while( input( PIN_B0 ) ){ //脚 RB0 为 1 吗? delay_ms( 5000 ); //软件延时 5000ms,即 5 秒 value=read_adc( ); //读 AD 口的值 printf("A/D value = 2%x\n\r", value); //通过 RS232 输出 A/D value =xx } read_adc( ADC_START_ONLY ); //开始 AD 转换,然后返回 AD 转换值 sleep( ); //CPU 睡眠 value=read_adc( ADC_READ_ONLY ); //读 后一次的 AD 转换结果 例子文件: ex_admm.c,ex_14kad.c; 文件 ex_admm.c 如下: #if defined(__PCM__) //若使用了 PCM 编译器,则 defined( __PCM__)返回值为 1 #include <16F877.h> //包含 18F877.h 头文件 #fuses HS,NOWDT,NOPROTECT,NOLVP //HS:高速晶振/谐振器, NOWDT:不使用 WDT // NOPROTECT:程序存储器代码不保护 #use delay(clock=20000000) //使能内置函数的功能:delay_ms()和 delay_us() //#USE DELAY()必须在#use rs232()使用之前出现. #use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)

//使用波特率为 9600,

Page 109: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 109

//发送脚为 PIN_C6 //接收脚为 PIN_C7 //使能内置函数:GETC,PUTC 和 PRINTF, kbhit();

#elif defined(__PCH__) #include <18F452.h> #fuses HS,NOWDT,NOPROTECT,NOLVP #use delay(clock=20000000) #use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7) // Jumpers: 8 to 11, 7 to 12 #endif //结束 if 定义 void main() { int i, value, min, max; //声明整型变量 i, value, min, max printf("Sampling:"); //通过 RS232 口输出 Sampling: setup_adc_ports( ALL_ANALOG ); //将所有的 AD/IO 口设置为模拟输入口 setup_adc( ADC_CLOCK_INTERNAL ); //设置 AD 转换采用内部指令时钟 set_adc_channel( 0 ); //选择 AD 通道 0 准备进行 AD 转换 do { min=255;

max=0; //采样 AD 口 31 次,将采样值送给 min 和 max

for(i=0; i<=30; ++i) { delay_ms(100); //软件延时 100ms,即 0.1 秒 value = Read_ADC(); //读 AD 口的值 if(value<min) min=value; //若 value<255,则将 value 的值送给 min if(value>max) max=value; //若 value>0,则将 value 的值送给 max } printf("\n\rMin: %2X Max: %2X\n\r",min,max); //通过 RS232 输出 min 和 max } while (TRUE); } 文件 ex_14kad.c 如下: #if defined(__PCM__) //若使用了 PCM 编译器,则 defined( __PCM__)返回值为 1 #include <14000.h> //包含 14000.h 头文件 #fuses HS,NOWDT,NOPROTECT,NOLVP //HS:高速晶振/谐振器, NOWDT:不使用 WDT // NOPROTECT:程序存储器代码不保护 #use delay(clock=20000000) //使能内置函数的功能:delay_ms()和 delay_us() //#USE DELAY()必须在#use rs232()使用之前出现. #use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)

//使用波特率为 9600, //发送脚为 PIN_C6 //接收脚为 PIN_C7 //使能内置函数:GETC,PUTC 和 PRINTF, kbhit();

//#include <cal9717n.h> // Put your calibration constants here #include <14kcal.c> //包含 14kcal.c 头文件

Page 110: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 110

#endif //结束 if 定义 void main() { int source; //声明整型变量 source float res; //声明浮点型变 res setup_adc_ports(ALL_ANALOG); //将所有的 AD/IO 口设置为模拟输入口 setup_adc(CURRENT_34); delay_ms(2000); //软件延时 2000ms,即 2 秒 do {

printf("\r\nChoose analog input channel:\r\n"); //通过 RS232 口输出 Choose analog input channel: printf("\r\n0) RA0/AN0 1) RA1/AN1 2) RA2/AN2 3) RA3/AN3"); //通过 RS232 口输出 0) RA0/AN0 1) RA1/AN1 2) RA2/AN2 3) RA3/AN3 printf("\r\n7) IntTemp 8) RC0/REFA 9) RD3/REFB"); //通过 RS232 口输出 7) IntTemp 8) RC0/REFA 9) RD3/REFB printf("\r\nA) RD4/AN4 B) RD5/AN5 C) RD6/AN6 D) RD7/AN7"); //通过 RS232 口输出 A) RD4/AN4 B) RD5/AN5 C) RD6/AN6 D) RD7/AN7

source = toupper( getc() ); //从 RS232 口读一个字符,转化为大写格式送给 source if (source >= 'A') source = source - 'A' + 10; //将读到的字符转换为 16 进制格式,存到 source 中 else source = source - '0'; //将读到的字符转换为 16 进制格式,存到 source 中 res = READ_CALIBRATED_AD(source); printf("\r\n\nCalibrated A/D = %E\n", res); } while(TRUE); } READ_BANK( ) 语法: value=read_bank( bank,offset ); 参数: bank 为 CPU 中 RAM 的 bank1,bank2 和 bank3,随 CPU 的不同, bank 的数量也不同,这里的 bank 是一个常数:1,2 或 3;

offset 是用户 RAM 的那个 bank 偏移量,bank 的开始端为 0 偏移量; 返回值: 是一个 8 位的整型数; 功能: 该函数从指定的存储器 bank,属于用户RAM区的单元读取数据; 该函数只能用于部

分 CUP 中,这里的 RAM 区,对于 auto 变量的存取,没有效率.例如:PIC16C57 芯片,设置指针的

大小为 5 位,将产生 有效的 ROM 代码,可是 auto 变量不能超过 1FH 地址;你能通过这个函

数写入硬件到达 bank 区,代替 8 位指针存储 ROM,在这种情况下, bank 可能是 1~3, offset 可能

是 0~15; 有效性: 该函数对 RAM 区超过 1Fh 以上的 PCB 芯片有效, 也对 RAM 区超过 FFh 以上的

PCM 芯片有效,对其它 CPU 无效; 要求: 没有; 例子: i=0;

Page 111: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 111

do{ c=read_bank( 1, i++); //读 bank1 区,偏移量为 i if( c!=0x13 ) lcd_putc( c ); }while(c!=0x13); 例子文件: ex_psp.c;文件 ex_psp.c 在前面已介绍; READ_CALIBRATION( ) 语法: value=read_calibration(n); 参数: n 是一个偏移量,进入校准存储器的起始地址为 0; 返回值: 是一个 8 位的字节数据; 功能: 该函数用来读 PIC14000 系列 CPU 校准存储,在位置 n 处的值; 有效性: 该函数只对 PIC14000 系列 CPU 有效; 要求: 没有; 例子: fin=read_calibration(16); //读校准存储在位置 16 处的值; 例子文件: ex_14kad.c with 14kcal.c; READ_EEPROM( ) 语法: value=read_eeprom(address); 参数: address 是一个整型数,依据芯片,可能是 8 位或 16 位; 返回值: 是一个 8 位的字节数据; 功能: 该函数从 EEPROM 中读指定地址处的一个字节数据,EEPROM 的开始地址为 0, 其地址范围依据芯片的不同而改变; 有效性: 该命令只对带有内置 EEPROM 的 CPU 有效; 要求: 没有; 例子: #define LAST_VOLUME 10 volume=read_EEPROM(LAST_VOLUME); //从 EEPROM 的地址 10 处读一个字节 例子文件: ex_intee.c READ_PROGRAM_EEPROM( ) 语法: value=read_program_eeprom(address); 参数: 在 PCM 中,address 是一个 16 的数据,而在 PCH 中,address 是一个 32 的数据; 返回值: 是一个 16 位的整型数据; 功能: 该函数从程序存储器中读取数据; 有效性: 只对允许从程序存储器中读取数据的 CPU 有效; 要求: 没有; 例子: checksum=0; for(i=0; i<8196; i++)

Page 112: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 112

checksum^=read_program_eeprom(i); //从程序存储器的地址 i 处,读取数据,并计算校验和;

printf("Checksum is %2X\r\n", checksum); //从 RS232 口输出 例子文件: 没有; READ_PROGRAM_MEMORY( ) READ_EXTERNAL_MEMORY( ) 语法: read_program_memory( address, dataptr, count ); read_external_memory( address, dataptr, count ); 参数: address 在 PCM 中,是一个 16 的数据,而在 PCH 中,address 是一个 32 的数据;在 PCM中,没有意义的位总是为 0; dataptr 是一个指向一个字节数据或更多字节数据的指针; count 是一个 8 位整数; 返回值: 没有定义; 功能: 该函数从程序存储器的地址 address 处开始,读 count 个字节数据,存到以 dataptr 为指

针,所指向的 RAM 中.这两个函数的操作是完全相同的; 有效性: 只对允许从程序存储器中读取数据的 CPU 有效; 要求: 没有; 例子: char buffer[64]; //声明数组 buffer[]在 RAM 中; read_external_memory( 0x40000, buffer, 64 ); //从外部存储器中,以 0x40000 为开始地址读取 64 个字节,存到数组 buffer[]中; 例子文件: 没有; REALLOC( ) 语法: realloc( ptr, size); 参数: ptr 是一个无效的指针,或是由先前的 calloc( ),malloc( )或 realloc( )函数返回的指针; size 是一个整数,用来说明被分配的字节数; 返回值: 如果可能的话,返回的是一个指向可能移动的分配存储器,否则的话,返回的是一个

0 指针,即无效的指针; 功能: realloc( )函数用来改变目标对象的大小,该目标对象由 size 指定了其大小,由 ptr 指针

所指着的对象; 目标对象的内容保持不变,一直到新的和旧的大小范围出现;如果新的 size 大

于旧的范围,则分配的空间是不确定的;若ptr是一个无效的0指针,则 realloc( )函数和malloc( ) 函数一样,只被指定了大小;若 ptr 同先前的 calloc( ),malloc( )或 realloc( )函数返回的指针不匹

配,或空间已被一个 call自由分配,或被 realloc( )函数分配,则其行为表现为未定义;若空间不能

分配,则由 ptr 所指的目标对象不被改变;若 size 是 0 而 ptr 是一个非 0 的指指针,则目标对象

可被自由分配; 有效性: 适合所有器件; 要求: 要求包含头文件 stdlibm.h; 例子: int * iptr; iptr=malloc( 10 ); realloc( ptr, 20 );

//如果可能的话, iptr 将指向一块为 20 个字节的存储区, 入口参数 ptr 由 iptr 代替;

Page 113: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 113

例子文件: 没有; RESET_CPU( ) 语法: reset_cpu( ); 参数: 没有; 返回值: 这个函数不返回任何值; 功能: 这是常用的使 CPU 器件复位的函数,在 PCB 和 PCM 元件中,它将跳到位置 0 处,对于

PIC18XXX 来说,在 power-up 状态下,不但会复位 CPU,还会复位寄存器; 有效性: 适合所有器件; 要求: 没有; 例子: if(checksum!=0) reset_cpu( ); //使 CPU 复位; 例子文件: 没有; RESTART_CAUSE( ) 语法: value=restart_cause( ); 参数: 没有; 返回值: 这个函数的返回值指出 后一次 CPU 复位的原因;当前的 value 值由设备决定的;通过 device.h 文件,来查找特定的 CPU 设备的特殊值;例如 value 的一些值如下: WDT_FROM_SLEEP, WDT_TIMEOUT, MCLR_FROM_SLEEP,和 NORMAL_POWER_UP; 功能: 这是常用的使 CPU 器件复位的函数,在 PCB 和 PCM 元件中,它将跳到位置 0 处,对于

PIC18XXX 来说,在 power-up 状态下,不但会复位 CPU,还会复位寄存器; 有效性: 适合所有器件; 要求: 定义的常数必须在头文件 device.h 中; 例子: switch( restart_cause( ) ) { case WDT_FROM_SLEEP: case WDT_TIMEOUT: handle_error( );

} 例子文件: ex_wdt.c; RESART_WAT( ) 语法: restart_wdt( ); 参数: 没有; 返回值: 没有定义; 功能: 该函数用来重新启动看门狗定时器.如果看门狗定时器被使能的话,这个函数必须被

周期性地调用,才不会让 CPU 复位; 如果软件出现死循环的话,看门狗定时器常用来引起硬件复位;

Page 114: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 114

看门狗定时器被使能,溢出时间被设置,且软件必须周期性地重新启动看门狗定时器;对于 PCB\PCM 元件和 PCH 元件来说,这样做的区别如下: PCB/PCM 的 CPU 元件操作如: #fuses WDT //使能看门狗定时器 setup_wdt( ); //对 PCB/PCM的CPU元件来说,是用来设置看门狗定时器的时间 restart_wdt( ); //重新启动看门狗定时器 PCH 的 CPU 元件操作如: setup_wdt( ); //使能看门狗定时器 #fuses WDT1 //对 PIC18 来说, WDT1 为 18ms 重新启动一次看门狗定时器 restart_wdt( ); //重新启动看门狗定时器 有效性: 适合所有器件; 要求: 要使用#fuses 例子: #fuses WDT //对 PCB/PCM 的 CPU 元件来说,是使能看门狗定时器; main( )

{ setup_wdt( WDT_2304MS );

//设置 PCB/PCM 元件的看门狗定时器溢出时间 2034ms; while(TRUE)

{ restart_wdt( ); //重新启动看门狗定时器; perform_activity( ); //执行其它函数; }

} 例子文件: ex_wdt.c; ROTATE_LEFT( ) 语法: rotate_left( address, bytes ); 参数: address 是一个指向存储器的指针; bytes 是指工作时,一同左移的字节数; 返回值: 没有定义; 功能: 该函数将一个数组或一个结构循环左移一位; address 可能是一个数组标识符名,也可能是一个字节数据或结构的地址(使用时,在字节数据或结构的前面加上:&,如:&data),在RAM 中,字节 BYTE 的 低位 bit0 被认为是 LSB; 有效性: 适合所有器件; 要求: 没有; 例子: x=0x86; //给整型变量赋值,单字节 y=0x4001; //给长整型变量赋值,双字节 struct{ int cell_1 : 4; //在 cells 中,分配 低位给 cell_1 int cell_2 : 4; int cell_3 : 4; int cell_4 : 4; //在 cells 中,分配 高位给 cell_4

}cells;

Page 115: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 115

//在 RAM 中, cells 为两个字节,其中 cell_1 为 低 4 位, cell_4 为 高 4 位; rotate_ left ( &cells, 2 ); //将 cells的两个字节一起循环左移1位,2表示两个字节工作; rotate_ left ( &cells, 2 ); //将 cells的两个字节一起循环左移1位,2表示两个字节工作; rotate_ left ( &cells, 2 ); //将 cells的两个字节一起循环左移1位,2表示两个字节工作; rotate_ left ( &cells, 2 ); //将 cells的两个字节一起循环左移1位,2表示两个字节工作; //移位 4 次后,cells 的结果为:cell_1 占据原来 cell_2 的位置, cell_2 占据原来 cell_3

的位置,cell_3 占据原来 cell_4 的位置, cell_4 占据原来 cell_1 的位置; rotate_left( &x, 1 ); //将 0x86 循环左移一位,x 现在是 0x0d,1 表示一个字节工作; rotate_left( &y, 2 ); //将0x4001循环左移一位, y现在是0x8002, 2表示两个字节工作; 例子文件: 没有; ROTATE_RIGHT( ) 语法: rotate_right( address, bytes ); 参数: address 是一个指向存储器的指针; bytes 是指工作时,一同左移的字节数; 返回值: 没有定义; 功能: 该函数将一个数组或一个结构循环右移一位; address 可能是一个数组标识符名,也可能是一个字节数据或结构的地址(使用时,在字节数据或结构的前面加上:&,如:&data),在RAM 中,字节 BYTE 的 低位 bit0 被认为是 LSB; 有效性: 适合所有器件; 要求: 没有; 例子: struct{ int cell_1 : 4; int cell_2 : 4; int cell_3 : 4; int cell_4 : 4; }cells; //在 RAM 中, cells 为两个字节,其中 cell_1 为 低 4 位, cell_4 为 高 4 位; rotate_right( &cells, 2 ); //将cells的两个字节一起循环右移1位,2表示两个字节工作; rotate_right( &cells, 2 ); //将cells的两个字节一起循环右移1位,2表示两个字节工作; rotate_right( &cells, 2 ); //将cells的两个字节一起循环右移1位,2表示两个字节工作; rotate_right( &cells, 2 ); //将cells的两个字节一起循环右移1位,2表示两个字节工作; //移位 4 次后,cells 的结果为:cell_1 占据原来 cell_4 的位置, cell_2 占据原来 cell_1的位置,cell_3 占据原来 cell_2 的位置, cell_4 占据原来 cell_3 的位置; 例子文件: 没有; RTOS_AWAIT( ) 只在 PCW,PCWH 和 PCWHD 软件包中,包含了 RTOS 功能; 语法: rtos_await( expre ); 参数: expre 是一个逻辑表达式; 返回值: 没有;

Page 116: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 116

功能: 该函数只能用于 RTOS 任务中.在继续执行 RTOS 任务代码的其余部分之前, rtos_await( )一直在等待 expre 变为 TRUE 值;当一个任务在等待 expre 变为 TRUE 值时, rtos_await( )允许其它任务先执行; 有效性: 适合所有器件; 要求: 必须使用#use rtos; 例子: rtos_await( kbhit( ) ); //若 getc()读到数据,则 kbhit()返回 1, rtos_await( )不等待;

//若 getc()没有读到数据, kbhit()返回 0, rtos_await( )等待; 例子文件: 没有; RTOS_DISABLE( ) 只在 PCW,PCWH 和 PCWHD 软件包中,包含了 RTOS 功能; 语法: rtos_disable( task ); 参数: task 是一个函数名,这个函数一定要被用于 RTOS 任务中; 返回值: 没有; 功能: rtos_disable( task )函数不使能函数 task( ),而引起函数 task( )不被执行,直到使能

rtos_enable( task );所有的任务都被默认为使能. 有效性: 适合所有器件; 要求: 必须使用#use rtos; 例子: rtos_disable( toggle_green ); //不使能函数 toggle_green( ); //toggle_green( )是 RTOS 中的一个函数; 例子文件: 没有; RTOS_ENABLE( ) 只在 PCW,PCWH 和 PCWHD 软件包中,包含了 RTOS 功能; 语法: rtos_enable( task ); 参数: task 是一个函数名,这个函数一定要被用于 RTOS 任务中; 返回值: 没有; 功能: rtos_enable( task )函数用来使能函数 task( ),使它按指定的速度被执行;所有的任务都

被默认为使能. 有效性: 适合所有器件; 要求: 必须使用#use rtos; 例子: rtos_enable( toggle_green ); //使能函数 toggle_green( ); //toggle_green( )是 RTOS 中的一个函数; 例子文件: 没有; RTOS_MSG_POLL( ) 只在 PCW,PCWH 和 PCWHD 软件包中,包含了 RTOS 功能; 语法: i=rtos_msg_poll( );

Page 117: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 117

参数: 没有; 返回值: 返回值是一个整数,用来指定在队列里有多少个信息; 功能: 这个函数只能用于 RTOS 任务里,返回的是任务队列里信息的数量, 有效性: 适合所有器件; 要求: 必须使用#use rtos; 例子: if( rtos_msg_poll( ) ) 例子文件: 没有; RTOS_MSG_READ( ) 只在 PCW,PCWH 和 PCWHD 软件包中,包含了 RTOS 功能; 语法: b=rtos_msg_read( ); 参数: 没有; 返回值: 返回值是一个字节,为任务里的一条信息; 功能: 这个函数只能用于 RTOS 任务里,用来读取任务队列里的下一条信息. 有效性: 适合所有器件; 要求: 必须使用#use rtos; 例子: if( rtos_msg_poll( ) ) //若任务队列里信息的数量不为 0 的话,则执行下面语句; b=rtos_msg_read( ); //从任务队列里,读取下一条信息; 例子文件: 没有; RTOS_MSG_SEND( ) 只在 PCW,PCWH 和 PCWHD 软件包中,包含了 RTOS 功能; 语法: rtos_msg_send( task, byte); 参数: task 是用于 RTOS 任务里的函数名;

byte 是一个字节,用来作为一条信息发送给任务; 返回值: 没有; 功能: 这个函数在 rtos_run( )被调用之后,随时可能被使用; rtos_msg_send( task, byte)用来

发送以 byte 为一条信息,给以 task 为函数名的任务; 有效性: 适合所有器件; 要求: 必须使用#use rtos; 例子: if( kbhit( ) ) //若 getc()读到数据,则 kbhit()返回 1 若 getc()没有读到数据, kbhit()返回 0 { rtos_msg_send( echo, getc( ) ); //将 getc( )的返回值,送给任务 echo( ); } 例子文件: 没有; RTOS_OVERRUN( ) 只在 PCW,PCWH 和 PCWHD 软件包中,包含了 RTOS 功能;

Page 118: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 118

语法: rtos_overrun( ); 参数: task 是用于 RTOS 任务里的函数名; 返回值: 返回值为 0(FALSE)或 1(TRUE); 功能: 如果指定的任务比分配给它执行的时间要长的话,则 rtos_overrun( )返回值为 TRUE;如果没有指定任务,那么 rtos_overrun( )返回值也为 TRUE,若任何一个任务在执行时,超出分

配给它的执行时间, 那么 rtos_overrun( )返回值也为 TRUE; 有效性: 适合所有器件; 要求: 必须使用#use rtos(statistics); // statistics: 统计表 例子: rtos_overrun( ); //没有指定任务,那么 rtos_overrun( )返回值为 TRUE 例子文件: 没有; RTOS_RUN( ) 只在 PCW,PCWH 和 PCWHD 软件包中,包含了 RTOS 功能; 语法: rtos_run( ); 参数: 没有; 返回值: 没有; 功能: 该函数开始执行所有被使能的 RTOS 任务(所有的任务被默认为使能),它用来控制

RTOS 任务按分配的速率执行;只有当 RTOS_TERMINATE( )被调用时, rtos_run( )才返回退出

雕用; 有效性: 适合所有器件; 要求: 必须使用#use rtos; 例子: rtos_run( ); //起动执行所有被使能的 RTOS 任务; 例子文件: 没有; RTOS_SIGNAL( ) 只在 PCW,PCWH 和 PCWHD 软件包中,包含了 RTOS 功能; 语法: rtos_signal( sem ); 参数: sem 是一个全局变量,用来声明当前的系统共享资源有效; 返回值: 没有; 功能: 该函数只能被用于RTOS任务里; 该函数将 sem增大,让正在等待的任务知道当前的

共享资源有效,正在被使用; 有效性: 适合所有器件; 要求: 必须使用#use rtos; 例子: rtos_signal( uart_use ); //告诉正在等待的任务, 共享资源有效,正在被使用; 例子文件: 没有; RTOS_STATS( )

Page 119: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 119

只在 PCW,PCWH 和 PCWHD 软件包中,包含了 RTOS 功能; 语法: rtos_stats( task, stat ); 参数: task 是正在被使用的 RTOS 任务函数名; stat 是下面的参数: rtos_min_time 执行指定的任务,所需要 CPU 的 小时间; rtos_max_time 执行指定的任务,所需要 CPU 的 大时间; rtos_total_time 一个任务所花费 CPU 的总时间; 返回值: 将 task 任务所指的 stat 返回,32 位整型值,单位为 us(微秒); 功能: 该函数将 task 任务所指的 stat 返回, 32 位整型值,单位为 us(微秒); 有效性: 适合所有器件; 要求: 必须使用#use rtos(statistics); // statistics: 统计表 例子: rtos_ stats( echo, rtos_total_time ); //将 echo( )函数所花费 CPU 的总时间返回; 例子文件: 没有; RTOS_TERMINATE( ) 只在 PCW,PCWH 和 PCWHD 软件包中,包含了 RTOS 功能; 语法: rtos_terminate( ); 参数: 没有; 返回值: 没有; 功能: 该函数将所有执行的 RTOS 任务终止;程序将继续执行位于 RTOS_RUN( )被调用后

的第一行代码; rtos_terminate( )将引起 rtos_run( )返回退出; 有效性: 适合所有器件; 要求: 必须使用#use rtos; 例子: rtos_terminate( ); //结束所有的 RTOS 任务执行,使 rtos_run( )返回退出; 例子文件: 没有; RTOS_WAIT( ) 只在 PCW,PCWH 和 PCWHD 软件包中,包含了 RTOS 功能; 语法: rtos_wait( sem ); 参数: sem 是一个全局变量,用来声明当前的系统共享资源有效; 返回值: 没有; 功能: 该函数只能被用于 RTOS 任务里;若 sem 比 0 大,则系统共享资源有效, rtos_wait(sem)等待;减小 sem,表示要求使用共享资源,继续执行 RTOS 任务的其它代码; rtos_wait( sem )在等

待共享资源有效时,允许其它 RTOS 任务执行; 有效性: 适合所有器件; 要求: 必须使用#use rtos; 例子: rtos_ wait( uart_use ); //sem 比 0 大,则等待共享资源有效; 例子文件: 没有;

Page 120: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 120

RTOS_YIELD( ) 只在 PCW,PCWH 和 PCWHD 软件包中,包含了 RTOS 功能; 语法: rtos_yield( ); 参数: 没有; 返回值: 没有; 功能 : 该函数只能被用于 RTOS 任务里 ;该函数用来停止当前的执行任务 ,退出受

RTOS_RUN( )函数的控制;当下一个任务执行时,它将从RTOS_YIELD( )函数后的代码行开始

执行; 有效性: 适合所有器件; 要求: 必须使用#use rtos; 例子: void yield( void ) { printf("Yielding…\r\n"); rtos_yield( ); //停止当前的执行任务; printf("Executing code after yield\r\n"); } 例子文件: 没有; SET_ADC_CHANNEL( ) 语法: set_adc_channel( chan ); 参数: chan 是要选择的 AD 口通道数; AD 口的通道数开始于 0,在 data sheet 里被表示为

AN0,AN1…….等等; 返回值: 没有定义; 功能: 该函数用来指定AD口的通道,便于后面的 read_adc( )可以访问该AD口的通道,注意,在你可以读到一个有效的值之前,若你改变了 AD 口的通道数,则必须等待一段时间,才可读

AD 口的电压值, 等待的时间要根据输入源的阻抗来修改,对于大多数应用程序来说,一般,等待的时间为 10us;若 AD 口的通道没有被改变,则在 read_adc( )访问之前,就不必再改变 AD 口

的通道; 有效性: 只适合带有 A/D 转换硬件的 CPU 器件; 要求: 没有; 例子: set_adc_channel( 2 ); //使用 AN2 的 A/D 口为当前的 A/D 转换,其它 A/D 转换停止; delay_us( 10 ); //延时 10 微秒; value=read_adc( ); //读 AN2( A/D 口)的值; 例子文件: ex_admm.c SET_PWM1_DUTY( ) SET_PWM2_DUTY( ) SET_PWM3_DUTY( ) SET_PWM4_DUTY( ) SET_PWM5_DUTY( )

Page 121: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 121

语法: set_pwm1_duty( value ); set_pwm2_duty( value ); set_pwm3_duty( value ); set_pwm4_duty( value ); set_pwm5_duty( value ); 参数: value 可能是 8 或 16 位的常数或常量; 返回值: 没有; 功能: 该函数向 PWM 写入 10 位值, 用来设置占空比,若没有意义的位没有被要求,则 value可能是一个 8 位值;若 value 是一个 8 位值可选项,则 value 被左两位, 低两位补为 0,从而得

到 10 位的值;这个 10 位值被用来决定 PWM,在每个周期中,高电平信号的时间数,如下: 若 value被声明为LONG INT,则每个周期中,PWM高电平时间: value*(1/clock)*t2div; 若 value 为声明 INT, 则每个周期中,PWM 高电平时间: value*4*(1/clock)*t2div;

这里的 clock 是晶振的频率; t2div 是 timer2 的预置分频值( 用 setup_timer_2( )来设置

如:setup_timer_2(T2_DIV_BY_ t2div, period, 1) ,period 为 T2 的周期; ); 有效性: 只对带有 CCP/PWM 的设备有效; 要求: 没有; 例子: //已知晶振频率为 20MHz;

//PWM 的频率为 1200Hz,占空比为 50%,则在每个周期中,高电平的时间为 416 微秒; //PWM 周期:(1/clock)*4*t2div*(period+1); long duty; //声明 duty 为 16 位;

duty=520; setup_ccp1(CCP_PWM); // Configure CCP1 as a PWM setup_timer_2(T2_DIV_BY_16, xxxx, 1); //设置 t2div=16; //PWM 周期:(1/clock)*4*t2div*(period+1); set_pwm1_duty( duty ); //因为 duty 为 16 位,416=value*(1/clock)*t2div;计算 value; //若 duty 为 8 位,则 416=value*4*(1/clock)*t2div 计算 value; 例子文件: ex_pwm.c SET_POWER_PWMX_DUTY( ) 语法: set_power_pwmX_duty( duty ); 参数: X 是 0,2,4,6; duty 为 0~16383 之间的整数; 返回值: 没有定义; 功能: 该函数将 duty 的值存到 PDCxL 或 PDCxH 寄存器,duty 是正在使用的 PWM 输出的

时间值; 有效性: 只对带有 PWM 的设备有效; 要求: 没有; 例子: set_power_pwm0_duty( 4000 ); 例子文件: 没有; SET_POWER_PWM_OVERRIDE( )

Page 122: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 122

语法: set_power_pwm_override( pwm, override, value ); 参数: pwm 是 0~7 之间的常数; override 为 TRUE 或 FALSE; value 为 0 或 1; 返回值: 没有定义; 功能: 参数 pwm 选择哪个模块将会受到影响;override 指定输出是由 OVDCONS 寄存器决

定输出,还是 PDC寄存器决定输出;当 override为 FALSE时,PDC寄存器决定输出; 当 override为 TRUE 时,输出由存储在 OVDCONS 中的 value 参数决定,当 value 为 1 时,PWM 脚在下一

个 duty 周期中被驱动为激活状态,若 value 为 0,PWM 脚在下一个 duty 周期中被驱动为非激

活状态; 有效性: 只对带有 PWM 的设备有效; 要求: 没有; 例子: set_power_pwm_override( 1, TRUE, 1); //不考虑 PWM1 被激活;

set_power_pwm_override( 1, FALSE, 0); //由 PDC 寄存器决定输出,要考虑 PWM1 活动状态;

例子文件: 没有; SET_RTCC( ) SET_TIMER0( ) SET_TIMER1( ) SET_TIMER2( ) SET_TIMER3( ) SET_TIMER4( ) SET_TIMER5( ) 语法: set_timer0( value ); 或 set_rtcc( value ); set_timer1( value ); set_timer2( value ); set_timer3( value ); set_timer4( value ); set_timer5( value ); 参数: timer1 和 timer3 的 value 为 16 位整型; timer2 的 value 为 8 位整型; timer0(即 RTCC)的 value 为 8 位整型,但在 PIC18XXX 中, timer0(即 RTCC)的 value为 16 位整型; 返回值: 没有定义; 功能: 设置实时时钟或计数器的计数值;RTCC 和 timer0 是一样的,所有的定时器向上计数;当定时器的计数值达到 大值时,它将跳到 0 处,继续计数(如:从 254,255,0,1,2….);

若定时时间为 x,不使用分频器时, 则 8 位定时器的初值为: 256 - x/(4/clock);

则 16 位定时器的初值为: 65536 - x/(4/clock); 这里的 x 为秒,clock 为晶振的频率,4/clock 为内部指令周期;

有效性: timer0 适合所有的 PIC 系列单片机;

Page 123: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 123

timer1 和 timer2 适合大多数的 PIC 系列单片机,但不适合所有的 PCM 器件; timer3 只适合 PIC18XXX 系列单片机; timer4 只适合一部分的 PCH 器件; timer5 只适合 PIC18XX31 系列单片机;

要求: 没有; 例子: set_timer0( 81 ); //81=256-( 0.000035/( 4/20000000 ) ),定时为 35us;

//晶振频率为 20MHz,不使用分频器,设置 timer0; // timer0 的溢出时间为 35us;

例子文件: ex_patg.c SET_TRIS_A( ) SET_TRIS_B( ) SET_TRIS_C( ) SET_TRIS_D( ) SET_TRIS_E( ) SET_TRIS_G( ) SET_TRIS_H( ) SET_TRIS_J( ) SET_TRIS_K( ) 语法: set_trs_a( value ); set_trs_b( value ); set_trs_c( value ); set_trs_d( value ); set_trs_e( value ); set_trs_g( value ); set_trs_h( value ); set_trs_j( value ); set_trs_k( value ); 参数: value 是一个 8 位整型数,每一位同 I/O 口的方向寄存器的位相对应,设置 I/O 口是输

入还是输出,如 0x01 表示将 低位设置为输入,其它 7 位被设置为输出; 返回值: 没有定义; 功能: 该函数用来设置 I/O 口的方向寄存器,它必须同 FAST_IO 一起被使用,当 I/O 口作为

一个字节存储器被访问时,常用来直接读写 I/O 口;内置函数默认使用 standard I/O,自动设置

I/O 口的输入/输出方向; value 的每一位值同 I/O 口的一个脚相对应,1 表示输入,0 表示输出; 有效性: 适合所有的器件(然而不是所有的器件都有这么多 I/O 口); 要求: 没有; 例子: set_tris_b( 0x0f ); //RB7,RB6,RB5,RB4 被设置为输出; //RB3,RB2,RB1,RB0 被设置为输入; 例子文件: lcd.c SET_UART_SPEED( ) 语法: set_uart_speed( baud, [stream] );

Page 124: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 124

参数: baud 为 100~115200 之间的一个常数,表示每秒多少位,即波特率; stream 是可选项,为一串标识符; 返回值: 没有定义; 功能: 该函数用来改变内置硬件 RS232 串口在运行时的波特率; 有效性: 该函数只对带有内置 UART 的器件有效; 要求: 必须使用#use rs232 才可使能该数; 例子: switch( input_b( )&3 ) { //根据脚 pin_B0 和脚 pin_B1 的输入值来设置波特率; case 0: set_uart_speed( 2400 ); break; case 1: set_uart_speed( 4800 ); break; case 2: set_uart_speed( 9600 ); break; case 3: set_uart_speed( 19200 ); break; } 例子文件: loader.c SETJMP( ) 语法: result=setjmp( env ); 参数: env:接收现场的目的数; 返回值: 如果是从直接调用的函数中返回,则该函数返回 0;若是从一个访问 longjmp 函数中

返回,则该函数返回的是一个非 0 值,且同 longjmp 函数的返回值相同; 功能: 将当前调用的相关信息存到 jmp_buf 型的目的数中,使你随时控制相应的 longjmp 调

用; 有效性: 适合所有器件; 要求: 必须使用#include <setjmp.h>才可使能该数; 例子: result=setjmp( jmpbuf ); 例子文件: 没有; SETUP_ADC( mode ) 语法: setup_adc( mode ); 参数: mode- 是从模拟到数据方式;根据CPU变更有效的可选项,在 device.h文件中,可找到

所有的可选项;一些典型的可选项包含如下: ADC_OFF ADC_CLOCK_INTERNAL ADC_CLOCK_DIV_32 返回值: 没有定义; 功能: 配置 AD 转换器; 有效性: 只对带有内置 AD 转换的设备有效; 要求: 常数必须被定义在 device.h 的头文件中; 例子: #device ADC=16 //这里的 16 是 read_adc()函数返回的位数. #device ICD=TRUE //产生兼容 Microchips ICD 硬件调试代码

setup_adc_ports( ALL_ANALOG ); //使用所有的 AD 口;

Page 125: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 125

setup_adc( ADC_CLOCK_INTERNAL ); //AD 转换采用内部时钟; set_adc_channel( 0 ); //设置当前正在使用 AD 转换通道 0 delay_us( 10 ); //延时 10 微秒; value=read_adc( ); //读 AD 转换通道 0 的数据,存到 value 中; setup_adc( ADC_OFF ); //关闭 AD 转换; 例子文件: ex_admm.c SETUP_ADC_PORTS( ) 语法: setup_adc_ports( value ); 参数: value- 是定义在 device.h 的设备头文件中; 返回值: 没有定义; 功能: 设置 ADC 脚为模拟口,数据口或模拟数据相结合的 I/O 口;根据芯片变更允许的结合

项;检查设备头文件,你可发现一个完整的列表;常数 ALL_ANALOG 和 NO_ANALOGS 对于

所有的 CPU 都有效;其它一些常数如下: ANALOG_RA3_REF 所有的模拟口中,RA3 都用做参考; RA0_RA1_RA3_ANALOG 表示只将 RA0,RA1,RA3 用作模拟口;

有效性: 只对带有内置 AD 转换的设备有效; 要求: 常数必须被定义在 device.h 的头文件中; 例子: #device ADC=16 //这里的 16 是 read_adc()函数返回的位数. #device ICD=TRUE //产生兼容 Microchips ICD 硬件调试代码

setup_adc_ports( ALL_ANALOG ); //将所有的 IO 口设置为模拟口 setup_adc_ports( RA0_RA1_RA3_ANALOG ); //将脚RA0,RA1和RA3 设为模拟口 //其它脚配置为数据 I/O 口; //+5V 用做参考电压; setup_adc_ports( RA0_RA1_ANALOG_RA3_REF ); //将脚 RA0 和 RA1 设为模拟口

// RA3 脚用作参考电压输入; //其它脚配置为数据 I/O 口;

例子文件: ex_admm.c SETUP_CCP1( ) SETUP_CCP2( ) SETUP_CCP3( ) SETUP_CCP4( ) SETUP_CCP5( ) SETUP_CCP6( ) 语法: setup_ccp1( mode ); setup_ccp2( mode ); setup_ccp3( mode ); setup_ccp4( mode ); setup_ccp5( mode );

Page 126: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 126

setup_ccp6( mode ); 参数: mode 是一个常数;在设备头文件中,有效的常数如下: CCP_OFF 不使能 CCP; CCP_CAPTURE_FE CCP 为下降沿捕获方式; CCP_CAPTURE_RE CCP 为上升沿捕获方式; CCP_CAPTURE_DIV_4 CCP 在 4 个脉冲后,进入捕获方式; CCP_CAPTURE_DIV_16 CCP 在 16 个脉冲后,进入捕获方式; CCP_COMPARE_SET_ON_MATCH 设置 CCP 为比较方式,在比较时,输出高; CCP_COMPARE_CLR_ON_MATCH 设置 CCP 为比较方式,在比较时,输出低; CCP_COMPARE_INT 设置 CCP 为比较方式,在比较时,产生中断; CCP_COMPARE_RESET_TIMER 设置 CCP 为比较方式,在比较时,复位定时器; CCP_PWM 设置CCP为 PWM方式,使能 PWM脉宽调制; 返回值: 没有定义; 功能: 初始化 CCP;当使用长整型变量 CCP_1 和 CCP_2 时,CCP 计数器可被访问,CCP 工作

在方式 3 中;在捕获方式中,若输入脚有事件发生时,它会将 timer1 的计数值拷贝到 CCP_x 中;在比较方式中,当 timer1 的计数值和 CCP_x 的值相等时,它将触发产生一个动作;在 PWM 方

式中,它将会产生方波;为了能够正确设置 CCP 的工作方式和 timer1 的应用设置,你可通过

PCW 的 help 求得帮助; 有效性: 只对带有 CCP 硬件的 CPU 设备有效; 要求: 常数必须被定义在 device.h 的头文件中; 例子: setup_ccp1( CCP_CAPTURE_RE ); //设置 CCP 为上升沿捕获方式; 例子文件: ex_pwm.c, ex_ccpmp.c 和 ex_ccp1s.c ; SETUP_COMPARATOR( ) 语法: setup_comparator( mode ); 参数: mode 是一个常数;在设备头文件中,有效的常数如下: A0_A3_A1_A2 //C1 使用 A0 和 A3 脚作为输入, A0 为 C1-, A3 为 C1+; //C2 使用 A1 和 A2 脚作为输入, A1 为 C2-, A2 为 C2+; //用来设置个比较器,C1 和 C2; A0_A2_A1_A2 //C1 使用 A0 和 A2 脚作为输入, A0 为 C1-, A2 为 C1+; //C2 使用 A1 和 A2 脚作为输入, A1 为 C2-, A2 为 C2+; //用来设置个比较器,C1 和 C2; NC_NC_A1_A2 //C2 使用 A1 和 A2 脚作为输入, A1 为 C2-, A2 为 C2+; NC_NC_NC_NC A0_VR_A1_VR A3_VR_A2_VR A0_A2_A1_A2_OUT_ON_A3_A4

//C1 使用 A0 和 A2 脚作为输入, A0 为 C1-, A2 为 C1+; //C1 输出脚为 A3;

//C2 使用 A1 和 A2 脚作为输入, A1 为 C2-, A2 为 C2+; //C2 输出脚为 A4; //用来设置个比较器,C1 和 C2;

Page 127: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 127

A3_A2_A1_A2 //C1 使用 A3 和 A2 脚作为输入, A3 为 C1-, A2 为 C1+; //C2 使用 A1 和 A2 脚作为输入, A1 为 C2-, A2 为 C2+; //用来设置个比较器,C1 和 C2; 返回值: 没有定义; 功能: 设置模拟比较模块,上面的常数表示有 4 个输入部分,分别是: C1-, C1+, C2-, C2+; 有效性: 该函数只对带有模拟比较器的 CPU 设备有效; 要求: 常数必须被定义在 device.h 的头文件中; 例子: setup_comparator( A0_A3_A1_A2 ); //A0 为 C1-, A3 为 C1+; // C1 使用 A0 和 A3 脚作为输入; // A1 为 C2-, A2 为 C2+; //C2 使用 A1 和 A2 脚作为输入; 例子文件: ex_comp.c ; SETUP_COUNTERS( ) 语法: setup_counters( rtcc_state,ps_state ); 参数: rtcc_state 是在设备头文件中定义的一个常数;

例如:RTCC_INTEERNAL,RTCC_EXT_L_TO_H 或 RTCC_EXT_H_TO_L; ps_state 也是在设备头文件中定义的一个常数; 例如:RTCC_DIV_2, RTCC_DIV_4,

RTCC_DIV_8, RTCC_DIV_16, RTCC_DIV_32, RTCC_DIV_64, RTCC_DIV_128, RTCC_DIV_256,WDT_18MS, WDT_36MS, WDT_72MS, WDT_144MS, WDT_288MS, WDT_576MS, WDT_1152MS, WDT_2304MS; 返回值: 没有定义; 功能: setup_counters()函数用来设置 RTCC 和 WDT, 参数 rtcc_state 用来决定 RTCC 采用

什么时钟作为它的计数时钟; 参数 ps_state 用来设置 RTCC 或 WDT 的分频器; 分频器将使

指定的计数器的周期变长;如果 RTCC 的分频器被设置了,则 WDT 将被设置为 WDT_18MS; 如果 WDT 的分频器被设置了,则 RTCC 将被设置为 RTCC_DIV_1,即 RTCC 不使用分频器; 该函数提供了兼容旧版本的特性;当在允许的情况下, setup_counters()函数是可以替

代 setup_timer_0()和 setup_WDT ();对于适合于 PCB 编译器的 CPU,如果 RTCC 使用的是外部

时钟,WDT 的的分频器也被使用了,则必须使用 setup_counters()函数来设置; 有效性: 适合所有设备. 要求: 所用到的常数必须被定义在设备头文件中; 例子: setup_counters(RTCC_INTERNAL,WDT_2304MS);

//设置RTCC采用内部时钟,WDT使用分频器,即WDT相隔2304ms后复位CPU; 例子文件: 没有 SETUP_EXTERNAL_MEMORY( ) 语法: setup_external_memory(mode); 参数: mode 是一个或更多的来自设备头文件的常数,这些常数是采用”或门”的关系相连接

的; 返回值: 没有定义; 功能: 设置外部存储器总线的方式;

Page 128: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 128

有效性: 只适合带有外部存储器的 CPU; 要求: 必须包含设备头文件; 例子: setup_external_memory(EXTMEM_WORD_WRITE | EXTMEM_WAIT_0);

setup_external_memory(EXTMEM_DISABLE); 例子文件: 没有; SETUP_LCD( ) 语法: setup_lcd(mode,prescale,[segments]); 参数: mode 是一个来自设备头文件的常数, 如:LCD_DISABLED,LCD_STATIC,LCD_MUX12, LCD_MUX13, LCD_MUX14; 下面的参数可通过”或门”的关系同上面的参数进行连接; STOP_ON_SLEEP,USE_TIMER_1; 对于设备的其它特殊可选项可参照设备头文件;

prescale 可能是 0~15,对于 LCD 的时钟段,可能是下面的参数,通过”或”连接在一起: SEGO_4, SEG5_8, SEG9_11, SEG12_15, SEG16_19, SEGO_28, SEG29_31,

ALL_LCD_PINS; 若省略 prescale 参数,编译器将所有可用到的段使能;

返回值: 没有定义; 功能: 该函数常用来初始化 923,924 的 LCD 控制器; 有效性: 只适合内置带有 LCD 硬件驱动的 CPU; 要求: 所用到的常数必须被定义在设备头文件中; 例子: setup_lcd(LCD_MUX14 | STOP_ON_SLEEP, 2); 例子文件: ex_92LCD.c; SETUP_LOW_VOLT_DETECT( ) 语法: setup_low_volt_detect(mode); 参数: mode 是一个来自设备头文件的常数:LVD_LVDIN,LVD_45,LVD42,LVD_40,LVD_38, LVD_36,LVD_35,LVD_33,LVD_30,LVD_28,LVD_27,LCD_25,LVD_23,LVD_21,LVD_19; 如果设备允许高电压检测,则下面的参数可通过”或门”的关系同上面的参数进行连接; LVD_TRIGGER_BELOW,LVD_TRIGGER_ABOVE; 返回值: 没有定义; 功能: 该函数控制设备的高/低电压检测模块;mode 常数指定了电压的失足点和偏离该点

的方向(如果设备中包含了高电压检测模块, 偏离”电压失足点”的改变是可用的);如果设备

经历了指定方向的”电压失足点”的改变,将会产生中断标志,若中断允许的话,则可进入中断

服务程序; 有效性: 只适合带有高/低电压检测模块的 CPU 设备; 要求: 所用到的常数必须被定义在设备头文件中; 例子文件: 没有; SETUP_OSCILLATOR( )

Page 129: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 129

语法: setup_oscillator(mode,finetune); 参数: mode 由芯片而定;例如有些芯片允许将速度设置为 OSC_8MHz 或 OSC_32 KHz;其它芯片允许将 OSC_TIMER1 改作它的时钟源;

finetune(只允许在某些芯片上使用)为有符号整数,使用范围为-31~+31; 返回值: 有些芯片返回的是一个状态,如 OSC_STATE_STABLE 表明振荡器工作稳定; 功能: 该函数用来控制一些芯片的内部RC振荡器,并将内部RC振荡器的状态返回;对于特

殊芯片,头文件会有该可选项; 注意:如果在#fuse中指定了 INTRC或 INTRC_IO,且#USE DELAY使用了一个有效的

速度可选项,那么编译器会在 main()的起始处,自动使用这个”有效的速度”设置; 警告:如果运行时,速度被改变,一些内置函数就不能产生正确的延时; 后一次使用

的#USE DELAY 控制正确的 CPU 速度;你可多次使用#USE DELAY 控制 CPU 的速度; 有效性: 只适合带有 OSCCON 寄存器的设备; 要求: 所用到的常数必须被定义在设备头文件中; 例子: setup_oscillator(OSC_2MHz); 例子文件: 没有; SETUP_POWER_PWM( ) 语法: setup_power_pwm(modes, postscale, time_base, period,

compare, compare_ postscale, dead_time ); 参数: modes 是下面每组参数中的某一个: PWM_CLOCK_DIV_4, PWM_CLOCK_DIV_16, PWM_CLOCK_DIV_64, PWM_CLOCK_DIV_128; PWM_OFF, PWM_FREE_RUN, PWM_SINGLE_SHORT, PWM_UP_DOWN, PWM_UP_DOWN_INT;

PWM_OVERRIDE_SYNC; PWM_UP_TRIGGER, PWM_DOWN_TRIGGER; PWM_UPDATE_DISABLE, PWM_UPDATE_ENABLE; PWM_DEAD_CLOCK_DIV_2, PWM_DEAD_CLOCK_DIV_4, PWM_DEAD_CLOCK_DIV_8, PWM_DEAD_CLOCK_DIV_16; postscale 是一个整数,在 1~16 之中;设置 PWM 发生器输出的占空比; time_base 是一个整数,在 0~65535 之中;为 PWM 发生器的初始值; period 是一个整数,在 0~4095 之中; PWM 发生器在到达 period 这个值之前,是一直为

递增计数; compare 是一个整数,在 0~255 之中;PWM 发生器的 time_base 值会同 compare 值进行

比较,来确定某个事件是否应该被触发; compare_ postscale 是一个整数,在 1~16 之中;该值影响 compare,特殊事件触发器; dead_time 是一个整数,在 1~15 之中; 该值指定一个长的 OFF 周期;

返回值: 没有; 功能: 该函数用来初始化和配置 PWM(脉宽调制)设备; 有效性: 只适合带有 PWM 的设备; 要求: 没有; 例子: setup_power_pwm(PWM_CLOCK_DIV_4 | PWM_FREE_RUN|PWM_DEAD_CLOCK_DIV_4,

Page 130: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 130

1, 10000, 1000, 0, 1, 0); 例子文件: 没有; SETUP_POWER_PWM_PINS() 语法: setup_power_pwm_pins(module0, module1, module2, module3); 参数: 用于指定每个模块(两个脚):PWM_OFF,PWM_ODD_ON,PWM_BOTH_ON, PWM_COMPLEMENTARY; 返回值: 没有; 功能: 该函数用来配置 PWM(脉宽调制)设备的引脚; 有效性: 只适合带有 PWM 的设备; 要求: 没有; 例子: setup_power_pwm_pins(PWM_OFF, PWM_OFF, PWM_OFF, PWM_OFF);

setup_power_pwm_pins(PWM_COMPLEMENTARY,PWM_COMPLEMENTARY, PWM_OFF, PWM_OFF); 例子文件: 没有; SETUP_PSP( ) 语法: setup_psp(mode); 参数: mode 可能是:PSP_ENABLED,PSP_DISABLED; 返回值: 没有; 功能: 该函数用来初始化 PSP 口(并联从端口);set_tris_e(value)函数可用来设置数据的传送

方向;通过使用变量 PSP_DATA 来读写 PSP 口的数据; 有效性: 只适合带有 PSP 口的设备; 要求: 所用到的常数必须被定义在设备头文件中; 例子: setup_psp(PSP_ENABLED); 例子文件: ex_psp.c 文件; SETUP_SPI() SETUP_SPI2() 语法: setup_spi(mode);

setup_spi2(mode); 参数: mode 可能是:

SPI_MASTER,SPI_SLAVE,SPI_SS_DISABLED; SPI_L_TO_H,SPI_H_TO_L; SPI_CLK_DIV_4, SPI_CLK_DIV_16, SPI_CLK_DIV_64,SPI_CLK_T2; 上面每组常数可通过’或’关系连接在一起; 返回值: 没有; 功能: 该函数用来初始化 SPI 口,适合 2 线/3 线串行设备; 有效性: 只适合带有 SPI 口硬件的设备; 要求: 所用到的常数必须被定义在设备头文件中; 例子: setup_spi(SPI_MASTER| SPI_L_TO_H| SPI_CLK_DIV_16);

Page 131: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 131

例子文件: ex_spi.c 文件; SETUP_TIMER_0( ) 语法: setup_timer_0( mode ); 参数: mode 可能是 1 个或 2 个常数,这些常数被定义在设备头文件中: RTCC_INTERNAL,RTCC_EXT_L_TO_H 或 RTCC_EXT_H_TO_L; RTCC_DIV_2, RTCC_DIV_4, RTCC_DIV_8, RTCC_DIV_16, RTCC_DIV_32, RTCC_DIV_64, RTCC_DIV_128, RTCC_DIV_256; 只有 PIC18XXX 系列才有:RTCC_OFF,RTCC_8_BIT; 若使用一个常数,可将上面的每组通过’或’连在一起; 返回值: 没有定义; 功能: 设置 timer0(或 RTCC); 有效性: 适合所有设备. 要求: 所用到的常数必须被定义在设备头文件中; 例子: setup_timer_0(RTCC_DIV_2 | RTCC_EXT_L_TO_H );

//设置 Timer0 的时钟源为外部时钟源,上升沿到来时有效; //每隔 2 个脉冲,TMR0 计数 1 次 例子文件: ex_stwt.c SETUP_TIMER_1( ) 语法: setup_timer_1( mode ); 参数: mode 的值可能是: T1_DISABLED,T1_INTERNAL,T1_EXTERNAL,T1_EXTERNAL_SYNC; T1_CLK_OUT; T1_DIV_BY_1, T1_DIV_BY_2, T1_DIV_BY_4, T1_DIV_BY_8;

来自不同组的常数可以通过’或’关系联系在一起; 返回值: 没有定义; 功能: 初始化定时器 1;通过 GET_TIMER1( ) 和 SET_TIMER1( )来读和写 timer1 的值; timer1 的值为 16 位值; 在内部时钟为 20MHz 和使用 T1_DIV_BY_8 模式,timer 每隔 1.6us 增加 1,每隔

104.8576ms 就会溢出;[4/(20x1000000)]x8=1.6us; 有效性: 只适合带有 timer1 硬件的设备; 要求: 所用到的常数必须被定义在设备头文件中; 例子: setup_timer_1( T1_DISABLED); //不使能 timer1

setup_timer_1(T1_INTERNAL | T1_DIV_BY_4); //初始化定时器 1;

//时钟源为内部指令时钟 //使用内部分频器,即每 4 个指令时钟到来,T1 计数一次; setup_timer_1(T1_INTERNAL | T1_DIV_BY_8);

//初始化定时器 1; //时钟源为内部指令时钟

//使用内部分频器,即每 8 个指令时钟到来,T1 计数一次;

Page 132: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 132

例子文件: ex_patg.c SETUP_TIMER_2( ) 语法: setup_timer_2( mode, period, postscale ); 参数: mode 的值可能是: T2_DISABLED, T2_DIV_BY_1, T2_DIV_BY_4, T2_DIV_BY_16; period 是 0~255 之间的整数,决定时钟值什么时候被复位; postscale 是 0~16 之间的整数,决定 timer2 在中断产生前要复位多少次(1 表示 timer2要复位 1 次, 2 表示 timer2 要复位 2 次,等等); 返回值: 没有定义; 功能: 初始化定时器 2;mode 指定来自晶振时钟的除数,即 timer2 的时钟源是晶振时钟的几

分频, 通过 GET_TIMER2( ) 和 SET_TIMER2( )来读和写 timer2 的值; timer2 是 8 位定时器/计数器; 有效性: 只适合带有 timer2 硬件的设备; 要求: 所用到的常数必须被定义在设备头文件中; 例子: setup_timer_2(T2_DIV_BY_4, 0xc0, 2); // timer2 的时钟源为晶振时钟的 4 分频; //在晶振时钟为 20MHz 时,每隔 0.8us,timer2 加 1 一次; // timer2 每隔 153.6us 溢出一次; // timer2 每隔 307.2us 中断一次; //计算方法: timer2 的时钟源周期为 [4/(20x1000000)]x4=0.8us; //0xc0 转换为十进制为 192;192x0.8us=153.6us; // timer2 中断时间间隔为: 2x153.6us=307.2us 例子文件: ex_pwm.c SETUP_TIMER_3( ) 语法: setup_timer_3( mode ); 参数: mode 的值可能是来自下面的常数之一,每组可通过’或’连在一起: T3_DISABLED,T3_INTERNAL,T3_EXTERNAL,T3_EXTERNAL_SYNC; T3_DIV_BY_1, T3_DIV_BY_2, T3_DIV_BY_4, T3_DIV_BY_8; 返回值: 没有定义; 功能: 初始化定时器 3 或 4; mode 指定来自晶振时钟的除数,即 timer2 的时钟源是晶振时钟

的几分频, 通过 GET_TIMER3( ) 和 SET_TIMER3( )来读和写 timer3 的值; timer3 是 16 位定

时器/计数器; 有效性: 只适合 PIC18 系列的设备; 要求: 所用到的常数必须被定义在设备头文件中; 例子: setup_timer_3(T3_INTERNAL | T3_DIV_BY_2); 例子文件: 没有; SETUP_TIMER_4( ) 语法: setup_timer_4( mode, period, postscale );

Page 133: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 133

参数: mode 的值可能是: T4_DISABLED, T4_DIV_BY_1, T4_DIV_BY_4, T4_DIV_BY_16; period 是 0~255 之间的整数,决定时钟值什么时候被复位; postscale 是 0~16 之间的整数,决定 timer4 在中断产生前要复位多少次(1 表示 timer4要复位 1 次, 2 表示 timer4 要复位 2 次,等等); 返回值: 没有定义; 功能: 初始化定时器 4;mode 指定来自晶振时钟的除数,即 timer4 的时钟源是晶振时钟的几

分频, 通过 GET_TIMER4( ) 和 SET_TIMER4( )来读和写 timer4 的值; timer4 是 8 位定时器/计数器; 有效性: 只适合带有 timer4 硬件的设备; 要求: 所用到的常数必须被定义在设备头文件中; 例子: setup_timer_4(T4_DIV_BY_4, 0xc0, 2); // timer4 的时钟源为晶振时钟的 4 分频; //在晶振时钟为 20MHz 时,每隔 0.8us,timer2 加 1 一次; // timer4 每隔 153.6us 溢出一次; // timer4 每隔 307.2us 中断一次; //计算方法: timer4 的时钟源周期为 [4/(20x1000000)]x4=0.8us; //0xc0 转换为十进制为 192;192x0.8us=153.6us; // timer2 中断时间间隔为: 2x153.6us=307.2us 例子文件: ex_pwm.c SETUP_TIMER_5( ) 语法: setup_timer_5( mode ); 参数: mode 可能是一个或两个常数,这些常数定义在设备头文件中; T5_DISABLED,T5_INTERNAL,T5_EXTERNAL,T5_EXTERNAL_SYNC; T5_DIV_BY_1, T5_DIV_BY_2, T5_DIV_BY_4, T5_DIV_BY_8; T5_ONE_SHOT, T5_DISABLE_SE_RESET 或 T5_ENABLE_DURING_SLEEP; 返回值: 没有定义; 功能: 初始化定时器 5; mode指定来自晶振时钟的除数,即 timer5的时钟源是晶振时钟的几

分频, 通过 GET_TIMER5( ) 和 SET_TIMER5( )来读和写 timer5 的值; timer5 是 16 位定时器/计数器; 有效性: 只适合 PIC18XX31 系列的设备; 要求: 所用到的常数必须被定义在设备头文件中; 例子: setup_timer_5(T5_INTERNAL | T5_DIV_BY_2); 例子文件: 没有; SEYUP_UART( ) 语法: setup_uart(baud,stream); setup_uart(baud); 参数: buad 是一个常数,表示波特率,即每秒的位数;1 或 0 也控制 ON/OFF 状态,stream 是一

个可选项,为某个串口的标识符; 芯片上的 UART 可使用下面的参数:

Page 134: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 134

UART_ADDRESS // setup_uart(UART_ADDRESS)表示 UART 只接收第 9 位为 1 的数据; UART_DATA // setup_uart(UART_DATA)表示 UART 接收所有数据; 芯片上的 EUART H/W 可使用下面的参数: UART_AUTODETECT

// setup_uart(UART_AUTODETECT)表示等待 0x55 字符,设置匹配的波特率; UART_ AUTODETECT_NOWAIT //除了返回接收到的 0x55 之外,当波特率匹配

时,KBHIT()的值为 TRUE,调用 GETC()会清除 0x55 这个字符; // setup_uart(UART_ AUTODETECT_NOWAIT)表示等待 0x55 字符,设置匹配的波特率; UART_WAKEUP_ON_RDA //当 RCV 脚由高变低时,PIC 单片机会从 sleep 中醒来;

返回值: 没有定义; 功能: 同SET_UART_SPEED()函数很相似;如果 setup_uart( )用1作为参数,表示打开UART,如果 setup_uart( )用 0 为参数,表示关闭 UART;如果 setup_uart( )用波特率作为参数,则表示打

开 UART,同时设置波特率; 有效性: 只适合内置 UART 的设备; 要求: 必须使用#use rs232 例子: setup_uart(9600); //设置串口波特率为 9600bps; setup_uart(9600, rsout); //将 rsout 的串口设置为 9600bps; 例子文件: 没有; SETUP_VREF() 语法: setup_vref( mode | value ); 参数: mode 可能是下面的常数之一:

FALSE //表示关闭; VREF_LOW //使用 VDD*value/24; VREF_HIGH //使用 VDD*value/32+VDD/4 可同 VREF_A2 相或后得到的值; value 为 0~15 之间的整数;

返回值: 没有定义; 功能: 该函数用来建立内部模拟参考电压,这个电压可用于模拟比较器或在 PIN_A2 上输

出; 有效性: 只对带有 Vref 硬件的设备有用; 要求: 所用到的常数必须被定义在设备头文件中; 例子: setup_vref( VREF_HIGH | 6 );

//在 VDD=5V 时,其 Vref 为 2.19V; //根据 VREF_HIGH 的表达式: VDD*value/32+VDD/4=5x6/32+5/4=2.19V //所以内部模拟参考电压为 2.19V;

例子文件: 见 ex_comp.c 文件; SETUP_WDT( ) 语法: setup_wdt( mode ); 参数: 对于 PCB 和 PCM 的器件, mode 的值如下:

Page 135: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 135

WDT_18MS, WDT_36MS, WDT_72MS, WDT_144MS, WDT_288MS, WDT_576MS, WDT_1152MS, WDT_2304MS;

对于 PIC18 的器件, mode 的值如下:WDT_ON,WDT_OFF; 返回值: 没有定义; 功能: 该函数用来设置看门狗定时器; 看门狗定时器常用于在软件出现死循环时,会引起硬件复位; 看门狗定时器必须被使能,设置溢出时间,且必须用软件周期性地复位看门狗定时器

的定时器,下面讲的是在 PCB/PCM 和 PCH 器件中,函数使用的差异之处; PCB/PCM PCH 使能/不使能看门狗 #fuse setup_wdt( ) 溢出时间 setup_wdt( ) #fuse 重起看门狗 restart_wdt( ) restart_wdt( ) 有效性: 适合所有设备; 要求: 所用到的常数必须被定义在设备头文件中,必须使用#fuse; 例子: #fuse WDT1 //WDT1 的意思是 18ms*1 //重起动 PIC18 单片机的看门狗; main() { setup_wdt(WDT_ON);

while(TRUE) { restart_wdt( ); //重起动 PIC18 单片机的看门狗; perform_activity( ); }

} 例子文件: 见 ex_wdt.c 文件; SHIFT_LEFT( ) 语法: shift_left( address,bytes,value ); 参数: address 是指向某个存储区的指针, bytes 表示字节数计数器,即有多少个字节; value是一个要被移入到 address 存储单元的位值(0/1); 返回值: 返回值为移出的位值(0/1); 功能: 将一个位值移入到数组或结构中; address 可能是一个数组/结构的标识符(如:&data),在 RAM 中, 低字节的 bit0 被称为 LSB; 有效性: 适合所有设备; 要求: 没有; 例子: byte buffer[3]; //从 PIN_A3 脚读入 24 位位值,每当 PIN_A2 脚上升沿到来时,就读入一位值;

for(i=0; i<=24; ++i ) { while( !input(PIN_A2) ); //等待时钟变高,即等待PIN_A2脚输入为高; shift_left( buffer, 3, input(PIN_A3) ); //将 PIN_A3 脚的电平值移入到 buffer 中 while( input(PIN_A2) ); //等待时钟变低,即等待 PIN_A2脚输入为低; }

例子文件: 见 ex_extee.c 和 9356.c 文件;

Page 136: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 136

SHIFT_RIGHT( ) 语法: shift_right( address,bytes,value ); 参数: address 是指向某个存储区的指针, bytes 表示字节数计数器,即有多少个字节; value是一个要被移入到 address 存储单元的位值(0/1); 返回值: 返回值为移出的位值(0/1); 功能: 将一个位值移入到数组或结构中; address 可能是一个数组/结构的标识符(如:&data),在 RAM 中, 低字节的 bit0 被称为 LSB; 有效性: 适合所有设备; 要求: 没有; 例子: struct {

byte time; byte command:4; byte source:4;

}msg //从 PIN_A1 脚读入 16 位位值,每当 PIN_A2 脚上升沿到来时,就读入一位值; for(i=0; i<=16; ++i) { while( !input(PIN_A2) ); //等待时钟变高,即等待 PIN_A2 脚输入为高;

shift_left(&msg, 3, input(PIN_A1) ); //将 PIN_A1 脚的电平值移入到 msg 中 while( input(PIN_A2) ); //等待时钟变低,即等待 PIN_A2 脚输入为低;

} for(i=0; i<=16; ++i) output_bit( PIN_A0, shift_right( &data,1,0 ) ); //将 data 地址单元的内容右移 1 位,然后将移出的位值通过 PIN_A0 脚输出; 例子文件: 见 ex_extee.c 和 9356.c 文件; SIN( ) COS( ) TAN( ) ASIN( ) ACOS( ) ATAN( ) SINH( ) COSH( ) TANH( ) ATAN2( ) 语法: val=sin( rad );

val=cos( rad ); val=tan( rad ); rad=asin( val ); rad1=acos( val ); rad=atan( val );

Page 137: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 137

rad2=atan2( val, val ); result=sinh( value ); result=cosh( value ); result=tanh( value );

参数: rad 是一个浮点数,表示的是角度,弧度范围为-2π~2π;

val 是一个浮点数,取值范围为-1.0~1.0; value 是一个浮点数;

返回值: 返回值 rad 是一个浮点数,表示的是角度,其弧度范围为-π/2~2π/2;

返回值 val 是一个浮点数,取值范围为-1.0~1.0; 返回值 rad1 是一个浮点数, 表示的是角度,其弧度范围为 0~π;

返回值 rad2 是一个浮点数, 表示的是角度,其弧度范围为-π~π;

功能: 这些函数执行的是基本的三角函数功能; val=sin( x ); 返回的是 sin x 的数学值,x 必须为弧度值, 其弧度范围为-2π~2π;

val=cos( x ); 返回的是 cos x 的数学值,x 必须为弧度值, 其弧度范围为-2π~2π;

val=tan( x ); 返回的是 tan x 的数学值,x 必须为弧度值, 其弧度范围为-2π~2π;

rad=asin( y ); 返回的是反正弦函数 arcsin y 的数学值,y 的范围为-1~+1, rad 值范围-π/2~π/2;

rad1=acos( y ); 返回的是反余弦函数 arccos y 的数学值,y 的范围为-1~+1, rad1 值范

围 0~π;

rad=atan( y ); 返回的是反正切函数 arctan y 的数学值,y为任意值, rad值范围-π/2~2π/2;

rad2=atan2( val, val ); 返回的是反正切函数 arctan y/x 的数学值, rad2 值范围-π~π;

result=sinh( value ); 返回的是双曲线函数 hsin x 的数学值, result 的范围为任意数; result=cosh( value ); 返回的是双曲线函数 hcos x 的数学值, result 的范围为任意数; result=tanh( value ); 返回的是双曲线函数 htan x 的数学值, result 的范围为任意数;

注意:错误挂起: 如果程序中包含了’error.h’头文件,则范围错误存储在变量 error 中,用户能够检查 error,

看它是否有错误存在,打印错误,可使用 perror( )函数; 域值错误由下面几个因素造成的: asin(y):当反正弦函数的输入参数 y 不在-1~+1 之间时,会出现错误; rad=asin( y ), y 的范围不在-1~+1 之间; rad=acos( y ), y 的范围不在-1~+1 之间; rad=atan2(val1, val 2), val1 和 val 2 同时为 0; 范围错误由下面几个因素造成的: result=sinh( value ), 因 result 的值太大了,而导致错误; result=cosh( value ), 因 result 的值太大了,而导致错误;

有效性: 适合所有设备; 要求: 必须包含 math.h 头文件; 例子: float phase; for( phase=0; phase<2*3.1415926; phase+=0.01 ) { set_analog_voltage( sin( phase )+1 ); } 例子文件: 见 ex_tank.c 文件;

Page 138: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 138

SLEEP( ) 语法: sleep( ); 参数: 没有; 返回值: 没有定义; 功能: 发布睡眠命令;让设备在一般状态随时进入低功耗模式,停止程序执行,直到被外部

特殊事件唤醒;在发布睡眠命令之后,只有依靠能引起唤醒的因素,程序才可继续执行;在声明

主程序 main()之后,编译器会将 sleep( )插入到程序中; 有效性: 适合所有设备; 要求: 没有; 例子: sleep( ); 例子文件: 见 ex_wakup.c 文件; SPI_DATA_IS_IN( ) SPI_DATA_IS_IN2( ) 语法: result=spi_data_is_in( );

result=spi_data_is_in2( ); 参数: 没有; 返回值: 返回值为 0(FALSE)或 1(TRUE); 功能: 若通过 SPI 口接收到数据,则本函数返回 TRUE 值; 有效性: 适合带有 SPI 口硬件的设备; 要求: 没有; 例子: while( !spi_data_is_in() && input(PIN_B2) ); if( spi_data_is_in() ) data=spi_read( ); 例子文件: 没有; SPI_READ( ) SPI_READ2( ) 语法: value=spi_read( data );

value=spi_read2( data ); 参数: data 是可选项,若有参数 data,则 data 是 1 个 8 位整型参数; 返回值: 返回值是 1 个 8 位整型值; 功能: 通过 SPI 口读取返回值,若 spi_read( )有输入参数 data,则表示输出 data 个时钟,同时

将接收到的数据 value 返回;若 SPI 口没有数据,则 spi_read( )将等待接收数据; 若本设备提供时钟,那么 spi_write( data )的后面是 spi_read()或 spi_read( data ); spi_read()和 spi_read( data )的作用是相同的,只是用来产生时钟;若没有数据发送,只需要用

spi_read(0)就可产生时钟; 若是其它设备提供时钟,那么调用 spi_read( )函数,是用来等待时钟和接收数据;或者

Page 139: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 139

用 spi_data_is_in( )来确定是否有数据被准备好; 有效性: 适合带有 SPI 口硬件的设备; 要求: 没有; 例子: in_data=spi_read(out_data); 例子文件: 见 ex_spi.c 文件; SPI_WRITE( ) SPI_WRITE2( ) 语法: spi_write( value ); spi_write2( value ); 参数: value 是 1 个 8 位整型参数; 返回值: 没有; 功能: 通过 SPI 口发送一个字节; spi_write( )可产生 8 个 clock;该函数将 value 的值通过 SPI口发送出去; 有效性: 适合带有 SPI 口硬件的设备; 要求: 没有; 例子: spi_write( data_out ); //通过 SPI 口发送 data_out 的值,同时会有 8 个 clock 产生; data_in=spi_read( ); //用来产生时钟移位同时将接收到的值返回; 例子文件: 见 ex_spi.c 文件; SPRINTF( ) 语法: sprintf( string, cstring, values… ); 参数: string 是一个字符串数组;

cstring 是一个字符串常数,或带有 NULL 结束符的字符串数组; values 是一系列由逗号隔开的变量;

返回值: 没有; 功能: 同 printf( )的操作一样,而且还将输出的字符串放进指定的 string 中;输出的文字必须

带有 1 个 NULL 的结束符;务必保证 string 足够大,可存放下数据,在这方面,函数不做检查;参考 printf( ); 有效性: 适合所有的设备; 要求: 没有; 例子: char mystring[20]; long mylong; mylong=1234; sprintf( mystring,”<%1u>”, mylong ); // mystring 现在有< 1 2 3 4 > \0 例子文件: 没有; SQRT( ) 语法: result=sqrt( value ); 参数: value 是一个浮点数;

Page 140: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 140

返回值: 返回值是一个浮点数; 功能: 计算非负数的浮点数 value 的平方根,若 value 为负数,则没有定义函数行为; 注意:错误挂起:

如果程序中包含了’error.h’头文件,则范围错误存储在变量 error 中,用户能够检查 error,看它是否有错误存在,打印错误,可使用 perror( )函数; 域值错误由下面几个因素造成的:

sqrt( value )的 value 是一个负数; 有效性: 适合所有的设备; 要求: 必须使用#include<math.h>; 例子: distance=sqrt( sqrt(x1-x2)+sqrt(y1-y2) ); 例子文件: 没有; SRAND( ) 语法: srand( n ); 参数: n 是 rand( )函数返回的任意数的序列; 返回值: 没有; 功能: 随机函数简略,srand()使用的是 rand( )函数返回的任意数的序列作为输入参数; 有效性: 适合所有的设备; 要求: 必须使用#include<stdlib.h>; 例子: srand( 10 );

I=rand( ); 例子文件: 没有; MEMCHR( ) MEMCMP( ) STRCAT( ) STRCHR( ) STRCMP( ) STRCOLL( ) STRCSPN( ) STRICMP( ) STRLEN( ) STRLWR( ) STRNCAT( ) STRNCMP( ) STRNCPY( ) STRPBRK( ) STRRCHR( ) STRSPN( ) STRSTR( ) STRXFRM( )

Page 141: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 141

语法: ptr=strcat( s1, s2 ); //将 S2 的字符串加在 S1 字符串的后面,结果以 s1 返回; ptr=strncat( s1, s2, n ); //从 S2 的字符串中取 n 个字符,加在 S1 字符串的后面,并在结

尾自动加上’\0’,结果以 s1 返回;注意:s1 必须有足够的空间; ptr=strchr( s1, c ); //在 s1 字符串中搜索字符 c,并将它在 s1 中的地址返回; ptr=strrchr( s1, c ); //在 s1 字符中反向搜索字符 c, 并将它在 s1 中的地址返回; cresult=strcmp( s1, s2 ); //两个字符串 s1 与 s2,从第 1 个字符开始比较,若相等,再比

较第 2 个字符,依此类推,直到不相等或已到字符串结尾,才停止比较;当 s1<s2 时,cresult<0; 当s1=s2 时,cresult=0; 当 s1>s2 时,cresult>0;

iresult=strncmp( s1, s2, n ); //比较 s1 和 s2 字符串的前 n 个字符,当 n 大于或等于 s1和 s2 的 大长度时,其使用方式则与 cresult=strcmp( s1, s2 )完全相同;

iresult=stricmp( s1, s2 ); //两个字符串比较时,忽略大小写,即’A’与’a’相同; 当 s1<s2时,iresult<0; 当 s1=s2 时,iresult=0; 当 s1>s2 时,iresult>0;

ptr=strncpy( s1, s2, n ); //从 s2 中拷贝 n 个字符到 s1 中,拷贝过去的字符可能没

有’\0’这个字符,因此,在拷贝后,要在 s1 的后面加上’\0’这个字符,才算完整; iresult=strcspn( s1, s2 ); //计算在 s1 中且不在 s2 中的字符有多少个,并将其返回; iresult=strspn( s1, s2 ); //计算既在 s1 中又在 s2 中的字符有多少个,并将其返回; iresult=strlen( s1 ); //返回字符串 s1 的字符个数,但不包括结束符 NULL(‘\0’); ptr=strlwr( s1 ); //将字符串 s 转换为小写字母,即(’A’..’Z’),(‘a’..’z’),非字母不转换; ptr=strupr( s1 ); //将字符串 s 转换为大写字母,即(’A’..’Z’),(‘a’..’z’),非字母不转换; ptr=strpbrk( s1, s2 ); //检查 s1 的第一个字符是否也在 s2 中,并将其指针返回; ptr=strstr( s1, s2 ); //在 s1 中检查是否有 s2 的字符串,若有则将其地址返回; iresult=strcoll( s1, s2 ); res=strxfrm( s1, s2, n ); iresult=memcmp( m1, m2, n ); //将 m1 和 m2 的前 n 个字符进行比较, 当 m1<m2

时,iresult<0; 当 m1=m2 时,iresult=0; 当 m1>m2 时,iresult>0; ptr=memchr( m1, c, n); //在 m1的前 n个字符中,查找是否具有 c的字符,若有,则将其

对应的地址返回; 参数: s1 和 s2 是字符串数组或数组名,注意 s1 和 s2 不可为常数(如”HI”); n 为要操作的 大的字符数; c 是一个 8 位字符; m1 和 m2 是指向存储器的指针; 返回值: 返回值 ptr 是 s1 指针的拷贝; iresult 是一个 8 位整数; result 是-1(小于),0(等于),或 1(大于); res 是一个整型数; 功能: 见上述; 有效性: 适合所有的设备; 要求: 必须使用#include<string.h>; 例子: char string1[10], string2[10]; strcpy( string1,”hi ”); //执行后 string1=”hi ”; strcpy( string2,”there”); //执行后 string2=”there”;

strcat(string1,string2); //将 string2 的字符号加在 string1 的后面,然后将 string1 返回; printf( “length is %u\r\n”, strlen(string1) ); //执行后: length is hi there

Page 142: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 142

例子文件: 见 ex_str.c 文件; STRCPY( ) STRCOPY( ) 语法: strcpy( dest, src);

strcopy( dest, src); 参数: dest 是一个指向 RAM 中字符串数组的指针;

src 是一个指向 RAM 中字符串数组的指针或者是一个字符串常数; 返回值: 返回值定义; 功能: 将一个字符串常数或 RAM 中的文字串拷贝到 RAM 的另一个文字串中; 文字串带

有结束符’\0’; 有效性: 适合所有的设备; 要求: 没有; 例子: char string[10], string2[10]; strcpy(string,″Hi there″); //将字符串常数″Hi there″拷贝到数组 string[10]中; strcpy( string2, string ); //将文字串数组 string[10]拷贝到数组 string2[10]中; 例子文件: 见 ex_str.c 文件; STRTOD( ) 语法: result=strtod( nptr, &endptr ); 参数: nptr 和 endptr 都是字符串数组; 返回值: 返回值 result是一个符点数;如果转换允许的话,则将转换值存放到 result中;如果没有

转换的话,则 result 为 0; 功能: strtod( nptr, &endptr )函数将 nptr 所指文字串的初始部分转换为浮点表示法; 转换后

的文字串部分存放到由指针 endptr 所指的单元;规定 endptr 不是一个空指针;如果 nptr 是一个

空的或没有你想要的浮点表示法的那种形式,则不进行转换,且将 nptr 所指向的值存储到由指

针 endptr 所指向的单元,条件是 endptr 不是一个空指针; 有效性: 适合所有的设备; 要求: 必须使用#include<stdlib.h>; 例子: float result; char str[12]= ″123.45hello″; char *ptr; result=strtod( str,&ptr ); // result=123.45, ptr= ″hello″; 例子文件: 没有; STRTOK( ) 语法: ptr=strtok( s1, s2 ); 参数: s1 和 s2 是一个指向字符串数组的指针或者是数组名,注意 s1 和 s2 不可为字符串常

数(如: ″hi″),s1 可能为 0,指示连续操作;

Page 143: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 143

返回值: 返回值 ptr 是一个指向 s1 字符的指针或者为 0; 功能: 首先访问 s1 的开始字符,检查第一个字符是否包含在 s2 中,如果在 s1 中没有找到含

有 s2 中的字符,则返回 null; 如果在 s1 中没有找到含有 s2 中的字符,则将第一取出的开始字符返回;函数接着从

那儿搜索下一个字符,检查是 s1 的其它文字中是否含有 s2 中的字符; 如果在 s1 中还是没有找到含有 s2 中的字符,则一直搜索,直到取到 s1 的结束部分,取出后来的要搜索的文字,返回 null; 如果在 s1中发现含有 s2中的字符,则用‵\0‵覆盖在s1中的当前位置;函数保存指

针,使它指向下一个文字串搜索的开始处;

每一次调用,都从保存处的指针开始搜索;

有效性: 适合所有的设备; 要求: 必须使用#include<string.h>; 例子: char string[30]; term[3], *ptr; strcpy(string,″one,two,three;″); //将字符串拷贝到 string 中; strcpy(term, ″,;″); //将字符串拷贝到 term 中; ptr=strtok( string,term); //检查 string 中的字符是否在 term 中,

//若在 term 中,则 string 中对应位置改用‵\0‵代替; //保存到 null 指针处, string 的内容不变; //null 指针处的内容为″one\0two\0three\0″

while(ptr!=0) { puts(ptr); ptr=strtok(0,term); } //打印输出: one two three 例子文件: 见 ex_str.c 文件; STRTOL( ) 语法: result=strtol( nptr, &endptr, base ); 参数: nptr 和 endptr 是字符串,base 是一个整型参数; 返回值: 返回值 result 是一个有符号的长整型数,16 位的值; 若有转换发生的话,则将转换后的值保存在 result 中;若没有转换发生的话,则返回 0; 功能: 函数 strtol( nptr, &endptr, base )是将 nptr 指向的字符串的初始部分转换成有符号的

长整型数,根基数由 base的值决定;转换后剩下的文字部分存储到由 endptr指针所指向的单元;若 nptr 是空指针或没有你想要的那种形式,如″w123hello″,则不进行转换,且将 nptr 的值存

储到由 endptr 指针所指向的单元,规定 endptr 不是 null 指针; 有效性: 适合所有的设备; 要求: 必须使用#include<stdlib.h>; 例子: signed long result; char str[2]=″123hello″;

Page 144: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 144

char *ptr;

result=strtol( str, &ptr, 10 ); // result=123 而 ptr 所指向的单元为 hello;

例子文件: 没有; STRTOUL( ) 语法: result=strtoul( nptr, &endptr, base ); 参数: nptr 和 endptr 是字符串,base 是一个整型参数; 返回值: 返回值 result 是一个无符号的长整型数,16 位的值; 若有转换发生的话,则将转换后的值保存在 result 中;若没有转换发生的话,则返回 0; 功能: 函数 strtoul( nptr, &endptr, base )是将 nptr 指向的字符串的初始部分转换成无符号的

长整型数,根基数由 base的值决定;转换后剩下的文字部分存储到由 endptr指针所指向的单元;若 nptr 是空指针或没有你想要的那种形式,如″w123hello″,则不进行转换,且将 nptr 的值存

储到由 endptr 指针所指向的单元,规定 endptr 不是 null 指针; 有效性: 适合所有的设备; 要求: 必须使用#include<stdlib.h>; 例子: long result; char str[2]=″123hello″;

char *ptr;

result=strtol( str, &ptr, 10 ); // result=123,ptr 所指向的单元为″hello″;

例子文件: 没有; SWAP( ) 语法: swap( ivalue ); 参数: ivalue 是一个字节型变量; 返回值: 返回值没有定义,注意该函数不返回结果; 功能: 函数 swap( ivalue )将指定字节的高 4 位同其低 4 位进行交换,同下面的功能是相同

的:byte=( byte<<4 ) | ( byte>>4 ); 有效性: 适合所有的设备; 要求: 没有; 例子: x=0x45;

swap(x); //x 现在为 0x54; 例子文件: 没有; TOLOWER ( ) TOUPPER ( ) 语法: result=tolower( cvalue );

result=toupper( cvalue ); 参数: cvalue 是一个字符;

Page 145: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 145

返回值: 返回值是一个 8 位字符; 功能: 函数 tolower( x )将′A′…′Z′的大写字母转换为对应的′a′…′z′的小写字

母,对其它字符,则不进行转换;

函数 toupper ( x )将′a′…′z′的小写字母转换为对应的′A′…′Z′的大写字

母,对其它字符,则不进行转换;

有效性: 适合所有的设备; 要求: 没有; 例子: switch( toupper( getc( ) ) ) { case ′R′: read_cmd( ); break;

case ′W′: write_cmd( ); break;

case ′Q′: done=TRUE; break; } 例子文件: 见 ex_str.c 文件; WRITE_BANK ( ) 语法: write_bank( bank, offset, value ); 参数: bank 是物理 RAM bank 的 1~3(根据设备的不同,取不同的 bank0~bank3);

offset 是某个 bank 的用户 RAM 区的偏移量(开始处是 0); value 是要写入 RAM 的 8 位数据;

返回值: 没有定义; 功能: 将某一个字节数据写入指定的存储器 bank 的用户 RAM 中;函数常用于一些设备上,通过自动变量访问所有的RAM是无效的;例如 PIC16C57芯片设置指针的大小为 5位,会产生

有效的 ROM 代码,然而自动变量不可超过 0x1f 的地址;用 8 位指针代替 5 位指针,你可采用

这个函数保存ROM,写入硬件,到达bank区;在某些情况下,bank可能为1~3;offset可能为0~15; 有效性: 只对 PCB 编译器下的元件且存储器超过 0x1f,才会有效, 对 PCM 编译器下的元件且

存储器超过 0xff,才会有效; 要求: 没有; 例子: i=0; do{

c=getc( ); write_bank( 1, i++; c ); //使用 bank1 作为 RS232 缓冲区;

}while( c!=0x13 ); 例子文件: 见 ex_psp.c 文件; WRITE_EEPROM ( ) 语法: write_eeprom( address, value ); 参数: address 是一个整型变量(根据所用的 CPU 不同,可能是 8 位或 16 位),范围是由设备

决定的; value 是一个 8 位整型数; 返回值: 没有定义; 功能: 将一个字节数据写入到制指定的数据 EEPROM 地址;执行该函数可能要花费几个毫

Page 146: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 146

秒时间;该函数只对带有内置的 EEPROM 才有效; 对带有外置的 EEPROM 的器件或内置分离的 EEPROM 的 CPU(如:12CE671),就不适

用了,参考文件:ex_extee.c 和 ce51x.c,ce61x 或 ce67x.c; 有效性: 只对芯片上支持硬件的 CPU 有效; 要求: 没有; 例子: #define LAST_VOLUME 10 //定义 EEPROM 的地址; volume++; write_eeprom( LAST_VOLUME, volume ); //向内部 EEPROM 的地址 10 写 volume 值; 例子文件: 见 ex_intee.c 文件; WRITE_EXTERNAL_MEMORY ( ) 语法: write_external_memory( address, dataptr, count ); 参数: address 对于 PCM 编译器下的器件来说是 16 位,而对于 PCH 编译器下的器件来说,则为 32 位;

dataptr 是一个指向一个或更多字节的指针; count 是一个 8 位整型参数;

返回值: 没有定义; 功能: write_external_memory( address, dataptr, count )将来自 dataptr 指针所指向的 count 个字节写入程序存储器的 address 处;它不同于 write_program_eeprom( ); 有效性: 只对 PCH 编译器下的 CPU 有效; 要求: 没有; 例子: for( i=0x1000; i<=0x1fff; i++ ) { value=read_adc( ); write_erternal_memory( i, value, 2 ); //向程序存储器地址 i写入来自value 的2个字节; delay_ms( 1000 ); } 例子文件: 见 loader.c 文件; WRITE_PROGRAM_EEPROM ( ) 语法: write_ program_eeprom( address, data ); 参数: address 对于 PCM 编译器下的器件来说是 16 位,而对于 PCH 编译器下的器件来说,则为 32 位; data 是 16 位参数;在 PCH 编译器下,没有意义的位总是为 0; 返回值: 没有定义; 功能: 向指定的程序 EEPROM 区写入数据; 有效性: 只允许设备写入程序存储器; 要求: 没有; 例子: write_program_eeprom( 0, 0x2800 ); //不使能程序; 例子文件: 见 ex_loader.c, loader.c 文件;

Page 147: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 147

WRITE_PROGRAM_MEMORY( ) 语法: write_ program_memory( address, dataptr, count ); 返回值: 没有定义; 功能: write_ program_memory( address, dataptr, count )将来自 dataptr 指针所指向的 count个字节写入程序存储器的 address 处; 有效性: 只对允许写入程序存储器的设备有效; 要求: 没有; 例子: for( i=0x1000; i<=0x1fff; i++ ) { value=read_adc( ); write_erternal_memory( i, value, 2 ); //向程序存储器地址 i写入来自value 的2个字节; delay_ms( 1000 ); } 例子文件: 见 loader.c 文件; 文件 rs485.c 如下: // int rs485_get_message( int * data_ptr, int wait ) // Data will be filled in at pointer as follows: // FROM_ID DATALEN DATA... // Function returns FALSE if no data want WAIT is FALSE // int rs485_send_message( int to, int len, int * data ) // void rs485_wait_for_bus() // Call before rs485_send_message unless this is a response // The following is our unit ID: #ifndef RS485_ID //若没有定义 RS485_ID,则执行编译下面语句; #define RS485_ID 0x10 //用 RS485_ID 代替 0x10; #endif //结束 if 定义; #ifndef RS485_USE_EXT_INT //若没有定义 RS485_USE_EXT_INT,则执行编译下面语句; #define RS485_USE_EXT_INT FALSE //用 RS485_USE_EXT_INT 代替 FALSE; #endif //结束 if 定义; #if (RS485_USE_EXT_INT==FALSE) //若不使用 INT0,则执行编译下面语句; #define RS485_RX_PIN PIN_C7 //用 RS485_RX_PIN 代替 PIN_C7; #define RS485_TX_PIN PIN_C6 //用 RS485_TX_PIN 代替 PIN_C6; #define RS485_ENABLE_PIN PIN_B4 //控制 RS485 的 DE 脚,low for RX, high for TX //用 RS485_ENABLE_PIN 代替 PIN_ B4; //当 PIN_ B4 输出低电平时,RS485 接收数据; //当 PIN_ B4 输出高电平时,RS485 发送数据; #define RS485_RX_ENABLE PIN_B5 //控制 RS485 的 RE 脚,should keep low. //用 RS485_RX_ENABLE 代替 PIN_ B5; #use rs232(baud=9600, xmit=RS485_TX_PIN, rcv=RS485_RX_PIN, enable=RS485_ENABLE_PIN, bits=9, long_data, errors, stream=RS485)

//设置 baud(波特率)为 9600,

Page 148: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 148

//设置 xmit(发送脚)为 RS485_TX_PIN(用脚 PIN_B3 代替), //设置 rcv (接收脚)为 RS485_RX_PIN(用脚 PIN_B0 代替), // enable=RS485_ENABLE_PIN, 在 发 送 期 间 将 指 定 的 脚

RS485_ENABLE_PIN 置高,即将 PIN_B4 置高,这使得采用 485 发送成为可能; // bits=9, 说明这是 9 位数据格式 //使用 long_data,说明 getc()返回的是 16 位整型数, putc()发送的是 16 位整型

数.这是 9 位数据格式; //errors, 说明 RS232 将接收到错误保存在变量 RS232_ERRORS 中;

// stream=RS485,说明使用 RS485 标识符同这个 RS232 端口发生联系; #use rs232(baud=9600, xmit=RS485_TX_PIN, rcv=RS485_RX_PIN, enable=RS485_ENABLE_PIN, bits=9, long_data, force_sw, multi_master, errors, stream=RS485_CD)

//设置 baud(波特率)为 9600, //设置 xmit(发送脚)为 RS485_TX_PIN(用脚 PIN_B3 代替), //设置 rcv (接收脚)为 RS485_RX_PIN(用脚 PIN_B0 代替), // enable=RS485_ENABLE_PIN, 在 发 送 期 间 将 指 定 的 脚

RS485_ENABLE_PIN 置高,即将 PIN_B4 置高,这使得采用 485 发送成为可能; // bits=9, 说明这是 9 位数据格式 // force_sw,即便 UART 脚被指定,也会产生软件串行 I/O 中断服务程序 //使用 long_data,说明 getc()返回的是 16 位整型数, putc()发送的是 16 位整型

数.这是 9 位数据格式; //errors, 说明 RS232 将接收到错误保存在变量 RS232_ERRORS 中;

// stream=RS485_CD,说明使用 RS485 标识符同这个 RS232 端口发生联系; #if getenv("AUART") //若 getenv("AUART")为 1, 则执行编译下面语句; //#define RCV_ON() {setup_uart(UART_ADDRESS);setup_uart(TRUE);}

#define RCV_OFF( ) {setup_uart(FALSE);} //关闭已经设置的波特率 9600 位/秒; //用 RCV_OFF( )代替语句{setup_uart(FALSE);},关闭 UART

#else //若 getenv("AUART")为 0, 则执行编译下面语句; //#define RCV_ON() {setup_uart(TRUE);}

#define RCV_OFF( ) {setup_uart(FALSE);} //关闭已经设置的波特率 9600 位/秒; ///用 RCV_OFF( )代替语句{setup_uart(FALSE);},关闭 UART

#endif //结束 if 定义; #else //若使用 INT0,则执行编译下面语句; #define RS485_RX_PIN PIN_B0 #define RS485_TX_PIN PIN_B3 #define RS485_ENABLE_PIN PIN_B4 //controls DE pin. low for RX, high for TX #define RS485_RX_ENABLE PIN_B5 //controls RE pin. should keep low. #use rs232(baud=9600, xmit=RS485_TX_PIN, rcv=RS485_RX_PIN, enable=RS485_ENABLE_PIN, bits=9, long_data, errors, stream=RS485)

//设置 baud(波特率)为 9600, //设置 xmit(发送脚)为 RS485_TX_PIN(用脚 PIN_B3 代替), //设置 rcv (接收脚)为 RS485_RX_PIN(用脚 PIN_B0 代替),

Page 149: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 149

// enable=RS485_ENABLE_PIN, 在 发 送 期 间 将 指 定 的 脚

RS485_ENABLE_PIN 置高,即将 PIN_B4 置高,这使得采用 485 发送成为可能; // bits=9, 说明这是 9 位数据格式 //使用 long_data,说明 getc()返回的是 16 位整型数, putc()发送的是 16 位整型

数.这是 9 位数据格式; //errors, 说明 RS232 将接收到错误保存在变量 RS232_ERRORS 中; // stream=RS485,说明使用 RS485 标识符同这个 RS232 端口发生联系;

#use rs232(baud=9600, xmit=RS485_TX_PIN, rcv=RS485_RX_PIN, enable=RS485_ENABLE_PIN, bits=9, long_data, multi_master, errors, stream=RS485_CD)

//设置 baud(波特率)为 9600, //设置 xmit(发送脚)为 RS485_TX_PIN(用脚 PIN_B3 代替), //设置 rcv (接收脚)为 RS485_RX_PIN(用脚 PIN_B0 代替), // enable=RS485_ENABLE_PIN, 在 发 送 期 间 将 指 定 的 脚

RS485_ENABLE_PIN 置高,即将 PIN_B4 置高,这使得采用 485 发送成为可能; // bits=9, 说明这是 9 位数据格式 //使用 long_data,说明 getc()返回的是 16 位整型数, putc()发送的是 16 位整型

数.这是 9 位数据格式; //errors, 说明 RS232 将接收到错误保存在变量 RS232_ERRORS 中; // stream=RS485_CD,说明使用 RS485 标识符同这个 RS232 端口发生联系;

#if defined(__PCH__) //若使用了 PCH 编译器,则 defined( __PCH__)返回值为 1

#bit ext_intf=0xFF2.1 //定义 ext_intf 的位地址为 0xff2.1; //外部中断 0 标志位;

#else #bit ext_intf=0x0B.1 //若没有使用 PCH 编译器,则定义 ext_intf 的位地址为 0x0b.1; //外部中断 0 标志位;

#endif //结束 if 定义; //#define RCV_ON() {enable_interrupts(INT_EXT);} #define RCV_OFF( ) {disable_interrupts(INT_EXT);} //不使能外部中断 0 #endif //结束 if 定义; #define RS485_wait_time 20 //Milliseconds,用 RS485_wait_time 代替 20; #bit rs485_collision = rs232_errors.6 //在 float high 模式里,置 1 表示一个 putc( )失败; #define RS485_RX_BUFFER_SIZE 64 //用 RS485_RX_BUFFER_SIZE 代替 64; int rs485_state, rs485_ni, rs485_no; //声明全局变量 rs485_state, rs485_ni, rs485_no int rs485_buffer[RS485_RX_BUFFER_SIZE]; //声明字节数组 rs485_buffer[ ]; void RCV_ON(void) {

Page 150: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 150

#if (RS485_USE_EXT_INT==FALSE) //若不使用 INT0,则执行编译下面语句; //在前面有: 若没有定义 RS485_USE_EXT_INT,则用 RS485_USE_EXT_INT 代替 FALSE;

while( kbhit(RS485) ) {getc();} //从 RS485 口读数据; //clear rx buffer. clear rda interrupt flag. clear overrun error flag.

#if getenv("AUART") setup_uart(UART_ADDRESS); //只接收第 9 位为 1 的数据; setup_uart(TRUE); //使用已经设置的波特率 9600 位/秒; #else setup_uart(TRUE); //使用已经设置的波特率 9600 位/秒; #endif //结束 if 定义; #else //若使用 INT0,则执行编译下面语句; ext_intf=0; //将外部中断 0 的标志位置 0; enable_interrupts(INT_EXT); //使能外部中断 0; #endif //结束 if 定义; } //RS485 初始化函数 void rs485_init() { RCV_ON(); // RS485 接收设置有两种:

//1 是 RS232 接收初始化,只接收第 9 位为 1 的数据,; //2 是外部中断 0 使能

rs485_state=0; rs485_ni=0; rs485_no=0; #if RS485_USE_EXT_INT==FALSE //若不使用 INT0,则执行编译下面语句; enable_interrupts(INT_RDA); //RS232 接收到的数据有用, 使能 UART 接收中断 #else //若使用 INT0,则执行编译下面语句; ext_int_edge(H_TO_L); //设置外部中断 0 的边沿触发方式为下降沿触发 enable_interrupts(INT_EXT); //使能外部中断 0; #endif //结束 if 定义; enable_interrupts(GLOBAL); //开总中断 output_low(RS485_RX_ENABLE); //将 RS485 的 DE 脚置低,允许 RS485 接收数据; //用 RS485_ENABLE_PIN 代替 PIN_ B4; //控制 RS485 的 DE 脚,low for RX, high for TX //当 PIN_ B4 输出低电平时,RS485 接收数据; //当 PIN_ B4 输出高电平时,RS485 发送数据; } void rs485_ptr_inc(int *index, int inc) { int i; //声明 8 位暂态变量 i; i=*index; //将指针的内容送给 i;

Page 151: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 151

i+=inc; //将 i 加 1 if (i>=RS485_RX_BUFFER_SIZE) //用 RS485_RX_BUFFER_SIZE 代替 64;

{ i-=RS485_RX_BUFFER_SIZE; //将 i 减去 64; }

*index=i; //修改指针的内容; } //RS485 接收中断服务函数如下: #if (RS485_USE_EXT_INT==FALSE) //若不使用 INT0,则执行编译下面语句; #int_rda //指示下面的是 UART 接收中断函数 #else //若使用 INT0,则执行编译下面语句; #int_ext //指示下面的函数是外部中断 0 的函数 #endif //结束 if 定义; void incomming_rs485() { int16 b; //声明 16 位暂态变量 b; static int8 cs, state, mlen, len, temp_ni; //声明 8 位静态变量 cs, state, mlen, len, temp_ni; static int16 to,source; //声明 16 位静态变量 to, source; b=fgetc(RS485); //从 RS485 接口接收两个字节; switch(state) { case 0: //接收 source(0x10)为从机地址; temp_ni=rs485_ni; //rs485_ni 的初始值为 0; source=b; //将从 485 口读到的数据存到 source 中,为即 0x0110; rs485_buffer[temp_ni]=source; //将 RS485_ID(即 0x10)存接收缓冲区; //而高 8 位丢弃; rs485_ptr_inc(&temp_ni, 1); //修改数组的下标值,加 1; break; case 1: //接收 to 为从机地址; to=b; //将从 485 口读到的数据存到 b 中; break; case 2: //get len len=b; //将从 485 口读到的数据存到 b 中,为接收的字节数; mlen=b; cs=len^(to&0xFF)^(source&0xFF); //计算校验和,存入 cs; rs485_buffer[temp_ni]=len; //将要接收的字节数存入数阻中; rs485_ptr_inc(&temp_ni, 1); //修改数组的下标值,加 1; #if (getenv("AUART")&&(RS485_USE_EXT_INT==FALSE))

//若不使用 INT0,则执行编译下面语句; //不管第 9 位是 0 还是 1,都接收

setup_uart(UART_DATA); //允许 485 口接收所有数据; #endif //结束 if 定义;

Page 152: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 152

break; case 255: //get checksum cs^=b; //将从 485 口读到的数据存到 b 中,计算校验和; if ( (!cs) && ( bit_test(to,8) ) && ( bit_test(source,8) ) && ( (to&0xFF)==RS485_ID))

{ //若 cs==0,且 to 的第 9 位为 1,且 ource 的第 9 位为 1,to=0x10,则接收 OK rs485_ni=temp_ni; //若接收到的校验和正确,则将 temp_ni 存入 rs485_ni } #if (getenv("AUART")&&(RS485_USE_EXT_INT==FALSE))

//若不使用 INT0,则执行编译下面语句; setup_uart(UART_ADDRESS); //只接收第 9 位为 1 的数据; #endif //结束 if 定义; state=0; //将置 state 0,为下一次接受做准备; return; //接收正确,返回; default: //get data rs485_buffer[temp_ni]=b; //将 RS485 读到的数据存入接收缓冲区; cs^=b; //将从 485 口读到的数据存到 b 中,计算校验和; rs485_ptr_inc(&temp_ni, 1); //修改数组的下标值,加 1; len--; //接收字节的长度自减 1; break; } //switch( )结束 if ( (state>=3) && (!len) ) { state=255; } else { //若 state<3 或 len 不等于 0 的话,则执行下面 state++; //修改,为下次接收数据做准备 } } int rs485_send_message( int to, int len, int * data ) { // Format: source | destination | data-length | data | checksum

int try, i, cs; //声明暂态 8 位整型变量 try, i, cs; // try 用设置重新发送的次数,发送次数超过 5,失败; // i 用作计数器; // cs 用来存放校验和; RCV_OFF(); //关闭已经设置的波特率 9600 位/秒;

for(try=1; try<=5; try++) { //设置重复发送次数为 5 次; rs485_collision = 0; //将 putc( )失败的标志位清 0,为发送数据做准备;

fputc( (int16) 0x100 | rs485_id, RS485_CD );

Page 153: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 153

//用 RS485_ID 代替 0x10,同 0x0100 相或后,表示第 9 位为 1(地址); //发送 0x0110

fputc( (int16) 0x100 | to, RS485_CD ); //将 to 的参数同 0x0100 相或后,表示第 9 位为 1,(地址); //to=0x10;

//发送数据 fputc( len, RS485_CD ); //将 len 的参数通过 RS485 发送出(数据); for(i=0,cs=rs485_id^to^len; i<len; i++) { cs^=*data; //计算校验和; fputc(*data,RS485_CD); //将发送缓冲区的的元素通过 RS485 发送出(数据); ++data; //修改发送缓冲区的的指针;

}

fputc(cs,RS485_CD); //发送校验和; if(rs485_collision) { //若 putc( )失败,则延时 10ms,执行重新发送 delay_ms(rs485_id); //用 RS485_ID 代替 0x10,延时 10ms continue; //循环一次 for( )语句;

}

RCV_ON(); // RS485 接收设置有两种: //1 是 RS232 接收初始化,只接收第 9 位为 1 的数据,; //2 是外部中断 0 使能

return(TRUE); //RS485 发送 OK } RCV_ON(); // RS485 接收设置有两种:

//1 是 RS232 接收初始化,只接收第 9 位为 1 的数据,; //2 是外部中断 0 使能

return(FALSE); //发送次数超过 5,失败; } int1 rs485_wait_for_bus(int1 clrwdt) { int i; RCV_OFF(); //关闭 UART for(i=0;i<=(rs485_wait_time*20);i++) { if(!input(RS485_RX_PIN)) return(TRUE); //若接收脚变低,则退出等待; else delay_us(50); if (clrwdt) { restart_wdt(); //重新启动看门狗; } }

Page 154: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 154

return(FALSE); } int rs485_get_message( int * data_ptr, int1 wait ) { // Data will be filled in at pointer as follows: // FROM_ID DATALEN DATA... // Function returns FALSE if no data want WAIT is FALSE int n; if(wait) while(rs485_ni==rs485_no) ; if(rs485_ni==rs485_no) return FALSE; else { *data_ptr=rs485_buffer[rs485_no]; rs485_no=(rs485_no+1)%sizeof(rs485_buffer); data_ptr++; n=rs485_buffer[rs485_no]+1; for(;n!=0;--n) { *data_ptr=rs485_buffer[rs485_no]; rs485_no=(rs485_no+1)%sizeof(rs485_buffer); data_ptr++; } return TRUE; } } 文件 EX_PBUSR.C 如下: #if defined(__PCB__) //若使用了 PCB 编译器,则 defined( __PCB__)返回值为 1 #include <16c56.h> //包含 16c56.h 头文件 #fuses HS, NOWDT, NOPROTECT //HS:高速晶振/谐振器, NOWDT:不使用 WDT // NOPROTECT:程序存储器代码不保护 #use delay(clock=20000000) //使能内置函数的功能:delay_ms()和 delay_us() //#USE DELAY()必须在#use rs232()使用之前出现. #elif defined(__PCM__) //若使用了 PCM 编译器,则 defined( __PCM__)返回值为 1 #include <16F877.h> //包含 16F877.h 头文件 #fuses HS, NOWDT, NOPROTECT, NOLVP //HS:高速晶振/谐振器, NOWDT:不使用 WDT // NOPROTECT:程序存储器代码不保护 #use delay(clock=20000000) //使能内置函数的功能:delay_ms()和 delay_us() //#USE DELAY()必须在#use rs232()使用之前出现. #elif defined(__PCH__) //若使用了 PCH 编译器,则 defined( __PCH__)返回值为 1 #include <18F452.h> //包含 18F452.h 头文件

Page 155: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 155

#fuses HS, NOWDT, NOPROTECT, NOLVP //HS:高速晶振/谐振器, NOWDT:不使用 WDT // NOPROTECT:程序存储器代码不保护 #use delay(clock=20000000) //使能内置函数的功能:delay_ms()和 delay_us() //#USE DELAY()必须在#use rs232()使用之前出现. #endif //结束 if 定义; #use rs232(baud=9600, float_high, bits=9, xmit=PIN_B0, rcv=PIN_B0)

// baud=9600,表示使用波特率为 9600, //FLOAT_HIGH, 表示用来开集电极输出 // bits=9, 表示发送/接收是 9 位数据格式 // xmit=PIN_B0,表示发送脚为 PIN_B0 // rcv=PIN_B0,表示接收脚为 PIN_B0 //使能内置函数:GETC,PUTC 和 PRINTF, kbhit();

#define PBUS_RAM_SIZE 16 //用 PBUS_RAM_SIZE 代替脚 16 BYTE pbus_ram[PBUS_RAM_SIZE]; //声明字节型数组 pbus_ram[]; enum pbus_states {PBUS_IDLE=0x80, PBUS_NEED_CS=0x84}; BYTE pbus_state=PBUS_IDLE; //声明字节型全局变量 pbus_state,并赋初值 BYTE pbus_next_loc, pbus_next_value;

//声明字节型全局变量 pbus_next_loc, pbus_next_value; //pbus_next_loc 是用来存数组的元素位置号码; // pbus_next_value 是用来存数组的元素;

short pbus_ram_changed; //声明位型全局变量,数组元素变化标志位 pbus_ram_changed #bit ninth_bit = RS232_ERRORS.7

//将变量 ninth_bit 的地址定位在 RS232_ERRORS.7 的位上 //RS232_ERRORS 在#use rs232 定义; // RS232_ERRORS.7 对于 9 位数据模式说(get 和 put),是第 9 位;

#bit collision = RS232_ERRORS.6 //将变量 collision 的地址定位在 RS232_ERRORS.6 的位上 //在 float high 模式里,RS232_ERRORS.6 置 1 表示一个 put(输出)失败;

#bit intf = 11.1 //将变量 intf 的地址定位在 11.1 的位上,即地址 0x0b 的第 1 位; //对应外部中断 0 的中断标志位; //下面为模拟串口接收函数 #int_ext //指出下面的函数是外部中断 0 的中断服务函数; void pbus_isr() { BYTE data; //声明字节型暂态变量; if( kbhit( ) ) { //若 getc()读到数据,则 kbhit()返回 1,否则, kbhit()返回 0; data=getc(); //从模拟串口读到一个字符,存入 data 中;

if(ninth_bit) //若接收到的第 9 位为 1,表示接收到的是地址,则执行下面语句 {

if(data==0xf2) pbus_state=0; //若地址符合,则将 pbus_state 置 0; }

else

Page 156: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 156

if(pbus_state==PBUS_NEED_CS) { //若接收到的第 9 位为 0, 且 pbus_state 为 0x84,则执行下面语句 if(data==(pbus_next_loc^pbus_next_value)) { //若校验和正确,则执行下面语句 pbus_state=PBUS_IDLE; //将 0x80 送给 pbus_state;

pbus_ram_changed=true; //将数组元素变化标志位 pbus_ram_changed 置为 true;

pbus_ram[pbus_next_loc]=pbus_next_value; //将pbus_next_value存到数组pbus_ram[]中,为pbus_next_loc第个元素;

} } else if(pbus_state==0) { //若接收到的第 9 位为 0,且 pbus_state 为 0, 则执行下面 pbus_next_loc=data; //将 data 存到数组的元素位置号码 pbus_next_loc 里; pbus_state=1;

//数组元素的位置号码保存后,将 pbus_state置 1,为接收数组元素做准备; } else if(pbus_state==1) {//若接收到的第 9 位为 0,且 pbus_state 为 1, 则执行下面 pbus_next_value=data; //将 data 存到数组的元素 pbus_next_value 里; pbus_state=PBUS_NEED_CS; //数组的元素保存后,将 pbus_state 置为 0x84,为接收校验和做准备; } } } //下面为模拟串口发送函数 void pbus_write_ram(BYTE loc, BYTE value) { BYTE checksum, i; //声明字节型暂态变量 checksum, i; pbus_ram_changed=true; retry: checksum=loc^value; //将 loc 异或 value 后送给 checksum disable_interrupts(GLOBAL); //关闭总中断允许位 pbus_ram[loc]=value; //将 value 存到数组 pbus_ram[]中,为 loc 第个元素; collision=false; //将 putc( )的失败位置 0,为向模拟串口发送数据做准备; ninth_bit=1; //将第 9 位置 1,为发送地址做准备;

putc(0xf2); //从模拟串口输出 0xf2; if(collision) goto error; //若 putc( )失败,则跳到标号 error 处;

ninth_bit=0; //将第 9 位置 0,为发送数据做准备; putc(loc); //从模拟串口输出传递参数 loc 的值; if(collision) goto error; //若 putc( )失败,则跳到标号 error 处; putc(value); //从模拟串口输出传递参数 value 的值; if(collision) goto error; //若 putc( )失败,则跳到标号 error 处; putc(checksum); //从模拟串口输出暂态变量 checksum 的值,发送校验和; if(collision) goto error; //若 putc( )失败,则跳到标号 error 处;

intf=false; //将外部中断 0 的中断标志位清 0; enable_interrupts(GLOBAL); //开总中断允许位; return;

Page 157: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 157

error: delay_ms(16); //延时 16ms enable_interrupts(GLOBAL); //开总中断允许位; goto retry; //发送失败,重发一次; } #if defined( __PCB__) #use rs232(baud=9600, xmit=PIN_A3, rcv=PIN_A2) // Jumpers: 11 to 17, 12 to 18 #elif defined(__PCM__) #use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7) // Jumpers: 8 to 11, 7 to 12 #elif defined(__PCH__) #use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7) // Jumpers: 8 to 11, 7 to 12 #endif #include <input.c> //包含 input.c 头文件 void main() { BYTE to, i, value; //声明字节型变量 to, i, value; printf("\r\nPress S to send.\r\n"); ext_int_edge( h_to_l ); //设置外部中断 0 的边沿触发方式为下降沿触发 enable_interrupts(global); //开总中断允许位; enable_interrupts(int_ext); //使能外部中断 0; pbus_ram_changed=false; //将数组元素变化标志位置 0; do { if(pbus_ram_changed) { //若数组元素变化标志位 pbus_ram_changed 为 1,则执行下面 printf("\r\nRAM Changed:\r\n"); pbus_ram_changed=false; //将数组元素变化标志位置 0; for(i=0;i<PBUS_RAM_SIZE;++i) printf(" %2X",pbus_ram[i]); //通过 RS232 将数组 pbus_ram[]中的元素输出 } if( kbhit() ) //若 getc()读到数据,则 kbhit()返回 1,否则, kbhit()返回 0; if(toupper(getc())=='S') { printf("\r\nLocation: "); to=gethex(); //从 PC 机的 RS232 口读一字节存到 to 中; printf("\r\nValue: "); value=gethex(); //从 PC 机的 RS232 口读一字节存到 value 中; pbus_write_ram(to,value); //通过模拟串口发送出去 } } while (TRUE); }

Page 158: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 158

文件 EX_PBUSM.C 如下: #if defined(__PCB__) //若使用了 PCB 编译器,则 defined( __PCB__)返回值为 1 #include <16c56.h> //包含 16c56.h 头文件 #fuses HS,NOWDT,NOPROTECT //HS:高速晶振/谐振器, NOWDT:不使用 WDT // NOPROTECT:程序存储器代码不保护 #use delay(clock=20000000) //使能内置函数的功能:delay_ms()和 delay_us() //#USE DELAY()必须在#use rs232()使用之前出现. #elif defined(__PCM__) #include <16F877.h> #fuses HS,NOWDT,NOPROTECT,NOLVP #use delay(clock=20000000) #elif defined(__PCH__) #include <18F452.h> #fuses HS,NOWDT,NOPROTECT,NOLVP #use delay(clock=20000000) #endif #use rs232(baud=9600, float_high, bits=9, xmit=PIN_B0, rcv=PIN_B0)

// baud=9600,表示使用波特率为 9600, //FLOAT_HIGH, 表示用来开集电极输出 // bits=9, 表示发送/接收是 9 位数据格式 // xmit=PIN_B0,表示发送脚为 PIN_B0 // rcv=PIN_B0,表示接收脚为 PIN_B0 //使能内置函数:GETC,PUTC 和 PRINTF, kbhit();

#define OUR_ID 1 //用 OUR_ID 代替 0x01; #define MAX_MESSAGES 4 //用 MAX_MESSAGES 代替 0x04; #define MAX_LENGTH 7 //用 MAX_LENGTH 代替 0x07; byte pbus_buffer[MAX_MESSAGES][MAX_LENGTH+1]; //声明 2 维数组 pbus_buffer[4][8]; byte next_in=0; // byte next_out=0; // enum pbus_states {PBUS_IDLE=0x80,PBUS_NEED_LEN=0x81,PBUS_NEED_TO=0x82, PBUS_NEED_FROM=0x83,PBUS_NEED_CS=0x84};

//C 编译器将 PBUS_IDLE=0x80, PBUS_NEED_LEN=0x81,PBUS_NEED_TO=0x82, // PBUS_NEED_FROM=0x83,PBUS_NEED_CS=0x84;

byte pbus_state=PBUS_IDLE; //给字节型变量 pbus_state 赋值为 0x80; byte checksum; //声明字节型变量 checksum,用来存放校验和; byte last_byte; //声明字节型变量 last_byte;

Page 159: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 159

#bit ninth_bit = RS232_ERRORS.7 //将变量 ninth_bit 的地址定位在 RS232_ERRORS.7 的位上 //RS232_ERRORS 在#use rs232 定义; // RS232_ERRORS.7 对于 9 位数据模式说(get 和 put),是第 9 位;

#bit collision = RS232_ERRORS.6 //将变量 collision 的地址定位在 RS232_ERRORS.6 的位上 //在 float high 模式里,RS232_ERRORS.6 置 1 表示一个 put(输出)失败;

#bit intf = 11.1 //定义 intf 为外部中断标志位的地址 11.1; #int_ext //指定下面的函数是 int0 的外部中断服务函数; void pbus_isr()

{ byte data; //声明字节型暂态变量 data; if(kbhit()) //若有数据输入,则执行下面语句;

{ data=getc(); //读 int0 的 IO 口; if(ninth_bit) //若接收到的第 9 位为 1,则执行下面语句; { switch(pbus_state)

{ case PBUS_IDLE : if(data==0xf1) pbus_state=PBUS_NEED_TO; //若接收到的数据为 0xf1,则 pbus_state=0x82,

break; case PBUS_NEED_TO : if(data==OUR_ID) pbus_state=PBUS_NEED_FROM; //若接收到的地址为 0x01,则 pbus_state=0x83, else pbus_state=PBUS_IDLE; //若接收到的数据不是 0x01, 则 pbus_state=0x80, checksum=data; //接收校验和; break; case PBUS_NEED_FROM : pbus_buffer[next_in][0] = data;

pbus_state=PBUS_NEED_LEN; // PBUS_NEED_LEN=0x81;

checksum^=data; break; case PBUS_NEED_LEN : last_byte = data+1; pbus_buffer[next_in][1] = data; pbus_state=2; checksum^=data; //计算累加和; break; }

} else //若接收到的第 9 位为 0,则执行下面语句;

if(pbus_state==PBUS_NEED_CS) //PBUS_NEED_CS=0x84; { if(checksum==data) next_in = (next_in+1) % MAX_MESSAGES;

pbus_state=PBUS_IDLE; }

else if(pbus_state<0x80) { pbus_buffer[next_in][pbus_state] = data;

Page 160: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 160

checksum^=data; if(++pbus_state>last_byte) pbus_state=PBUS_NEED_CS; } } } //发送涵数: void pbus_send( byte * message, byte to, byte len) { byte checksum,i; retry: checksum=len^OUR_ID^to; disable_interrupts(GLOBAL); //关闭总中断允许位;

collision=false; //将变量 collision 的地址定位在 RS232_ERRORS.6 的位上 //在 float high 模式里,RS232_ERRORS.6 置 1 表示一个 put(输出)失败;

ninth_bit=1; //准备发送的第 9 位值; putc(0xf1); if(collision) goto error; putc(to); if(collision) goto error; putc(OUR_ID); if(collision) goto error; putc(len); if(collision) goto error; ninth_bit=0; //准备发送的第 9 位值为 0,表示下面开始发送数据; for(i=1;i<=len;++i) { checksum^=*message; putc(*(message++)); if(collision) goto error; } putc(checksum); if(collision) goto error; intf=false; enable_interrupts(GLOBAL); return; //退出涵数; error: delay_ms(16); enable_interrupts(GLOBAL); goto retry; } #if defined( __PCB__) #use rs232(baud=9600, xmit=PIN_A3, rcv=PIN_A2) // Jumpers: 11 to 17, 12 to 18 #elif defined(__PCM__) #use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7) // Jumpers: 8 to 11, 7 to 12

Page 161: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 161

#elif defined(__PCH__) #use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7) // Jumpers: 8 to 11, 7 to 12 #endif #include <input.c> void main() { byte to,len,i,msg[MAX_LENGTH]; printf("\r\nOur unit ID is %d\r\nPress S to send.\r\n",OUR_ID); ext_int_edge( h_to_l ); enable_interrupts(global); enable_interrupts(int_ext); do { if(next_in!=next_out) { printf("\r\nMessage from #%d: ",pbus_buffer[next_out][0]); for(i=2;i<=pbus_buffer[next_out][1]+1;++i) printf(" %2X",pbus_buffer[next_out][i]); next_out=(next_out+1) % MAX_MESSAGES; } if(kbhit()) if(toupper(getc())=='S') { printf("\r\nSend to: "); to=gethex(); printf("\r\nLength: "); len=gethex(); for(i=0;i<len;++i) { printf("\r\nByte %d: ",i+1); msg[i]=gethex(); } pbus_send(msg,to,len); printf("\r\nSent."); } } while (TRUE); } 文件 EX_ENCRY.C 如下: /////////////////////////////////////////////////////////////////////////

Page 162: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 162

//// EX_ENCRY.C //// //// //// //// This program shows how to implement two serial ports to //// //// transfer data between the ports and to encrypt/decrypt //// //// the data on one side for a secure communications link. //// //// //// //// +------+ +-----+ +-----+ +------+ //// //// | PC | | PIC | | PIC | | PC | //// //// | A |====| A |=============| B |====| B | //// //// +------+ +-----+ secure +-----+ +------+ //// //// wire //// //// //// //// Configure the CCS prototype card as described below. //// //// //// //// This example will work with the AFL. The //// //// following conditional compilation lines are used to include a //// //// valid device for each compiler. Change the device, clock and //// //// RS232 pins for your hardware if needed. //// ///////////////////////////////////////////////////////////////////////// //// (C) Copyright 1996,2003 Custom Computer Services //// //// This source code may only be used by licensed users of the CCS //// //// C compiler. This source code may only be distributed to other //// //// licensed users of the CCS C compiler. No other use, //// //// reproduction or distribution is permitted without written //// //// permission. Derivative programs created using this software //// //// in object code form are not restricted in any way. //// ///////////////////////////////////////////////////////////////////////// #if defined(__PCM__) #include <16F877.h> #fuses HS,NOWDT,NOPROTECT,NOLVP #use delay(clock=20000000) #elif defined(__PCH__) #include <18F452.h> #fuses HS,NOWDT,NOPROTECT,NOLVP #use delay(clock=20000000) #endif #define BUFFER_SIZE 32 ///////////////////////////////////////////////////////////////// PORT 1 #use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)

Page 163: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 163

byte buffer1[BUFFER_SIZE]; byte next_in1 = 0; byte next_out1 = 0; //指定下面的函熟是接收中断服务函数 #int_rda void serial_isr1() { int t; //声明暂态变量 t; buffer1[next_in1]=getc(); //从 RS232 口接收一个字节 t=next_in1; next_in1=(next_in1+1) % BUFFER_SIZE; //将接收缓冲区的计数器 next_in1 加 1 if(next_in1==next_out1) next_in1=t; // Buffer full !! } #define bkbhit1 (next_in1!=next_out1) //用 bkbhit1 代替表达式(next_in1!=next_out1)的值 byte bgetc1() { byte c; while(!bkbhit1) ; c=buffer1[next_out1]; next_out1=(next_out1+1) % BUFFER_SIZE; return(c); } void putc1(char c) { putc(c); } ///////////////////////////////////////////////////////////////// PORT 2 #use rs232(baud=9600, xmit=PIN_B1, rcv=PIN_B0) byte buffer2[BUFFER_SIZE]; byte next_in2 = 0; byte next_out2 = 0; #int_ext void serial_isr2() { int t; buffer2[next_in2]=getc();

Page 164: PIC 单片机 CCS 之C 语言 中文版权归芜湖联合大学 94 电气张功勤 …read.pudn.com/downloads515/ebook/2137329/PICC_mcu_CCS.pdf · pic 单片机ccs 之c 语言 中文版权归芜湖联合大学94

PIC 单片机 CCS 之 C 语言 中文版权归芜湖联合大学 94 电气张功勤个人所有,任何转载,摘抄必须经本人同意,否则,必究其法律责任

联系电话:13662655920 164

t=next_in2; next_in2=(next_in2+1) % BUFFER_SIZE; if(next_in2==next_out2) next_in2=t; // Buffer full !! } #define bkbhit2 (next_in2!=next_out2) byte bgetc2() { byte c; while(!bkbhit2) ; c=buffer2[next_out2]; next_out2=(next_out2+1) % BUFFER_SIZE; return(c); } void putc2(char c) { putc(c); } /////////////////////////////////////////////////////////////////////////////////////// void main() { char c; enable_interrupts(global); enable_interrupts(int_rda); enable_interrupts(int_ext); printf(putc2,"\r\n\Running...\r\n"); do { if(bkbhit1) { c = bgetc1(); putc2(c); } if(bkbhit2) { c = bgetc2(); putc1(c); } } while (TRUE); }