普中51单片机开发板笔记
简介
什么是单片机?
单板机
将CPU芯片、存储器芯片、I/O接口芯片和简单的I/O设备(小键盘、LED显示器)等装配在一块印刷电路板上,再配上监控程序(固化在ROM中),就构成了一台单板微型计算机(简称单板机)。
单片机
在一片集成电路芯片上集成微处理器、存储器、I/O接口电路,从而构成了单芯片微型计算机,即单片机。 Intel公司推出了MCS-51系列单片机:集成8位CPU、4K字节ROM、128字节RAM、4个8位并口、1个全双工串行口、2个16位定时/计数器。寻址范围64K,并有控制功能较强的布尔处理器
单片机能做什么?
工业自动化:数据采集、测控技术。
智能仪器仪表:数字示波器、数字信号源、数字万用表、感应电流表等。
消费类电子产品:洗衣机、电冰箱、空调机、电视机、微波炉、手机、IC卡、汽车电子设备等。
通讯方面:调制解调器、程控交换技术、手机、小灵通等。
武器装备:飞机、军舰、坦克、导弹、航天飞机、鱼雷制导、智能武器等。
等等…
凡是与控制或简单计算有关的电子设备都可以用单片机来实现,根据具体实际情况还可以选择不同性能的单片机,如:atmel,stc,pic,avr,凌阳,80C51,arm等
怎样开始学习?
1.实践第一。
2.补充必要的理论知识,即缺什么补什么。
3.做工程项目积累经验。(可在网络上搜集题目,也可自己有什么想法大胆的去试验)
单片机的预备知识
电平特性
数字电路中只有两种电平:高电平和低电平
- 高电平:5V或者3.3V,取决单片机电源。
- 低电平:0V
RS232电平:计算机串口的电平
- 高电平:-12V
- 低电平:+12V
所以当我们用单片机跟电脑通信的时候,我们要通过各种元器件将单片机的电平转换为计算机可识别的电平才能跟电脑进行通信。
2进制与16进制的表示及转换
二进制
- 由于数字电路中的只有两种电平的特性,计算机中使用的数字采用都是二进制的。
- 二进制是使用0和1两个数码来表示的数,它的基数是2,进位规则是“逢二进一”。
十六进制
- 十六进制的基数是F,进位规则是”逢十六进一“。
二进制和十六进制之间的转换
十进制 | 二进制 | 十六进制 | 十进制 | 二进制 | 十六进制 |
---|---|---|---|---|---|
0 | 0 | 0 | 8 | 1000 | 8 |
1 | 1 | 1 | 9 | 1001 | 9 |
2 | 10 | 2 | 10 | 1010 | A |
3 | 11 | 3 | 11 | 1011 | B |
4 | 100 | 4 | 12 | 1100 | C |
5 | 101 | 5 | 13 | 1101 | D |
6 | 110 | 6 | 14 | 1110 | E |
7 | 111 | 7 | 15 | 1111 | F |
二进制逻辑运算
运算类型 | 介绍 | 用法 |
---|---|---|
与 | 有0得0 | 1 & 1 = 1; 1 & 0 = 0; 0 & 0 = 0 |
或 | 有1得1 | 1 | 1 = 1; 1 & 0 = 1; 0 | 0 = 0; |
非 | 1的非得0,0的非得1 | ~1 = 0; ~0 = 1; |
异或 | 相同为0,不同为1 | 1 ^ 1 = 0; 1 ^ 0 = 1; 0 ^ 0 = 0; |
8051单片机介绍
80C51是MCS-51系列中的一个典型品种;其它厂商以8051为基核开发出的CMOS工艺单片机产品统称为80C51系列。当前常用的
80C51系列单片机主要产品有:
Intel的:80C31、80C51、87C51,80C32、80C52、87C52等;
ATMEL的:89C51、89C52、89C2051等;
Philips、华邦、Dallas、STC
**Siemens(Infineon)**等公司的许多产品 。
80C51的引脚封装
P3口第二功能各引脚功能定义:
引脚 | 功能 | 引脚 | 功能 |
---|---|---|---|
P3.0 | RXD串行口输入 | P3.4 | T0定时器0外部输入 |
P3.1 | TXD串行口输出 | P3.5 | T1定时器1外部输入 |
P3.2 | INT0外部中断0输入 | P3.6 | WR外部写控制 |
P3.3 | INT1外部中断1输入 | P3.7 | RD外部读控制 |
8051内部结构
总线(BUS)是计算机各部件之间传送信息的公共通道。微机中有内部总线和外部总线两类。内部总线是CPU内部之间的连线。外部总线是指CPU与其它部件之间的连线。 外部总线有三种:数据总线DB(Data Bus), 地址总线 AB(Address Bus)和控制总线 CB(Control Bus)。
CPU:由运算和控制逻辑组成,同时还包括中断系统和部分外部特殊功能寄存器;
RAM:用以存放可以读写的数据,如运算的中间结果、最终结果以及欲显示的数据;
ROM:用以存放程序、一些原始数据和表格;
I/O口:四个8位并行I/O口,既可用作输入,也可用作输出;
T/C:两个定时/记数器**,**既可以工作在定时模式,也可以工作在记数模式;
五个中断源的中断控制系统;
一个全双工UART(通用异步接收发送器)的串行I/O口,用于实现单片机之间或单片机与微机之间的串行通信;
片内振荡器和时钟产生电路,石英晶体和微调电容需要外接。最高振荡频率取决于单片机型号及性能。
单片机工作的基本时序
机器周期和指令周期
- 振荡周期:也称时钟周期, 是指为单片机提供时钟脉冲信号的振荡源的周期,我们开发板上为12MHZ。
- 状态周期:每个状态周期为时钟周期的 2 倍, 是振荡周期经二分频后得到的。
- 机器周期:一个机器周期包含 6 个状态周期S1~S6, 也就是 12 个时钟周期。 在一个机器周期内, CPU可以完成一个独立的操作。
- 指令周期:它是指CPU完成一条操作所需的全部时间。 每条指令执行时间都是有一个或几个机器周期组成。MCS - 51 系统中, 有单周期指令、双周期指令和四周期指令。
学单片机到底学什么
对I/O口的控制,无论单片机对外界进行何种控制,都是通过I/O口进行的。
接受外部的控制,通过I/O来感受外部的电压。
51单片机总共有P0、P1、P2、P3四个8位双向输入输出端口,每个端口都有锁存器、输出驱动器和输入缓冲器。4个I/O端口都能作输入输出口用。
C51基础知识
单片机IO口的结构
上下拉电阻
上拉电阻就是将不确定的信号通过一个电阻拉到高电平,同时此电阻起到一个限流的作用,下拉就是下拉到低电平。
- OC门要输出高电平,外部必须加上拉电阻。
- 加大普通IO口的驱动能力。
- 起到限流的作用。
- 抵抗电磁干扰。
上下拉电阻的选取原则
- 从降低功耗方面考虑应该足够大,因为电阻越大,电流越小。
- 从确保足够的引脚驱动能力考虑应该足够小,电阻越小,电流才能越大。
- 开漏输出时,过大的上拉电阻会导致信号上升沿变缓。
C语言基础
C语言是一种编译型程序设计语言,它兼顾了多种高级语言的特点,并具备汇编语言的功能。目前,使用C语言进行程序设计已经成为软件开发的一个主流。用C语言开发系统可以大大缩短开发周期,明显增强程序的可读性,便于改进、扩充和移植。
一个简单的单片机C程序要有什么?
#include <reg51.h>
void main() {
while(1) {
}
}
-
包涵头文件
-
程序主函数
其实课堂上学习 C语言的很大一部分内容在初期单片机编程中都用不到,因此没必要因为觉的自己的 C 语言基础不是很好而对单片机望而止步!
C语言中常用的语句
if
-else
语句
if (表达式) {
语句1;
} else {
语句2;
}
其语义是:如果表达式的值为真(非0),则执行语句1,否则执行语句2 。
例如:
if (a > b) {
c = 1;
} else {
c = 2;
}
可使用三目运算简化**
if
-else
**语句表达式 ? 语句1 : 语句2;
上面代码可简化为
c = a > b ? 1 : 2;
while
语句
while
语句的一般形式为:
while (表达式) {
循环体
}
其中表达式是循环条件,语句为循环体。
while
语句的语义是:当表达式的值为真(非0)时, 执行循环体语句。
例如:
while ( i < 10) {
i = i + 1;
}
do
-while
语句
do {
循环体
} while (表达式);
这个循环与
while
循环的不同在于:它先执行循环体中的语句,然后再判断表达式是否为真,如果为真则继续循环;如果为假,则终止循环。因此,do
-while
循环至少要执行一次循环语句。
例如:
do {
a = a + 1;
} while (a < 10);
for
语句
for(表达式1; 表达式2; 表达式3) {
循环体;
}
它的执行过程如下:
- 执行
表达式1
;- 执行
表达式2
,若值为真(非0),则执行循环语句;若其值为假(0),则结束循环;- 执行
表达式3
;- 跳转到第2步。
例如:
for (a = 0; a < 10; a++) {
// a++相当于a = a + 1;
b = 0;
}
单目运算与双目运算
表达式 | 说明 | 表达式 | 说明 |
---|---|---|---|
a++ | 先运算a再自增1。如: a = 3; b = a++ + 5; 执行完后 a = 4, b = 8 | a *= 2 | 等价于a = a * 2; |
–a | a先自减1再参与运算。如: a = 3; b = --a + 5; 执行完后 a = 2, b = 7 | a /= 2 | 等价于a = a / 2; |
a %= 2 | 等价于a = a % 2; m % n 表示求m除以n的余数 | a &= 2 | 等价于a = a & 2; |
a |= 2 | 等价于 a = a | 2; | a ^= 2 | 等价于a = a ^ 2; |
a += 2 | 等价于a = a + 2; | a ~= 2 | 等价于a = a ~ 2; |
a -= 2 | 等价于a = a - 2; |
switch
switch (表达式) {
case 常量表达式1: 语句1;
case 常量表达式2: 语句2;
…
case 常量表达式n: 语句n;
default : 语句n+1;
}
其语义是:计算表达式的值。 并逐个与其后的常量表达式值相比较,当表达式的值与某个常量表达式的值相等时, 即执行其后的语句,然后不再进行判断,继续执行后面所有case后的语句。如表达式的值与所有case后的常量表达式均不相同时,则执行default后的语句。
例如:
switch (a) {
case (0):
b = 0;
break;
case (1):
b = 1;
break;
default :
b=3;
}
break
语句的含义是跳出这个switch
语句,如果没有这条语句,则会从满足条件的地方(即与switch
(表达式)括号中表达式匹配的case
)开始执行,直到switch
结构结束。当break
语句用于do
-while
、for
、while
循环语句中时,可使程序终止循环 。
函数
函数的定义
返回变量类型 函数名 (函数参数) {
函数体;
}
如:
unsigned char read (unsigned char addr) {
unsigned char dat; // 定义一个变量存放返回值
... // 函数中的程序。
return dat; // 函数的返回值
}
函数的调用
在函数调用之前要在主函数前面加入上该函数的声明。(或者你可以放在头文件里面,包含该头文件时,就可以声明了。)
C51的数据类型扩充定义
sfr
:特殊功能寄存器声明
sfr 变量名 = 地址值;
特殊功能寄存器在reg51.H
这个头文件里面都帮我们定义好了,所以平时我们就不要自己去定义寄存器的名字。
sbit
:特殊功能位声明
sbit 变量名 = 地址值;
在给某个引脚取名的时候经常会用到。
bit
: 位变量声明
用来定义位数据变量
例:sfr SCON = 0X98;
sbit LED = P0^2;
C51中常用到的一些预处理命令
#define
#define A P0
注意后面不用加分号
#typedef
typedef unsigned char int;
注意后面要加分号
重新定义一些常用的关键词,可以增强程序的可移植性,因为在不同的编译软件上面,C语言的数据类型的关键词的位宽是不一样的。
#ifndef…#endif
条件编译,常用于头文件的定义还有一些程序条件编译
C51基本数据类型
类型 | 符号 | 关键字 | 所占位数 | 数的表示范围 |
---|---|---|---|---|
整型 | 有 | (signed) int | 16 | -32768~32767 |
(signed) short | 16 | -32768~32767 | ||
(signed) long | 32 | -2147483648~2147483647 | ||
无 | unsigned int | 16 | 0~65535 | |
unsigned short int | 16 | 0~65535 | ||
unsigned long int | 32 | 0~4294967295 | ||
实型 | 有 | float | 32 | 3.4e-38~3.4e38 |
double | 64 | 1.7e-308~1.7e308 | ||
字符型 | char | 8 | -128~127 | |
无 | unsigned char | 8 | 0~255 |
常用的运算符
+
、-
、*
、/
(加、减、乘、除)
>
、>=
、<
、<=
(大于、大于等于、小于、小于等于)
==
、!=
(测试等于、测试不等于。它是逻辑运算符)
比如说:
if(a == 1) 或者 if(a != 1) {
b=2;
}
&&
、||
、!
(逻辑与、逻辑或、逻辑非 )
比如说:
if ((a > 0) && (b > 0)) {
do something
}
单片机最小系统
1.电源电路
2.复位电路
3.时钟电路
4.下载电路
开发环境搭建
KEIL4的安装
第一步、正常安装Keil 4
,默认一路点下一步,直到安装完成。
第二部、打开Keil
软件,选择File
>> Licence Management ...
>> 复制CID
码 >> 打开破解工具 >> 粘贴CID
码 >> 点击Generate
生成密钥并复制 >> 返回 Keil
软件粘贴密钥后点击Add Lic
创建工程模板
第一步、新建工程:打开Keil
软件,选择Projet
>> New μVision Projet...
>> 选择保存路径,并命名为Template
>> 弹出提示后点击取消
>> 选择Atmel
中的AT89C52
或者AT89C51
>> 弹出提示框点击否
第二部、新建main
程序,选择 File
>> New
>> 命名为main.c
>> 在编辑区中粘贴以下代码:
#include "reg52.h"
void main() {
while(1) {
}
}
第三步、在新建工程Source Group 1
上单击右键,选择Add Files to Group 'Source Group 1...
,添加刚刚创建的main.c
文件。
第四步、点击Build
编译程序,保证程序无误。
第四步、点击Target Options...
图标,点击Output
选项卡,勾选Create HEX File
选项,点击OK
配置Sublime text 编译51程序
{
"shell_cmd": "\"%KEIL_CMD%/C51\" \"${file}\" & \"%KEIL_CMD%/LX51\" \"${file_base_name}.obj\" to \"${file_base_name}.abs\" >> nul & \"%KEIL_CMD%/OHx51\" \"${file_base_name}.abs\" >> nul & DEL *.lst *.obj *.map *.abs >> nul",
"file_regex": "^(..[^:]*):([0-9]+):?([0-9]+)?:? (.*)$",
"working_dir": "${file_path}",
"selector": "source.c",
"encoding":"cp936"
}
其中%KEIL_CMD%
为Keil
软件安装路径的环境变量,需要自己手动配置,我的环境变量配置如下:
01、点亮一个LED灯
LED是什么
LED,即发光二极管,是一种半导体固体发光器件。如图:
LED工作原理
LED的工作是有方向性的,只有当正级接到LED阳极,负极接到LED的阴极的时候才能工作,如果反接LED是不能正常工作的。
看懂原理图
开发板上面LED的原理图如下图,LED的阳极串联一个电阻,然后连接到电源VCC,而LED的阴极连接到单片机的P2口,如果你想点亮一盏LED就对把单片机相对应的IO赋为低电平。
驱动程序
C语言知识点:
sbit 变量名 = 地址值;
在给某个引脚取名的时候经常会用到。
#include "reg52.h"
sbit led = P2^0;
void main(){
while(1){
led = 0;
}
}
02、LED闪烁
C语言知识
typedef
typedef unsigned char u8;
typedef unsigned int u16;
重新定义一些常用的关键词,可以增强程序的可移植性,因为在不同的编译软件上面,C语言的数据类型的关键词的位宽是不一样的。
while循环
while(i < 10) {
i = i + 1;
}
while语句的语义是:计算表达式的值,当值为真(非0)时, 执行循环体语句。
延时函数
void delay (u16 i) {
//大约延时10us
while(i--);
}
驱动程序
/*
实验现象:使第一个LED不停地闪烁
*/
#include "reg52.h"
typedef unsigned int u16;
sbit led = P2^0;
void delay(u16 i){
while(i--);
}
void main(){
while(1){
delay(50000);
led = ~led;
}
}
03、流水灯
定义宏
#define A P0
将所有的A替换成P0
循环左移右移函数
_crol_(a,b);
循环左移函数,a是左移的值,b是左移的位数。
_cror_(a,b);
循环右移函数,a是右移的值,b是右移的位数。以上两个函数都包含在
instrins.h
库函数里。
驱动程序
方法①
/*
实验现象:LED灯来回流动点亮
*/
#include "reg52.h"
#include <intrins.h>
typedef unsigned int u16;
typedef unsigned char u8;
#define LED P2
void delay(u16 i) {
while(i--);
}
void main() {
u8 flag = 0, i = 0;
LED = ~0x01;
while(1) {
delay(50000);
if (!(i++ % 7)) flag = !flag;
LED = flag ? _crol_(LED,1) : _cror_(LED,1);
}
}
方法②
void main() {
u8 v = 1, i = 0;
while(1) {
LED = 0xff ^ 1 << i;
i += v;
if (i >= 7 || i <= 0) v *= -1;
delay(50000);
}
}
04、蜂鸣器
在图片上认识蜂鸣器:有绿色电路板的一种是无源蜂鸣器,没有电路板而用黑胶封闭的一种是有源蜂鸣器。
- 电磁式蜂鸣器由振荡器、电磁线圈、磁铁、振动膜片及外壳等组成。
接通电源后,振荡器产生的音频信号电流通过电磁线圈,使电磁线圈产生磁场,振动膜片在电磁线圈和磁铁的相互作用下,周期性地振动发声。
- 压电式蜂鸣器主要由多谐振荡器、压电蜂鸣片、阻抗匹配器及共鸣箱、外壳等组成。
多谐振荡器由晶体管或集成电路构成,当接通电源后(1.5~15V直流工作电压),多谐振荡器起振,输出1.5~2.5kHZ的音频信号,阻抗匹配器推动压电蜂鸣片发声。
在单片机应用的设计上,很多方案都会用到蜂鸣器,大部分都是使用蜂鸣器来做提示或报警,比如按键按下、开始工作、工作结束或是故障等等。
自激蜂鸣器是直流电压驱动的,不需要利用交流信号进行驱动,只需对驱动口输出驱动电平并通过放大电路放大驱动电流就能使蜂鸣器发出声音,非常简单。
改变单片机引脚输出波形的频率,就可以调整控制蜂鸣器音调,产生各种不同音色、音调的声音。
改变输出电平的高低电平占空比,则可以控制蜂鸣器的声音大小。
电路图
ULN2003简介
ULN2003 是高耐压、大电流达林顿陈列,由七个硅NPN 达林顿管组成。
ULN2003是大电流驱动阵列,多用于单片机、智能仪表、PLC、数字量输出卡等控制电路中。可直接驱动蜂鸣器、继电器等负载 。
驱动程序
#include "reg52.h"
typedef unsigned int u16;
sbit beep = P2^5;
void delay(u16 i) {
while(i--);
}
void main() {
while(1) {
beep = ~beep;
delay(100); // 通过修改此延时时间达到不同的发声效果
}
}
知识拓展
可通过改变输出波形的频率,形成不同音调,模拟出音乐,例如:
#include "reg52.h"
#define RldTmr(fr) 65536 - (11059200 / 12) / (fr << 1)
#define FuDian(n) (n << 1)