c语言单片机编程之头文件编写
- 格式:docx
- 大小:21.63 KB
- 文档页数:20
C语言的头文件常用于声明函数、变量、宏和结构体等的定义,以便在多个源文件中共享和重用这些声明。
以下是C语言头文件的一般写法:
c
#ifndef HEADER_NAME_H
#define HEADER_NAME_H
// 在这里写下头文件的内容
#endif /* HEADER_NAME_H */
头文件的命名通常使用全大写字母,可以根据需要选择有意义的名称。
头文件中应该包含以下内容:
防止多重包含:使用条件编译指令#ifndef、#define 和#endif,以避免头文件被重复包含。
函数声明:声明函数的原型,例如int add(int a, int b);。
变量声明:声明变量的外部链接性,例如extern int globalVariable;。
宏定义:定义常量、宏函数和条件编译宏等,例如#define PI 3.14159。
结构体定义:定义结构体类型,例如struct Person { char name[20]; int age; };。
请注意以下几点:
头文件中通常只包含声明,而不包含具体的实现代码。
实现代码应该在对应的源文件中编写。
头文件应该包含所需的其他头文件,以确保所有依赖关系得到满足。
在编写头文件时,应使用预处理指令#ifdef 和#ifndef 来避免重复定义和冲突。
头文件应该尽量精简和模块化,只包含与该头文件相关的声明。
在头文件中避免定义全局变量,因为头文件可能会被多个源文件包含,这样会导致变量的重复定义。
正确编写和组织头文件可以提高代码的可读性、可维护性和重用性,推荐遵循良好的编码规范和项目约定。
51单片机C语言头文件及其使用2007-05-29 16:33很多初学单片机者往往对C51的头文件感到很神秘,而为什么要那样写,甚至有的初学者喜欢问,P1口的P为什么要大写,不大写行不行呢?其实这样的问题,看过本文后,就会明白。
其实这个是在头文件中用sfr定义的,现在定义好了的是这样的sfr P1 = 0x90;,也就是说,到底大写,还是小写,就是在这里面决定的。
这就说明,如果你要用小写,就得在头文件中改为小写。
其实它都是为了编程序方便才这样写的,在程序编译时,就会变成相应的地址(如P1就变成了0x90)。
还有一点就是,现在有很多改进型的单片机,它们有很多新增的特殊功能寄存器在标准的reg51.h或reg52.h中没有定义,这就需要自己加进头文件(相关厂家已经把它们定义好了),当然也可以直接在程序中定义。
下面是一个标准的C51头文件:(此文件一般在C:\KEIL\C51\INC下,INC文件夹根目录里有不少头文件,并且里面还有很多以公司分类的文件夹,里面也都是相关产品的头文件。
如果我们要使用自己写的头文件,使用的时候只需把对应头文件拷贝到INC文件夹里就可以了。
)/* BYTE Registers */sfr P0 = 0x80;sfr P1 = 0x90;sfr P2 = 0xA0;sfr P3 = 0xB0;sfr PSW = 0xD0;sfr ACC = 0xE0;sfr B = 0xF0;sfr SP = 0x81;sfr DPL = 0x82;sfr DPH = 0x83;sfr PCON = 0x87;sfr TCON = 0x88;sfr TMOD = 0x89;sfr TL0 = 0x8A;sfr TL1 = 0x8B;sfr TH0 = 0x8C;sfr TH1 = 0x8D;sfr IE = 0xA8;sfr IP = 0xB8;sfr SCON = 0x98;sfr SBUF = 0x99;/* 8052 Extensions */sfr T2CON = 0xC8;sfr RCAP2L = 0xCA;sfr RCAP2H = 0xCB;sfr TL2 = 0xCC;/* BIT Registers */ /* PSW */sbit CY = PSW^7;sbit AC = PSW^6;sbit F0 = PSW^5;sbit RS1 = PSW^4;sbit RS0 = PSW^3;sbit OV = PSW^2;sbit P = PSW^0; //8052 only/* TCON */sbit TF1 = TCON^7;sbit TR1 = TCON^6;sbit TF0 = TCON^5;sbit TR0 = TCON^4;sbit IE1 = TCON^3;sbit IT1 = TCON^2;sbit IE0 = TCON^1;sbit IT0 = TCON^0;/* IE */sbit EA = IE^7;sbit ET2 = IE^5; //8052 onlysbit ES = IE^4;sbit ET1 = IE^3;sbit EX1 = IE^2;sbit ET0 = IE^1;sbit EX0 = IE^0;/* IP */sbit PT2 = IP^5;sbit PS = IP^4;sbit PT1 = IP^3;sbit PX1 = IP^2;sbit PT0 = IP^1;sbit PX0 = IP^0;/* P3 */sbit RD = P3^7;sbit WR = P3^6;sbit T1 = P3^5;sbit INT1 = P3^3;sbit INT0 = P3^2;sbit TXD = P3^1;sbit RXD = P3^0;/* SCON */sbit SM0 = SCON^7;sbit SM1 = SCON^6;sbit SM2 = SCON^5;sbit REN = SCON^4;sbit TB8 = SCON^3;sbit RB8 = SCON^2;sbit TI = SCON^1;sbit RI = SCON^0;/* P1 */sbit T2EX = P1^1; // 8052 onlysbit T2 = P1^0; // 8052 only/* T2CON */sbit TF2 = T2CON^7;sbit EXF2 = T2CON^6;sbit RCLK = T2CON^5;sbit TCLK = T2CON^4;sbit EXEN2 = T2CON^3;sbit TR2 = T2CON^2;sbit C_T2 = T2CON^1;sbit CP_RL2 = T2CON^0;还有一点就是,现在有很多改进型的单片机,它们有很多新增的特殊功能寄存器在标准的reg51.h或reg52.h中没有定义,这就需要自己加进头文件(相关厂家已经把它们定义好了),当然也可以直接在程序中定义。
函数原形的头文件读者可参考返回非整型值的函数assert.h - assert(), 声明宏ctype.h –字符类型函数float.h –浮点数原形limits.h –数据类型的大小和范围math.h –浮点运算函数stdarg.h –变量参数表.stddef.h –标准定义stdio.h –标准输入输出IO 函数stdlib.h –包含内存分配函数的标准库string.h –字符串处理函数3 字符类型库下列函数按照输入的ACS II 字符集字符分类使用这些函数之前应当用"#include <ctype.h>" 包含int isalnum(int c)如果c 是数字或字母返回非零数值否则返回零int isalpha(int c)如果c 是字母返回非零数值否则返回零int iscntrl(int c)如果c 是控制字符如FF, BELL, LF ..等返回非零数值否则返回零int isdigit(int c)如果c 是数字返回非零数值否则返回零int isgraph(int c)如果c 是一个可打印字符而非空格返回非零数值否则返回零int islower(int c)如果c 是小写字母返回非零数值否则返回零int isprint(int c)如果c 是一个可打印字符返回非零数值否则返回零int ispunct(int c)如果c 是一个可打印字符而不是空格数字或字母返回非零数值否则返回零int isspace(int c)如果c 是一个空格字符返回非零数值包括空格CR, FF, HT, NL, 和VT 否则返回零int isupper(int c)如果c 是大写字母返回非零数值否则返回零int isxdigit(int c)如果c 是十六进制数字返回非零数值否则返回零int tolower(int c)如果c 是大写字母则返回c 对应的小写字母其它类型仍然返回cint toupper(int c)如果c 是小写字母则返回c 对应的大写字母其它类型仍然返回c4 浮点运算库下列函数支持浮点数运算使用这些函数之前必须用#include <math.h> 包含float asin(float x)以弧度形式返回x 的反正弦值float acos(float x)以弧度形式返回x 的反余弦值float atan(float x)以弧度形式返回x 的反正切值float atan2(float x, float y)返回y/x 的反正切其范围在- ~+ 之间float ceil(float x)返回对应x 的一个整型数小数部分四舍五入float cos(float x)返回以弧度形式表示的x 的余弦值float cosh(float x)返回x 的双曲余弦函数值float exp(float x)返回以e 为底的x 的幂即e xfloat exp10(float x)返回以10 为底的幂即10xfloat fabs(float x)返回x 的绝对值float floor(float x)返回不大于x 的最大整数float fmod(float x, float y)返回x/y 的余数float frexp(float x, int *pexp)把浮点数x 分解成数字部分y 尾数和以2 为底的指数n 两个部分即x=y 2 n y 的范围为0.5 y 1 y 值被函数返回而n 值存放到pexp 指向的变量中float fround(float x)返回最接近x 的整型数float ldexp(float x, int exp)返回x 2 e x pfloat log(float x)返回x 的自然对数float log10(float x)返回以10 为底的x 的对数float modf(float x, float *pint)把浮点数分解成整数部分和小数部分整数部分存放到pint 指向的变量小数部分应当大于或等于0 而小于1 并且作为函数返回值返回float pow(float x, float y)返回x y 值float sqrt(float x)返回x 的平方根float sin(float x)返回以弧度形式表示的x 的正弦值float sinh(float x)返回x 的双曲正弦函数值float tan(float x)返回以弧度形式表示的x 的正切值float tanh(float x)返回x 的双曲正切函数值5 标准输入输出库标准的文件输入输出是不能真正植入微控制器MCU 的标准stdio.h 的许多内容不可以使用不过有一些IO 函数是被支持的同样使用之前应用"#include <stdio.h>"预处理并且需要初始化输出端口最低层的IO 程序是单字符的输入(getchar)和输出(putchar)程序如果你针对不同的装置使用高层的IO 函数例如用printf 输出LCD 你需要全部重新定义最底层的函数为在ATMEL 的AVR Studio 模拟器终端IO 窗口使用标准IO 函数应当在编译选项中选中相应的单选钮注意作为缺省单字符输出函数putchar 是输出到UART 装置没有修改无论如何为使输出能如期望的那样出现在程序终端窗口中'\n' 字符必须被映射为成对的回车和换行CR/LFint getchar()使用查寻方式从UART 返回一个字符int printf(char *fmt, ..)按照格式说明符输出格式化文本frm 字符串格式说明符是标准格式的一个子集%d--输出有符号十进制整数%o --输出无符号八进制整数%x - 输出无符号十六进制整数%X –除了大写字母使用'A'-'F'外同%x%u - 输出无符号十进制整数%s –输出一个以C 中空字符NULL 结束的字符串%c –以ASCII 字符形式输出只输出一个字符%f –以小数形式输出浮点数%S –输出在FLASH 存贮器中的字符串常量printf 支持三个版本取决于你的特别需要和代码的大小越高的要求代码越大基本形: 只有%c, %d, %x, %u, 和%s 格式说明符是承认的长整形: 针对长整形数的修改%ld, %lu, %lx 被支持, 以适用于精度要求较高的领域浮点形: 全部格式包括%f 被支持你使用编译选项对话框来选择版本代码大小的增加是值得关注的int putchar(int c)输出单个字符这个库程序使用了UART 以查寻方式输出单个字符注意输出’\n’字符至程序终端窗口int puts(char *s)输出以NL 结尾的字符串int sprintf(char *buf, char *fmt)按照格式说明符输出格式化文本frm 字符串到一个缓冲区格式说明符同printf( )"const char *" 支持功能cprintf 和csprintf 是将FLASH 中的格式字符串分别以prinf 和sprinf 形式输出6 标准库和内存分配函数标准库头文件<stdlib.h>定义了宏NULL 和RAND_MAX 和新定义的类型size_t 并且描述了下列函数注意在你调用任意内存分配程序比如.. calloc malloc 和realloc)之前必须调用_NewHeap 来初始化堆heapint abs(int i)返回i 的绝对值int atoi(char *s)转换字符串s 为整型数并返回它字符串s 起始必须是整型数形式字符否则返回0double atof(const char *s)转换转换字符串s 为双精度浮点数并返回它字符串s 起始必须是浮点数形式字符串long atol(char *s)转换字符串s 为长整型数并返回它字符串s 起始必须是长整型数形式字符否则返回0void *calloc(size_t nelem, size_t size)分配"nelem"个数据项的内存连续空间每个数据项的大小为size 字节并且初始化为0 如果分配成功返回分配内存单元的首地址否则返回0void exit(status)终止程序运行典型的是无限循环它是担任用户main 函数的返回点void free(void *ptr)释放ptr 所指向的内存区void *malloc(size_t size)分配size 字节的存贮区如果分配成功则返回内存区地址如内存不够分配则返回0void _NewHeap(void *start, void *end)初始化内存分配程序的堆一个典型的调用是将符号_bss_end+1 的地址用作"start"值符号_bss_end 定义为编译器用来存放全局变量和字符串的数据内存的结束加1 的目的是堆栈检查函数使用_bss_end 字节存贮为标志字节这个结束值不能被放入堆栈中extern char _bss_end;_NewHeap(&_bss_end+1, &_bss_end + 201); // 初始化200 字节大小的堆int rand(void)返回一个在0 和RAND_MAX 之间的随机数void *realloc(void *ptr, size_t size)重新分配ptr 所指向内存区的大小为size 字节size 可比原来大或小返回指向该内存区的地址指针void srand(unsigned seed)初始化随后调用的随机数发生器的种子数long strtol(char *s, char **endptr, int base)按照"base."的格式转换"s"中起始字符为长整型数如果"endptr"不为空* endptr 将设定"s"中转换结束的位置unsigned long strtoul(char *s, char **endptr, int base)除了返回类型为无符号长整型数外其余同"strtol"7 字符串函数用"#include <string.h>"预处理后编译器支持下列函数<string.h>定义了NULL 类型size_t和下列字符串及字符阵列函数void *memchr(void *s, int c, size_t n)在字符串s 中搜索n 个字节长度寻找与c 相同的字符如果成功返回匹配字符的地址指针否则返回NULLint memcmp(void *s1, void *s2, size_t n)对字符串s1 和s2 的前n 个字符进行比较如果相同则返回0 如果s1 中字符大于s2 中字符则返回1 如果s1 中字符小于s2 中字符则返回-1void *memcpy(void *s1, void *s2, size_t n)拷贝s2 中n 个字符至s1 但拷贝区不可以重迭void *memmove(void *s1, void *s2, size_t n)拷贝s2 中n 个字符至s1 返回s1 其与memcpy 基本相同但拷贝区可以重迭void *memset(void *s, int c, size_t n)在s 中填充n 个字节的c 它返回schar *strcat(char *s1, char *s2)拷贝s2 到s1 的结尾返回s1char *strchr(char *s, int c)在s1 中搜索第一个出现的c 包括结束NULL 字符如果成功返回指向匹配字符的指针如果没有匹配字符找到返回空指针int strcmp(char *s1, char *s2)比较两个字符串如果相同返回0 如果s1>s2 则返回1 如果s1<s2 则返回-1char *strcpy(char *s1, char *s2)拷贝字符串s2 至字符串s1 返回s1size_t strcspn(char *s1, char *s2)在字符串s1 搜索与字符串s2 匹配的第一个字符包括结束NULL 字符其返回s1 中找到的匹配字符的索引size_t strlen(char *s)返回字符串s 的长度不包括结束NULL 字符char *strncat(char *s1, char *s2, size_t n)拷贝字符串s2 不含结束NULL 字符中n 个字符到s1 如果s2 长度比n 小则只拷贝s2返回s1int strncmp(char *s1, char *s2, size_t n)基本和strcmp 函数相同但其只比较前n 个字符char *strncpy(char *s1, char *s2, size_t n)基本和strcpy 函数相同但其只拷贝前n 个字符char *strpbrk(char *s1, char *s2)基本和strcspn 函数相同但它返回的是在s1 匹配字符的地址指针否则返回NULL 指针char *strrchr(char *s, int c)在字符串s 中搜索最后出现的c 并返回它的指针否则返回NULL .size_t strspn(char *s1, char *s2)在字符串s1 搜索与字符串s2 不匹配的第一个字符包括结束NULL 字符其返回s1 中找到的第一个不匹配字符的索引char *strstr(char *s1, char *s2)在字符串s1 中找到与s2 匹配的子字符串如果成功它返回s1 中匹配子字符串的地址指针否则返回NULL"const char *" 支持函数这些函数除了它的操作对象是在FLASH 中常数字符串外其余同c 中的函数size_t cstrlen(const char *s)char *cstrcpy(char *dst, const char *src);int cstrcmp(const char *s1, char *s2);8 变量参数函数<stdarg.h>提供再入式函数的变量参数处理它定义了不确定的类型va_list 和三个宏va_start(va_list foo, <last-arg>)初始化变量foova_arg(va_list foo, <promoted type>)访问下一个参数分派指定的类型注意那个类型必须是高级类型如int long 或double小的整型类型如"char"不能被支持va_end(va_list foo)结束变量参数处理例如printf()可以使用vfprintf()来实现#include <stdarg.h>int printf(char *fmt, ...){va_list ap;va_start(ap, fmt);vfprintf(fmt, ap);va_end(ap);}9 堆栈检查函数有几个库函数是用于检查堆栈是否溢出内存图如下如果硬件堆栈增长到软件堆栈中那么软件堆栈的内容将会被改变也就是说局部变量和别的堆栈项目被改变硬件堆栈是用作函数的返回地址如果你的函数调用层次太深偶然会发生这种情况同样地软件堆栈溢出进数据区域将会改变全局变量或其它静态分配的项目如果你使用动态分配内存还会改变堆项目这种情况在你定义了太多的局部变量或一个局部集合变量太大也会偶然发生高端地址硬件堆栈区警戒线软件堆栈区警戒线数据区低端地址警戒线启动代码写了一个正确的关于数据区的地址字节和一个类似的正确的关于软件堆栈的地址字节作为警戒线[注意如果你使用了你自己的启动文件而其又是以6.20 版本之前的启动文件为基础的你将需要额外改造为新的启动文件]注意如果你使用动态分配内存你必须跳过警戒线字节_bss_end 来分配你的堆参考内存分配函数堆栈检查你调用_StackCheck(void)函数来检查堆栈溢出如果警戒线字节仍然保持正确的值那么函数检查通过如果堆栈溢出那么警戒线字节将可能被破坏注意当你的程序堆栈溢出的时候你的程序将可能运行不正常或偶然崩溃当_StackCheck 检查错误条件时它调用了带一个参数的函数_StackOverflowed(char c) 如果参数是1 那么硬件堆栈有过溢出如果参数是0 那么软件堆栈曾经溢出在那个例子中制造了两个功能调用它是两个堆栈都可能溢出的无论如何在_StackOverflowed 执行起作用时第二个调用不可以出现作为例子如果函数复位了CPU 那么将不能返回_StackCheck 函数缺省的_StackOverflowed 函数当它被调用时库会用一个缺省的_StackOverflowed 函数来跳转到0 的位置因此复位CPU 和程序你可能希望用一个函数来代替它以指示更多的错__。
如何编写自己的C语言头文件编写自己的C语言头文件是一种优雅和灵活的编程技巧,它可使您的代码更加模块化和可重用。
在本文中,我将指导您如何编写自己的C语言头文件,并提供一些有用的建议和示例代码。
首先,让我们澄清一下什么是C语言头文件。
C语言头文件包含了函数、变量和类型的声明,供其他源代码文件使用。
头文件的扩展名通常是.h,如"header.h"。
当您需要在多个源代码文件中共享函数和变量时,头文件很有用。
以下是编写自己的C语言头文件的一般步骤:1.开始编写头文件前,请先明确需要共享哪些函数、变量和类型。
将它们分组并组织成逻辑上相关的部分。
2.在头文件的开头使用宏保护,以防止重复包含。
例如,使用以下格式:```c#ifndef HEADER_H#define HEADER_H/*内容*/#endif```这样,当多个源代码文件都包含了同一个头文件时,预处理器会确保只包含一次。
3. 添加所需的包含(include)指令,以便在头文件中使用其他的标准库函数和类型。
例如,您可以添加如下指令:```c#include <stdio.h>#include <string.h>```4.开始声明函数、变量和类型。
对于函数,只需声明函数的原型,不需要具体的实现。
例如:```cint add(int a, int b);void print_hello(;```对于变量和类型,您可以在头文件中声明它们的类型和名称,但最好将其定义留在源代码文件中。
5.如果有需要,添加注释,用于说明头文件的用途、函数/变量的功能和使用方法。
良好的注释可以提高代码的可读性和可维护性。
在编写自己的C语言头文件时,还有一些编码规范和最佳实践值得遵循:1. 避免在头文件中定义全局变量。
全局变量应该尽量避免使用,因为它们可能引起命名冲突和其他不可预测的问题。
如果需要共享变量,请在头文件中声明其外部链接(`extern`)并在源代码文件中定义它。
如何高效编程之头文件在网上查了很长时间关于头文件的资料,但是发现很难找到适合我的。
学单片机的朋友知道,很多程序经常要调用相同的函数,如果每写一个程序都把这些函数重新写一遍或者复制过来,那是很浪费时间的,现在我通过学习总结以及别人的经验,跟大家分享,欢迎大家转载学习。
写程序最好是结构化编程,因为这样的程序看起来就不那么长了,一目了然,可以很快就知道这个程序实现什么功能,而且排错也非常简单。
把常用的函数声明、自定义类型、外部变量的声明等写进头文件,与之配对的扩展名为.c的文件就写常用的函数,main.c最好就写一个主函数。
之前学的51单片机,现在玩430单片机,就以430单片机为例,其他编程软件道理与这个相同。
在IAR下新建工程,包含了main.c、mydefine.c和mydefine.h(mydefine.c 和mydefine.h是一对)三个文件(注:可包含多个配对的头文件和C文件)。
先把程序贴出来,再详解其中缘由。
main.c内容:#include "mydefine.h"void main( void ){// Stop watchdog timer to prevent time out resetWDTCTL = WDTPW + WDTHOLD;SegInitial(); //数码管控制引脚初始化long m = 0;while(1){disp(m); //显示m的值delay(10);m++;if(m == 1000000)m = 0;}}mydefine.h的内容#ifndef _MYDEFINE_H#define _MYDEFINE_H#include "msp430x14x.h"typedef unsigned int uint; typedef unsigned char uchar;void write_595(uchar dat);void SegInitial(void);void disp(long num);void delays(uint x);void delay(uint x);#endifmydefine.c的内容#include "mydefine.h"#include "msp430x14x.h"/*********************************流水灯74hc595各引脚定义*********************************/ #define CLK0 P2OUT &= ~BIT4#define CLK1 P2OUT |= BIT4#define STB0 P2OUT &= ~BIT2#define STB1 P2OUT |= BIT2#define DS0 P2OUT &= ~BIT5#define DS1 P2OUT |= BIT5#define LEDOFF P5OUT = 0x00uchar dis_num[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8 e}; //数码管0~F共阳编码ucharbitnum[]={0x01,0x02,0x04,0x08,0x10,0x20}; //数码管位选uchardispbuf[6];//数码管显示缓冲区//以下是延时函数void delay(uint x){uint a,b;for(a=x;a>0;a--)for(b=10000;b>0;b--);}//控制流水灯,使用P2.2(STB),P2.4(CLK),P2.5(DS) void write_595(uchar dat){uint n;for(n = 0;n<8;n++){if((dat&0x80) == 0x80)DS1;elseDS0;dat <<= 1;CLK0;CLK1;}STB1;STB0;}/*****************************************数码管显示初始化函数*****************************************/ void SegInitial(void){P5DIR = 0XFF;P4DIR = 0XFF;P5OUT = 0X00;P4OUT = 0X00;}/****************************************数码管防重影延时函数*****************************************/ void delays(uint x){for(;x>0;x--);}/*****************************************数码管显示函数位选 P5.0~P5.5段选 P4*****************************************/ void disp(long num){uint i;dispbuf[0] = num%10;dispbuf[1] = num/10%10;dispbuf[2] = num/100%10;dispbuf[3] = num/1000%10;dispbuf[4] = num/10000%10;dispbuf[5] = num/100000%10;for(i=0;i<6;i++){P4OUT = dis_num[dispbuf[i]];P5OUT = bitnum[i];delays(400);P5OUT=0X00;}}首先看main.c里面就写了一个主函数,它告诉读者该程序的主要功能。
PIC单片机的C语言编程简介PIC(Peripheral Interface Controller)是一种广泛使用的单片机系列,由美国微芯科技公司(Microchip Technology Inc.)开发和生产。
其特点是体积小、功耗低、功能强大,并且具有高性价比,因此在嵌入式系统领域得到了广泛的应用。
在PIC单片机的编程中,C语言是最常用的编程语言之一。
本文将介绍如何在PIC单片机上使用C语言进行编程。
准备工作在开始C语言编程之前,我们需要准备以下工具和设备:1.PIC单片机开发板:选择一款适合你的需求的PIC单片机开发板,例如PIC16F877A。
2.编程软件:Microchip公司的MPLAB IDE是最常用的PIC单片机编程软件之一,可以在官方网站上免费下载安装。
3.编程语言:C语言是PIC单片机常用的编程语言,具有丰富的库函数和易于学习的语法。
第一个C程序编写第一个C程序是入门PIC单片机编程的第一步。
以下是一个简单的LED闪烁程序示例:#include <xc.h>// 包含使用于PIC单片机的头文件#define _XTAL_FREQ 4000000 // 定义晶振频率为4MHz// 主函数void main(void){TRISB = 0b00000000; // 将PORTB所有引脚设为输出PORTB = 0b00000001; // 将RB0引脚输出高电平while(1){PORTBbits.RB0 = 1; // RB0引脚输出高电平__delay_ms(1000); // 延时1秒PORTBbits.RB0 = 0; // RB0引脚输出低电平__delay_ms(1000); // 延时1秒}}在这个程序中,我们使用了xc.h头文件来包含适用于PIC单片机的库函数和宏定义。
使用#define指令定义了晶振频率为4MHz,可以根据自己的实际情况进行修改。
在main函数中,通过TRISB寄存器将PORTB所有引脚设置为输出模式,并使用PORTB寄存器将RB0引脚输出高电平。
目录实例3:用单片机控制第一个灯亮 (3)实例4:用单片机控制一个灯闪烁:认识单片机的工作频率 (3)实例5:将 P1口状态分别送入P0、P2、P3口:认识I/O口的引脚功能 (4)实例6:使用P3口流水点亮8位LED (4)实例7:通过对P3口地址的操作流水点亮8位LED (5)实例8:用不同数据类型控制灯闪烁时间 (7)实例9:用P0口、P1 口分别显示加法和减法运算结果 (8)实例10:用P0、P1口显示乘法运算结果 (8)实例11:用P1、P0口显示除法运算结果 (9)实例12:用自增运算控制P0口8位LED流水花样 (9)实例13:用P0口显示逻辑”与”运算结果 (10)实例14:用P0口显示条件运算结果 (10)实例15:用P0口显示按位"异或"运算结果 (11)实例16:用P0显示左移运算结果 (11)实例17:"万能逻辑电路”实验 (11)实例18:用右移运算流水点亮P1口8位LED (11)实例19:用if语句控制P0口8位LED的流水方向 (12)实例20:用swtich语句的控制P0口8位LED的点亮状态 (13)实例21:用for语句控制蜂鸣器鸣笛次数 (14)实例22:用while语句控制LED (15)实例23:用do—while语句控制P0口8位LED流水点亮 (16)实例24:用字符型数组控制P0口8位LED流水点亮 (17)实例25:用P0口显示字符串常量 (18)实例26:用P0 口显示指针运算结果 (19)实例27:用指针数组控制P0口8位LED流水点亮 (19)实例28:用数组的指针控制P0 口8 位LED流水点亮 (20)实例29:用P0 、P1口显示整型函数返回值 (21)实例30:用有参函数控制P0口8位LED流水速度 (22)实例31:用数组作函数参数控制流水花样 (23)实例32:用指针作函数参数控制P0口8位LED流水点亮 (24)实例33:用函数型指针控制P1口灯花样 (25)实例34:用指针数组作为函数的参数显示多个字符串 (26)实例35:字符函数ctype。
如何高效编程之头文件在网上查了很长时间关于头文件的资料,但是发现很难找到适合我的。
学单片机的朋友知道,很多程序经常要调用相同的函数,如果每写一个程序都把这些函数重新写一遍或者复制过来,那是很浪费时间的,现在我通过学习总结以及别人的经验,跟大家分享,欢迎大家转载学习。
写程序最好是结构化编程,因为这样的程序看起来就不那么长了,一目了然,可以很快就知道这个程序实现什么功能,而且排错也非常简单。
把常用的函数声明、自定义类型、外部变量的声明等写进头文件,与之配对的扩展名为.c的文件就写常用的函数,main.c 最好就写一个主函数。
之前学的51单片机,现在玩430单片机,就以430单片机为例,其他编程软件道理与这个相同。
在IAR下新建工程,包含了main.c、mydefine.c和mydefine.h(mydefine.c和mydefine.h是一对)三个文件(注:可包含多个配对的头文件和C 文件)。
先把程序贴出来,再详解其中缘由。
main.c内容:#include "mydefine.h"void main( void ){// Stop watchdog timer to prevent time out resetWDTCTL = WDTPW + WDTHOLD;SegInitial(); //数码管控制引脚初始化long m = 0;while(1){disp(m); //显示m的值delay(10);m++;if(m == 1000000)m = 0;}}mydefine.h的内容#ifndef _MYDEFINE_H#define _MYDEFINE_H#include "msp430x14x.h"typedef unsigned int uint; typedef unsigned char uchar;void write_595(uchar dat);void SegInitial(void);void disp(long num);void delays(uint x);void delay(uint x);#endifmydefine.c的内容#include "mydefine.h"#include "msp430x14x.h"/*********************************流水灯74hc595各引脚定义*********************************/ #define CLK0 P2OUT &= ~BIT4#define CLK1 P2OUT |= BIT4#define STB0 P2OUT &= ~BIT2#define STB1 P2OUT |= BIT2#define DS0 P2OUT &= ~BIT5#define DS1 P2OUT |= BIT5#define LEDOFF P5OUT = 0x00uchar dis_num[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8, 0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e}; //数码管0~F共阳编码uchar bitnum[]={0x01,0x02,0x04,0x08,0x10,0x20}; //数码管位选uchardispbuf[6]; //数码管显示缓冲区//以下是延时函数void delay(uint x){uint a,b;for(a=x;a>0;a--)for(b=10000;b>0;b--);//控制流水灯,使用P2.2(STB),P2.4(CLK),P2.5(DS) void write_595(uchar dat){uint n;for(n = 0;n<8;n++){if((dat&0x80) == 0x80)DS1;elseDS0;dat <<= 1;CLK0;CLK1;}STB1;STB0;}/*****************************************数码管显示初始化函数*****************************************/ void SegInitial(void){P5DIR = 0XFF;P4DIR = 0XFF;P5OUT = 0X00;P4OUT = 0X00;}/****************************************数码管防重影延时函数*****************************************/ void delays(uint x){for(;x>0;x--);}/*****************************************数码管显示函数位选 P5.0~P5.5段选 P4*****************************************/ void disp(long num){uint i;dispbuf[0] = num%10;dispbuf[1] = num/10%10;dispbuf[2] = num/100%10;dispbuf[3] = num/1000%10;dispbuf[4] = num/10000%10;dispbuf[5] = num/100000%10;for(i=0;i<6;i++){P4OUT = dis_num[dispbuf[i]];P5OUT = bitnum[i];delays(400);P5OUT=0X00;}}首先看main.c里面就写了一个主函数,它告诉读者该程序的主要功能。
mydefine.h里面包含了一些函数的声明,如果使用到外部变量(或函数),则需要在该变量(或函数)前写extern加以说明其为外部变量(或函数)。
写头文件一定要注意:#ifndef XXXX#define XXXX......#endif其中XXXX习惯大写,名称不要与关键字相同,习惯写法请参照上面的程序,#ifndef XXXX #define XXXX ..... #endif的作用是有些头文件已经在其他文件里包含过了,但是你在这个文件也包含了,如果没有上面那一句,则编译器会报错:重复定义!mydefine.c 中用到了mydefine.h中的定义,则需要把mydefine包含进来,包含mydefine.h的意思是mydefine.h替换为mydefine.h的内容,即mydefine.c的完整内容为:#include "msp430x14x.h"typedef unsigned int uint;typedef unsigned char uchar;void write_595(uchar dat);void SegInitial(void);void disp(long num);void delays(uint x);void delay(uint x);/*********************************流水灯74hc595各引脚定义*********************************/#define CLK0 P2OUT &= ~BIT4#define CLK1 P2OUT |= BIT4#define STB0 P2OUT &= ~BIT2#define STB1 P2OUT |= BIT2#define DS0 P2OUT &= ~BIT5#define DS1 P2OUT |= BIT5/*********************************流水灯74hc595各引脚定义*********************************/#define LEDOFF P5OUT = 0x00uchar dis_num[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8, 0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e}; uchar bitnum[]={0x01,0x02,0x04,0x08,0x10,0x20};uchar dispbuf[6];//以下是延时函数void delay(uint x){uint a,b;for(a=x;a>0;a--)for(b=10000;b>0;b--);}//控制流水灯,使用P2.2(STB),P2.4(CLK),P2.5(DS) void write_595(uchar dat){uint n;for(n = 0;n<8;n++){if((dat&0x80) == 0x80)DS1;elseDS0;dat <<= 1;CLK0;CLK1;}STB1;STB0;}/*****************************************数码管显示初始化函数*****************************************/void SegInitial(void){P5DIR = 0XFF;P4DIR = 0XFF;P5OUT = 0X00;P4OUT = 0X00;}/****************************************数码管延时函数*****************************************/ void delays(uint x){for(;x>0;x--);}/*****************************************数码管显示函数位选 P5.0~P5.5段选 P4*****************************************/ void disp(long num){uint i;dispbuf[0] = num%10;dispbuf[1] = num/10%10;dispbuf[2] = num/100%10;dispbuf[3] = num/1000%10;dispbuf[4] = num/10000%10;dispbuf[5] = num/100000%10;for(i=0;i<6;i++){P4OUT = dis_num[dispbuf[i]];P5OUT = bitnum[i];delays(400);P5OUT=0X00;}}下面讲一下mydefine.c的功能,一些常用函数都写在里面,一般情况下我们写好头文件后不必对函数的原型进行深究,只需知道函数的功能即可,即头文件里的函数声明,多个C文件编译链接的时候,相当于主函数放在前面,其他函数放在后面,调用函数的时候就必须先对这些函数进行声明,否则编译器不知道你的函数原型是什么,而这些头文件就起到了函数声明的作用,所谓头文件就可以理解为在main函数前面事先要处理的程序(即声明和定义)。