所用软件 https://pan.baidu.com/s/1vDTN2o8ffvczzNQGfyjHng 提取码:gdzf,链接里压缩包的解压密码:51
单片机:AT89C52 普中科技
目录
1、点亮一个LED灯
先安装这个程序,识别单片机
打开keil5软件,新建项目
#include <REGX52.H>
void main()
{
//二进制转化为十六进制
P2=0x55;//0101 0101 间隔亮灭
while(1)
{
}
}
十进制 | 二进制 | 十六进制 | 十进制 | 二进制 | 十六进制 |
0 | 0000 | 0 | 8 | 1000 | 8 |
1 | 0001 | 1 | 9 | 1001 | 9 |
2 | 0010 | 2 | 10 | 1010 | A |
3 | 0011 | 3 | 11 | 1011 | B |
4 | 0100 | 4 | 12 | 1100 | C |
5 | 0101 | 5 | 13 | 1101 | D |
6 | 0110 | 6 | 14 | 1110 | E |
7 | 0111 | 7 | 15 | 1111 | F |
2.LED灯闪
#include <REGX52.H>
#include <INTRINS.H>
void Delay500ms() //@12.000MHz
{
unsigned char i, j, k;
_nop_();
i = 4;
j = 205;
k = 187;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void main()
{
while(1)
{
P2=0x55;
Delay500ms();
P2=0xFF;
Delay500ms();
}
}
编译
生成文件
然后按下单片机电源键,
3.LED流水灯
#include <REGX52.H>
void Delay500ms() //@12.000MHz
{
unsigned char i, j, k;
i = 4;
j = 205;
k = 187;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void main()
{
while(1)
{
P2=0xFE;//1111 1110
Delay500ms();
P2=0xFD;//1111 1101
Delay500ms();
P2=0xFB;//1111 1011
Delay500ms();
P2=0xF7;//1111 0111
Delay500ms();
P2=0xEF;//1110 1111
Delay500ms();
P2=0xDF;//1101 1111
Delay500ms();
P2=0xBF;//1011 1111
Delay500ms();
P2=0x7F;//0111 1111
Delay500ms();
}
}
4.LED流水灯Plus(自定义延时时间)
在下面的程序中使用到了数据类型unsigned int xms,即xms在单片机中能表示0~65535
#include <REGX52.H>
void Delay1ms(unsigned int xms) //@12.000MHz
{
unsigned char i, j;
while(xms)
{
i = 2;
j = 239;
do
{
while (--j);
} while (--i);
xms--;
}
}
void main()
{
P2=0xFE;//1111 1110
Delay1ms(500);
P2=0xFD;//1111 1101
Delay1ms(500);
P2=0xFB;//1111 1011
Delay1ms(500);
P2=0xF7;//1111 0111
Delay1ms(500);
P2=0xEF;//1110 1111
Delay1ms(500);
P2=0xDF;//1101 1111
Delay1ms(500);
P2=0xBF;//1011 1111
Delay1ms(500);
P2=0x7F;//0111 1111
Delay1ms(500);
}
5.独立按键控制LED
#include <REGX52.H>
void main()
{
while(1)
{
if(P3_1==0)//按键K1针脚连接单片机P3_1
{
P2_0=0;
}
else
{
P2_0=1;
}
}
}
6.独立按键控制LED亮灭
因为按键按下去会有抖动,因此设置延时时间。
类别 | 运算符 | 意义 | 类别 | 运算符 | 意义 |
算术 | + | 加 | 逻辑 | && | 逻辑与 |
- | 减 | || | 逻辑或 | ||
* | 乘 | ! | 逻辑非 | ||
/ | 除 | 位运算 | << | 按位左移 | |
% | 取余 | >> | 按位右移 | ||
= | 赋值 | & | 按位与 | ||
判断 | > | 大于 | | | 按位或 | |
>= | 大于等于 | ^ | 按位异或 | ||
< | 小于 | ~ | 按位取反 | ||
<= | 小于等于 | ||||
== | 等于 | ||||
!= | 不等于 |
语句 | 解释 | 语句 | 解释 |
if(逻辑表达式) { 语句体1; } else { 语句体2; } | 如果逻辑表达式成立 执行语句体1 否则 执行语句体2 (else可以不写) | for(初始化;逻辑表达式;更改条件) { 循环体; } | 先执行初始化 再判断逻辑表达式 若成立则执行循环体 执行后更改条件 再判断逻辑表达式 直到表达式不成立 |
while(逻辑表达式) { 循环体; } | 如果逻辑表达式成立 执行循环体 执行后再次判断 若还成立则继续执行直到表达式不成立 | switch(变量) { case 常量1:语句体1;break; case 常量2:语句体2;break; (...) default:语句体x;break; } | 将变量与case后的各个常量对比 若有相等,则执行相应的语句体 若没有一个相等,则执行default后的语句体 (default可以不写) |
#include <REGX52.H>
void Delay(unsigned int xms) //@12.000MHz
{
unsigned char i, j;
while(xms)
{
i = 2;
j = 239;
do
{
while (--j);
} while (--i);
xms--;
}
}
void main()
{
while(1)
{
if(P3_1==0)
{
//按键按下去亮,松开灭
Delay(20);
while(P3_1==0);
Delay(20);
P2_0=~P2_0;//状态取反
}
}
}
7.独立按键控制LED显示二进制
#include <REGX52.H>
void Delay(unsigned int xms) //@12.000MHz
{
unsigned char i, j;
while(xms--)
{
i = 2;
j = 239;
do
{
while (--j);
} while (--i);
}
}
void main()
{
unsigned char LEDNum=0;
while(1)
{
if(P3_1==0)
{
Delay(20);
while(P3_1==0);
Delay(20);
//P2++;
//P2=~P2;这两步与结果状态相反
LEDNum++;
P2=~LEDNum;
}
}
}
8.独立按键控制LED移位
K1向左K2向右
#include <REGX52.H>
void Delay(unsigned int xms);
unsigned char LEDNum;//全局变量默认初始值为0
void main()
{
P2=~0x01;
while(1)
{
//K1控制向左移位
if(P3_1==0)
{
Delay(20);
while(P3_1==0);
Delay(20);
LEDNum++;
if(LEDNum>7)
{
LEDNum=0;
}
P2=~(0x01<<LEDNum);
}
//K2控制向右移位
if(P3_0==0)
{
Delay(20);
while(P3_0==0);
Delay(20);
if(LEDNum==0)
LEDNum=7;
else
LEDNum--;
P2=~(0x01<<LEDNum);
}
}
}
void Delay(unsigned int xms)
{
unsigned char i, j;
while(xms--)
{
i=2;
j=239;
do
{
while(--j);
}while(--i);
}
}
9.静态数码管显示
单个数码管,共阴时,拉高电压即可点亮。共阳时,拉低电平点亮。
四位一体引脚定义
实现流程
定义数组
代码书写:
数码管LED6输出低电平---->138译码器Y5--->1010(CBAY)-->P2_4=1 P2_3=0 P2_2=1
LED6显示6--->a f c d e g 为1(共阴极)
#include <REGX52.H>
void main()
{
//控制哪个LED亮
P2_4=1;
P2_3=1;
P2_2=1;
//控制LED显示的数字
P0=0x7D;
while(1)
{
}
}
#include <REGX52.H>
unsigned char NixieTable[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};
void Nixie(unsigned char Location,Number)
{
switch(Location)
{
//数码管位置
case 1:P2_4=1;P2_3=1;P2_2=1;break;
case 2:P2_4=1;P2_3=1;P2_2=0;break;
case 3:P2_4=1;P2_3=0;P2_2=1;break;
case 4:P2_4=1;P2_3=0;P2_2=0;break;
case 5:P2_4=0;P2_3=1;P2_2=1;break;
case 6:P2_4=0;P2_3=1;P2_2=0;break;
case 7:P2_4=0;P2_3=0;P2_2=1;break;
case 8:P2_4=0;P2_3=0;P2_2=0;break;
}
P0=NixieTable[Number];
}
void main()
{
Nixie(7,2);//在第7个位置显示2
while(1)
{
}
}
//数码管断码表
0 1 2 3 4 5 6 7 8 9 0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,
A B C D E F 空
0x77,0x7C,0x39,0x5E,0x79,0x71,0x00,
10.动态数码管显示
#include <REGX52.H>
unsigned char NixieTable[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};
void Delay(unsigned char xms) //@12.000MHz
{
unsigned char i, j;
while(xms--)
{
i = 2;
j = 239;
do
{
while (--j);
} while (--i);
}
}
void Nixie(unsigned char Location,Number)
{
switch(Location)
{
//
case 1:P2_4=1;P2_3=1;P2_2=1;break;
case 2:P2_4=1;P2_3=1;P2_2=0;break;
case 3:P2_4=1;P2_3=0;P2_2=1;break;
case 4:P2_4=1;P2_3=0;P2_2=0;break;
case 5:P2_4=0;P2_3=1;P2_2=1;break;
case 6:P2_4=0;P2_3=1;P2_2=0;break;
case 7:P2_4=0;P2_3=0;P2_2=1;break;
case 8:P2_4=0;P2_3=0;P2_2=0;break;
}
P0=NixieTable[Number];//显示的数字
}
void main()
{
while(1)
{
Nixie(1,1);
Delay(200);
Nixie(2,2);
Delay(200);
Nixie(3,3);
Delay(200);
}
}
消影--->防止数据篡位
#include <REGX52.H>
unsigned char NixieTable[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};
void Delay(unsigned char xms) //@12.000MHz
{
unsigned char i, j;
while(xms--)
{
i = 2;
j = 239;
do
{
while (--j);
} while (--i);
}
}
void Nixie(unsigned char Location,Number)
{
switch(Location)
{
//
case 1:P2_4=1;P2_3=1;P2_2=1;break;
case 2:P2_4=1;P2_3=1;P2_2=0;break;
case 3:P2_4=1;P2_3=0;P2_2=1;break;
case 4:P2_4=1;P2_3=0;P2_2=0;break;
case 5:P2_4=0;P2_3=1;P2_2=1;break;
case 6:P2_4=0;P2_3=1;P2_2=0;break;
case 7:P2_4=0;P2_3=0;P2_2=1;break;
case 8:P2_4=0;P2_3=0;P2_2=0;break;
}
P0=NixieTable[Number];//ÏÔʾµÄÊý×Ö
//消影
Delay(1);
P0=0x00;
}
void main()
{
while(1)
{
Nixie(1,1);
Nixie(2,2);
Nixie(3,3);
}
}
11.模块化编程
模块化编程框图
模块化实现数码管显示
main.c
#include <REGX52.H>
#include "Delay.h"
#include "Nixie.h"
void main()
{
while(1)
{
Nixie(1,1);
Nixie(2,2);
Nixie(3,3);
}
}
Delay.c
void Delay(unsigned char xms) //@12.000MHz
{
unsigned char i, j;
while(xms--)
{
i = 2;
j = 239;
do
{
while (--j);
} while (--i);
}
}
Delay.h
#ifndef __DELAY_H__
#define __DELAY_H__
void Delay(unsigned int xms);
#endif
Nixie.c
#include <REGX52.H>
#include "Delay.h"
unsigned char NixieTable[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};
void Nixie(unsigned char Location,Number)
{
switch(Location)
{
//LED灯位置
case 1:P2_4=1;P2_3=1;P2_2=1;break;
case 2:P2_4=1;P2_3=1;P2_2=0;break;
case 3:P2_4=1;P2_3=0;P2_2=1;break;
case 4:P2_4=1;P2_3=0;P2_2=0;break;
case 5:P2_4=0;P2_3=1;P2_2=1;break;
case 6:P2_4=0;P2_3=1;P2_2=0;break;
case 7:P2_4=0;P2_3=0;P2_2=1;break;
case 8:P2_4=0;P2_3=0;P2_2=0;break;
}
P0=NixieTable[Number];//显示的数字
//消影
Delay(1);
P0=0x00;
}
Nixie.h
#ifndef __NIXIE_H__
#define __NIXIE_H__
void Nixie(unsigned char Location,Number);
#endif
12.LCD 1602 调试工具
占用端口为P0口和P2口
#include <REGX52.H>
#include "LCD1602.h"
#include "Delay.h"
int Result=0;
void main()
{
LCD_Init();
//LCD_ShowChar(1,1,'A');
//LCD_ShowString(1,3,"Hello");
//LCD_ShowNum(1,9,123,3);
//Result=1+1;
//LCD_ShowNum(1,1,Result,2);//显示1+1
while(1)
{
//每秒加1
Result++;
Delay(1000);
LCD_ShowNum(1,1,Result,3);
}
}
13.矩阵键盘
编写程序,在显示屏上显示键位对应的数字
main.c
#include <REGX52.H>
#include "Delay.h"
#include "LCD1602.h"
#include "MatrixKey.h"
unsigned char KeyNum;
void main()
{
LCD_Init();
LCD_ShowString(1,1,"HelloWorld");
while(1)
{
KeyNum=MatrixKey();
if(KeyNum)
{
LCD_ShowNum(2,1,KeyNum,2);
}
}
}
MatrixKey.c
#include <REGX52.H>
#include "Delay.h"
unsigned char MatrixKey()
{
unsigned char KeyNumber=0;
//扫描第一列
P1=0xFF;
P1_3=0;
if(P1_7==0){Delay(20);while(P1_7==0);Delay(20);KeyNumber=1;}
if(P1_6==0){Delay(20);while(P1_6==0);Delay(20);KeyNumber=5;}
if(P1_5==0){Delay(20);while(P1_5==0);Delay(20);KeyNumber=9;}
if(P1_4==0){Delay(20);while(P1_4==0);Delay(20);KeyNumber=13;}
//扫描第二列
P1=0xFF;
P1_2=0;
if(P1_7==0){Delay(20);while(P1_7==0);Delay(20);KeyNumber=2;}
if(P1_6==0){Delay(20);while(P1_6==0);Delay(20);KeyNumber=6;}
if(P1_5==0){Delay(20);while(P1_5==0);Delay(20);KeyNumber=10;}
if(P1_4==0){Delay(20);while(P1_4==0);Delay(20);KeyNumber=14;}
//扫描第三列
P1=0xFF;
P1_1=0;
if(P1_7==0){Delay(20);while(P1_7==0);Delay(20);KeyNumber=3;}
if(P1_6==0){Delay(20);while(P1_6==0);Delay(20);KeyNumber=7;}
if(P1_5==0){Delay(20);while(P1_5==0);Delay(20);KeyNumber=11;}
if(P1_4==0){Delay(20);while(P1_4==0);Delay(20);KeyNumber=15;}
//扫描第四列
P1=0xFF;
P1_0=0;
if(P1_7==0){Delay(20);while(P1_7==0);Delay(20);KeyNumber=4;}
if(P1_6==0){Delay(20);while(P1_6==0);Delay(20);KeyNumber=8;}
if(P1_5==0){Delay(20);while(P1_5==0);Delay(20);KeyNumber=12;}
if(P1_4==0){Delay(20);while(P1_4==0);Delay(20);KeyNumber=16;}
return KeyNumber;
}
MatrixKey.h
#ifndef __MATRIXKEY_H__
#define __MATRIXKEY_H__
unsigned char MatrixKey();
#endif
14.矩阵键盘密码锁
#include <REGX52.H>
#include "Delay.h"
#include "LCD1602.h"
#include "MatrixKey.h"
unsigned char KeyNum;
unsigned int Password,Count;
void main()
{
LCD_Init();
LCD_ShowString(1,1,"Password:");
while(1)
{
KeyNum=MatrixKey();
if(KeyNum)
{
if(KeyNum<=10)//如果s1-s10被按下,输入密码
{
if(Count<4)//只允许输入4位
{
Password*=10;//密码左移一位
Password+=KeyNum%10;
Count++;
}
LCD_ShowNum(2,1,Password,4);//更新显示
}
if(KeyNum==11)//s11为确认键
{
if(Password==2345)//2345为正确密码
{
LCD_ShowString(1,14,"OK ");
Password=0;//密码清零
Count=0;//计次清零
LCD_ShowNum(2,1,Password,4);//更新显示
}
else
{
LCD_ShowString(1,14,"ERR");
Password=0;
Count=0;
LCD_ShowNum(2,1,Password,4);//更新显示
}
}
if(KeyNum==12)//s12设置为取消键
{
Password=0;
Count=0;
LCD_ShowNum(2,1,Password,4);//更新显示
}
}
}
}
15.定时器
定时器的核心部件是一个加法的计数器,其本质是对脉冲进行计数。
最大存储65535
压电陶瓷会发生固定频率的振动。
中断程序流程
STC89C52中断资源
定时器相关寄存器
独立按键控制流水灯
main.c
#include <REGX52.H>
#include "Timer0.h"
#include "Key.h"
#include <INTRINS.H>
unsigned char KeyNum,LEDMode;
void main()
{
P2=0xFE;
Timer0Init();
while(1)
{
KeyNum=Key();
if(KeyNum)
{
if(KeyNum==1);
{
LEDMode++;
if(LEDMode>=2)LEDMode=0;
}
}
}
}
void Timer0_Routine() interrupt 1
{
static unsigned int T0Count;
TL0 = 0x18; //设置定时初始值
TH0 = 0xFC; //设置定时初始值
T0Count++;
if(T0Count>=500)
{
T0Count=0;
if(LEDMode==0) //模式判断
P2=_crol_(P2,1); //LED输出(循环左移函数,即使流水灯循环左移)
if(LEDMode==1)
P2=_cror_(P2,1);
}
}
Timer0.c
#include <REGX52.H>
void Timer0Init(void) //1毫秒@12.000MHz
{
TMOD &= 0xF0; //设置定时器模式
TMOD |= 0x01; //设置定时器模式
TL0 = 0x18; //设置定时初始值
TH0 = 0xFC; //设置定时初始值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0=1;
EA=1;
PT0=0;
}
Timer0.h
#ifndef __TIMER0_H__
#define __TIMER0_H__
void Timer0Init(void);
#endif
Key.c
#include <REGX52.H>
#include "Delay.h"
/**
* @brief 获取独立按键键码
* @param
* @retval 按下按键的键码,范围:0-4,无按键按下返回0。
*/
unsigned char Key()
{
unsigned char KeyNumber=0;
if(P3_1==0){Delay(20);while(P3_1==0);Delay(20);KeyNumber=1;}
if(P3_0==0){Delay(20);while(P3_0==0);Delay(20);KeyNumber=2;}
if(P3_2==0){Delay(20);while(P3_2==0);Delay(20);KeyNumber=3;}
if(P3_3==0){Delay(20);while(P3_3==0);Delay(20);KeyNumber=4;}
return KeyNumber;
}
Key.h
#ifndef __KEY_H__
#define __KEY_H__
unsigned char Key();
#endif
16.制作一天时间的定时器
#include <REGX52.H>
#include "Delay.h"
#include "LCD1602.h"
#include "Timer0.h"
unsigned char Sec,Min,Hour;
void main()
{
Timer0Init();//定时器初始化
LCD_Init(); //显示屏初始化
LCD_ShowString(1,1,"Clock:");
LCD_ShowString(2,1," : :");
while(1)
{
LCD_ShowNum(2,1,Hour,2);
LCD_ShowNum(2,4,Min,2);
LCD_ShowNum(2,7,Sec,2);
}
}
void Timer0_Routine() interrupt 1
{
static unsigned int T0Count;
TL0 = 0x18;
TH0 = 0xFC;
T0Count++;
if(T0Count>=1000)
{
T0Count = 0;
Sec++;
if(Sec>=60)
{
Sec=0;
Min++;
if(Min>=60)
{
Min=0;
Hour++;
if(Hour>=24)
{
Hour=0;
}
}
}
}
}
17.串口通信
1.串口介绍
2.硬件电路
3.电平标准
单片机用TTL,电脑用RS232,RS485可传输千米
4. 通信接口