一. 入门
1.1 开发环境的安装
- 用什么写代码--语言是C,环境是keil
- Keil C51是美国Keil Software公司出品的51系列兼容单片机C语言软件开发系统,与汇编相比,C语言在功能上、结构性、可读性、可维护性上有明显的优势,因而易学易用。
- Keil安装
- Keil 破戒
- 使用
- 创建项目工程文件夹,可以当作模板Template
- 创建文件,取名main.c (要打开拓展名,在文件夹窗口上找 “查看”,勾选“文件拓展名”)
- 进入keil主页面,工具栏project->new uVision project->选择第一步的工程文件夹位置->输入
工程名字->选择芯片类型AT89c52->会提示是否拷贝STARTUP.A51,选择是->生成了工程目录-
在工程目录Source Group1上右键鼠标->add Exiting file to Source Group1...->选择代码文
件main.c
- 编程,新手如果看不懂以下代码,可以忽略,这次实验只是强调开发流程
- 编译,选择输出文件有hex
#include "reg52.h"
sbit led1 = P3^7;//根据原理图(电路图),设备变量led1指向P3组IO口的第7口
sbit led2 = P3^6;//根据原理图(电路图),设备变量led2指向P3组IO口的第6口
void main()
{
led1 = 0;//根据电路图,低电平点亮led
led2 = 0;
while(1);
}
1.2 用什么把代码放进单片机里面
STC-ISP 是一款单片机下载编程烧录软件,是针对STC系列单片机而设计的,可下载STC89系列、12C2052系列和12C5410等系列的STC单片机,使用简便。
- 单片机通过type-C数据线和电脑连接(如果不识别,安装ch340驱动,在资料包中)
- 选择单片机型号STC89C52RC
- 选择生成的执行程序文件template.hex
- 点击”下载/编程“按钮
- 单片机开关拨动重新上电
- 自动检测并下载了程序,看到灯亮。如果失败,仔细对照 以上每一步内容
二、 初识单片机
1.2.1 什么是单片机
- 单片机(Single-Chip Microcomputer)是一种集成电路芯片,
- 把具有数据处理能力的中央处理器CPU、随机存储器RAM、只读存储器ROM、
- 多种I/O口和中断系统、定时器/计数器等功能(可能还包括显示驱动电路、脉宽调制电路、模拟多路转换器、A/D转换器等电路)
- 集成到一块硅片上构成的一个小而完善的微型计算机系统,在工业控制领域广泛应用。
什么是单片机开发板
- 基于单片机设计一些外接电路,模块以满足学习,日常调研等工作需求
- STC89系列单片机
- 命名规则,封装LQFP44, 特性 定时器,计数器,串口,看门狗,IO
三、 基本IO口控制
1.2.1 关于灯LED的那些事儿
思维发散:
- 单片机编程是什么:人类要求单片机干具体的活,有点像提前写个小纸条贴冰箱上,告诉你女朋友
煮鸡蛋不加水 - 单片机执行程序怎么理解: 女朋友看到纸条后,照做!
- 单片机能做什么事情: IO口供电,串口数据传输等
- 肉眼可见的引脚是什么:方便人类对单片机IO口,串口接东西
- 单片机CPU怎么找到IO口:通过寻址,说白了有一些地址数据,头文件帮你做很多了
- 怎么写纸条(编程)找到IO口呢:ANSI C
sfr"指令": 用来直接描述硬件地址,小白先理解成"一组IO口"的起始地址中数据 sfr P0 = 0x80; P0 = 0;
- 怎么找到IO口的具体一个引脚呢:
sbit"指令",对应可位寻址空间的一个位,小白先理解成"一个IO口/针脚"的地址中数据 sbit led2 = P3^6
c语言的一个字节,char型就是8位
注:sfr sbit 非c的标准库 只有在51单片机中使用
上官一号89C52有5组这样的输入输出口,分别为P0,P1,P2,P3每组对应8个针脚,P4是RC系列才有只有7个
针脚
1. sfr
指令
"sfr"
是 Special Function Register 的缩写,用于定义特殊功能寄存器的地址。通常这些寄存器用于控制微控制器的各种外设(例如I/O端口,定时器,中断控制器等)。例如,sfr P0 = 0x80;
这行代码定义了一个名为 P0
的寄存器,并将其地址设置为 0x80
。
sfr P0 = 0x80; // 定义特殊功能寄存器 P0,其地址为 0x80
P0 = 0; // 将 P0 寄存器的值设置为 0
在这个例子中,P0
是微控制器的一个 I/O 端口。通过设置 P0
的值,我们可以控制这个端口上的所有引脚。例如,将 P0
设置为 0 意味着将端口 P0 上的所有引脚都拉低(即设置为 0)。
2. sbit
指令
"sbit"
是用于定义单个位的地址。例如,可以用它来定义某个 I/O 端口的特定引脚。下面的代码定义了 P3
端口的第 6 位(引脚)。
sbit led2 = P3^6; // 定义 led2 位,表示 P3 端口的第 6 引脚
在这个例子中,P3
是一个 I/O 端口,而 P3^6
表示这个端口的第 6 位。通过操作 led2
,可以单独控制 P3 端口的第 6 引脚。例如:
led2 = 1; // 将 P3 端口的第 6 引脚设置为高电平
led2 = 0; // 将 P3 端口的第 6 引脚设置为低电平
总结
sfr
指令:用于定义整个 I/O 端口或特殊功能寄存器。例如:sfr P0 = 0x80;
定义了地址为0x80
的寄存器P0
。sbit
指令:用于定义特定 I/O 端口的某个位。例如:sbit led2 = P3^6;
定义了P3
端口的第 6 引脚。
四、 输入&&输出
是对单片机来讲的,IO口的 输入(把外面东西拿回来)/输出(给东西给外面)
89C52比较简单粗暴,关于引脚输入还是输出的功能不需要配置
- 比如
sbit IFfire = P1^0;
int main()
{
int io_data;
//什么情况叫做输入
io_data = IFfire; // 给变量赋值,就是输入 —— 或者理解为,这个针脚有数据啦,拿个变量来
保存
if(io_data == 0){
}
//什么情况叫做输出
IFfire = 1; // 被给予一个数值,引起IO口电压变化(一般1输出高电平,0输出低电平),此时为输
出,来影响外接的电路
return 0;
}
如何使用 sbit
指令来定义和操作一个单独的 I/O 引脚。以下是逐行的中文解释:
sbit IFfire = P1^0; // 定义一个名为 IFfire 的位变量,它代表 P1 端口的第 0 引脚
sbit IFfire = P1^0;
:这行代码使用sbit
指令定义了一个位变量IFfire
,它表示 P1 端口的第 0 位(即第 0 引脚)。
int main() // 主函数入口
{
int io_data; // 定义一个整型变量 io_data
int io_data;
:定义一个整型变量io_data
,用于存储 I/O 引脚的数据。
io_data = IFfire; // 读取 P1 端口第 0 引脚的值,并赋值给变量 io_data
io_data = IFfire;
:这行代码将 P1 端口第 0 引脚的电平状态(高或低)读入到变量io_data
中。这就是所谓的“输入”操作,因为它是从引脚读取数据。
if(io_data == 0){
// 如果 io_data 的值为 0,则执行这里的代码
}
if(io_data == 0){}
:检查io_data
的值是否为 0。如果是 0,则表示 P1 端口第 0 引脚当前为低电平。
IFfire = 1; // 将 P1 端口第 0 引脚的电平设置为高电平(输出)
IFfire = 1;
:这行代码将 P1 端口第 0 引脚的电平设置为高电平。这是“输出”操作,因为它改变了引脚的电平,从而影响外部电路。
return 0; // 返回 0,表示程序正常结束
}
return 0;
:主函数返回 0,表示程序正常结束。
总结
sbit IFfire = P1^0;
:定义了 P1 端口第 0 引脚为IFfire
。io_data = IFfire;
:读取 P1 端口第 0 引脚的电平状态到变量io_data
中(输入操作)。if(io_data == 0){}
:检查 P1 端口第 0 引脚的电平状态是否为低电平。IFfire = 1;
:将 P1 端口第 0 引脚的电平设置为高电平(输出操作)。
五、52开发板入门
5.1 为什么灯会亮
得看电路图,但是不要怕,初中电路知识而已!也叫单片机原理图,是硬件设计者设计的
记住:原理图中标号一样代表是同一根“电线”
简单的串联电路,D4,D5,D6板子上有标记, D5一端通过电阻接5v,另外一端接着"LED1标志的线",我
们发现在89C52RC的电路图中也有LED1的标志,是在P3的IO口组中,在P3.7引脚,所以编程让P3.7出
低电平(0)就让D5灯完成一个串联电路,所以亮
led 表示二极管,key表示按键。
D4是完整的串联电路,通过电源5v->电阻->二极管,然后接地(GND)即可点亮。
GND 就是低电平 0;
D4不是完整的串联电路,通过电源5v->电阻->二极管,然后将P3^7口等于0,即接地(GND)可点亮。
D4不是完整的串联电路,通过电源5v->电阻->二极管,然后将P3^6口等于0,即接地(GND)可点亮。
D5为P3^7口,将P3^7口等于0就会亮。
D6为P3^6口,将P3^6口等于0就会亮。
- 下面看一下代码:
#include "reg52.h"
sbit ledOne = P3^7; // i|o口赋值给变量
sbit ledtwo = P3^6; // i|o口赋值给变量
void main()
{
// D5为P3^7口,将P3^7口给个低电平,就会亮。
// D6为P3^6口,将P3^6口给个低电平,就会亮。
ledOne = 0;
ledtwo = 0;
}
5.2 怎么做,D5D6,才会闪烁
- 使用STC-ISP自带延时函数
#include "reg52.h"
sbit ledOne = P3^7;
sbit ledTwo = P3^6;
void Delay500ms() //@11.0592MHz //使用STC工具中的延迟生成器自动生成延时函数
{
unsigned char i, j, k;
i = 4;
j = 129;
k = 119;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void main() //重复执行
{
//灯灭,给一个高电平
//重复执行
while(1){
//灯亮,给一个P3.7低电平
ledOne = 0 ;
ledTwo = 0 ;
//数数,数的期间,维持低电平,灯亮,延迟
Delay500ms();
//灯灭,给一个高电平
ledOne = 1;
ledTwo = 1 ;
//数数,数的期间,维持高电平,灯灭,延迟
Delay500ms();
}
}
5.2.1打开STC-ISP软件---找到软件延时计算器,按照以下我给参数进行修改。
一步使代码变万能
软件所生成的函数是延时 500ms,就是说单片机执行这个函数的程序体时用时为 500ms,那么首先我们用 while 循环把程序体框住,然后每执行一次让控制 while 循环结束的变量减一,这个变量我们通过形参传递到函数中。
注意:当使用 _nop_() 函数(可理解为软件延时)时,必须在开头添加头文件 #include <intrins.h>。不然回报错。
- 优化后的代码如下:
void Delay500ms() //@11.0592MHz //使用STC工具中的延迟生成器自动生成延时函数
{
unsigned char i, j, k;
i = 4;
j = 129;
k = 119;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
至此,51 单片机的延时函数就编写完成啦, 快去试着生成一个延时函数,将它应用到你的项目当中吧。
1.2.2 按键控制灯
原理:按键和灯不是我们传统理解的思维,传统按键和灯是在同一个电路中的。而我们单片机编程按键
和灯是分开的两个电路,通过单片机作为媒介来处理数据,通过逻辑来实现按键控制灯
查询法按键控制灯
- 怎么知道sw1按键被按下
KEY1位置和GND接通,表现为低电平,值为0
- 怎么知道sw1按键没有被按下
KEY1位置通过上拉电阻到5V,表现为高电平,值为1
通过图a2得知
同理LED的分析,
KEY1接到STC89C52RC的P2.1口,我们只要不断检测P2.1口的值(0-按下,1-松开)就知道按键是
否被按下
- 按键控制灯
#include "reg52.h"
sbit key1 = P2^1;
sbit ledOne = P3^7;
void main()
{
while(1){
//注意:用“==”两个等于号表示判断,新手容易犯错
if(key1 == 0){ //KEY1位置和GND接通,表现为低电平,值为0
//灯亮,给一个P3.7低电平
ledOne = 0;
}
}
}
- 按键控制灯,SW1开,SW2关, 软件消除抖动
#include "reg52.h"
#include <intrins.h>
sbit key1 = P2^1;
sbit key2 = P2^0;
sbit ledOne = P3^7;
void Delay50ms() //@11.0592MHz
{
unsigned char i, j, k;
_nop_();
_nop_();
i = 3;
j = 26;
k = 223;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void main()
{
//查询法检测,是否被按下
while(1){
if(key1 == 0)//KEY1位置和GND接通,表现为低电平,值为0
{
//感觉被按下,不知道是抖动还是人为,延迟50ms再判断一次
//软件消除抖动
Delay50ms();
if(key1 == 0){
//灯亮,给一个P3.7低电平
ledOne = 0;
}
}
if(key2 == 0){//KEY2位置和GND接通,表现为低电平,值为0
Delay50ms();
if(key2 == 0){
//灯亮,给一个P3.7低电平
ledOne = 1;//灭
}
}
}
- 按键按下一次,灯状态改变
#include "reg52.h"
#include <intrins.h>
sbit key1 = P2^1;
sbit key2 = P2^0;
sbit ledOne = P3^7;
void Delay50ms() //@11.0592MHz
{
unsigned char i, j, k;
_nop_();
_nop_();
i = 3;
j = 26;
k = 223;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void main()
{
ledOne = 1; //初始灯是灭的状态
//查询法检测,是否被按下
while(1){
if(key1 == 0)//KEY1位置和GND接通,表现为低电平,值为0
{
//感觉被按下,不知道是抖动还是人为,延迟50ms再判断一次
//软件消除抖动
Delay50ms();
if(key1 == 0){
//记住,key1被按下,记住,在其他地方点灯
ledOne = !ledOne;
}
}
if(key2 == 0){//KEY2位置和GND接通,表现为低电平,值为0
ledOne = 1;
}
}
}
- 状态位来控制LED
#include "reg52.h"
#include <intrins.h>
#define ON_STATUS 1
#define OFF_STATUS 0
sbit key1 = P2^1;
sbit key2 = P2^0;
sbit ledOne = P3^7;
void Delay10ms() //@11.0592MHz
{
unsigned char i, j;
i = 18;
j = 235;
do
{
while (--j);
} while (--i);
}
void main()
{
int ledMark = OFF_STATUS;
ledOne = 1; //初始灯是灭的状态
//查询法检测,是否被按下
while(1){
if(key1 == 0)//KEY1位置和GND接通,表现为低电平,值为0
{
//感觉被按下,不知道是抖动还是人为,延迟50ms再判断一次
//软件消除抖动
Delay10ms();
if(key1 == 0){
//记住,key1被按下,记住,在其他地方点灯
ledMark = ON_STATUS;
}
}
Delay10ms();
if(key2 == 0){//KEY2位置和GND接通,表现为低电平,值为0
ledMark = OFF_STATUS;
}
if(ledMark == OFF_STATUS){
ledOne = 1;
}
else{
ledOne = 0;
}
}
}
六、入门项目电动车报警器
1.3.1 硬件清单列表
振动传感器模块,继电器模块,433M无线模块,反应出来的代码都是高低电平,跟以上学习按键,LED
并没有区别
但是!做出来有乐趣,好玩刺激。
1.3.2 振动传感器控制灯
通过我们已经掌握的LED来了解下振动传感器是怎么回事
- 如何知道是否发生振动
振动传感器检测是否有振动产生。
- 振动后的信号表现又是什么
传感器监测到振动之后,向I|0输出低电压。绿灯会亮。如果没有监测到振动时,就输出高电压
- 振动传感器控制灯
#include "reg52.h"
sbit led1 = P3^7;//根据原理图(电路图),设备变量led1指向P3组IO口的第7口
sbit vibrate = P3^3;//Do接到了P3.3口 振动传感器
void Delay2000ms() //@11.0592MHz
{
unsigned char i, j, k;
// _nop_();
i = 15;
j = 2;
k = 235;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void main()
{
//查询方式判断是否发生震动
while(1){
if(vibrate == 0)//模块说明告诉我们,震动的话,D0输出低电平
{
led1 = 0;//亮灯
Delay2000ms(); // 延迟2秒
led1 = 1;
}
else{
led1 = 1;//灭灯
}
}
1.3.3 继电器工作逻辑
其实就是电子开关,怎么开怎么关弄清楚就可以了
- 怎么控制“闭合”开关呢
-
- 传感器监测到振动之后,向I|0输出低电压。继电器开关闭合。
- 怎么控制"断开"开关呢
-
- 默认是闭合状态,如果没有监测到振动时,就输出高电压,继电器开关闭合。
通过继电器来控制电路,比如智能插座,比如220V的灯,比如我们项目不带开关的傻瓜式报警器
当设置继电器为低电平处罚时,STC89C52RC的IO输出低电平,就会导致COM口和NO口闭合,也
就是完成报警器的串联电路,开始响
现在我们就可以来写程序,完成振动控制警报的功能
#include "reg52.h"
sbit vibrate = P3^3;//Do接到了P3.3口
sbit switcher = P1^1; //继电器
void Delay2000ms() //@11.0592MHz
{
unsigned char i, j, k;
// _nop_();
i = 15;
j = 2;
k = 235;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void main()
{
//查询方式判断是否发生震动
while(1){
if(vibrate == 0)//模块说明告诉我们,震动的话,D0输出低电平
{
//当发生震动适合,导通继电器,给继电器IN一个低电平
switcher = 0;
Delay2000ms(); //闭合两秒之后,继电器断开
switcher = 1;//高电平,继电器N0和COM不通
}
else{
switcher = 1;
}
}
}
1.3.4 遥控发送接收433M
https://wenku.baidu.com/view/8fe8f444bed5b9f3f80f1c33.html
- 遥控按下后信号怎么被接收
- 接收后的信号表现又是什么
-
- 默认低电平,按键之后是高电平。
- 遥控控制LED
#include "reg52.h"
sbit D0_ON = P1^2; //遥控传感器 A键
sbit D1_OFF = P1^3; //遥控传感器 B键
sbit switcher = P1^1; // 继电器
void main()
{
//查询方式哪个按键被按下
while(1)
{
if(D0_ON == 1)//收到遥控信号A,D0表现为高电平
{
//A被按下,我们导通继电器,给继电器IN一个低电平
switcher = 0; //喇叭报警
}
if(D1_OFF == 1)//收到遥控信号C,D1表现为高电平
{
//B被按下,我们不导通继电器,给继电器IN一个高电平
switcher = 1; //喇叭关闭
}
}
}
1.3.4 项目开发
接线
- 开发流程代码
#include "reg52.h"
#include<intrins.h>
#define J_ON 1
#define J_OFF 0
sbit switcher = P1^0; // 继电器
sbit D0_ON = P1^1; // A 键
sbit D1_OFF = P1^2; // B 键
sbit vibrate = P1^3; // 振动传感器
void Delay2000ms() //@11.0592MHz
{
unsigned char i, j, k;
_nop_();
i = 15;
j = 2;
k = 235;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void Delay500ms() //@11.0592MHz
{
unsigned char i, j, k;
_nop_();
i = 4;
j = 129;
k = 119;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void main()
{
int mark = J_OFF;
while(1)
{
//1. 如果a按键被按下,设定为开启警报模式
if(D0_ON == 1){
//长响,表示进入警报模式
switcher = 0;
Delay2000ms();
switcher = 1;
//设定警报模式标记
mark = J_ON ;
}
//2. 如果b按键被按按下,设定为关闭警报模式
if(D1_OFF == 1){
//短响,表示进入解除警报模式
switcher = 0;
Delay500ms();
switcher = 1;
//设定警报解除模式标记
mark = J_OFF ;
}
//3. 如果标记是在警报模式下
if(mark == J_ON){
//3.1 如果发生了震动
if(vibrate == 0){
//喇叭响,给继电器低电平,导通
switcher = 0;
Delay2000ms();//闭合2秒之后,继电器断开
switcher = 1;//高电平,继电器N0和COM不通
}//3.2 如果不发生震动
else{
//喇叭不响,给继电器高电平,不导通
switcher = 1;
}
}
}
}