【金善愚】 单片机应用实践——基础篇 笔记整理
课程视频 :https://space.bilibili.com/483942191/channel/collectiondetail?sid=144001
仿真软件:Proteus 8.13
安装链接:https://pan.baidu.com/s/1-1fscykdvulV60xA4Hygaw?pwd=xeob
代码软件:Keil μvision V5.14.2
安装链接:https://pan.baidu.com/s/1MRdG2EkxORr6M6XH-n5ang?pwd=l2rm
文章目录
一、点亮LED 灯
1.仿真原理图
电阻 RES
电容 CAP
晶振 crystal
按键 button
2.代码
//包含单片机的头文件,建立软件和硬件的联系
#include<reg51.h>
//sbit LED0 = P1^0; //位操作,取P1的0位命名为LED
//sbit LED1 = P1^1;
//sbit LED2 = P1^2;
//sbit LED3 = P1^3;
void main()
{
while(1) //保持循环执行
{
P1 = 0xF0; //P1.7 - P1.0 赋值 1111_0000
//LED0 = 0;
//LED1 = 0;
//LED2 = 0;
//LED3 = 0; //P1其他位默认为1
}
}
2.软硬件关联
(1)生成HEX文件
a.点击图示的快捷图标
b.生成
c.编译
d.文件位置
(2)仿真中关联代码
a.双击单片机,找到HEX文件位置,关联代码
(3)开始仿真
二、LED 闪烁
1.基本数据类型
2.代码
(1)用循环语句方式
#include<reg5l.h>
void main ( )
{
unsigned int i;//无符号整形0~65535
while (1)
{
i =20000;
P1 = 0xFO;//1111 0000
while ( i--)
{
}
i = 20000;
P1 = 0x0F;//0000 1111
while ( i--);
//for(i = 0 ; i<50000;i++) //用for语句
}
}
(2)用延时函数方式
#include<reg51.h>
void delay();//声明函数
void main()
{
while(1)
{
P1 = 0xf0;
delay();
P1 = 0x0f;
delay();
}
}
void delay()
{
unsigned int ms = 500000;
while(ms--)
{
}
}
(3)用带参数的延时函数
/****************************************
功 能:带有参数的延时函数实现小灯的闪烁
时 间:****/**/**
****************************************/
#include<reg51.h>
//声明引脚
sbit LED = P1^7;
//函数声明
void DelayXms(unsigned int xms);
/****************************************
函数名: main
功 能: 主函数
参 数: 无
返回值: 无
****************************************/
void main()
{
while(1)
{
LED = 0;
DelayXms(1000);//调用函数
LED = 1;
DelayXms(1000);
}
}
/****************************************
函数名: DelayXms
功 能: 延时函数
参 数: unsigned int
返回值: 无
****************************************/
void DelayXms(unsigned int xms)
{
unsigned int i,j; // 0 -65535 0000H - FFFFH
for(i = xms;i>0;i--)
{
for(j = 124;j>0;j--)
{
}
}
}
2.调试
(1)设置
晶振和仿真
(2)进入调试模式
(3)时间等状态
(4)分步调试
①运行到鼠标所在位置
②单步运行
③进入函数
④运行全部(直至断点)
⑤设置断点
二、LED 流水灯
1.用简单顺序语句的方法实现
#include<reg51.h>
void DelayXms(unsigned int xms); //函数声明,或者将延迟函数放在main()函数前面,否则会报错
void main()
{
while(1)
{
P1 = 0xfe; //1111 1110
DelayXms(1000); //调用函数
P1 = 0xfd; //1111 1101
DelayXms(1000);
P1 = 0xfb; //1111 1011
DelayXms(1000);
P1 = 0xf7; //1111 0111
DelayXms(1000);
P1 = 0xef; //1110 1111
DelayXms(1000);
P1 = 0xdf; //1101 1111
DelayXms(1000);
P1 = 0xbf; //1011 1111
DelayXms(1000);
P1 = 0x7f; //0111 1111
DelayXms(1000);
}
}
//延时函数
void DelayXms(unsigned int xms)
{
unsigned int i,j; // 0 -65535 0000H - FFFFH
for(i = xms;i>0;i--)
for(j = 124;j>0;j--);
}
2.用数组的方法实现(多文件)
1.创建工程目录下新建4个文件夹,并修改设置下的存放路径
Listings 放中间文件
Output 放输出HEX等文件
Project 放工程文件
Source 放 .c、 .h文件
2.创建模块的 .c文件并创建其对应的.h文件
- .c文件负责函数的定义及变量的定义
- .h文件负责函数的声明及变量的声明(不允许赋初值)以及常量和I/O口的宏定义
(1) delay.c
#include"delay.h" //""头文件会在当前目录下查找。< >头文件一般是系统头文件,会在安装目录下寻找
/*************************************
函数名:DelayXms
功 能:毫秒级延时函数
参 数: unsigned int(1 - 65535)
返回值:无
***********************************/
void DelayXms(unsigned int xms)
{
unsigned int i,j; // 0 -65535 0000H - FFFFH
for(i = xms;i>0;i--)
for(j = 124;j>0;j--);
}
(2) delay.h
#ifndef __DELAY_H__
#define __DELAY_H__
void DelayXms(unsigned int xms); //声明加分号
#endif
2.创建main函数的 .c文件,可直接引用模块头文件使用
main.c
#include<reg51.h>
#include"delay.h"
unsigned char code LEDBUF[] = {
0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};
//创建数组,常量可存放在ROM中,添加关键词code。变量可存放在RAM中
void main()
{
unsigned char cnt;//unsigned char 类型范围是0 -255
while(1)
{
for (cnt = 0; cnt<8;cnt++)
{
P1 = LEDBUF[cnt];
DelayXms(1000);
}
}
}
3.用库函数的方法实现
1._crol_函数
_crol_函数功能:将 c 进行b位左位移,并将值以unsigned char类型返回
//文档定义
#include <intrins.h>
unsigned char _crol_ (
unsigned char c, /* character to rotate left */
unsigned char b); /* bit positions to rotate */
函数返回类型为unsigned char,函数的两个形参也是unsigned char类型。
c 为要被进行 位左移 的形式参数
b 为要进行的 位移数
注释:向左循环移位时,从左边出去会从右边重新补入
2._cror_函数
与_crol_函数类似,区别只是进行的是右位移
注释:向右循环移位时,从右边出去会从左边重新补入
3.main.c 代码
#include<reg51.h>
#include <intrins.h>
#include"delay.h"
void main()
{
unsigned char temp = 0xfe; //1111 1110
while(1)
{
P1 = temp;
temp = _crol_(temp,1);
DelayXms(1000);
}
}
4.用移位运算符的方法实现
1.位运算符 及 位表达式
⚠️注意:位表达式c<<1的值是0011 1100B,而c的值并未改变,仍是1001 1110B。移出补0。
2.代码
(1)main.c 用移位+补位方法
#include<reg51.h>
#include <intrins.h>
#include"delay.h"
void main()
{
unsigned char temp = 0xfe; //1111 1110
while(1)
{
P1 = temp; // 输出
DelayXms(1000); // 延时
if (temp & 0x80) // 判断temp最高位是否为1
{
temp = temp<<1; // 左移
temp = temp|1; // 如果左移之前temp最高位为1,则在temp的最低位补1
}
else
{
temp<<=1; // 左移
}
}
}
(2)main.c 用反向方法
#include<reg51.h>
#include <intrins.h>
#include"delay.h"
void main()
{
unsigned char temp = 0x1; //0000 0001
unsigned char i;
while(1)
{
P1 = ~(temp<<i++);
DelayXms(1000);
if (8 == i) i=0;
}
}
三、蜂鸣器
1.蜂鸣器工作电路
图中 D4为 续流二极管:
一种配合电感性负载使用的二极管,当电感性负载的电流有突然的变化或减少时,电感二端会产生突变电压,可能会破坏其他元件。配合续流二极管时,其电流可以较平缓地变化,避免突波电压的发生。
2.仿真原理图
3.代码
#include<reg51.h>
#include"delay.h"
sbit Sound = P3^7;
void main()
{
unsigned int i;
while(1)
{
for(i = 0;i<100;i++)
{
Sound = ~Sound;
DelayXms(1);
}
for(i = 0;i<100;i++)
{
Sound = ~Sound;
DelayXms(5);
}
}
}
四、数码管
1.静态显示
(1)仿真原理图
数码管seg
CC-共阴
CA-共阳
(2)代码
#include<reg51.h>
void main()
{
while(1)
{
P2 = 0xc0;
}
}
2.动态显示
(1)仿真原理图
(2)代码
#include<reg51.h>
#include"delay.h"
void DelayXms();
unsigned char code leddata[] = {
//数码管的段码表
0x3F, //0
0x06, //1
0x5B, //2
0x4F, //3
0x66, //4
0x6D, //5
0x7D, //6
0x07, //7
0x7F, //8
0x6F //9
};
unsigned char LEDBuf[] = {
0,3,0,5};//数据缓存区
void main()
{
while(1)
{
P2 = 0xfe;//1111 1110 第一个数码管的位选打开,其他的关掉,打开第一个
P0 = leddata[LEDBuf[0]];
DelayXms(10);
P2 = 0xfd;//1111 1101 第一个数码管的位选关掉,同时打开第二个数码管的位选
P0 = leddata[LEDBuf[1]];
DelayXms(10);
P2 = 0xfb;//1111 1011 第二个数码管的位选关掉,同时打开第三个数码管的位选
P0 = leddata[LEDBuf[2]];
DelayXms(10);
P2 = 0xf7;//1111 0111 第三个数码管的位选关掉,同时打开第四个数码管的位选
P0 = leddata[LEDBuf[3]];
DelayXms(10);
}
}
(3)模块化
display.h
#ifndef __DISPLAY_H__
#define __DISPLAY_H__
#include <reg51.h>
#include "delay.h"
//宏定义
#define GPIO_DIG P0 //段码IO
#define GPIO_PLACE P2 //位选IO
#define N 4 //数码管的个数
//变量声明
unsigned char code leddata[];
extern unsigned char LEDBuf[]; //定义成外部变量
//函数声明
void Display();
#endif
display.c (if语句实现)
#include "display.h"
#include "delay.h"
unsigned char LEDBuf[] = {
0,6,2,3};//数据缓存区
unsigned char code PLACE_CODE[] = {
0xfe,0xfd,0xfb,0xf7};//数码管位选信号
//数码管的段码表
unsigned char code leddata[] = {
0x3F, //0
0x06, //1
0x5B, //2
0x4F, //3
0x66, //4
0x6D, //5
0x7D, //6
0x07, //7
0x7F, //8
0x6F, //9
0x77, //A 10
0x7C, //B 11
0x39, //C 12
0x5E, //D 13
0x79, //E 14
0x71, //F 15
0x76, //H 16
0x38, //L 17
0x37, //N 18
0x3E, //U 19
0x73, //P 20
0x5C, //O 21
0x40, //- 22
0x00, //熄灭 23
};
void Display()
{
//static unsigned char i = 0; //静态变量,只在第一次初始化有效
unsigned char i;
//1.送位选
GPIO_PLACE = PLACE_CODE[i];
//2.送段码
GPIO_DIG = leddata[LEDBuf[i]];
//3.延时 1ms <10ms
DelayXms(10);
//4.消隐
GPIO_DIG = 0x00;
i++;
if (N == i)
i = 0;
}
display.c (switch case 语句实现)
void Display()
{
//static unsigned char i = 0; //静态变量,只在第一次初始化有效
unsigned char i;
//1.送位选
//2.送段码
//3.延时 1ms <10ms
//4.消隐
switch(i)
{
case 0:
GPIO_PLACE = leddata[LEDBuf[0]];
GPIO_PLACE = PLACE_CODE[0];
DelayXms(10);
GPIO_DIG = 0x00;
i++;
break;
case 1:
GPIO_PLACE = leddata[LEDBuf[1]];
GPIO_PLACE = PLACE_CODE[1];
DelayXms(10);
GPIO_DIG = 0x00;
i++;
break;
case 2:
GPIO_PLACE = leddata[LEDBuf[2]];
GPIO_PLACE = PLACE_CODE[2];
DelayXms(10);
GPIO_DIG = 0x00;
i++;
break;
case 3:
GPIO_PLACE = leddata[LEDBuf[3]];
GPIO_PLACE = PLACE_CODE[3];
DelayXms(10);
GPIO_DIG = 0x00;
i = 0;
break;
default:break;
}
}
main.c
#include <reg51.h>
#include "display.h"
#include "delay.h"
void main()
{
while(1)
{
Display();
}
}
3.应用层程序开发
项目1:数码管开机初始显示 - - - -,正常运行时显示4567
main.c
#include <reg51.h>
#include "display.h"
#include "delay.h"
void main()
{
unsigned int i;
for(i = 0;i<500;i++)
{
Display();
}
while(1)
{
LEDBuf[0] = 4; //调用前修改底层参数值
LEDBuf[1] = 5;
LEDBuf[2] = 6;
LEDBuf[3] = 7;
Display();
}
}
项目2:显示任意4位十进制数
main.c
#include <reg51.h>
#include "display.h"
#include "delay.h"
void main()
{
unsigned int i; //0 - 65535
unsigned int num = 1995; //十进制数
for(i = 0;i<500;i++)
{
Display();
}
while(1)
{
LEDBuf[0] = num/1000;
LEDBuf[1] = num/100%10;
LEDBuf[2] = num/10%10;
LEDBuf[3] = num%10;
Display();
}
}
项目3:逐渐加1
#include <reg51.h>
#include "display.h"
#include "delay.h"
void main()
{
unsigned int i; //0 - 65535
unsigned int num = 1995; //十进制数
for(i = 0;i<500;i++)
{
Display();
}
while(1)
{
LEDBuf[0] = num/1000;
LEDBuf[1] = num/100%10;
LEDBuf[2] = num/10%10;
LEDBuf[3] = num%10;
for(i = 0;i<50;i++) //延时
{
Display();
}
num++;
if (num >2000)
num = 1994;
}
}
项目4:
1、开机时显示闪烁的8888
2、正常工作时,需要分时显示2个参数,大概每隔2S切换显示一个参数
3、 参数1的范围是0-3
参数2的范围是0-99
中间用 - 隔开
main.c