单片机c语言知识点
- 格式:doc
- 大小:72.50 KB
- 文档页数:13
中国科学技术大学业余无线电协会编目 录§1 前言 (1)§2 单片机简介 (2)2.1 数字电路简介 (2)2.2 MCS-51单片机简介 (2)2.3 Easy 51 Kit Pro简介 (5)2.4 Easy 51 Kit Pro电路功能分析 (5)§3 MCS-51单片机的C语言编程 (8)3.1 汇编语言 (8)3.2 建立你的第一个C项目 (8)3.3 生成hex文件 (12)3.4 Keil C语言 (14)3.5 单片机I/O (18)3.6 中断 (25)3.7 定时器/计数器 (27)3.8 定时器的应用举例 (29)3.9 外部中断 (34)3.10 串行通信 (38)3.11 定时器2 (43)3.12 看门狗 (47)3.13 空闲模式和掉电模式 (50)§4 MCS-51单片机C语言编程应用进阶 (51)4.1 扫描式键盘 (51)4.2 EEPROM芯片AT93C46的读写 (55)4.3 Keil C的高级使用 (63)§5 编写高质量的单片机C程序 (64)5.1 文件结构 (64)5.2 程序的版式 (66)5.3 单片机程序命名规则与变量选择 (70)5.4 表达式和基本语句 (73)5.5 函数设计 (77)5.6 单片机程序框架 (79)附图:Easy 51 Kit Pro电路图(最小系统板) (80)附图:Easy 51 Kit Pro电路图(学习板) (81)§1 前言什么是单片机,目前还没有一个确切的定义。
普通认为单片机是将CPU、RAM、ROM、定时器/计数器以及输入输出(I/O)接口电路等计算机主要部件集成在一块芯片上,这样所组成的芯片级微型计算机称为单片微型计算机(Single Chip Microcomputer)。
简称为单片微机或单片机。
利用单片机程序,可以实现对硬件系统的小型化的智能控制。
第1部分单片机概述及数学基础一、填空题1、十进制255的二进制是11111111,十六进制是FF 。
2、单片机是将CPU、存储器、特殊功能寄存器、定时/计数器和输入/输出接口电路、以及相互连接的总线等集成在一块芯片上。
3、十进制127的二进制是1111111,十六进制是7F。
4、+59的原码是00111011,-59的补码是11000101。
5、十进制数100转换为二进制数是1100100;十六进制数100转换为十进制数是256。
6、十进制数40转换为二进制数是101000;二进制数10.10转换为十进制数是 2. 5。
7、十进制99的二进制是1100 011,十六进制是63。
二、判断题(×)1、AT89S51是一种高性能的16位单片机。
8位机(×)2、有符号正数的符号位是用1表示的。
三、选择题()1、计算机中最常用的字符信息编码是(A)A. ASCIIB.BCD码C. 余3码D. 循环码四、简答题1、何谓单片机?单片机与一般微型计算机相比,具有哪些特点?第2部分51单片机硬件结构、存储系统及I/O接口一、填空题1、AT89S51单片机共有 4 个8位的并行I/O口,其中既可用作地址/数据口,又可用作一般的I/O口的是P0。
2、若采用12MHz的晶振,则MCS-51单片机的振荡周期为__ 1/12 μS __ ,机器周期为____1μS __。
3、AT89S51单片机字长是___8___位,有___40根引脚。
4.89S51单片机是8位单片机,其PC计数器是16位。
5.若单片机使用的晶振频率是6MHz,那么一个振荡周期是1/6µS,一个机器周期是2μSµS。
6.89S51单片机是+5 V供电的。
4.0-5.5V7.堆栈是内部数据RAM区中,数据按先进后出的原则出入栈的。
8.MSC-51系列单片机具有 4 个并行输入/输出端口,其中_P0_口是一个两用接口,它可分时输出外部存储器的低八位地址和传送数据,而_P1__口是一个专供用户使用的I/O口,常用于第二功能的是P3 口。
单片机C语言(C51)常用库函数单片机C语言(C51)常用库函数在单片机编程中,使用库函数可以大大提高开发效率和简化代码结构。
C51是一种常用的单片机编程语言,它提供了许多常用的库函数,本文将介绍一些常用的C51库函数及其用法。
1. 字符串处理函数字符串处理是单片机编程中常见的任务。
C51提供了一些常用的字符串处理函数,如strcpy、strcat、strcmp等。
这些函数可以简化对字符串的操作。
- strcpy:用于将一个字符串复制到另一个字符串中。
用法示例:```char str1[20];char str2[20] = "Hello, world!";strcpy(str1, str2);```- strcat:用于将一个字符串追加到另一个字符串的末尾。
用法示例:```char str1[20] = "Hello,";char str2[20] = " world!";strcat(str1, str2);```- strcmp:用于比较两个字符串是否相等。
用法示例:```char str1[20] = "Hello";char str2[20] = "World";if (strcmp(str1, str2) == 0) {// 字符串相等的处理逻辑} else {// 字符串不相等的处理逻辑}```2. 数学函数单片机编程中常常需要进行数学运算,C51提供了一些常用的数学函数,如abs、sqrt、sin等。
这些函数可以帮助实现各种数学计算。
- abs:用于计算一个整数的绝对值。
用法示例:```int num = -10;int abs_num = abs(num);```- sqrt:用于计算一个浮点数的平方根。
用法示例:```float x = 16.0;float sqrt_x = sqrt(x);```- sin:用于计算一个角度的正弦值。
PICC入门笔记PIC单片机C语言编程入门笔记一、C语言基础复习--------没C语言基础看起来可能有点困难。
(1) 条件判断语句if语句,switch语句(2) 循环执行语句do while语句,while语句,for语句(3) 转向语句break语句,goto语句,continue语句,return语句第三章: 控制语句1.if语句C语言的if语句有三种基本形式。
1、如果表达式的值为真,则执行其后的语句,否则不执行该语句。
if(表达式) 语句;2、如果表达式的值为真,则执行语句1,否则执行语句2 。
If(表达式)语句1;else语句2;3、依次判断表达式的值,当出现某个值为真时,则执行其对应的语句。
然后跳到整个if语句之外继续执行程序。
如果所有的表达式均为假,则执行语句n 。
然后继续执行后续程序。
If(表达式1)语句1;else if(表达式2)语句2;else if(表达式3)语句3;…else if(表达式m)语句m;else语句n;2、条件运算符和条件表达式由条件运算符组成条件表达式的一般形式为:表达式1? 表达式2:表达式3其求值规则为:如果表达式1的值为真,则以表达式2 的值作为条件表达式的值,否则以表达式3的值作为整个条件表达式的值。
例:max=(a>b)?a:b;意义:如果在条件语句中,只执行单个的赋值语句时,常可使用条件表达式来实现。
不但使程序简洁,也提高了运行效率。
3、switch语句C语言还提供了另一种用于多分支选择的switch语句,其一般形式为:switch(表达式){case常量表达式1: 语句1;case常量表达式2: 语句2;…case常量表达式n: 语句n;default : 语句n+1;}其语义是:计算表达式的值。
并逐个与其后的常量表达式值相比较,当表达式的值与某个常量表达式的值相等时,即执行其后的语句,然后不再进行判断,继续执行后面所有case后的语句。
#ifndef x#define x...#endif这是宏定义的一种,它可以根据是否已经定义了一个变量来进行分支选择,一般用于调试等等.实际上确切的说这应该是预处理功能中三种(宏定义,文件包含和条件编译)中的一种----条件编译。
C语言在对程序进行编译时,会先根据预处理命令进行“预处理”。
C语言编译系统包括预处理,编译和链接等部分。
#ifndef x//先测试x是否被宏定义过#define x程序段1 //如果x没有被宏定义过,定义x,并编译程序段1#endif程序段2 //如果x已经定义过了则编译程序段2的语句,“忽视”程序段1。
千万不要忽略了头件的中的#ifndef,这是一个很关键的东西。
比如你有两个C文件,这两个C文件都include了同一个头文件。
而编译时,这两个C文件要一同编译成一个可运行文件,于是问题来了,大量的声明冲突。
还是把头文件的内容都放在#ifndef和#endif中吧。
不管你的头文件会不会被多个文件引用,你都要加上这个。
一般格式是这样的:#ifndef <标识>#define <标识>............#endif<标识>在理论上来说可以是自由命名的,但每个头文件的这个“标识”都应该是唯一的。
标识的命名规则一般是头文件名全大写,前后加下划线,并把文件名中的“.”也变成下划线,如:stdio.h#ifndef _STDIO_H_#define _STDIO_H_......#endif这里是static是静态局部变量,不会随着函数的结束而撤销,放在main函数里是没有实际意义的,下面一个是static的例子:void f(){static int x=0;int y=0;x++;y++;printf("%d %d\n", x, y);}void main(){f();f();f();}这里运行了3次f(),但是static只会被定义一次,并不会随着f()函数的结束而消亡,但是y是局部变量,运行了3次它就被创建了3次消亡了3次,所以它的输出为:1 12 13 1. typedef & #define的问题有下面两种定义pStr数据类型的方法,两者有什么不同?哪一种更好一点?答案与分析:通常讲,typedef要比#define要好,特别是在有指针的场合。
请看例子:在上述的变量定义中,s1、s2、s3都被定义为char *,而s4则定义成了char,不是我们所预期的指针变量,根本原因就在于#define只是简单的字符串替换而typedef 则是为一个类型起新名字。
#define用法例子:以下程序的输出结果是: 36。
因为如此原因,在许多C语言编程规范中提到使用#define定义时,如果定义中包含表达式,必须使用括号,则上述定义应该如下定义才对:当然,如果你使用typedef就没有这样的问题。
4. typedef & #define的另一例下面的代码中编译器会报一个错误,你知道是哪个语句错了吗?答案与分析:是p2++出错了。
这个问题再一次提醒我们:typedef和#define不同,它不是简单的文本替换。
上述代码中const pStr p2并不等于const char * p2。
const pStr p2和const long x本质上没有区别,都是对变量进行只读限制,只不过此处变量p2的数据类型是我们自己定义的而不是系统固有类型而已。
因此,const pStr p2的含义是:限定数据类型为char *的变量p2为只读,因此p2++错误。
(注:关于const的限定内容问题,在本系列第二篇有详细讲解)。
#define与typedef引申谈1) #define宏定义有一个特别的长处:可以使用#ifdef ,#ifndef等来进行逻辑判断,还可以使用#undef来取消定义。
2) typedef也有一个特别的长处:它符合范围规则,使用typedef定义的变量类型其作用范围限制在所定义的函数或者文件内(取决于此变量定义的位置),而宏定义则没有这种特性。
5. typedef & 复杂的变量声明在编程实践中,尤其是看别人代码的时候,常常会遇到比较复杂的变量声明,使用typedef作简化自有其价值,比如:下面是三个变量的声明,我想使用typdef分别给它们定义一个别名,请问该如何做?答案与分析:对复杂变量建立一个类型别名的方法很简单,你只要在传统的变量声明表达式里用类型名替代变量名,然后把关键字typedef加在该语句的开头就行了。
(注:如果你对有些变量的声明语法感到难以理解,请参阅本系列第十篇的相关内容)。
sfr,sfr16,esfr,sbit 收藏伪指令sfr、sfr16 和sbit 与Cx51 编译器完全兼容,我们可以在两种情况下都使用SFR 寄存器定义文件:Ax51 宏汇编器和Cx51 编译器。
伪指令esfr 在Philips 80C51MX 架构的扩展SFR 空间定义符号。
该伪指令只能在AX51 宏汇编器中使用。
这些伪指令的格式如下:sfr sfr_symbol = address;esfr sfr_symbol = address;sfr16 sfr_symbol = address; ; 被Ax51 忽略sbit sfr_symbol = bit_address;其中sfr_symbol 是要定义的特殊功能寄存器(SFR)符号的名称。
address 是在0x80 - 0xFF 范围内的一个SFR 地址。
bit_address 是一个SFR 位的地址,形式为地址^位位置(address^bitpos)或sfr_symbol ^ bitpos。
地址(address)或特殊功能寄存器符号(sfr_symbol)指向一个位可寻址的SFR 和位位置,指明SFR 中的位位置,范围为0-7。
使用伪指令esfr、sfr 或sbit 定义的符号可以用在适合SFR 地址或SFR 位地址使用的任意位置。
例程sfr P0 = 0x80;sfr P1 = 0x90;sbit P0_0 = P0^0;sbit P1_1 = 0x90^1;esfr MXCON = 0xFF; /* 扩展的Philips 80C51MX SFR */sfr16 T2 = 0xCC; /* 被Ax51 忽略*/reg51.h 详解/* BYTE Register */sfr P0 = 0x80; //P0口sfr P1 = 0x90; //P1口sfr P2 = 0xA0; //P2口sfr P3 = 0xB0; //P3口sfr PSW = 0xD0; //程序状态字,具体位意义见位定义sfr ACC = 0xE0; //累加器,程序员最常用的sfr B = 0xF0; //寄存器,主要用于乘除sfr SP = 0x81; //堆栈指针,初始化为07;先加1后压栈,先出栈再减1,sfr DPL = 0x82;sfr DPH = 0x83; //数据指针,用途大sfr PCON = 0x87; //电源控制sfr TCON = 0x88; //Timer/Counter控制sfr TMOD = 0x89; //Timer/Counter方式控制sfr TL0 = 0x8A;sfr TL1 = 0x8B; //sfr TH0 = 0x8C; //存着当前的计数值sfr TH1 = 0x8D; //我就想不明白,当时设计的时候,为什么不把TH0,TL0放在连续的地址!sfr IE = 0xA8; //好东西,中断控制sfr IP = 0xB8; //中断优先级控制,没有设计过要求时间严格的系统,所以至今没有用过sfr SCON = 0x98; //哇,熟悉,串口控制寄存器sfr SBUF = 0x99; //哇,更熟悉,串口缓冲寄存器/* BIT Register *//* PSW */sbit CY = 0xD7; //进位或借位,有就是1,没有就是0sbit AC = 0xD6; //辅助进借位,(麻烦b)sbit F0 = 0xD5; //没有具体用途,可以由用户决定他的意义,所以它就没有意义sbit RS1 = 0xD4;sbit RS0 = 0xD3; //工作寄存器选择,这个在下面解释sbit OV = 0xD2; //over!溢出,有是1,没有是0sbit P = 0xD0; //奇偶校验,奇数个1是1/* TCON */sbit TF1 = 0x8F; //T1的中断请求标志sbit TR1 = 0x8E; //Timer 1 running,好记吧~sbit TF0 = 0x8D; //sbit TR0 = 0x8C; //把上面两个1换成0sbit IE1 = 0x8B; //interrupt external 1 外中断请求标志sbit IT1 = 0x8A; //interrupt triggle 1 外中断触发方式sbit IE0 = 0x89;sbit IT0 = 0x88; //同样,把上面的两个1换成0/* IE */sbit EA = 0xAF; //Enable all哇,重要,全局中断控制,光着他,哈哈,什么都不用作了,就像放假一样sbit ES = 0xAC; //Enable Serial,开串口中断sbit ET1 = 0xAB; //Enable Timer/Counter 1sbit EX1 = 0xAA; //Enable External 1sbit ET0 = 0xA9; //Enable Timer/counter 0sbit EX0 = 0xA8; //Enable External 0/* IP */sbit PS = 0xBC; //串行中断优先级sbit PT1 = 0xBB; //T1优先级sbit PX1 = 0xBA; //外部中断1优先级sbit PT0 = 0xB9; //sbit PX0 = 0xB8; //上面两个1换成0/* P3 */ //控制寄存器!!!!sbit RD = 0xB7; //读sbit WR = 0xB6; //写sbit T1 = 0xB5; //T/C1sbit T0 = 0xB4; //T/C0sbit INT1 = 0xB3; //外中断1sbit INT0 = 0xB2; //外中断0sbit TXD = 0xB1; //串行发送sbit RXD = 0xB0; //串行接收/* SCON */sbit SM0 = 0x9F; //sbit SM1 = 0x9E; //串口工作方式sbit SM2 = 0x9D; //什么鬼特征位,要用查书,或者等我以后解释,啊哈sbit REN = 0x9C; //串行接收允许sbit TB8 = 0x9B; //收到的第九位sbit RB8 = 0x9A; //要发的第九位sbit TI = 0x99; //哇,熟悉吧,发送完成中断标志sbit RI = 0x98; //接收完成中断标志bit和sbit都是C51扩展的变量类型。