LED灯
接口:P2_1=0(低电平)
P2=0x3C 放在循环外更高效
点亮:直接用P2=0x3C
闪烁:加延迟
流水灯:每个都亮一次+延迟
延迟设置:12MHz,1毫秒,Y1(51系列)
定义头文件:<INTRINS.H>
——任意数值延迟
void Delay1ms(unsigned int xms) //@12.000MHz
{
unsigned char i, j;
while(xms)
{
i = 2;
j = 239;
do
{
while (--j);
} while (--i);
xms--;
}
}
独立按键
接口:P3_1==0(低电平)
单个使用
void main()
{
while(1)
{
if(P3_0==0)
{
Delay(20);
while(P3_0==0);
Delay(20); //消抖
P2_1=~P2_1; //需要操作的按键
}
}
}
多个使用的模块化处理
Key.c
#include <REGX52.H>
#include "Delay.h"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
main.c 主程序使用该功能
#include <REGX52.H>
#include "Delay.h"unsigned char Key();
unsigned char KeyNum;void main()
{
while(1)
{
KeyNum=Key();
if(KeyNum)
{
if(KeyNum==1)P2_1=~P2_1;
if(KeyNum==2)P2_2=~P2_2;
if(KeyNum==3)P2_3=~P2_3;
if(KeyNum==4)P2_4=~P2_4;
}
}
}
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;
}
静态数码管
显示一个数字
unsigned char a[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};
/*共阴极,高电平有效,分别是0,1,2,3,4,5,6,7,8,9*/
void NT(unsigned char loc,num) //什么位置,显示什么数字
{
switch(loc) //什么位置
{
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;/*P2_4是最高位,P2_2是最低位,高电平有效,想要显示*/
}
P0=a[num]; //显示什么数字,在上面的数组里0~9
}void main()
{
NT(6,8); //什么位置,显示什么数字
while(1)
{
}
}
显示多个数字
加上延迟即可
unsigned char a[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};
/*此处调用延迟函数*/
void NT(unsigned char loc,num)
{
switch(loc)
{
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=a[num];
Delay(1);
P0=0x00; //消影
}void main()
{
while(1)
{
NT(1,1);
Delay(1);
NT(2,4);
Delay(1);
NT(3,7);Delay(1);
}
补充:模块化
创建 .c 项目文件
记录函数
创建 .h 项目文件
#ifndef __函数名_H__
#define __函数名_H__函数; //.c的函数
#endif
主文件:
开头处引用函数
例如:#include "shuma.h" //内部引用使用双引号
液晶屏LCD1602
使用前提:需要有LCD1602.c和LCD1602.h文件,并在开头处调用(模块化知识)
void main()
{
LCD_Init(); //上电初始化,必写
LCD_ShowChar(1,1,'B'); //行,列,显示字符
LCD_ShowString(1,3,"hello"); //行,列,显示字符串
LCD_ShowNum(1,9,123,3); //行,列,显示数字,位数
LCD_ShowSignedNum(1,13,-66,2); //行,列,有符号数字,位数(不包括符号)
while(1)
{
}
}
计数器功能
#include "LCD1602.h"
#include "Delay.h"int result=0; //赋初值
void main()
{
LCD_Init();
while(1)
{
result++; //自加
Delay(1000); //延迟一秒
LCD_ShowNum(1,1,result,3); //反复显示,放在循坏外则无变化
}
}
矩阵键盘
由于引脚冲突,采用逐列扫描
MatrixKey.c
#include <REGX52.H>
#include "Delay.h"unsigned char MatrixKey()
{
unsigned char KeyNumber=0;
P1=0xFF; //赋初值:1111 1111
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
密码锁功能
unsigned char KeyNum;
unsigned int password,count;void main()
{
LCD_Init(); //上电初始化
LCD_ShowString(1,1,"password"); //第一行,第一列,显示"password"
while(1)
{
KeyNum=MatrixKey(); //键盘输入
if(KeyNum!=0)
{
if(KeyNum<=10)
{
if(count<4) //计数,小于4次,意思是四位密码
{
password*=10; //密码左移一位;
password+=KeyNum%10; //1~9对10取余还是本身;
count++;
}
}
LCD_ShowNum(2,1,password,4);
}
if(KeyNum==11) //“确认”功能
{
if(password==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) //手动“清零”功能
{
password=0;
count=0; //清零
LCD_ShowNum(2,1,password,4); //更新显示
}
}
}
定时器
内部定时器:三个(T0,T1,T2)
有四种工作模式,常用模式1:16位定时器/计数器
细分三个部分:时钟——计数——中断
(每来一个时钟脉冲就进行计数,加到溢出就申请中断,中断结束回到主程序)
时钟部分:
若接T0 pin_外部引脚:计数器
只用内部晶振_12MHz:定时器
相关寄存器
关于寄存器的理解:
灯和开关的关系,开关可以简单理解为是个寄存器。
具体配置需要阅读手册,查看每个位的功能进行配置,把二进制转化为十六进制进行置位。
可位寻址:可以单个位赋值;不可位寻址:只能整体赋值
定时器的寄存器:
TCON 定时器/计数器中断控制寄存器:可位寻址
TF0=0;//清除TF0标志
TR0=1; //定时器开始工作
TMOD 定时器/计数器工作模式寄存器:不可位寻址
“与或式赋值法”,操作某一位而不影响其他位:模式1
TMOD=TMOD&0xF0 //高四位保持不变,低四位清零
TMOD=TMOD|0x01 //高四位保持不变,第四位置1
TL0/TH0 定时器0,高位和低位计数单元:赋初值_1毫秒
TH0=0x18 //高位
TL0=0xFC //低位
TL1/TH1 定时器1,高位和低位计数单元:使用计数器0时,此定时器用不上
中断寄存器:
IE 中断允许寄存器:
ET0=1;
EA=1;
IP 中断优先级中断寄存器:
PT0=0;
定时器功能
Timer0.c //定时器0初始化,1毫秒
void Timer0_Init(void)
{
TMOD &= 0xF0;
TMOD |= 0x01;
TF0 = 0;
TR0 = 1;
TL0 = 0x18;
TH0 = 0xFC;
ET0=1;
EA=1;
PT0=0; //中断
}/*定时器中断函数模板
void Timer0_Routine() interrupt 1
{
static unsigned int T0count;
TL0 = 0x18; //定时初值
TH0 = 0xFC; //定时初值
T0count++;
if(T0count>=1000) //1秒
{
T0count=0; //清零
执行某个任务;
}
}*/
Timer0.h
#ifndef __TIMER0_H__
#define __TIMER0_H__void Timer0_Init(void);
#endif
main主函数 :
#include <REGX52.H>
#include "Delay.h"
#include "LCD1602.h"
#include "Timer0.h" //所需的头文件(前文有提到)unsigned char sec=55,min=59,hour=23; //赋初值,秒分时
/*主函数*/
void main()
{
LCD_Init(); //上电初始化
Timer0_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) //1秒
{
T0count=0; //清零
sec++;
if(sec>=60)
{
sec=0;
min++;
if(min>=60)
{
min=0;
hour++;
if(hour>=24)
{
hour=0;
}
}
}
}
}
串口
89C52有1个UART(UART是常用的接口,引脚定义TXD,RXD)
有四种工作模式,常用的是模式1:8位UART,波特率可变
相关寄存器
串口部分:
SCON 串行控制寄存器: 模式1
SCON=0x40(01000000)
PCON 电源控制寄存器:前两位控制串口
PCON=PCON|0x80
SBUF 串行口缓存寄存器:
void UART_SendByte(unsigned char Byte)
{
SBUF=Byte; //SBUF在等号左边:写入
while(TI==0); //判断“发送中断请求标志位”是否为1
TI=0; //一旦为1,就要置0,完成数据发送
}
定时器部分:
TMOD 定时器/计数器工作模式寄存器:不可位寻址
定时器1模式2(串口专用)
TMOD=TMOD&0x0F //低四位保持不变,高四位清零
TMOD=TMOD|0x20 //低四位保持不变,第三位置1
TL0/TH0 定时器1,高位和低位计数单元:波特率设置
TH1=0xF3 //设定定时初值
TL1=0xF3 //设定定时器重装值
IE 中断允许寄存器:
ET1=0;
TCON 定时器/计数器中断控制寄存器:可位寻址
TR1=1; //定时器开始工作
模块化处理
UART.c
#include <REGX52.H>
void UART_Init(void) //串口初始化,4800bps@11.0592MHz
{
PCON &= 0x7F;
SCON = 0x50; //0x50能够接收数据,0x40只能发不能接收
TMOD &= 0x0F;
TMOD |= 0x20;
TL1 = 0xFA;
TH1 = 0xFA;
ET1 = 0;
TR1 = 1;
}void UART_SendByte(unsigned char Byte) //串口发送一个字节的数据
{
SBUF=Byte;
while(TI==0);
TI=0;
}
UART.h
#ifndef __UART_H__
#define __UART_H__void UART_Init(void);
void UART_SendByte(unsigned char Byte);#endif
功能实现
功能1:单片机向电脑发送数据
模块化处理后,只需要调用UART_SendByte()函数
void main()
{
UART_Init();
UART_SendByte(0x66); //单向发送数据
while(1)
{
}
}
功能2:电脑向单片机发送数据
模块化处理后,需要配置中断
void main()
{
UART_Init();
while(1)
{}
}void UART_Routine() interrupt 4
{
if(RI==1)
{
P2=~SBUF; //点亮LED灯
RI=0;
}
}
LED点阵屏显示
74HC595
类型:串行输入并行输出的位移寄存器
SER:串行数据输入
SERCLK:移位寄存器时钟
RCLK:存储寄存器时钟
工作模式:输入数据到SER,SERCLK中每来一个高电平就会往前移一位,RCLK中来一个高电平就会实现位移
模块化处理
Matrix_LED.c
#include <REGX52.H>
#include "Delay.h"sbit RCK=P3^5;
sbit SCK=P3^6;
sbit SER=P3^4;#define MATRIX_LED_PORT P0
void _74HC595_WriteByte(unsigned char Byte)
{
unsigned char i;
for(i=0;i<8;i++)
{
SER=Byte&(0x80>>i);
SCK=1;
SCK=0;
}
RCK=1;
RCK=0;
}void MatrixLED_Init()
{
SCK=0;
RCK=0;}
void MatruxLED_showcolum(unsigned char Column,Date) //列,显示的数字
{
_74HC595_WriteByte(Date);
MATRIX_LED_PORT=~(0x80>>Column);
Delay(1);
MATRIX_LED_PORT=0xFF;
}
Matrix_LED.h
#ifndef __MATRIX_LED_H__
#define __MATRIX_LED_H__void _74HC595_WriteByte(unsigned char Byte);
void MatrixLED_Init();
void MatruxLED_showcolum(unsigned char Column,Date);#endif
功能:斜对角点亮LED点阵屏
void main()
{MatrixLED_Init();
while(1)
{
MatruxLED_showcolum(0,0x3C);
MatruxLED_showcolum(1,0x42);
MatruxLED_showcolum(2,0xA9);
MatruxLED_showcolum(3,0x85);
MatruxLED_showcolum(4,0x85);
MatruxLED_showcolum(5,0xA9);
MatruxLED_showcolum(6,0x43);
MatruxLED_showcolum(7,0x3C);
}
}